diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /libjava/classpath/java/awt | |
download | cbb-gcc-4.6.4-15d2061ac0796199866debe9ac87130894b0cdd3.tar.bz2 cbb-gcc-4.6.4-15d2061ac0796199866debe9ac87130894b0cdd3.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig;
imported gcc-4.6.4 source tree from verified upstream tarball.
downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.
if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
Diffstat (limited to 'libjava/classpath/java/awt')
363 files changed, 110260 insertions, 0 deletions
diff --git a/libjava/classpath/java/awt/AWTError.java b/libjava/classpath/java/awt/AWTError.java new file mode 100644 index 000000000..80356eee4 --- /dev/null +++ b/libjava/classpath/java/awt/AWTError.java @@ -0,0 +1,64 @@ +/* AWTError.java -- A serious AWT error occurred. + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +/** + * This error is thrown when a critical Abstract Window Toolkit (AWT) error + * occurs. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @status updated to 1.4 + */ +public class AWTError extends Error +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -1819846354050686206L; + + /** + * Create a new instance with the specified descriptive error message. + * + * @param message the descriptive error message + */ + public AWTError(String message) + { + super(message); + } +} // class AWTError diff --git a/libjava/classpath/java/awt/AWTEvent.java b/libjava/classpath/java/awt/AWTEvent.java new file mode 100644 index 000000000..c4f772827 --- /dev/null +++ b/libjava/classpath/java/awt/AWTEvent.java @@ -0,0 +1,399 @@ + +/* AWTEvent.java -- the root event in AWT + Copyright (C) 1999, 2000, 2002, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.ActionEvent; +import java.awt.event.AdjustmentEvent; +import java.awt.event.ComponentEvent; +import java.awt.event.ContainerEvent; +import java.awt.event.FocusEvent; +import java.awt.event.InputMethodEvent; +import java.awt.event.InvocationEvent; +import java.awt.event.ItemEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.PaintEvent; +import java.awt.event.TextEvent; +import java.awt.event.WindowEvent; +import java.util.EventObject; + +/** + * AWTEvent is the root event class for all AWT events in the JDK 1.1 event + * model. It supersedes the Event class from JDK 1.0. Subclasses outside of + * the java.awt package should have IDs greater than RESERVED_ID_MAX. + * + * <p>Event masks defined here are used by components in + * <code>enableEvents</code> to select event types not selected by registered + * listeners. Event masks are appropriately set when registering on + * components. + * + * @author Warren Levy (warrenl@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class AWTEvent extends EventObject +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -1825314779160409405L; + + /** + * The ID of the event. + * + * @see #getID() + * @see #AWTEvent(Object, int) + * @serial the identifier number of this event + */ + protected int id; + + /** + * Indicates if the event has been consumed. False mean it is passed to + * the peer, true means it has already been processed. Semantic events + * generated by low-level events always have the value true. + * + * @see #consume() + * @see #isConsumed() + * @serial whether the event has been consumed + */ + protected boolean consumed; + + /** + * Used for implementing a simple linked list in EventQueue. + */ + transient AWTEvent queueNext; + + /** + * Who knows? It's in the serial version. + * + * @serial No idea what this is for. + */ + byte[] bdata; + + /** + * Indicates if this event is dispatched by the KeyboardFocusManager. + */ + boolean isFocusManagerEvent = false; + + /** Mask for selecting component events. */ + public static final long COMPONENT_EVENT_MASK = 0x00001; + + /** Mask for selecting container events. */ + public static final long CONTAINER_EVENT_MASK = 0x00002; + + /** Mask for selecting component focus events. */ + public static final long FOCUS_EVENT_MASK = 0x00004; + + /** Mask for selecting keyboard events. */ + public static final long KEY_EVENT_MASK = 0x00008; + + /** Mask for mouse button events. */ + public static final long MOUSE_EVENT_MASK = 0x00010; + + /** Mask for mouse motion events. */ + public static final long MOUSE_MOTION_EVENT_MASK = 0x00020; + + /** Mask for window events. */ + public static final long WINDOW_EVENT_MASK = 0x00040; + + /** Mask for action events. */ + public static final long ACTION_EVENT_MASK = 0x00080; + + /** Mask for adjustment events. */ + public static final long ADJUSTMENT_EVENT_MASK = 0x00100; + + /** Mask for item events. */ + public static final long ITEM_EVENT_MASK = 0x00200; + + /** Mask for text events. */ + public static final long TEXT_EVENT_MASK = 0x00400; + + /** + * Mask for input method events. + * @since 1.3 + */ + public static final long INPUT_METHOD_EVENT_MASK = 0x00800; + + /** + * Mask if input methods are enabled. Package visible only. + */ + static final long INPUT_ENABLED_EVENT_MASK = 0x01000; + + /** + * Mask for paint events. + * @since 1.3 + */ + public static final long PAINT_EVENT_MASK = 0x02000; + + /** + * Mask for invocation events. + * @since 1.3 + */ + public static final long INVOCATION_EVENT_MASK = 0x04000; + + /** + * Mask for hierarchy events. + * @since 1.3 + */ + public static final long HIERARCHY_EVENT_MASK = 0x08000; + + /** + * Mask for hierarchy bounds events. + * @since 1.3 + */ + public static final long HIERARCHY_BOUNDS_EVENT_MASK = 0x10000; + + /** + * Mask for mouse wheel events. + * @since 1.4 + */ + public static final long MOUSE_WHEEL_EVENT_MASK = 0x20000; + + /** + * Mask for window state events. + * @since 1.4 + */ + public static final long WINDOW_STATE_EVENT_MASK = 0x40000; + + /** + * Mask for window focus events. + * @since 1.4 + */ + public static final long WINDOW_FOCUS_EVENT_MASK = 0x80000; + + /** + * This is the highest number for event ids that are reserved for use by + * the AWT system itself. Subclasses outside of java.awt should use higher + * ids. + */ + public static final int RESERVED_ID_MAX = 1999; + + + /** + * Initializes a new AWTEvent from the old Java 1.0 event object. + * + * @param event the old-style event + * @throws NullPointerException if event is null + */ + public AWTEvent(Event event) + { + this(event.target, event.id); + consumed = event.consumed; + } + + /** + * Create an event on the specified source object and id. + * + * @param source the object that caused the event + * @param id the event id + * @throws IllegalArgumentException if source is null + */ + public AWTEvent(Object source, int id) + { + super(source); + this.id = id; + } + + /** + * Retarget the event, such as converting a heavyweight component to a + * lightweight child of the original. This is not for general use, but + * is for event targeting systems like KeyboardFocusManager. + * + * @param source the new source + */ + public void setSource(Object source) + { + this.source = source; + } + + /** + * Returns the event type id. + * + * @return the id number of this event + */ + public int getID() + { + return id; + } + + /** + * Create a string that represents this event in the format + * <code>classname[eventstring] on sourcecomponentname</code>. + * + * @return a string representing this event + */ + public String toString () + { + String src; + if (source instanceof Component) + src = ((Component) source).getName(); + else if (source instanceof MenuComponent) + src = ((MenuComponent) source).getName(); + else if (source != null) + src = source.toString(); + else + src = "null"; + String string = getClass ().getName () + "[" + paramString () + "] on " + + src; + return string; + } + + /** + * Returns a string representation of the state of this event. It may be + * empty, but must not be null; it is implementation defined. + * + * @return a string representation of this event + */ + public String paramString() + { + return ""; + } + + /** + * Consumes this event so that it will not be processed in the default + * manner. + */ + protected void consume() + { + consumed = true; + } + + /** + * Tests whether not not this event has been consumed. A consumed event + * is not processed in the default manner. + * + * @return true if this event has been consumed + */ + protected boolean isConsumed() + { + return consumed; + } + + /** + * Converts an event id to the appropriate event mask. + * + * @param id the event id + * + * @return the event mask for the specified id + */ + static long eventIdToMask(int id) + { + long mask = 0; + switch (id) + { + case ActionEvent.ACTION_PERFORMED: + mask = ACTION_EVENT_MASK; + break; + case AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED: + mask = ADJUSTMENT_EVENT_MASK; + break; + case ComponentEvent.COMPONENT_MOVED: + case ComponentEvent.COMPONENT_RESIZED: + case ComponentEvent.COMPONENT_SHOWN: + case ComponentEvent.COMPONENT_HIDDEN: + mask = COMPONENT_EVENT_MASK; + break; + case ContainerEvent.COMPONENT_ADDED: + case ContainerEvent.COMPONENT_REMOVED: + mask = CONTAINER_EVENT_MASK; + break; + case FocusEvent.FOCUS_GAINED: + case FocusEvent.FOCUS_LOST: + mask = FOCUS_EVENT_MASK; + break; + case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED: + case InputMethodEvent.CARET_POSITION_CHANGED: + mask = INPUT_METHOD_EVENT_MASK; + break; + case InvocationEvent.INVOCATION_DEFAULT: + mask = INVOCATION_EVENT_MASK; + break; + case ItemEvent.ITEM_STATE_CHANGED: + mask = ITEM_EVENT_MASK; + break; + case KeyEvent.KEY_TYPED: + case KeyEvent.KEY_PRESSED: + case KeyEvent.KEY_RELEASED: + mask = KEY_EVENT_MASK; + break; + case MouseEvent.MOUSE_CLICKED: + case MouseEvent.MOUSE_PRESSED: + case MouseEvent.MOUSE_RELEASED: + mask = MOUSE_EVENT_MASK; + break; + case MouseEvent.MOUSE_MOVED: + case MouseEvent.MOUSE_ENTERED: + case MouseEvent.MOUSE_EXITED: + case MouseEvent.MOUSE_DRAGGED: + mask = MOUSE_MOTION_EVENT_MASK; + break; + case MouseEvent.MOUSE_WHEEL: + mask = MOUSE_WHEEL_EVENT_MASK; + break; + case PaintEvent.PAINT: + case PaintEvent.UPDATE: + mask = PAINT_EVENT_MASK; + break; + case TextEvent.TEXT_VALUE_CHANGED: + mask = TEXT_EVENT_MASK; + break; + case WindowEvent.WINDOW_OPENED: + case WindowEvent.WINDOW_CLOSING: + case WindowEvent.WINDOW_CLOSED: + case WindowEvent.WINDOW_ICONIFIED: + case WindowEvent.WINDOW_DEICONIFIED: + case WindowEvent.WINDOW_ACTIVATED: + case WindowEvent.WINDOW_DEACTIVATED: + mask = WINDOW_EVENT_MASK; + break; + case WindowEvent.WINDOW_GAINED_FOCUS: + case WindowEvent.WINDOW_LOST_FOCUS: + mask = WINDOW_FOCUS_EVENT_MASK; + break; + case WindowEvent.WINDOW_STATE_CHANGED: + mask = WINDOW_STATE_EVENT_MASK; + break; + default: + mask = 0; + } + return mask; + } +} // class AWTEvent diff --git a/libjava/classpath/java/awt/AWTEventMulticaster.java b/libjava/classpath/java/awt/AWTEventMulticaster.java new file mode 100644 index 000000000..722dc752d --- /dev/null +++ b/libjava/classpath/java/awt/AWTEventMulticaster.java @@ -0,0 +1,1210 @@ +/* AWTEventMulticaster.java -- allows multicast chaining of listeners + Copyright (C) 1999, 2000, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.AdjustmentEvent; +import java.awt.event.AdjustmentListener; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.ContainerEvent; +import java.awt.event.ContainerListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.HierarchyBoundsListener; +import java.awt.event.HierarchyEvent; +import java.awt.event.HierarchyListener; +import java.awt.event.InputMethodEvent; +import java.awt.event.InputMethodListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.awt.event.TextEvent; +import java.awt.event.TextListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; +import java.awt.event.WindowListener; +import java.awt.event.WindowStateListener; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.EventListener; + +/** + * This class is used to implement a chain of event handlers. Dispatching + * using this class is thread safe. Here is a quick example of how to + * add and delete listeners using this class. For this example, we will + * assume are firing <code>AdjustmentEvent</code>'s. However, this + * same approach is useful for all events in the <code>java.awt.event</code> + * package, and more if this class is subclassed. + * + * <p><code> + * AdjustmentListener al; + * public void addAdjustmentListener(AdjustmentListener listener) + * { + * al = AWTEventMulticaster.add(al, listener); + * } + * public void removeAdjustmentListener(AdjustmentListener listener) + * { + * al = AWTEventMulticaster.remove(al, listener); + * } + * </code> + * + * <p>When it come time to process an event, simply call <code>al</code>, + * assuming it is not <code>null</code>, and all listeners in the chain will + * be fired. + * + * <p>The first time <code>add</code> is called it is passed + * <code>null</code> and <code>listener</code> as its arguments. This + * starts building the chain. This class returns <code>listener</code> + * which becomes the new <code>al</code>. The next time, <code>add</code> + * is called with <code>al</code> and <code>listener</code> and the + * new listener is then chained to the old. + * + * @author Bryce McKinlay + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.1 + * @status updated to 1.4 + */ +public class AWTEventMulticaster + implements ComponentListener, ContainerListener, FocusListener, KeyListener, + MouseListener, MouseMotionListener, WindowListener, + WindowFocusListener, WindowStateListener, ActionListener, + ItemListener, AdjustmentListener, TextListener, + InputMethodListener, HierarchyListener, HierarchyBoundsListener, + MouseWheelListener +{ + /** + * A variable in the event chain. + */ + protected final EventListener a; + + /** + * A variable in the event chain. + */ + protected final EventListener b; + + /** + * Initializes a new instance of <code>AWTEventMulticaster</code> with + * the specified event listener parameters. The parameters should not be + * null, although it is not required to enforce this with a + * NullPointerException. + * + * @param a the "a" listener object + * @param b the "b" listener object + */ + protected AWTEventMulticaster(EventListener a, EventListener b) + { + this.a = a; + this.b = b; + } + + /** + * Removes one instance of the specified listener from this multicaster + * chain. This descends recursively if either child is a multicaster, and + * returns a multicaster chain with the old listener removed. + * + * @param oldl the object to remove from this multicaster + * @return the resulting multicaster with the specified listener removed + */ + protected EventListener remove(EventListener oldl) + { + // If oldl is an immediate child, return the other child. + if (a == oldl) + return b; + if (b == oldl) + return a; + // If a and/or b are Multicaster's, search them recursively. + if (a instanceof AWTEventMulticaster) + { + EventListener newa = ((AWTEventMulticaster) a).remove(oldl); + if (newa != a) + return new AWTEventMulticaster(newa, b); + } + if (b instanceof AWTEventMulticaster) + { + EventListener newb = ((AWTEventMulticaster) b).remove(oldl); + if (newb != b) + return new AWTEventMulticaster(a, newb); + } + // oldl was not found. + return this; + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void componentResized(ComponentEvent e) + { + ((ComponentListener) a).componentResized(e); + ((ComponentListener) b).componentResized(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void componentMoved(ComponentEvent e) + { + ((ComponentListener) a).componentMoved(e); + ((ComponentListener) b).componentMoved(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void componentShown(ComponentEvent e) + { + ((ComponentListener) a).componentShown(e); + ((ComponentListener) b).componentShown(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void componentHidden(ComponentEvent e) + { + ((ComponentListener) a).componentHidden(e); + ((ComponentListener) b).componentHidden(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void componentAdded(ContainerEvent e) + { + ((ContainerListener) a).componentAdded(e); + ((ContainerListener) b).componentAdded(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void componentRemoved(ContainerEvent e) + { + ((ContainerListener) a).componentRemoved(e); + ((ContainerListener) b).componentRemoved(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void focusGained(FocusEvent e) + { + ((FocusListener) a).focusGained(e); + ((FocusListener) b).focusGained(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void focusLost(FocusEvent e) + { + ((FocusListener) a).focusLost(e); + ((FocusListener) b).focusLost(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void keyTyped(KeyEvent e) + { + ((KeyListener) a).keyTyped(e); + ((KeyListener) b).keyTyped(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void keyPressed(KeyEvent e) + { + ((KeyListener) a).keyPressed(e); + ((KeyListener) b).keyPressed(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void keyReleased(KeyEvent e) + { + ((KeyListener) a).keyReleased(e); + ((KeyListener) b).keyReleased(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void mouseClicked(MouseEvent e) + { + ((MouseListener) a).mouseClicked(e); + ((MouseListener) b).mouseClicked(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void mousePressed(MouseEvent e) + { + ((MouseListener) a).mousePressed(e); + ((MouseListener) b).mousePressed(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void mouseReleased(MouseEvent e) + { + ((MouseListener) a).mouseReleased(e); + ((MouseListener) b).mouseReleased(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void mouseEntered(MouseEvent e) + { + ((MouseListener) a).mouseEntered(e); + ((MouseListener) b).mouseEntered(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void mouseExited(MouseEvent e) + { + ((MouseListener) a).mouseExited(e); + ((MouseListener) b).mouseExited(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void mouseDragged(MouseEvent e) + { + ((MouseMotionListener) a).mouseDragged(e); + ((MouseMotionListener) b).mouseDragged(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void mouseMoved(MouseEvent e) + { + ((MouseMotionListener) a).mouseMoved(e); + ((MouseMotionListener) b).mouseMoved(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void windowOpened(WindowEvent e) + { + ((WindowListener) a).windowOpened(e); + ((WindowListener) b).windowOpened(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void windowClosing(WindowEvent e) + { + ((WindowListener) a).windowClosing(e); + ((WindowListener) b).windowClosing(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void windowClosed(WindowEvent e) + { + ((WindowListener) a).windowClosed(e); + ((WindowListener) b).windowClosed(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void windowIconified(WindowEvent e) + { + ((WindowListener) a).windowIconified(e); + ((WindowListener) b).windowIconified(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void windowDeiconified(WindowEvent e) + { + ((WindowListener) a).windowDeiconified(e); + ((WindowListener) b).windowDeiconified(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void windowActivated(WindowEvent e) + { + ((WindowListener) a).windowActivated(e); + ((WindowListener) b).windowActivated(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void windowDeactivated(WindowEvent e) + { + ((WindowListener) a).windowDeactivated(e); + ((WindowListener) b).windowDeactivated(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + * @since 1.4 + */ + public void windowStateChanged(WindowEvent e) + { + ((WindowStateListener) a).windowStateChanged(e); + ((WindowStateListener) b).windowStateChanged(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + * @since 1.4 + */ + public void windowGainedFocus(WindowEvent e) + { + ((WindowFocusListener) a).windowGainedFocus(e); + ((WindowFocusListener) b).windowGainedFocus(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + * @since 1.4 + */ + public void windowLostFocus(WindowEvent e) + { + ((WindowFocusListener) a).windowLostFocus(e); + ((WindowFocusListener) b).windowLostFocus(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void actionPerformed(ActionEvent e) + { + ((ActionListener) a).actionPerformed(e); + ((ActionListener) b).actionPerformed(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void itemStateChanged(ItemEvent e) + { + ((ItemListener) a).itemStateChanged(e); + ((ItemListener) b).itemStateChanged(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void adjustmentValueChanged(AdjustmentEvent e) + { + ((AdjustmentListener) a).adjustmentValueChanged(e); + ((AdjustmentListener) b).adjustmentValueChanged(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + */ + public void textValueChanged(TextEvent e) + { + ((TextListener) a).textValueChanged(e); + ((TextListener) b).textValueChanged(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + * @since 1.2 + */ + public void inputMethodTextChanged(InputMethodEvent e) + { + ((InputMethodListener) a).inputMethodTextChanged(e); + ((InputMethodListener) b).inputMethodTextChanged(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + * @since 1.2 + */ + public void caretPositionChanged(InputMethodEvent e) + { + ((InputMethodListener) a).caretPositionChanged(e); + ((InputMethodListener) b).caretPositionChanged(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + * @since 1.3 + */ + public void hierarchyChanged(HierarchyEvent e) + { + ((HierarchyListener) a).hierarchyChanged(e); + ((HierarchyListener) b).hierarchyChanged(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + * @since 1.3 + */ + public void ancestorMoved(HierarchyEvent e) + { + ((HierarchyBoundsListener) a).ancestorMoved(e); + ((HierarchyBoundsListener) b).ancestorMoved(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + * @since 1.3 + */ + public void ancestorResized(HierarchyEvent e) + { + ((HierarchyBoundsListener) a).ancestorResized(e); + ((HierarchyBoundsListener) b).ancestorResized(e); + } + + /** + * Handles this event by dispatching it to the "a" and "b" listener + * instances. + * + * @param e the event to handle + * @since 1.4 + */ + public void mouseWheelMoved(MouseWheelEvent e) + { + ((MouseWheelListener) a).mouseWheelMoved(e); + ((MouseWheelListener) b).mouseWheelMoved(e); + } + + /** + * Chain <code>ComponentListener</code> a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static ComponentListener add(ComponentListener a, ComponentListener b) + { + return (ComponentListener) addInternal(a, b); + } + + /** + * Chain <code>ContainerListener</code> a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static ContainerListener add(ContainerListener a, ContainerListener b) + { + return (ContainerListener) addInternal(a, b); + } + + /** + * Chain <code>FocusListener</code> a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static FocusListener add(FocusListener a, FocusListener b) + { + return (FocusListener) addInternal(a, b); + } + + /** + * Chain <code>KeyListener</code> a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static KeyListener add(KeyListener a, KeyListener b) + { + return (KeyListener) addInternal(a, b); + } + + /** + * Chain <code>MouseListener</code> a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static MouseListener add(MouseListener a, MouseListener b) + { + return (MouseListener) addInternal(a, b); + } + + /** + * Chain <code>MouseMotionListener</code> a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static MouseMotionListener add(MouseMotionListener a, + MouseMotionListener b) + { + return (MouseMotionListener) addInternal(a, b); + } + + /** + * Chain <code>WindowListener</code> a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static WindowListener add(WindowListener a, WindowListener b) + { + return (WindowListener) addInternal(a, b); + } + + /** + * Chain <code>WindowStateListener</code> a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + * @since 1.4 + */ + public static WindowStateListener add(WindowStateListener a, + WindowStateListener b) + { + return (WindowStateListener) addInternal(a, b); + } + + /** + * Chain <code>WindowFocusListener</code> a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + * @since 1.4 + */ + public static WindowFocusListener add(WindowFocusListener a, + WindowFocusListener b) + { + return (WindowFocusListener) addInternal(a, b); + } + + /** + * Chain <code>ActionListener</code> a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static ActionListener add(ActionListener a, ActionListener b) + { + return (ActionListener) addInternal(a, b); + } + + /** + * Chain <code>ItemListener</code> a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static ItemListener add(ItemListener a, ItemListener b) + { + return (ItemListener) addInternal(a, b); + } + + /** + * Chain <code>AdjustmentListener</code> a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static AdjustmentListener add(AdjustmentListener a, + AdjustmentListener b) + { + return (AdjustmentListener) addInternal(a, b); + } + + /** + * Chain <code>AdjustmentListener</code> a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + public static TextListener add(TextListener a, TextListener b) + { + return (TextListener) addInternal(a, b); + } + + /** + * Chain <code>InputMethodListener</code> a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + * @since 1.2 + */ + public static InputMethodListener add(InputMethodListener a, + InputMethodListener b) + { + return (InputMethodListener) addInternal(a, b); + } + + /** + * Chain <code>HierarchyListener</code> a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + * @since 1.3 + */ + public static HierarchyListener add(HierarchyListener a, HierarchyListener b) + { + return (HierarchyListener) addInternal(a, b); + } + + /** + * Chain <code>HierarchyBoundsListener</code> a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + * @since 1.3 + */ + public static HierarchyBoundsListener add(HierarchyBoundsListener a, + HierarchyBoundsListener b) + { + return (HierarchyBoundsListener) addInternal(a, b); + } + + /** + * Chain <code>MouseWheelListener</code> a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + * @since 1.4 + */ + public static MouseWheelListener add(MouseWheelListener a, + MouseWheelListener b) + { + return (MouseWheelListener) addInternal(a, b); + } + + /** + * Removes the listener <code>oldl</code> from the listener <code>l</code>. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static ComponentListener remove(ComponentListener l, + ComponentListener oldl) + { + return (ComponentListener) removeInternal(l, oldl); + } + + /** + * Removes the listener <code>oldl</code> from the listener <code>l</code>. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static ContainerListener remove(ContainerListener l, + ContainerListener oldl) + { + return (ContainerListener) removeInternal(l, oldl); + } + + /** + * Removes the listener <code>oldl</code> from the listener <code>l</code>. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static FocusListener remove(FocusListener l, FocusListener oldl) + { + return (FocusListener) removeInternal(l, oldl); + } + + /** + * Removes the listener <code>oldl</code> from the listener <code>l</code>. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static KeyListener remove(KeyListener l, KeyListener oldl) + { + return (KeyListener) removeInternal(l, oldl); + } + + /** + * Removes the listener <code>oldl</code> from the listener <code>l</code>. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static MouseListener remove(MouseListener l, MouseListener oldl) + { + return (MouseListener) removeInternal(l, oldl); + } + + /** + * Removes the listener <code>oldl</code> from the listener <code>l</code>. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static MouseMotionListener remove(MouseMotionListener l, + MouseMotionListener oldl) + { + return (MouseMotionListener) removeInternal(l, oldl); + } + + /** + * Removes the listener <code>oldl</code> from the listener <code>l</code>. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static WindowListener remove(WindowListener l, WindowListener oldl) + { + return (WindowListener) removeInternal(l, oldl); + } + + /** + * Removes the listener <code>oldl</code> from the listener <code>l</code>. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + * @since 1.4 + */ + public static WindowStateListener remove(WindowStateListener l, + WindowStateListener oldl) + { + return (WindowStateListener) removeInternal(l, oldl); + } + + /** + * Removes the listener <code>oldl</code> from the listener <code>l</code>. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + * @since 1.4 + */ + public static WindowFocusListener remove(WindowFocusListener l, + WindowFocusListener oldl) + { + return (WindowFocusListener) removeInternal(l, oldl); + } + + /** + * Removes the listener <code>oldl</code> from the listener <code>l</code>. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static ActionListener remove(ActionListener l, ActionListener oldl) + { + return (ActionListener) removeInternal(l, oldl); + } + + /** + * Removes the listener <code>oldl</code> from the listener <code>l</code>. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static ItemListener remove(ItemListener l, ItemListener oldl) + { + return (ItemListener) removeInternal(l, oldl); + } + + /** + * Removes the listener <code>oldl</code> from the listener <code>l</code>. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static AdjustmentListener remove(AdjustmentListener l, + AdjustmentListener oldl) + { + return (AdjustmentListener) removeInternal(l, oldl); + } + + /** + * Removes the listener <code>oldl</code> from the listener <code>l</code>. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + public static TextListener remove(TextListener l, TextListener oldl) + { + return (TextListener) removeInternal(l, oldl); + } + + /** + * Removes the listener <code>oldl</code> from the listener <code>l</code>. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + * @since 1.2 + */ + public static InputMethodListener remove(InputMethodListener l, + InputMethodListener oldl) + { + return (InputMethodListener) removeInternal(l, oldl); + } + + /** + * Removes the listener <code>oldl</code> from the listener <code>l</code>. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + * @since 1.3 + */ + public static HierarchyListener remove(HierarchyListener l, + HierarchyListener oldl) + { + return (HierarchyListener) removeInternal(l, oldl); + } + + /** + * Removes the listener <code>oldl</code> from the listener <code>l</code>. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + * @since 1.3 + */ + public static HierarchyBoundsListener remove(HierarchyBoundsListener l, + HierarchyBoundsListener oldl) + { + return (HierarchyBoundsListener) removeInternal(l, oldl); + } + + /** + * Removes the listener <code>oldl</code> from the listener <code>l</code>. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + * @since 1.4 + */ + public static MouseWheelListener remove(MouseWheelListener l, + MouseWheelListener oldl) + { + return (MouseWheelListener) removeInternal(l, oldl); + } + + /** + * Chain <code>EventListener</code> a and b. + * + * @param a the "a" listener, may be null + * @param b the "b" listener, may be null + * @return latest entry in the chain + */ + protected static EventListener addInternal(EventListener a, EventListener b) + { + if (a == null) + return b; + if (b == null) + return a; + return new AWTEventMulticaster(a, b); + } + + /** + * Removes the listener <code>oldl</code> from the listener <code>l</code>. + * + * @param l the listener chain to reduce + * @param oldl the listener to remove + * @return the resulting listener chain + */ + protected static EventListener removeInternal(EventListener l, + EventListener oldl) + { + if (l == oldl) + return null; + if (l instanceof AWTEventMulticaster) + return ((AWTEventMulticaster) l).remove(oldl); + return l; + } + + /** + * Saves all Serializable listeners to a serialization stream. + * + * @param s the stream to save to + * @param k a prefix stream put before each serializable listener + * @throws IOException if serialization fails + */ + protected void saveInternal(ObjectOutputStream s, String k) + throws IOException + { + // This is not documented by Sun, but I think it is correct. + if (a instanceof AWTEventMulticaster) + ((AWTEventMulticaster) a).saveInternal(s, k); + else if (a instanceof Serializable) + { + s.writeObject(k); + s.writeObject(a); + } + if (b instanceof AWTEventMulticaster) + ((AWTEventMulticaster) b).saveInternal(s, k); + else if (b instanceof Serializable) + { + s.writeObject(k); + s.writeObject(b); + } + } + + /** + * Saves a Serializable listener chain to a serialization stream. + * + * @param s the stream to save to + * @param k a prefix stream put before each serializable listener + * @param l the listener chain to save + * @throws IOException if serialization fails + */ + protected static void save(ObjectOutputStream s, String k, EventListener l) + throws IOException + { + // This is not documented by Sun, but I think it is correct. + if (l instanceof AWTEventMulticaster) + ((AWTEventMulticaster) l).saveInternal(s, k); + else if (l instanceof Serializable) + { + s.writeObject(k); + s.writeObject(l); + } + } + + /** + * Returns an array of all chained listeners of the specified type in the + * given chain. A null listener returns an empty array, and a listener + * which is not an AWTEventMulticaster returns an array of one element. If + * no listeners in the chain are of the specified type, an empty array is + * returned. + * + * @param l the listener chain to convert to an array + * @param type the type of listeners to collect + * @return an array of the listeners of that type in the chain + * @throws ClassCastException if type is not assignable from EventListener + * @throws NullPointerException if type is null + * @throws IllegalArgumentException if type is Void.TYPE + * @since 1.4 + */ + public static <T extends EventListener> T[] getListeners(EventListener l, + Class<T> type) + { + ArrayList<EventListener> list = new ArrayList<EventListener>(); + if (l instanceof AWTEventMulticaster) + ((AWTEventMulticaster) l).getListeners(list, type); + else if (type.isInstance(l)) + list.add(l); + EventListener[] r = (EventListener[]) Array.newInstance(type, list.size()); + list.toArray(r); + return (T[]) r; + } + + /** + * Collects all instances of the given type in the chain into the list. + * + * @param l the list to collect into + * @param type the type of listeners to collect + * @throws NullPointerException if type is null + * @see #getListeners(EventListener, Class) + */ + private void getListeners(ArrayList l, Class type) + { + if (a instanceof AWTEventMulticaster) + ((AWTEventMulticaster) a).getListeners(l, type); + else if (type.isInstance(a)) + l.add(a); + if (b instanceof AWTEventMulticaster) + ((AWTEventMulticaster) b).getListeners(l, type); + else if (type.isInstance(b)) + l.add(b); + } +} // class AWTEventMulticaster diff --git a/libjava/classpath/java/awt/AWTException.java b/libjava/classpath/java/awt/AWTException.java new file mode 100644 index 000000000..2df3dd801 --- /dev/null +++ b/libjava/classpath/java/awt/AWTException.java @@ -0,0 +1,64 @@ +/* AWTException.java -- Generic AWT exception + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +/** + * This is a generic exception that indicates an exception occurred in the + * Abstract Window Toolkit (AWT) system. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @status updated to 1.4 + */ +public class AWTException extends Exception +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -1900414231151323879L; + + /** + * Create a new instance with the specified detailed error message. + * + * @param message the detailed error message + */ + public AWTException(String message) + { + super(message); + } +} // class AWTException diff --git a/libjava/classpath/java/awt/AWTKeyStroke.java b/libjava/classpath/java/awt/AWTKeyStroke.java new file mode 100644 index 000000000..bdccbf0d7 --- /dev/null +++ b/libjava/classpath/java/awt/AWTKeyStroke.java @@ -0,0 +1,676 @@ +/* AWTKeyStroke.java -- an immutable key stroke + Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.StringTokenizer; + +/** + * This class mirrors KeyEvents, representing both low-level key presses and + * key releases, and high level key typed inputs. However, this class forms + * immutable strokes, and can be efficiently reused via the factory methods + * for creating them. + * + * <p>For backwards compatibility with Swing, this supports a way to build + * instances of a subclass, using reflection, provided the subclass has a + * no-arg constructor (of any accessibility). + * + * @author Eric Blake (ebb9@email.byu.edu) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @see #getAWTKeyStroke(char) + * @since 1.4 + * @status updated to 1.4 + */ +public class AWTKeyStroke implements Serializable +{ + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = -6430539691155161871L; + + /** The mask for modifiers. */ + private static final int MODIFIERS_MASK = 0x3fef; + + /** + * The cache of recently created keystrokes. This maps KeyStrokes to + * KeyStrokes in a cache which removes the least recently accessed entry, + * under the assumption that garbage collection of a new keystroke is + * easy when we find the old one that it matches in the cache. + */ + private static final LinkedHashMap<AWTKeyStroke,AWTKeyStroke> cache = + new LinkedHashMap<AWTKeyStroke,AWTKeyStroke>(11, 0.75f, true) + { + /** The largest the keystroke cache can grow. */ + private static final int MAX_CACHE_SIZE = 2048; + + /** Prune stale entries. */ + protected boolean removeEldestEntry(Map.Entry<AWTKeyStroke,AWTKeyStroke> + eldest) + { + return size() > MAX_CACHE_SIZE; + } + }; + + /** The most recently generated keystroke, or null. */ + private static AWTKeyStroke recent; + + /** + * The no-arg constructor of a subclass, or null to use AWTKeyStroke. Note + * that this will be left accessible, to get around private access; but + * it should not be a security risk as it is highly unlikely that creating + * protected instances of the subclass via reflection will do much damage. + */ + private static Constructor ctor; + + /** + * A table of keyCode names to values. This is package-private to + * avoid an accessor method. + * + * @see #getAWTKeyStroke(String) + */ + static final HashMap<String,Object> vktable = new HashMap<String,Object>(); + static + { + // Using reflection saves the hassle of keeping this in sync with KeyEvent, + // at the price of an expensive initialization. + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + Field[] fields = KeyEvent.class.getFields(); + int i = fields.length; + try + { + while (--i >= 0) + { + Field f = fields[i]; + String name = f.getName(); + if (name.startsWith("VK_")) + vktable.put(name.substring(3), f.get(null)); + } + } + catch (Exception e) + { + throw (Error) new InternalError().initCause(e); + } + return null; + } + }); + } + + /** + * The typed character, or CHAR_UNDEFINED for key presses and releases. + * + * @serial the keyChar + */ + private char keyChar; + + /** + * The virtual key code, or VK_UNDEFINED for key typed. Package visible for + * use by Component. + * + * @serial the keyCode + */ + int keyCode; + + /** + * The modifiers in effect. To match Sun, this stores the old style masks + * for shift, control, alt, meta, and alt-graph (but not button1); as well + * as the new style of extended modifiers for all modifiers. + * + * @serial bitwise or of the *_DOWN_MASK modifiers + */ + private int modifiers; + + /** + * True if this is a key release; should only be true if keyChar is + * CHAR_UNDEFINED. + * + * @serial true to distinguish key pressed from key released + */ + private boolean onKeyRelease; + + /** + * Construct a keystroke with default values: it will be interpreted as a + * key typed event with an invalid character and no modifiers. Client code + * should use the factory methods instead. + * + * @see #getAWTKeyStroke(char) + * @see #getAWTKeyStroke(Character, int) + * @see #getAWTKeyStroke(int, int, boolean) + * @see #getAWTKeyStroke(int, int) + * @see #getAWTKeyStrokeForEvent(KeyEvent) + * @see #getAWTKeyStroke(String) + */ + protected AWTKeyStroke() + { + keyChar = KeyEvent.CHAR_UNDEFINED; + } + + /** + * Construct a keystroke with the given values. Client code should use the + * factory methods instead. + * + * @param keyChar the character entered, if this is a key typed + * @param keyCode the key pressed or released, or VK_UNDEFINED for key typed + * @param modifiers the modifier keys for the keystroke, in old or new style + * @param onKeyRelease true if this is a key release instead of a press + * @see #getAWTKeyStroke(char) + * @see #getAWTKeyStroke(Character, int) + * @see #getAWTKeyStroke(int, int, boolean) + * @see #getAWTKeyStroke(int, int) + * @see #getAWTKeyStrokeForEvent(KeyEvent) + * @see #getAWTKeyStroke(String) + */ + protected AWTKeyStroke(char keyChar, int keyCode, int modifiers, + boolean onKeyRelease) + { + this.keyChar = keyChar; + this.keyCode = keyCode; + // No need to call extend(), as only trusted code calls this constructor. + this.modifiers = modifiers; + this.onKeyRelease = onKeyRelease; + } + + /** + * Registers a new subclass as being the type of keystrokes to generate in + * the factory methods. This operation flushes the cache of stored keystrokes + * if the class differs from the current one. The new class must be + * AWTKeyStroke or a subclass, and must have a no-arg constructor (which may + * be private). + * + * @param subclass the new runtime type of generated keystrokes + * @throws IllegalArgumentException subclass doesn't have no-arg constructor + * @throws ClassCastException subclass doesn't extend AWTKeyStroke + */ + protected static void registerSubclass(final Class<?> subclass) + { + if (subclass == null) + throw new IllegalArgumentException(); + if (subclass.equals(ctor == null ? AWTKeyStroke.class + : ctor.getDeclaringClass())) + return; + if (subclass.equals(AWTKeyStroke.class)) + { + cache.clear(); + recent = null; + ctor = null; + return; + } + try + { + ctor = (Constructor) AccessController.doPrivileged + (new PrivilegedExceptionAction() + { + public Object run() + throws NoSuchMethodException, InstantiationException, + IllegalAccessException, InvocationTargetException + { + Constructor<?> c = + subclass.getDeclaredConstructor((Class<?>[])null); + c.setAccessible(true); + // Create a new instance, to make sure that we can, and + // to cause any ClassCastException. + AWTKeyStroke dummy = (AWTKeyStroke) c.newInstance(); + return c; + } + }); + } + catch (PrivilegedActionException e) + { + // e.getCause() will not ever be ClassCastException; that should + // escape on its own. + throw (RuntimeException) + new IllegalArgumentException().initCause(e.getCause()); + } + cache.clear(); + recent = null; + } + + /** + * Returns a keystroke representing a typed character. + * + * @param keyChar the typed character + * @return the specified keystroke + */ + public static AWTKeyStroke getAWTKeyStroke(char keyChar) + { + return getAWTKeyStroke(keyChar, KeyEvent.VK_UNDEFINED, 0, false); + } + + /** + * Returns a keystroke representing a typed character with the given + * modifiers. Note that keyChar is a <code>Character</code> instead of a + * <code>char</code> to avoid accidental ambiguity with + * <code>getAWTKeyStroke(int, int)</code>. The modifiers are the bitwise + * or of the masks found in {@link InputEvent}; the new style (*_DOWN_MASK) + * is preferred, but the old style will work. + * + * @param keyChar the typed character + * @param modifiers the modifiers, or 0 + * @return the specified keystroke + * @throws IllegalArgumentException if keyChar is null + */ + public static AWTKeyStroke getAWTKeyStroke(Character keyChar, int modifiers) + { + if (keyChar == null) + throw new IllegalArgumentException(); + return getAWTKeyStroke(keyChar.charValue(), KeyEvent.VK_UNDEFINED, + extend(modifiers), false); + } + + /** + * Returns a keystroke representing a pressed or released key event, with + * the given modifiers. The "virtual key" should be one of the VK_* + * constants in {@link KeyEvent}. The modifiers are the bitwise or of the + * masks found in {@link InputEvent}; the new style (*_DOWN_MASK) is + * preferred, but the old style will work. + * + * @param keyCode the virtual key + * @param modifiers the modifiers, or 0 + * @param release true if this is a key release instead of a key press + * @return the specified keystroke + */ + public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers, + boolean release) + { + return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, keyCode, + extend(modifiers), release); + } + + /** + * Returns a keystroke representing a pressed key event, with the given + * modifiers. The "virtual key" should be one of the VK_* constants in + * {@link KeyEvent}. The modifiers are the bitwise or of the masks found + * in {@link InputEvent}; the new style (*_DOWN_MASK) is preferred, but the + * old style will work. + * + * @param keyCode the virtual key + * @param modifiers the modifiers, or 0 + * @return the specified keystroke + */ + public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers) + { + return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, keyCode, + extend(modifiers), false); + } + + /** + * Returns a keystroke representing what caused the key event. + * + * @param event the key event to convert + * @return the specified keystroke, or null if the event is invalid + * @throws NullPointerException if event is null + */ + public static AWTKeyStroke getAWTKeyStrokeForEvent(KeyEvent event) + { + switch (event.id) + { + case KeyEvent.KEY_TYPED: + return getAWTKeyStroke(event.getKeyChar(), KeyEvent.VK_UNDEFINED, + extend(event.getModifiersEx()), false); + case KeyEvent.KEY_PRESSED: + return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, event.getKeyCode(), + extend(event.getModifiersEx()), false); + case KeyEvent.KEY_RELEASED: + return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, event.getKeyCode(), + extend(event.getModifiersEx()), true); + default: + return null; + } + } + + /** + * Parses a string and returns the keystroke that it represents. The syntax + * for keystrokes is listed below, with tokens separated by an arbitrary + * number of spaces: + * <pre> + * keyStroke := <modifiers>* ( <typedID> | <codeID> ) + * modifiers := ( shift | control | ctrl | meta | alt + * | button1 | button2 | button3 ) + * typedID := typed <single Unicode character> + * codeID := ( pressed | released )? <name> + * name := <the KeyEvent field name less the leading "VK_"> + * </pre> + * + * <p>Note that the grammar is rather weak, and not all valid keystrokes + * can be generated in this manner (for example, a typed space, or anything + * with the alt-graph modifier!). The output of AWTKeyStroke.toString() + * will not meet the grammar. If pressed or released is not specified, + * pressed is assumed. Examples:<br> + * <code> + * "INSERT" => getAWTKeyStroke(KeyEvent.VK_INSERT, 0);<br> + * "control DELETE" => + * getAWTKeyStroke(KeyEvent.VK_DELETE, InputEvent.CTRL_MASK);<br> + * "alt shift X" => getAWTKeyStroke(KeyEvent.VK_X, + * InputEvent.ALT_MASK | InputEvent.SHIFT_MASK);<br> + * "alt shift released X" => getAWTKeyStroke(KeyEvent.VK_X, + * InputEvent.ALT_MASK | InputEvent.SHIFT_MASK, true);<br> + * "typed a" => getAWTKeyStroke('a'); + * </code> + * + * @param s the string to parse + * @throws IllegalArgumentException if s is null or cannot be parsed + * @return the specified keystroke + */ + public static AWTKeyStroke getAWTKeyStroke(String s) + { + if (s == null) + throw new IllegalArgumentException("null argument"); + StringTokenizer t = new StringTokenizer(s, " "); + if (! t.hasMoreTokens()) + throw new IllegalArgumentException("no tokens '" + s + "'"); + int modifiers = 0; + boolean released = false; + String token = null; + do + { + token = t.nextToken(); + if ("shift".equals(token)) + { + modifiers |= KeyEvent.SHIFT_MASK; + modifiers |= KeyEvent.SHIFT_DOWN_MASK; + } + else if ("ctrl".equals(token) || "control".equals(token)) + { + modifiers |= KeyEvent.CTRL_MASK; + modifiers |= KeyEvent.CTRL_DOWN_MASK; + } + else if ("meta".equals(token)) + { + modifiers |= KeyEvent.META_MASK; + modifiers |= KeyEvent.META_DOWN_MASK; + } + else if ("alt".equals(token)) + { + modifiers |= KeyEvent.ALT_MASK; + modifiers |= KeyEvent.ALT_DOWN_MASK; + } + else if ("button1".equals(token)) + modifiers |= KeyEvent.BUTTON1_DOWN_MASK; + else if ("button2".equals(token)) + modifiers |= KeyEvent.BUTTON2_DOWN_MASK; + else if ("button3".equals(token)) + modifiers |= KeyEvent.BUTTON3_DOWN_MASK; + else if ("typed".equals(token)) + { + if (t.hasMoreTokens()) + { + token = t.nextToken(); + if (! t.hasMoreTokens() && token.length() == 1) + return getAWTKeyStroke(token.charAt(0), + KeyEvent.VK_UNDEFINED, modifiers, + false); + } + throw new IllegalArgumentException("Invalid 'typed' argument '" + + s + "'"); + } + else if ("pressed".equals(token)) + { + if (t.hasMoreTokens()) + token = t.nextToken(); + break; + } + else if ("released".equals(token)) + { + released = true; + if (t.hasMoreTokens()) + token = t.nextToken(); + break; + } + else + break; + } + while (t.hasMoreTokens()); + // Now token contains the VK name we must parse. + Integer code = (Integer) vktable.get(token); + if (code == null) + throw new IllegalArgumentException("Unknown token '" + token + + "' in '" + s + "'"); + if (t.hasMoreTokens()) + throw new IllegalArgumentException("Too many tokens: " + s); + return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, code.intValue(), + modifiers, released); + } + + /** + * Returns the character of this keystroke, if it was typed. + * + * @return the character value, or CHAR_UNDEFINED + * @see #getAWTKeyStroke(char) + */ + public final char getKeyChar() + { + return keyChar; + } + + /** + * Returns the virtual key code of this keystroke, if it was pressed or + * released. This will be a VK_* constant from KeyEvent. + * + * @return the virtual key code value, or VK_UNDEFINED + * @see #getAWTKeyStroke(int, int) + */ + public final int getKeyCode() + { + return keyCode; + } + + /** + * Returns the modifiers for this keystroke. This will be a bitwise or of + * constants from InputEvent; it includes the old style masks for shift, + * control, alt, meta, and alt-graph (but not button1); as well as the new + * style of extended modifiers for all modifiers. + * + * @return the modifiers + * @see #getAWTKeyStroke(Character, int) + * @see #getAWTKeyStroke(int, int) + */ + public final int getModifiers() + { + return modifiers; + } + + /** + * Tests if this keystroke is a key release. + * + * @return true if this is a key release + * @see #getAWTKeyStroke(int, int, boolean) + */ + public final boolean isOnKeyRelease() + { + return onKeyRelease; + } + + /** + * Returns the AWT event type of this keystroke. This is one of + * {@link KeyEvent#KEY_TYPED}, {@link KeyEvent#KEY_PRESSED}, or + * {@link KeyEvent#KEY_RELEASED}. + * + * @return the key event type + */ + public final int getKeyEventType() + { + return keyCode == KeyEvent.VK_UNDEFINED ? KeyEvent.KEY_TYPED + : onKeyRelease ? KeyEvent.KEY_RELEASED : KeyEvent.KEY_PRESSED; + } + + /** + * Returns a hashcode for this key event. It is not documented, but appears + * to be: <code>(getKeyChar() + 1) * (getKeyCode() + 1) + * * (getModifiers() + 1) * 2 + (isOnKeyRelease() ? 1 : 2)</code>. + * + * @return the hashcode + */ + public int hashCode() + { + return (keyChar + 1) * (keyCode + 1) * (modifiers + 1) * 2 + + (onKeyRelease ? 1 : 2); + } + + /** + * Tests two keystrokes for equality. + * + * @param o the object to test + * @return true if it is equal + */ + public final boolean equals(Object o) + { + if (! (o instanceof AWTKeyStroke)) + return false; + AWTKeyStroke s = (AWTKeyStroke) o; + return this == o || (keyChar == s.keyChar && keyCode == s.keyCode + && modifiers == s.modifiers + && onKeyRelease == s.onKeyRelease); + } + + /** + * Returns a string representation of this keystroke. For typed keystrokes, + * this is <code>"keyChar " + KeyEvent.getKeyModifiersText(getModifiers()) + + getKeyChar()</code>; for pressed and released keystrokes, this is + * <code>"keyCode " + KeyEvent.getKeyModifiersText(getModifiers()) + * + KeyEvent.getKeyText(getKeyCode()) + * + (isOnKeyRelease() ? "-R" : "-P")</code>. + * + * @return a string representation + */ + public String toString() + { + if (keyCode == KeyEvent.VK_UNDEFINED) + return "keyChar " + KeyEvent.getKeyModifiersText(modifiers) + keyChar; + return "keyCode " + KeyEvent.getKeyModifiersText(modifiers) + + KeyEvent.getKeyText(keyCode) + (onKeyRelease ? "-R" : "-P"); + } + + /** + * Returns a cached version of the deserialized keystroke, if available. + * + * @return a cached replacement + * @throws ObjectStreamException if something goes wrong + */ + protected Object readResolve() throws ObjectStreamException + { + AWTKeyStroke s = cache.get(this); + if (s != null) + return s; + cache.put(this, this); + return this; + } + + /** + * Gets the appropriate keystroke, creating one if necessary. + * + * @param keyChar the keyChar + * @param keyCode the keyCode + * @param modifiers the modifiers + * @param release true for key release + * @return the specified keystroke + */ + private static AWTKeyStroke getAWTKeyStroke(char keyChar, int keyCode, + int modifiers, boolean release) + { + // Check level 0 cache. + AWTKeyStroke stroke = recent; // Avoid thread races. + if (stroke != null && stroke.keyChar == keyChar + && stroke.keyCode == keyCode && stroke.modifiers == modifiers + && stroke.onKeyRelease == release) + return stroke; + // Create a new object, on the assumption that if it has a match in the + // cache, the VM can easily garbage collect it as it is temporary. + Constructor c = ctor; // Avoid thread races. + if (c == null) + stroke = new AWTKeyStroke(keyChar, keyCode, modifiers, release); + else + try + { + stroke = (AWTKeyStroke) c.newInstance(); + stroke.keyChar = keyChar; + stroke.keyCode = keyCode; + stroke.modifiers = modifiers; + stroke.onKeyRelease = release; + } + catch (Exception e) + { + throw (Error) new InternalError().initCause(e); + } + // Check level 1 cache. + AWTKeyStroke cached = cache.get(stroke); + if (cached == null) + cache.put(stroke, stroke); + else + stroke = cached; + return recent = stroke; + } + + /** + * Converts the modifiers to the appropriate format. + * + * @param mod the modifiers to convert + * @return the adjusted modifiers + */ + private static int extend(int mod) + { + if ((mod & (KeyEvent.SHIFT_MASK | KeyEvent.SHIFT_DOWN_MASK)) != 0) + mod |= KeyEvent.SHIFT_MASK | KeyEvent.SHIFT_DOWN_MASK; + if ((mod & (KeyEvent.CTRL_MASK | KeyEvent.CTRL_DOWN_MASK)) != 0) + mod |= KeyEvent.CTRL_MASK | KeyEvent.CTRL_DOWN_MASK; + if ((mod & (KeyEvent.META_MASK | KeyEvent.META_DOWN_MASK)) != 0) + mod |= KeyEvent.META_MASK | KeyEvent.META_DOWN_MASK; + if ((mod & (KeyEvent.ALT_MASK | KeyEvent.ALT_DOWN_MASK)) != 0) + mod |= KeyEvent.ALT_MASK | KeyEvent.ALT_DOWN_MASK; + if ((mod & (KeyEvent.ALT_GRAPH_MASK | KeyEvent.ALT_GRAPH_DOWN_MASK)) != 0) + mod |= KeyEvent.ALT_GRAPH_MASK | KeyEvent.ALT_GRAPH_DOWN_MASK; + if ((mod & KeyEvent.BUTTON1_MASK) != 0) + mod |= KeyEvent.BUTTON1_DOWN_MASK; + return mod & MODIFIERS_MASK; + } +} // class AWTKeyStroke diff --git a/libjava/classpath/java/awt/AWTPermission.java b/libjava/classpath/java/awt/AWTPermission.java new file mode 100644 index 000000000..3e50c059f --- /dev/null +++ b/libjava/classpath/java/awt/AWTPermission.java @@ -0,0 +1,121 @@ +/* AWTPermission.java -- AWT related permissions + Copyright (C) 2000, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.security.BasicPermission; + +/** + * This class implements permissions for AWT. This is a named + * permission. No actions are defined. + * + * <p>The following table provides a list of all the possible AWTPermission + * permission names with a description of what that permission allows.<br> + * <table border=1> + * <tr><th>Permission Name</th><th>Permission Allows</th><th>Risks</th</tr> + * <tr> + * <td><code>accessClipboard</code></td> + * <td>posting and reading the AWT clipboard</td> + * <td>the clipboard may contain sensitive data</td></tr> + * <tr> + * <td><code>accessEventQueue</code></td> + * <td>access to the AWT event queue</td> + * <td>malicious code could remove real events and replace them with bogus + * ones, including simulating the user granting permission</td></tr> + * <tr> + * <td><code>listenToAllAWTEvents</code></td> + * <td>listen to system-wide AWT events</td> + * <td>malicious code can read passwords entered in an AWT event, and in + * combination with accessEventQueue, could fake system events</td></tr> + * <tr> + * <td><code>showWindowWithoutWarningBanner</code></td> + * <td>display a window without a banner notification of insecurity</td> + * <td>malicious code could install a Trojan horse applet that looks like + * a normal window, and thus steal data like passwords</td></tr> + * <tr> + * <td><code>readDisplayPixels</code></td> + * <td>read back pixels from the display screen</td> + * <td>malicious code could snoop on the user's actions</td></tr> + * <tr> + * <td><code>createRobot</code></td> + * <td>create an instance of java.awt.Robot</td> + * <td>these objects can generate events as though they were the user; so + * malicious code could control the system</td></tr> + * <tr> + * <td><code>fullScreenExclusive</code></td> + * <td>enter full-screen exclusive mode</td> + * <td>malicious code could masquerade as a trusted program</td></tr> + * </table> + * + * @author Tom Tromey (tromey@redhat.com) + * @since 1.2 + * @status updated to 1.4 + */ +public final class AWTPermission extends BasicPermission +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 8890392402588814465L; + + /** + * Construct a AWTPermission with the given name. + * + * @param name the permission name + * @throws NullPointerException if name is null + * @throws IllegalArgumentException if name is invalid + */ + public AWTPermission(String name) + { + super(name); + } + + /** + * Create a new permission with the specified name. The actions argument + * is ignored, as AWT permissions have no actions. + * + * @param name the permission name + * @param actions ignored + * @throws NullPointerException if name is null + * @throws IllegalArgumentException if name is invalid + */ + public AWTPermission(String name, String actions) + { + super(name); + } +} // class AWTPermission diff --git a/libjava/classpath/java/awt/ActiveEvent.java b/libjava/classpath/java/awt/ActiveEvent.java new file mode 100644 index 000000000..e42959fe3 --- /dev/null +++ b/libjava/classpath/java/awt/ActiveEvent.java @@ -0,0 +1,61 @@ +/* ActiveEvent.java -- a self-dispatching event + Copyright (C) 2000, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +/** + * An interface for events which can dispatch themselves in another thread. + * This has two uses: first, if your code is in a critical section, calling a + * synchronized method might deadlock. But by using an ActiveEvent to call + * the second section, it will not obtain the lock until you have left the + * critical section, avoiding deadlock. The second use is for calling + * untrusted code. For example, system code should use an ActiveEvent to + * invoke user code securely. + * + * @author Tom Tromey (tromey@cygnus.com) + * @since 1.2 + * @status updated to 1.4 + */ +public interface ActiveEvent +{ + /** + * Dispatch the event, according to what the event needs done. Invoked + * automatically if this is placed on the <code>EventDispatchQueue</code>. + */ + void dispatch(); +} // interface ActiveEvent diff --git a/libjava/classpath/java/awt/Adjustable.java b/libjava/classpath/java/awt/Adjustable.java new file mode 100644 index 000000000..8f633e91a --- /dev/null +++ b/libjava/classpath/java/awt/Adjustable.java @@ -0,0 +1,171 @@ +/* Adjustable.java -- Objects with a numeric adjustment scale + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.AdjustmentListener; + +/** + * This interface is for objects that take a numeric value that can be + * adjusted within a bounded range. For example, a scroll bar. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.0 + * @status updated to 1.4 + */ +public interface Adjustable +{ + /** Constant for an adjustable object with horizontal orientation. */ + int HORIZONTAL = 0; + + /** Constant for an adjustable object with vertical orientation. */ + int VERTICAL = 1; + + /** Constant for an adjustable object with no orientation. */ + int NO_ORIENTATION = 2; + + /** + * Returns a constant representing the orientation of the object. + * + * @return the orientation of this object + * @see #HORIZONTAL + * @see #VERTICAL + * @see #NO_ORIENTATION + */ + int getOrientation(); + + /** + * Sets the minimum value this object can have. + * + * @param minimum the new minimum value + */ + void setMinimum(int minimum); + + /** + * Returns the minimum value this object can have. + * + * @return the minimum value + */ + int getMinimum(); + + /** + * Sets the maximum value this object can have. + * + * @param maximum the new maximum value + */ + void setMaximum(int maximum); + + /** + * Returns the maximum value this object can have. + * + * @return the maximum value + */ + int getMaximum(); + + /** + * Sets the increment value for incrementing the value by units. + * + * @param increment the unit increment value + */ + void setUnitIncrement(int increment); + + /** + * Returns the increment value for incrementing the value by units. + * + * @return the unit increment value + */ + int getUnitIncrement(); + + /** + * Sets the increment value for incrementing the value by blocks. + * + * @param increment the block increment value + */ + void setBlockIncrement(int increment); + + /** + * Returns the increment value for incrementing the value by blocks. + * + * @return the block increment value + */ + int getBlockIncrement(); + + /** + * Sets the length of the indicator for this object to the specified value. + * + * @param length the indicator length + */ + void setVisibleAmount(int length); + + /** + * Returns the length of the indicator for this object. + * + * @return the indicator length + */ + int getVisibleAmount(); + + /** + * Sets the current value of the object. + * + * @param value the new value + */ + void setValue(int value); + + /** + * Returns the current value of the object. + * + * @return the current value + */ + int getValue(); + + /** + * Adds a listener that will receive adjustment events for this object. + * + * @param listener the adjustment listener to add + * @see java.awt.event.AdjustmentEvent + */ + void addAdjustmentListener(AdjustmentListener listener); + + /** + * Removes an adjustment listener from this object. + * + * @param listener the adjustment listener to remove + * @see java.awt.event.AdjustmentEvent + */ + void removeAdjustmentListener(AdjustmentListener listener); +} // interface Adjustable diff --git a/libjava/classpath/java/awt/AlphaComposite.java b/libjava/classpath/java/awt/AlphaComposite.java new file mode 100644 index 000000000..d6c43d139 --- /dev/null +++ b/libjava/classpath/java/awt/AlphaComposite.java @@ -0,0 +1,215 @@ +/* AlphaComposite.java -- provides a context for performing alpha compositing + Copyright (C) 2002, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import gnu.java.awt.java2d.AlphaCompositeContext; + +import java.awt.image.ColorModel; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see Composite + * @see CompositeContext + * @since 1.3 + * @status updated to 1.4 except for createContext, needs documentation + */ +public final class AlphaComposite implements Composite +{ + /** Map Long to AlphaComposites. See getInstance for details. */ + private static final LinkedHashMap cache = new LinkedHashMap(11, 0.75f, true) + { + /** The largest the alpha composite cache can grow. */ + private static final int MAX_CACHE_SIZE = 2048; + + /** Prune stale entries. */ + protected boolean removeEldestEntry(Map.Entry eldest) + { + return size() > MAX_CACHE_SIZE; + } + }; + + public static final int CLEAR = 1; + public static final int SRC = 2; + public static final int DST = 9; + public static final int SRC_OVER = 3; + public static final int DST_OVER = 4; + public static final int SRC_IN = 5; + public static final int DST_IN = 6; + public static final int SRC_OUT = 7; + public static final int DST_OUT = 8; + public static final int SRC_ATOP = 10; + public static final int DST_ATOP = 11; + public static final int XOR = 12; + public static final AlphaComposite Clear = getInstance(CLEAR); + public static final AlphaComposite Src = getInstance(SRC); + public static final AlphaComposite Dst = getInstance(DST); + public static final AlphaComposite SrcOver = getInstance(SRC_OVER); + public static final AlphaComposite DstOver = getInstance(DST_OVER); + public static final AlphaComposite SrcIn = getInstance(SRC_IN); + public static final AlphaComposite DstIn = getInstance(DST_IN); + public static final AlphaComposite SrcOut = getInstance(SRC_OUT); + public static final AlphaComposite DstOut = getInstance(DST_OUT); + public static final AlphaComposite SrcAtop = getInstance(SRC_ATOP); + public static final AlphaComposite DstAtop = getInstance(DST_ATOP); + public static final AlphaComposite Xor = getInstance(XOR); + + private final int rule; + private final float alpha; + private AlphaComposite(int rule, float alpha) + { + this.rule = rule; + this.alpha = alpha; + } + + /** + * Creates an AlphaComposite object with the specified rule. + * + * @param rule The compositing rule. + * + * @exception IllegalArgumentException If rule is not one of the following: + * CLEAR, SRC, DST, SRC_OVER, DST_OVER, SRC_IN, DST_IN, SRC_OUT, DST_OUT, + * SRC_ATOP, DST_ATOP, or XOR. + */ + public static AlphaComposite getInstance(int rule) + { + return getInstance(rule, 1); + } + + /** + * Creates an AlphaComposite object with the specified rule and the constant + * alpha to multiply with the alpha of the source. The source is multiplied + * with the specified alpha before being composited with the destination. + * + * @param rule The compositing rule. + * + * @exception IllegalArgumentException If rule is not one of the following: + * CLEAR, SRC, DST, SRC_OVER, DST_OVER, SRC_IN, DST_IN, SRC_OUT, DST_OUT, + * SRC_ATOP, DST_ATOP, or XOR. + */ + public static AlphaComposite getInstance(int rule, float alpha) + { + if (rule < CLEAR || rule > XOR || ! (alpha >= 0 && alpha <= 1)) + throw new IllegalArgumentException(); + // This long is guaranteed unique for all valid alpha composites. + Long l = new Long(rule + Double.doubleToLongBits(alpha)); + AlphaComposite a = (AlphaComposite) cache.get(l); + if (a == null) + { + a = new AlphaComposite(rule, alpha); + cache.put(l, a); + } + return a; + } + + /** + * Creates a {@link CompositeContext} that can be used to perform + * compositing operations according to this AlphaComposite settings. + * + * @param srcColorModel the color model of the source raster + * @param dstColorModel the color model of the destination raster + * @param hints the rendering hints to use + * + * @return a {@link CompositeContext} that can be used to perform + * compositing operations according to this AlphaComposite settings + */ + public CompositeContext createContext(ColorModel srcColorModel, + ColorModel dstColorModel, + RenderingHints hints) + { + return new AlphaCompositeContext(this, srcColorModel, dstColorModel); + } + + /** + * Return an <code>AlphaComposite</code> similar to <code>this</code>, + * that uses the specified rule. If <code>rule</code> is the same as + * <code>this.rule</code>, then <code>this</code> is returned. + * + * @since 1.6 + */ + public AlphaComposite derive(int rule) + { + if (this.rule == rule) + return this; + else + return AlphaComposite.getInstance(rule, this.getAlpha()); + } + + /** + * Return an <code>AlphaComposite</code> similar to <code>this</code>, + * that uses the specified <code>alpha</code>. + * + * If <code>alph</code> is the same as <code>this.alpha</code>, + * then <code>this</code> is returned. + * + * @since 1.6 + */ + public AlphaComposite derive(float alpha) + { + if (this.getAlpha() == alpha) + return this; + else + return AlphaComposite.getInstance(this.getRule(), alpha); + } + + public float getAlpha() + { + return alpha; + } + + public int getRule() + { + return rule; + } + + public int hashCode() + { + return 31 * Float.floatToIntBits(alpha) + rule; + } + + public boolean equals(Object o) + { + if (! (o instanceof AlphaComposite)) + return false; + AlphaComposite a = (AlphaComposite) o; + return rule == a.rule && alpha == a.alpha; + } +} // class AlphaComposite diff --git a/libjava/classpath/java/awt/AttributeValue.java b/libjava/classpath/java/awt/AttributeValue.java new file mode 100644 index 000000000..080e92e22 --- /dev/null +++ b/libjava/classpath/java/awt/AttributeValue.java @@ -0,0 +1,98 @@ +/* AttributeValue.java -- parent of type-safe enums of attributes + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +/** + * This class is undocumented by Sun, but it is the parent of several other + * classes, all of which are type-safe enumerations. This takes care of + * <code>equals</code>, <code>toString</code>, and <code>hashCode</code>, so + * that you don't have to (although hashCode is commonly overridden). + * + * @author Eric Blake (ebb9@email.byu.edu) + */ +class AttributeValue +{ + /** The value of the enumeration. Package visible for speed. */ + final int value; + + /** The list of enumeration names for the given subclass. */ + private final String[] names; + + /** + * Construct a type-safe enumeration element. For example,<br> + * <pre> + * class Foo extends AttributeValue + * { + * private static final String[] names = { "one", "two" } + * public static final Foo ONE = new Foo(0); + * public static final Foo TWO = new Foo(1); + * private Foo(int value) { super(value, names); } + * } + * </pre> + * + * @param value the position of this enumeration element, consecutive from 0 + * @param names the constant list of enumeration names for the subclass + */ + AttributeValue(int value, String[] names) + { + this.value = value; + this.names = names; + } + + /** + * Returns the hashcode of this element. This is the index of the element + * in the enumeration. Note that equals defaults to the == relation. + * + * @return the hashcode + */ + public int hashCode() + { + return value; + } + + /** + * Returns the name of this enumeration element. + * + * @return the element name + */ + public String toString() + { + return names[value]; + } +} // class AttributeValue diff --git a/libjava/classpath/java/awt/BasicStroke.java b/libjava/classpath/java/awt/BasicStroke.java new file mode 100644 index 000000000..eac69d986 --- /dev/null +++ b/libjava/classpath/java/awt/BasicStroke.java @@ -0,0 +1,902 @@ +/* BasicStroke.java -- + Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import gnu.java.awt.java2d.CubicSegment; +import gnu.java.awt.java2d.LineSegment; +import gnu.java.awt.java2d.QuadSegment; +import gnu.java.awt.java2d.Segment; + +import java.awt.geom.FlatteningPathIterator; +import java.awt.geom.GeneralPath; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.util.Arrays; + +/** + * A general purpose {@link Stroke} implementation that can represent a wide + * variety of line styles for use with subclasses of {@link Graphics2D}. + * <p> + * The line cap and join styles can be set using the options illustrated + * here: + * <p> + * <img src="doc-files/capjoin.png" width="350" height="180" + * alt="Illustration of line cap and join styles" /> + * <p> + * A dash array can be used to specify lines with alternating opaque and + * transparent sections. + */ +public class BasicStroke implements Stroke +{ + /** + * Indicates a mitered line join style. See the class overview for an + * illustration. + */ + public static final int JOIN_MITER = 0; + + /** + * Indicates a rounded line join style. See the class overview for an + * illustration. + */ + public static final int JOIN_ROUND = 1; + + /** + * Indicates a bevelled line join style. See the class overview for an + * illustration. + */ + public static final int JOIN_BEVEL = 2; + + /** + * Indicates a flat line cap style. See the class overview for an + * illustration. + */ + public static final int CAP_BUTT = 0; + + /** + * Indicates a rounded line cap style. See the class overview for an + * illustration. + */ + public static final int CAP_ROUND = 1; + + /** + * Indicates a square line cap style. See the class overview for an + * illustration. + */ + public static final int CAP_SQUARE = 2; + + /** The stroke width. */ + private final float width; + + /** The line cap style. */ + private final int cap; + + /** The line join style. */ + private final int join; + + /** The miter limit. */ + private final float limit; + + /** The dash array. */ + private final float[] dash; + + /** The dash phase. */ + private final float phase; + + // The inner and outer paths of the stroke + private Segment start, end; + + /** + * Creates a new <code>BasicStroke</code> instance with the given attributes. + * + * @param width the line width (>= 0.0f). + * @param cap the line cap style (one of {@link #CAP_BUTT}, + * {@link #CAP_ROUND} or {@link #CAP_SQUARE}). + * @param join the line join style (one of {@link #JOIN_ROUND}, + * {@link #JOIN_BEVEL}, or {@link #JOIN_MITER}). + * @param miterlimit the limit to trim the miter join. The miterlimit must be + * greater than or equal to 1.0f. + * @param dash The array representing the dashing pattern. There must be at + * least one non-zero entry. + * @param dashPhase is negative and dash is not null. + * + * @throws IllegalArgumentException If one input parameter doesn't meet + * its needs. + */ + public BasicStroke(float width, int cap, int join, float miterlimit, + float[] dash, float dashPhase) + { + if (width < 0.0f ) + throw new IllegalArgumentException("width " + width + " < 0"); + else if (cap < CAP_BUTT || cap > CAP_SQUARE) + throw new IllegalArgumentException("cap " + cap + " out of range [" + + CAP_BUTT + ".." + CAP_SQUARE + "]"); + else if (miterlimit < 1.0f && join == JOIN_MITER) + throw new IllegalArgumentException("miterlimit " + miterlimit + + " < 1.0f while join == JOIN_MITER"); + else if (join < JOIN_MITER || join > JOIN_BEVEL) + throw new IllegalArgumentException("join " + join + " out of range [" + + JOIN_MITER + ".." + JOIN_BEVEL + + "]"); + else if (dashPhase < 0.0f && dash != null) + throw new IllegalArgumentException("dashPhase " + dashPhase + + " < 0.0f while dash != null"); + else if (dash != null) + if (dash.length == 0) + throw new IllegalArgumentException("dash.length is 0"); + else + { + boolean allZero = true; + + for ( int i = 0; i < dash.length; ++i) + { + if (dash[i] != 0.0f) + { + allZero = false; + break; + } + } + + if (allZero) + throw new IllegalArgumentException("all dashes are 0.0f"); + } + + this.width = width; + this.cap = cap; + this.join = join; + limit = miterlimit; + this.dash = dash == null ? null : (float[]) dash.clone(); + phase = dashPhase; + } + + /** + * Creates a new <code>BasicStroke</code> instance with the given attributes. + * + * @param width the line width (>= 0.0f). + * @param cap the line cap style (one of {@link #CAP_BUTT}, + * {@link #CAP_ROUND} or {@link #CAP_SQUARE}). + * @param join the line join style (one of {@link #JOIN_ROUND}, + * {@link #JOIN_BEVEL}, or {@link #JOIN_MITER}). + * @param miterlimit the limit to trim the miter join. The miterlimit must be + * greater than or equal to 1.0f. + * + * @throws IllegalArgumentException If one input parameter doesn't meet + * its needs. + */ + public BasicStroke(float width, int cap, int join, float miterlimit) + { + this(width, cap, join, miterlimit, null, 0); + } + + /** + * Creates a new <code>BasicStroke</code> instance with the given attributes. + * The miter limit defaults to <code>10.0</code>. + * + * @param width the line width (>= 0.0f). + * @param cap the line cap style (one of {@link #CAP_BUTT}, + * {@link #CAP_ROUND} or {@link #CAP_SQUARE}). + * @param join the line join style (one of {@link #JOIN_ROUND}, + * {@link #JOIN_BEVEL}, or {@link #JOIN_MITER}). + * + * @throws IllegalArgumentException If one input parameter doesn't meet + * its needs. + */ + public BasicStroke(float width, int cap, int join) + { + this(width, cap, join, 10, null, 0); + } + + /** + * Creates a new <code>BasicStroke</code> instance with the given line + * width. The default values are: + * <ul> + * <li>line cap style: {@link #CAP_SQUARE};</li> + * <li>line join style: {@link #JOIN_MITER};</li> + * <li>miter limit: <code>10.0f</code>. + * </ul> + * + * @param width the line width (>= 0.0f). + * + * @throws IllegalArgumentException If <code>width</code> is negative. + */ + public BasicStroke(float width) + { + this(width, CAP_SQUARE, JOIN_MITER, 10, null, 0); + } + + /** + * Creates a new <code>BasicStroke</code> instance. The default values are: + * <ul> + * <li>line width: <code>1.0f</code>;</li> + * <li>line cap style: {@link #CAP_SQUARE};</li> + * <li>line join style: {@link #JOIN_MITER};</li> + * <li>miter limit: <code>10.0f</code>. + * </ul> + */ + public BasicStroke() + { + this(1, CAP_SQUARE, JOIN_MITER, 10, null, 0); + } + + /** + * Creates a shape representing the stroked outline of the given shape. + * THIS METHOD IS NOT YET IMPLEMENTED. + * + * @param s the shape. + */ + public Shape createStrokedShape(Shape s) + { + PathIterator pi = s.getPathIterator(null); + + if( dash == null ) + return solidStroke( pi ); + + return dashedStroke( pi ); + } + + /** + * Returns the line width. + * + * @return The line width. + */ + public float getLineWidth() + { + return width; + } + + /** + * Returns a code indicating the line cap style (one of {@link #CAP_BUTT}, + * {@link #CAP_ROUND}, {@link #CAP_SQUARE}). + * + * @return A code indicating the line cap style. + */ + public int getEndCap() + { + return cap; + } + + /** + * Returns a code indicating the line join style (one of {@link #JOIN_BEVEL}, + * {@link #JOIN_MITER} or {@link #JOIN_ROUND}). + * + * @return A code indicating the line join style. + */ + public int getLineJoin() + { + return join; + } + + /** + * Returns the miter limit. + * + * @return The miter limit. + */ + public float getMiterLimit() + { + return limit; + } + + /** + * Returns the dash array, which defines the length of alternate opaque and + * transparent sections in lines drawn with this stroke. If + * <code>null</code>, a continuous line will be drawn. + * + * @return The dash array (possibly <code>null</code>). + */ + public float[] getDashArray() + { + return dash; + } + + /** + * Returns the dash phase for the stroke. This is the offset from the start + * of a path at which the pattern defined by {@link #getDashArray()} is + * rendered. + * + * @return The dash phase. + */ + public float getDashPhase() + { + return phase; + } + + /** + * Returns the hash code for this object. The hash is calculated by + * xoring the hash, cap, join, limit, dash array and phase values + * (converted to <code>int</code> first with + * <code>Float.floatToIntBits()</code> if the value is a + * <code>float</code>). + * + * @return The hash code. + */ + public int hashCode() + { + int hash = Float.floatToIntBits(width); + hash ^= cap; + hash ^= join; + hash ^= Float.floatToIntBits(limit); + + if (dash != null) + for (int i = 0; i < dash.length; i++) + hash ^= Float.floatToIntBits(dash[i]); + + hash ^= Float.floatToIntBits(phase); + + return hash; + } + + /** + * Compares this <code>BasicStroke</code> for equality with an arbitrary + * object. This method returns <code>true</code> if and only if: + * <ul> + * <li><code>o</code> is an instanceof <code>BasicStroke</code>;</li> + * <li>this object has the same width, line cap style, line join style, + * miter limit, dash array and dash phase as <code>o</code>.</li> + * </ul> + * + * @param o the object (<code>null</code> permitted). + * + * @return <code>true</code> if this stroke is equal to <code>o</code> and + * <code>false</code> otherwise. + */ + public boolean equals(Object o) + { + if (! (o instanceof BasicStroke)) + return false; + BasicStroke s = (BasicStroke) o; + return width == s.width && cap == s.cap && join == s.join + && limit == s.limit && Arrays.equals(dash, s.dash) && phase == s.phase; + } + + private Shape solidStroke(PathIterator pi) + { + double[] coords = new double[6]; + double x, y, x0, y0; + boolean pathOpen = false; + GeneralPath output = new GeneralPath( ); + Segment[] p; + x = x0 = y = y0 = 0; + + while( !pi.isDone() ) + { + switch( pi.currentSegment(coords) ) + { + case PathIterator.SEG_MOVETO: + x0 = x = coords[0]; + y0 = y = coords[1]; + if( pathOpen ) + { + capEnds(); + convertPath(output, start); + start = end = null; + pathOpen = false; + } + break; + + case PathIterator.SEG_LINETO: + p = (new LineSegment(x, y, coords[0], coords[1])). + getDisplacedSegments(width/2.0); + if( !pathOpen ) + { + start = p[0]; + end = p[1]; + pathOpen = true; + } + else + addSegments(p); + + x = coords[0]; + y = coords[1]; + break; + + case PathIterator.SEG_QUADTO: + p = (new QuadSegment(x, y, coords[0], coords[1], coords[2], + coords[3])).getDisplacedSegments(width/2.0); + if( !pathOpen ) + { + start = p[0]; + end = p[1]; + pathOpen = true; + } + else + addSegments(p); + + x = coords[2]; + y = coords[3]; + break; + + case PathIterator.SEG_CUBICTO: + p = new CubicSegment(x, y, coords[0], coords[1], + coords[2], coords[3], + coords[4], coords[5]).getDisplacedSegments(width/2.0); + if( !pathOpen ) + { + start = p[0]; + end = p[1]; + pathOpen = true; + } + else + addSegments(p); + + x = coords[4]; + y = coords[5]; + break; + + case PathIterator.SEG_CLOSE: + if (x == x0 && y == y0) + { + joinSegments(new Segment[] { start.first, end.first }); + } + else + { + p = (new LineSegment(x, y, x0, y0)).getDisplacedSegments(width / 2.0); + addSegments(p); + } + convertPath(output, start); + convertPath(output, end); + start = end = null; + pathOpen = false; + output.setWindingRule(GeneralPath.WIND_EVEN_ODD); + break; + } + pi.next(); + } + + if( pathOpen ) + { + capEnds(); + convertPath(output, start); + } + return output; + } + + private Shape dashedStroke(PathIterator pi) + { + // The choice of (flatnessSq == width / 3) is made to be consistent with + // the flattening in CubicSegment.getDisplacedSegments + FlatteningPathIterator flat = new FlatteningPathIterator(pi, + Math.sqrt(width / 3)); + + // Holds the endpoint of the current segment (or piece of a segment) + double[] coords = new double[2]; + + // Holds end of the last segment + double x, y, x0, y0; + x = x0 = y = y0 = 0; + + // Various useful flags + boolean pathOpen = false; + boolean dashOn = true; + boolean offsetting = (phase != 0); + + // How far we are into the current dash + double distance = 0; + int dashIndex = 0; + + // And variables to hold the final output + GeneralPath output = new GeneralPath(); + Segment[] p; + + // Iterate over the FlatteningPathIterator + while (! flat.isDone()) + { + switch (flat.currentSegment(coords)) + { + case PathIterator.SEG_MOVETO: + x0 = x = coords[0]; + y0 = y = coords[1]; + + if (pathOpen) + { + capEnds(); + convertPath(output, start); + start = end = null; + pathOpen = false; + } + + break; + + case PathIterator.SEG_LINETO: + boolean segmentConsumed = false; + + while (! segmentConsumed) + { + // Find the total remaining length of this segment + double segLength = Math.sqrt((x - coords[0]) * (x - coords[0]) + + (y - coords[1]) + * (y - coords[1])); + boolean spanBoundary = true; + double[] segmentEnd = null; + + // The current segment fits entirely inside the current dash + if ((offsetting && distance + segLength <= phase) + || distance + segLength <= dash[dashIndex]) + { + spanBoundary = false; + } + + // Otherwise, we need to split the segment in two, as this + // segment spans a dash boundry + else + { + segmentEnd = (double[]) coords.clone(); + + // Calculate the remaining distance in this dash, + // and coordinates of the dash boundary + double reqLength; + if (offsetting) + reqLength = phase - distance; + else + reqLength = dash[dashIndex] - distance; + + coords[0] = x + ((coords[0] - x) * reqLength / segLength); + coords[1] = y + ((coords[1] - y) * reqLength / segLength); + } + + if (offsetting || ! dashOn) + { + // Dash is off, or we are in offset - treat this as a + // moveTo + x0 = x = coords[0]; + y0 = y = coords[1]; + + if (pathOpen) + { + capEnds(); + convertPath(output, start); + start = end = null; + pathOpen = false; + } + } + else + { + // Dash is on - treat this as a lineTo + p = (new LineSegment(x, y, coords[0], coords[1])).getDisplacedSegments(width / 2.0); + + if (! pathOpen) + { + start = p[0]; + end = p[1]; + pathOpen = true; + } + else + addSegments(p); + + x = coords[0]; + y = coords[1]; + } + + // Update variables depending on whether we spanned a + // dash boundary or not + if (! spanBoundary) + { + distance += segLength; + segmentConsumed = true; + } + else + { + if (offsetting) + offsetting = false; + dashOn = ! dashOn; + distance = 0; + coords = segmentEnd; + + if (dashIndex + 1 == dash.length) + dashIndex = 0; + else + dashIndex++; + + // Since the value of segmentConsumed is still false, + // the next run of the while loop will complete the segment + } + } + break; + + // This is a flattened path, so we don't need to deal with curves + } + flat.next(); + } + + if (pathOpen) + { + capEnds(); + convertPath(output, start); + } + return output; + } + + /** + * Cap the ends of the path (joining the start and end list of segments) + */ + private void capEnds() + { + Segment returnPath = end.last; + + end.reverseAll(); // reverse the path. + end = null; + capEnd(start, returnPath); + start.last = returnPath.last; + end = null; + + capEnd(start, start); + } + + /** + * Append the Segments in s to the GeneralPath p + */ + private void convertPath(GeneralPath p, Segment s) + { + Segment v = s; + p.moveTo((float)s.P1.getX(), (float)s.P1.getY()); + + do + { + if(v instanceof LineSegment) + p.lineTo((float)v.P2.getX(), (float)v.P2.getY()); + else if(v instanceof QuadSegment) + p.quadTo((float)((QuadSegment)v).cp.getX(), + (float)((QuadSegment)v).cp.getY(), + (float)v.P2.getX(), + (float)v.P2.getY()); + else if(v instanceof CubicSegment) + p.curveTo((float)((CubicSegment)v).cp1.getX(), + (float)((CubicSegment)v).cp1.getY(), + (float)((CubicSegment)v).cp2.getX(), + (float)((CubicSegment)v).cp2.getY(), + (float)v.P2.getX(), + (float)v.P2.getY()); + v = v.next; + } while(v != s && v != null); + + p.closePath(); + } + + /** + * Add the segments to start and end (the inner and outer edges of the stroke) + */ + private void addSegments(Segment[] segments) + { + joinSegments(segments); + start.add(segments[0]); + end.add(segments[1]); + } + + private void joinSegments(Segment[] segments) + { + double[] p0 = start.last.cp2(); + double[] p1 = new double[]{start.last.P2.getX(), start.last.P2.getY()}; + double[] p2 = new double[]{segments[0].first.P1.getX(), segments[0].first.P1.getY()}; + double[] p3 = segments[0].cp1(); + Point2D p; + + p = lineIntersection(p0[0],p0[1],p1[0],p1[1], + p2[0],p2[1],p3[0],p3[1], false); + + double det = (p1[0] - p0[0])*(p3[1] - p2[1]) - + (p3[0] - p2[0])*(p1[1] - p0[1]); + + if( det > 0 ) + { + // start and segment[0] form the 'inner' part of a join, + // connect the overlapping segments + joinInnerSegments(start, segments[0], p); + joinOuterSegments(end, segments[1], p); + } + else + { + // end and segment[1] form the 'inner' part + joinInnerSegments(end, segments[1], p); + joinOuterSegments(start, segments[0], p); + } + } + + /** + * Make a cap between a and b segments, + * where a-->b is the direction of iteration. + */ + private void capEnd(Segment a, Segment b) + { + double[] p0, p1; + double dx, dy, l; + Point2D c1,c2; + + switch( cap ) + { + case CAP_BUTT: + a.add(new LineSegment(a.last.P2, b.P1)); + break; + + case CAP_SQUARE: + p0 = a.last.cp2(); + p1 = new double[]{a.last.P2.getX(), a.last.P2.getY()}; + dx = p1[0] - p0[0]; + dy = p1[1] - p0[1]; + l = Math.sqrt(dx * dx + dy * dy); + dx = 0.5*width*dx/l; + dy = 0.5*width*dy/l; + c1 = new Point2D.Double(p1[0] + dx, p1[1] + dy); + c2 = new Point2D.Double(b.P1.getX() + dx, b.P1.getY() + dy); + a.add(new LineSegment(a.last.P2, c1)); + a.add(new LineSegment(c1, c2)); + a.add(new LineSegment(c2, b.P1)); + break; + + case CAP_ROUND: + p0 = a.last.cp2(); + p1 = new double[]{a.last.P2.getX(), a.last.P2.getY()}; + dx = p1[0] - p0[0]; + dy = p1[1] - p0[1]; + if (dx != 0 && dy != 0) + { + l = Math.sqrt(dx * dx + dy * dy); + dx = (2.0/3.0)*width*dx/l; + dy = (2.0/3.0)*width*dy/l; + } + + c1 = new Point2D.Double(p1[0] + dx, p1[1] + dy); + c2 = new Point2D.Double(b.P1.getX() + dx, b.P1.getY() + dy); + a.add(new CubicSegment(a.last.P2, c1, c2, b.P1)); + break; + } + a.add(b); + } + + /** + * Returns the intersection of two lines, or null if there isn't one. + * @param infinite - true if the lines should be regarded as infinite, false + * if the intersection must be within the given segments. + * @return a Point2D or null. + */ + private Point2D lineIntersection(double X1, double Y1, + double X2, double Y2, + double X3, double Y3, + double X4, double Y4, + boolean infinite) + { + double x1 = X1; + double y1 = Y1; + double rx = X2 - x1; + double ry = Y2 - y1; + + double x2 = X3; + double y2 = Y3; + double sx = X4 - x2; + double sy = Y4 - y2; + + double determinant = sx * ry - sy * rx; + double nom = (sx * (y2 - y1) + sy * (x1 - x2)); + + // lines can be considered parallel. + if (Math.abs(determinant) < 1E-6) + return null; + + nom = nom / determinant; + + // check if lines are within the bounds + if(!infinite && (nom > 1.0 || nom < 0.0)) + return null; + + return new Point2D.Double(x1 + nom * rx, y1 + nom * ry); + } + + /** + * Join a and b segments, where a-->b is the direction of iteration. + * + * insideP is the inside intersection point of the join, needed for + * calculating miter lengths. + */ + private void joinOuterSegments(Segment a, Segment b, Point2D insideP) + { + double[] p0, p1; + double dx, dy, l; + Point2D c1,c2; + + switch( join ) + { + case JOIN_MITER: + p0 = a.last.cp2(); + p1 = new double[]{a.last.P2.getX(), a.last.P2.getY()}; + double[] p2 = new double[]{b.P1.getX(), b.P1.getY()}; + double[] p3 = b.cp1(); + Point2D p = lineIntersection(p0[0],p0[1],p1[0],p1[1],p2[0],p2[1],p3[0],p3[1], true); + if( p == null || insideP == null ) + a.add(new LineSegment(a.last.P2, b.P1)); + else if((p.distance(insideP)/width) < limit) + { + a.add(new LineSegment(a.last.P2, p)); + a.add(new LineSegment(p, b.P1)); + } + else + { + // outside miter limit, do a bevel join. + a.add(new LineSegment(a.last.P2, b.P1)); + } + break; + + case JOIN_ROUND: + p0 = a.last.cp2(); + p1 = new double[]{a.last.P2.getX(), a.last.P2.getY()}; + dx = p1[0] - p0[0]; + dy = p1[1] - p0[1]; + l = Math.sqrt(dx * dx + dy * dy); + dx = 0.5*width*dx/l; + dy = 0.5*width*dy/l; + c1 = new Point2D.Double(p1[0] + dx, p1[1] + dy); + + p0 = new double[]{b.P1.getX(), b.P1.getY()}; + p1 = b.cp1(); + + dx = p0[0] - p1[0]; // backwards direction. + dy = p0[1] - p1[1]; + l = Math.sqrt(dx * dx + dy * dy); + dx = 0.5*width*dx/l; + dy = 0.5*width*dy/l; + c2 = new Point2D.Double(p0[0] + dx, p0[1] + dy); + a.add(new CubicSegment(a.last.P2, c1, c2, b.P1)); + break; + + case JOIN_BEVEL: + a.add(new LineSegment(a.last.P2, b.P1)); + break; + } + } + + /** + * Join a and b segments, removing any overlap + */ + private void joinInnerSegments(Segment a, Segment b, Point2D p) + { + double[] p0 = a.last.cp2(); + double[] p1 = new double[] { a.last.P2.getX(), a.last.P2.getY() }; + double[] p2 = new double[] { b.P1.getX(), b.P1.getY() }; + double[] p3 = b.cp1(); + + if (p == null) + { + // Dodgy. + a.add(new LineSegment(a.last.P2, b.P1)); + p = new Point2D.Double((b.P1.getX() + a.last.P2.getX()) / 2.0, + (b.P1.getY() + a.last.P2.getY()) / 2.0); + } + else + // This assumes segments a and b are single segments, which is + // incorrect - if they are a linked list of segments (ie, passed in + // from a flattening operation), this produces strange results!! + a.last.P2 = b.P1 = p; + } +} diff --git a/libjava/classpath/java/awt/BorderLayout.java b/libjava/classpath/java/awt/BorderLayout.java new file mode 100644 index 000000000..c06eb834b --- /dev/null +++ b/libjava/classpath/java/awt/BorderLayout.java @@ -0,0 +1,742 @@ +/* BorderLayout.java -- A layout manager class + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + + +/** + * This class implements a layout manager that positions components + * in certain sectors of the parent container. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public class BorderLayout implements LayoutManager2, java.io.Serializable +{ + + /** + * Constant indicating the top of the container + */ + public static final String NORTH = "North"; + + /** + * Constant indicating the bottom of the container + */ + public static final String SOUTH = "South"; + + /** + * Constant indicating the right side of the container + */ + public static final String EAST = "East"; + + /** + * Constant indicating the left side of the container + */ + public static final String WEST = "West"; + + /** + * Constant indicating the center of the container + */ + public static final String CENTER = "Center"; + + + /** + * The constant indicating the position before the first line of the + * layout. The exact position depends on the writing system: For a + * top-to-bottom orientation, it is the same as {@link #NORTH}, for + * a bottom-to-top orientation, it is the same as {@link #SOUTH}. + * + * <p>This constant is an older name for {@link #PAGE_START} which + * has exactly the same value. + * + * @since 1.2 + */ + public static final String BEFORE_FIRST_LINE = "First"; + + /** + * The constant indicating the position after the last line of the + * layout. The exact position depends on the writing system: For a + * top-to-bottom orientation, it is the same as {@link #SOUTH}, for + * a bottom-to-top orientation, it is the same as {@link #NORTH}. + * + * <p>This constant is an older name for {@link #PAGE_END} which + * has exactly the same value. + * + * @since 1.2 + */ + public static final String AFTER_LAST_LINE = "Last"; + + /** + * The constant indicating the position before the first item of the + * layout. The exact position depends on the writing system: For a + * left-to-right orientation, it is the same as {@link #WEST}, for + * a right-to-left orientation, it is the same as {@link #EAST}. + * + * <p>This constant is an older name for {@link #LINE_START} which + * has exactly the same value. + * + * @since 1.2 + */ + public static final String BEFORE_LINE_BEGINS = "Before"; + + /** + * The constant indicating the position after the last item of the + * layout. The exact position depends on the writing system: For a + * left-to-right orientation, it is the same as {@link #EAST}, for + * a right-to-left orientation, it is the same as {@link #WEST}. + * + * <p>This constant is an older name for {@link #LINE_END} which + * has exactly the same value. + * + * @since 1.2 + */ + public static final String AFTER_LINE_ENDS = "After"; + + /** + * The constant indicating the position before the first line of the + * layout. The exact position depends on the writing system: For a + * top-to-bottom orientation, it is the same as {@link #NORTH}, for + * a bottom-to-top orientation, it is the same as {@link #SOUTH}. + * + * @since 1.4 + */ + public static final String PAGE_START = BEFORE_FIRST_LINE; + + /** + * The constant indicating the position after the last line of the + * layout. The exact position depends on the writing system: For a + * top-to-bottom orientation, it is the same as {@link #SOUTH}, for + * a bottom-to-top orientation, it is the same as {@link #NORTH}. + * + * @since 1.4 + */ + public static final String PAGE_END = AFTER_LAST_LINE; + + /** + * The constant indicating the position before the first item of the + * layout. The exact position depends on the writing system: For a + * left-to-right orientation, it is the same as {@link #WEST}, for + * a right-to-left orientation, it is the same as {@link #EAST}. + * + * @since 1.4 + */ + public static final String LINE_START = BEFORE_LINE_BEGINS; + + /** + * The constant indicating the position after the last item of the + * layout. The exact position depends on the writing system: For a + * left-to-right orientation, it is the same as {@link #EAST}, for + * a right-to-left orientation, it is the same as {@link #WEST}. + * + * @since 1.4 + */ + public static final String LINE_END = AFTER_LINE_ENDS; + + + /** + * Serialization constant. + */ + private static final long serialVersionUID = -8658291919501921765L; + + + /** + * @serial + */ + private Component north; + + /** + * @serial + */ + private Component south; + + /** + * @serial + */ + private Component east; + + /** + * @serial + */ + private Component west; + + /** + * @serial + */ + private Component center; + + /** + * @serial + */ + private Component firstLine; + + /** + * @serial + */ + private Component lastLine; + + /** + * @serial + */ + private Component firstItem; + + /** + * @serial + */ + private Component lastItem; + + /** + * @serial The horizontal gap between components + */ + private int hgap; + + /** + * @serial The vertical gap between components + */ + private int vgap; + + + // Some constants for use with calcSize(). + private static final int MIN = 0; + private static final int MAX = 1; + private static final int PREF = 2; + + + /** + * Initializes a new instance of <code>BorderLayout</code> with no + * horiztonal or vertical gaps between components. + */ + public BorderLayout() + { + this(0,0); + } + + /** + * Initializes a new instance of <code>BorderLayout</code> with the + * specified horiztonal and vertical gaps between components. + * + * @param hgap The horizontal gap between components. + * @param vgap The vertical gap between components. + */ + public BorderLayout(int hgap, int vgap) + { + this.hgap = hgap; + this.vgap = vgap; + } + + /** + * Returns the horitzontal gap value. + * + * @return The horitzontal gap value. + */ + public int getHgap() + { + return(hgap); + } + + /** + * Sets the horizontal gap to the specified value. + * + * @param hgap The new horizontal gap. + */ + public void setHgap(int hgap) + { + this.hgap = hgap; + } + + /** + * Returns the vertical gap value. + * + * @return The vertical gap value. + */ + public int getVgap() + { + return(vgap); + } + + /** + * Sets the vertical gap to the specified value. + * + * @param vgap The new vertical gap value. + */ + public void setVgap(int vgap) + { + this.vgap = vgap; + } + + /** + * Adds a component to the layout in the specified constraint position, + * which must be one of the string constants defined in this class. + * + * @param component The component to add. + * @param constraints The constraint string. + * + * @exception IllegalArgumentException If the constraint object is not + * a string, or is not one of the specified constants in this class. + */ + public void addLayoutComponent(Component component, Object constraints) + { + if (constraints != null && ! (constraints instanceof String)) + throw new IllegalArgumentException("Constraint must be a string"); + + addLayoutComponent((String) constraints, component); + } + + /** + * Adds a component to the layout in the specified constraint position, + * which must be one of the string constants defined in this class. + * + * @param constraints The constraint string. + * @param component The component to add. + * + * @exception IllegalArgumentException If the constraint object is not + * one of the specified constants in this class. + * + * @deprecated This method is deprecated in favor of + * <code>addLayoutComponent(Component, Object)</code>. + */ + public void addLayoutComponent(String constraints, Component component) + { + String str = constraints; + + if (str == null || str.equals(CENTER)) + center = component; + else if (str.equals(NORTH)) + north = component; + else if (str.equals(SOUTH)) + south = component; + else if (str.equals(EAST)) + east = component; + else if (str.equals(WEST)) + west = component; + else if (str.equals(BEFORE_FIRST_LINE)) + firstLine = component; + else if (str.equals(AFTER_LAST_LINE)) + lastLine = component; + else if (str.equals(BEFORE_LINE_BEGINS)) + firstItem = component; + else if (str.equals(AFTER_LINE_ENDS)) + lastItem = component; + else + throw new IllegalArgumentException("Constraint value not valid: " + str); + } + + /** + * Removes the specified component from the layout. + * + * @param component The component to remove from the layout. + */ + public void removeLayoutComponent(Component component) + { + if (north == component) + north = null; + if (south == component) + south = null; + if (east == component) + east = null; + if (west == component) + west = null; + if (center == component) + center = null; + if (firstItem == component) + firstItem = null; + if (lastItem == component) + lastItem = null; + if (firstLine == component) + firstLine = null; + if (lastLine == component) + lastLine = null; + } + + /** + * Returns the minimum size of the specified container using this layout. + * + * @param target The container to calculate the minimum size for. + * + * @return The minimum size of the container + */ + public Dimension minimumLayoutSize(Container target) + { + return calcSize(target, MIN); + } + + /** + * Returns the preferred size of the specified container using this layout. + * + * @param target The container to calculate the preferred size for. + * + * @return The preferred size of the container + */ + public Dimension preferredLayoutSize(Container target) + { + return calcSize(target, PREF); + } + + /** + * Returns the maximum size of the specified container using this layout. + * + * @param target The container to calculate the maximum size for. + * + * @return The maximum size of the container + */ + public Dimension maximumLayoutSize(Container target) + { + return new Dimension (Integer.MAX_VALUE, Integer.MAX_VALUE); + } + + /** + * Returns the X axis alignment, which is a <code>float</code> indicating + * where along the X axis this container wishs to position its layout. + * 0 indicates align to the left, 1 indicates align to the right, and 0.5 + * indicates align to the center. + * + * @param parent The parent container. + * + * @return The X alignment value. + */ + public float getLayoutAlignmentX(Container parent) + { + return 0.5F; + } + + /** + * Returns the Y axis alignment, which is a <code>float</code> indicating + * where along the Y axis this container wishs to position its layout. + * 0 indicates align to the top, 1 indicates align to the bottom, and 0.5 + * indicates align to the center. + * + * @param parent The parent container. + * + * @return The Y alignment value. + */ + public float getLayoutAlignmentY(Container parent) + { + return 0.5F; + } + + /** + * Instructs this object to discard any layout information it might + * have cached. + * + * @param parent The parent container. + */ + public void invalidateLayout(Container parent) + { + // Nothing to do here. + } + + /** + * Lays out the specified container according to the constraints in this + * object. + * + * @param target The container to lay out. + */ + public void layoutContainer(Container target) + { + synchronized (target.getTreeLock()) + { + Insets i = target.getInsets(); + int top = i.top; + int bottom = target.height - i.bottom; + int left = i.left; + int right = target.width - i.right; + + boolean left_to_right = target.getComponentOrientation().isLeftToRight(); + + Component my_north = north; + Component my_east = east; + Component my_south = south; + Component my_west = west; + + // Note that we currently don't handle vertical layouts. + // Neither does JDK 1.3. + if (firstLine != null) + my_north = firstLine; + if (lastLine != null) + my_south = lastLine; + if (firstItem != null) + { + if (left_to_right) + my_west = firstItem; + else + my_east = firstItem; + } + if (lastItem != null) + { + if (left_to_right) + my_east = lastItem; + else + my_west = lastItem; + } + + if (my_north != null) + { + Dimension n = calcCompSize(my_north, PREF); + my_north.setBounds(left, top, right - left, n.height); + top += n.height + vgap; + } + + if (my_south != null) + { + Dimension s = calcCompSize(my_south, PREF); + my_south.setBounds(left, bottom - s.height, right - left, s.height); + bottom -= s.height + vgap; + } + + if (my_east != null) + { + Dimension e = calcCompSize(my_east, PREF); + my_east.setBounds(right - e.width, top, e.width, bottom - top); + right -= e.width + hgap; + } + + if (my_west != null) + { + Dimension w = calcCompSize(my_west, PREF); + my_west.setBounds(left, top, w.width, bottom - top); + left += w.width + hgap; + } + + if (center != null) + center.setBounds(left, top, right - left, bottom - top); + } + } + + /** + * Returns a string representation of this layout manager. + * + * @return A string representation of this object. + */ + public String toString() + { + return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + "]"; + } + + private Dimension calcCompSize(Component comp, int what) + { + if (comp == null || ! comp.isVisible()) + return new Dimension(0, 0); + if (what == MIN) + return comp.getMinimumSize(); + else if (what == MAX) + return comp.getMaximumSize(); + return comp.getPreferredSize(); + } + + /** + * This is a helper function used to compute the various sizes for this + * layout. + */ + private Dimension calcSize(Container target, int what) + { + synchronized (target.getTreeLock()) + { + Insets ins = target.getInsets(); + + ComponentOrientation orient = target.getComponentOrientation (); + boolean left_to_right = orient.isLeftToRight (); + + Component my_north = north; + Component my_east = east; + Component my_south = south; + Component my_west = west; + + // Note that we currently don't handle vertical layouts. Neither + // does JDK 1.3. + if (firstLine != null) + my_north = firstLine; + if (lastLine != null) + my_south = lastLine; + if (firstItem != null) + { + if (left_to_right) + my_west = firstItem; + else + my_east = firstItem; + } + if (lastItem != null) + { + if (left_to_right) + my_east = lastItem; + else + my_west = lastItem; + } + + Dimension ndim = calcCompSize(my_north, what); + Dimension sdim = calcCompSize(my_south, what); + Dimension edim = calcCompSize(my_east, what); + Dimension wdim = calcCompSize(my_west, what); + Dimension cdim = calcCompSize(center, what); + + int width = edim.width + cdim.width + wdim.width + (hgap * 2); + // Check for overflow. + if (width < edim.width || width < cdim.width || width < cdim.width) + width = Integer.MAX_VALUE; + + if (ndim.width > width) + width = ndim.width; + if (sdim.width > width) + width = sdim.width; + + width += (ins.left + ins.right); + + int height = edim.height; + if (cdim.height > height) + height = cdim.height; + if (wdim.height > height) + height = wdim.height; + + int addedHeight = height + (ndim.height + sdim.height + (vgap * 2) + + ins.top + ins.bottom); + // Check for overflow. + if (addedHeight < height) + height = Integer.MAX_VALUE; + else + height = addedHeight; + + return(new Dimension(width, height)); + } + } + + /** + * Return the component at the indicated location, or null if no component + * is at that location. The constraints argument must be one of the + * location constants specified by this class. + * @param constraints the location + * @return the component at that location, or null + * @throws IllegalArgumentException if the constraints argument is not + * recognized + * @since 1.5 + */ + public Component getLayoutComponent(Object constraints) + { + if (constraints == CENTER) + return center; + if (constraints == NORTH) + return north; + if (constraints == EAST) + return east; + if (constraints == SOUTH) + return south; + if (constraints == WEST) + return west; + if (constraints == PAGE_START) + return firstLine; + if (constraints == PAGE_END) + return lastLine; + if (constraints == LINE_START) + return firstItem; + if (constraints == LINE_END) + return lastItem; + throw new IllegalArgumentException("constraint " + constraints + + " is not recognized"); + } + + /** + * Return the component at the specified location, which must be one + * of the absolute constants such as CENTER or SOUTH. The container's + * orientation is used to map this location to the correct corresponding + * component, so for instance in a right-to-left container, a request + * for the EAST component could return the LINE_END component. This will + * return null if no component is available at the given location. + * @param container the container whose orientation is used + * @param constraints the absolute location of the component + * @return the component at the location, or null + * @throws IllegalArgumentException if the constraint is not recognized + */ + public Component getLayoutComponent(Container container, Object constraints) + { + ComponentOrientation orient = container.getComponentOrientation(); + if (constraints == CENTER) + return center; + // Note that we don't support vertical layouts. + if (constraints == NORTH) + return north; + if (constraints == SOUTH) + return south; + if (constraints == WEST) + { + // Note that relative layout takes precedence. + if (orient.isLeftToRight()) + return firstItem == null ? west : firstItem; + return lastItem == null ? west : lastItem; + } + if (constraints == EAST) + { + // Note that relative layout takes precedence. + if (orient.isLeftToRight()) + return lastItem == null ? east : lastItem; + return firstItem == null ? east : firstItem; + } + throw new IllegalArgumentException("constraint " + constraints + + " is not recognized"); + } + + /** + * Return the constraint corresponding to a component in this layout. + * If the component is null, or is not in this layout, returns null. + * Otherwise, this will return one of the constraint constants defined + * in this class. + * @param c the component + * @return the constraint, or null + * @since 1.5 + */ + public Object getConstraints(Component c) + { + if (c == null) + return null; + if (c == center) + return CENTER; + if (c == north) + return NORTH; + if (c == east) + return EAST; + if (c == south) + return SOUTH; + if (c == west) + return WEST; + if (c == firstLine) + return PAGE_START; + if (c == lastLine) + return PAGE_END; + if (c == firstItem) + return LINE_START; + if (c == lastItem) + return LINE_END; + return null; + } +} diff --git a/libjava/classpath/java/awt/BufferCapabilities.java b/libjava/classpath/java/awt/BufferCapabilities.java new file mode 100644 index 000000000..522fdf7f6 --- /dev/null +++ b/libjava/classpath/java/awt/BufferCapabilities.java @@ -0,0 +1,253 @@ +/* BufferCapabilities.java -- double-buffering capabilities descriptor + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.image.BufferStrategy; + +/** + * A double-buffering capability descriptor. This class exposes + * details about the double-buffering algorithms used by image + * buffers. + * + * BufferCapabilities represents algorithms that involve at least two + * buffers but it can also specify so-called "multi-buffer" schemes + * involving more than two buffers. This class describes the + * capabilities of the front and back buffers as well as the results + * of "flipping" -- that is, what happens when an image is transferred + * from the back buffer to the front buffer. + * + * Flipping may or may not be supported or may be supported only in + * fullscreen mode. If it is not supported then "blitting" is implied + * -- that is, the contents of the back buffer are copied using a fast + * block transfer operation from the back buffer to the front buffer. + * + * The front buffer is the one that is displayed. + * + * @author Eric Blake (ebb9@email.byu.edu) + * + * @see BufferStrategy#getCapabilities() + * @see GraphicsConfiguration#getBufferCapabilities() + * + * @since 1.4 + */ +public class BufferCapabilities implements Cloneable +{ + /** + * A type-safe enumeration of buffer flipping results. + * + * @see AttributeValue + */ + public static final class FlipContents extends AttributeValue + { + /** + * The names of the different flipping results. + */ + private static final String[] NAMES + = { "undefined", "background", "prior", "copied" }; + + /** + * The contents of the back buffer are undefined after flipping. + */ + public static final FlipContents UNDEFINED = new FlipContents(0); + + /** + * The back buffer is cleared with the background color after + * flipping. + */ + public static final FlipContents BACKGROUND = new FlipContents(1); + + /** + * The back buffer contains the pre-flipping contents of the front + * buffer after flipping. In other words a true "flip" has been + * performed. + */ + public static final FlipContents PRIOR = new FlipContents(2); + + /** + * The back buffer has the same contents as the front buffer after + * flipping. + */ + public static final FlipContents COPIED = new FlipContents(3); + + /** + * Create a new flipping result descriptor. + * + * @param value the enumeration value + */ + private FlipContents(int value) + { + super(value, NAMES); + } + } + + /** + * Front buffer capabilities descriptor. + */ + private final ImageCapabilities front; + + /** + * Back buffer capabilities descriptor. + */ + private final ImageCapabilities back; + + /** + * Describes the results of a "flip" operation. + */ + private final FlipContents flip; + + /** + * Creates a buffer capabilities object. + * + * @param frontCaps front buffer capabilities descriptor + * @param backCaps back buffer capabilities descriptor + * @param flip the results of a flip operation or null if + * flipping is not supported + * + * @exception IllegalArgumentException if frontCaps or backCaps is + * null + */ + public BufferCapabilities(ImageCapabilities frontCaps, + ImageCapabilities backCaps, + FlipContents flip) + { + if (frontCaps == null || backCaps == null) + throw new IllegalArgumentException(); + this.front = frontCaps; + this.back = backCaps; + this.flip = flip; + } + + /** + * Retrieve the front buffer's image capabilities. + * + * @return the front buffer's image capabilities + */ + public ImageCapabilities getFrontBufferCapabilities() + { + return front; + } + + /** + * Retrieve the back buffer's image capabilities. + * + * @return the back buffer's image capabilities + */ + public ImageCapabilities getBackBufferCapabilities() + { + return back; + } + + /** + * Return whether or not flipping is supported. + * + * @return true if flipping is supported, false otherwise + */ + public boolean isPageFlipping() + { + return flip != null; + } + + /** + * Retrieve the result of a flipping operation. If this method + * returns null then flipping is not supported. This implies that + * "blitting", a fast block transfer, is used to copy the contents + * of the back buffer to the front buffer. Other possible return + * values are: + * <ul> + * <li><code>FlipContents.UNDEFINED</code> the contents of the + * back buffer are undefined after flipping.</li> + * <li><code>FlipContents.BACKGROUND</code> the contents of the + * back buffer are cleared to the background color after + * flipping.</li> + * <li><code>FlipContents.PRIOR</code> the back buffer contains + * the pre-flipping contents of the front * buffer after + * flipping.</li> + * <li><code>FlipContents.COPIED</code> the back buffer has the + * same contents as the front buffer after flipping.</li> + * </ul> + * + * @return the result of a flipping operation or null if flipping is + * not supported + */ + public FlipContents getFlipContents() + { + return flip; + } + + /** + * Returns true if flipping is only supported in fullscreen mode. + * + * @return true if flipping is only supported in fullscreen mode, + * false otherwise + */ + public boolean isFullScreenRequired() + { + return true; + } + + /** + * Returns true if flipping can involve more than two buffers. One + * or more intermediate buffers may be available in addition to the + * front and back buffers. + * + * @return true if there are more than two buffers available for + * flipping, false otherwise + */ + public boolean isMultiBufferAvailable() + { + return false; + } + + /** + * Clone this buffering capability descriptor. + * + * @return a clone of this buffer capability descriptor + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); + } + } +} diff --git a/libjava/classpath/java/awt/Button.java b/libjava/classpath/java/awt/Button.java new file mode 100644 index 000000000..458a45e53 --- /dev/null +++ b/libjava/classpath/java/awt/Button.java @@ -0,0 +1,467 @@ +/* Button.java -- AWT button widget + Copyright (C) 1999, 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.peer.ButtonPeer; +import java.lang.reflect.Array; +import java.util.EventListener; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleValue; + +/** + * This class provides a button widget for the AWT. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + */ +public class Button extends Component + implements java.io.Serializable, Accessible +{ + +/* + * Static Variables + */ + +// FIXME: Need readObject/writeObject for serialization + +// Serialization version constant +private static final long serialVersionUID = -8774683716313001058L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * @serial The action command name for this button. + * This is package-private to avoid an accessor method. + */ +String actionCommand; + +/** + * @serial The label for this button. + * This is package-private to avoid an accessor method. + */ +String label; + +// List of ActionListeners for this class. +private transient ActionListener action_listeners; + + /* + * The number used to generate the name returned by getName. + */ + private static transient long next_button_number; + + protected class AccessibleAWTButton extends AccessibleAWTComponent + implements AccessibleAction, AccessibleValue + { + private static final long serialVersionUID = -5932203980244017102L; + + protected AccessibleAWTButton() + { + // Do nothing here. + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleAction#getAccessibleActionCount() + */ + public int getAccessibleActionCount() + { + // Only 1 action possible + return 1; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleAction#getAccessibleActionDescription(int) + */ + public String getAccessibleActionDescription(int i) + { + // JDK 1.4.2 returns the string "click" for action 0. However, the API + // docs don't say what the string to be returned is, beyond being a + // description of the action. So we return the same thing for + // compatibility with 1.4.2. + if (i == 0) + return "click"; + return null; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleAction#doAccessibleAction(int) + */ + public boolean doAccessibleAction(int i) + { + if (i != 0) + return false; + processActionEvent(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, actionCommand)); + return true; + } + + public String getAccessibleName() + { + return label; + } + + public AccessibleAction getAccessibleAction() + { + return this; + } + + public AccessibleValue getAccessibleValue() + { + return this; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleValue#getCurrentAccessibleValue() + */ + public Number getCurrentAccessibleValue() + { + // Docs say return 1 if selected, but buttons can't be selected, right? + return new Integer(0); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleValue#setCurrentAccessibleValue(java.lang.Number) + */ + public boolean setCurrentAccessibleValue(Number number) + { + // Since there's no selection with buttons, we're ignoring this. + // TODO someone who knows shoulw check this. + return false; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleValue#getMinimumAccessibleValue() + */ + public Number getMinimumAccessibleValue() + { + return new Integer(0); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleValue#getMaximumAccessibleValue() + */ + public Number getMaximumAccessibleValue() + { + return new Integer(0); + } + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.PUSH_BUTTON; + } + } + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of <code>Button</code> with no label. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true + */ +public +Button() +{ + this(""); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of <code>Button</code> with the specified + * label. The action command name is also initialized to this value. + * + * @param label The label to display on the button. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true + */ +public +Button(String label) +{ + this.label = label; + actionCommand = label; + + if (GraphicsEnvironment.isHeadless ()) + throw new HeadlessException (); +} + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * Returns the label for this button. + * + * @return The label for this button. + */ +public String +getLabel() +{ + return(label); +} + +/*************************************************************************/ + +/** + * Sets the label for this button to the specified value. + * + * @param label The new label for this button. + */ +public synchronized void +setLabel(String label) +{ + this.label = label; + actionCommand = label; + if (peer != null) + { + ButtonPeer bp = (ButtonPeer) peer; + bp.setLabel (label); + } +} + +/*************************************************************************/ + +/** + * Returns the action command name for this button. + * + * @return The action command name for this button. + */ +public String +getActionCommand() +{ + return(actionCommand); +} + +/*************************************************************************/ + +/** + * Sets the action command name for this button to the specified value. + * + * @param actionCommand The new action command name. + */ +public void +setActionCommand(String actionCommand) +{ + this.actionCommand = actionCommand == null ? label : actionCommand; +} + +/*************************************************************************/ + +/** + * Adds a new entry to the list of listeners that will receive + * action events from this button. + * + * @param listener The listener to add. + */ +public synchronized void +addActionListener(ActionListener listener) +{ + action_listeners = AWTEventMulticaster.add(action_listeners, listener); +} + +/*************************************************************************/ + +/** + * Removes the specified listener from the list of listeners that will + * receive action events from this button. + * + * @param listener The listener to remove. + */ +public synchronized void +removeActionListener(ActionListener listener) +{ + action_listeners = AWTEventMulticaster.remove(action_listeners, listener); +} + + /** + * Returns all added <code>ActionListener</code> objects. + * + * @return an array of listeners + * + * @since 1.4 + */ + public synchronized ActionListener[] getActionListeners() + { + return (ActionListener[]) + AWTEventMulticaster.getListeners(action_listeners, + ActionListener.class); + } + +/** + * Returns all registered EventListers of the given listenerType. + * listenerType must be a subclass of EventListener, or a + * ClassClassException is thrown. + * + * @param listenerType the listener type to return + * + * @return an array of listeners + * + * @exception ClassCastException If listenerType doesn't specify a class or + * interface that implements @see java.util.EventListener. + * + * @since 1.3 + */ + public <T extends EventListener> T[] getListeners(Class<T> listenerType) + { + if (listenerType == ActionListener.class) + return (T[]) getActionListeners(); + return (T[]) Array.newInstance(listenerType, 0); + } + +/*************************************************************************/ + +/** + * Notifies this button that it should create its native peer object. + */ +public void +addNotify() +{ + if (peer == null) + peer = getToolkit ().createButton (this); + super.addNotify(); +} + +/*************************************************************************/ + +/** + * Processes an event for this button. If the specified event is an + * instance of <code>ActionEvent</code>, then the + * <code>processActionEvent()</code> method is called to dispatch it + * to any registered listeners. Otherwise, the superclass method + * will be invoked. Note that this method will not be called at all + * unless <code>ActionEvent</code>'s are enabled. This will be done + * implicitly if any listeners are added. + * + * @param event The event to process. + */ +protected void +processEvent(AWTEvent event) +{ + if (event instanceof ActionEvent) + processActionEvent((ActionEvent)event); + else + super.processEvent(event); +} + +/*************************************************************************/ + +/** + * This method dispatches an action event for this button to any + * registered listeners. + * + * @param event The event to process. + */ +protected void +processActionEvent(ActionEvent event) +{ + if (action_listeners != null) + action_listeners.actionPerformed(event); +} + +void +dispatchEventImpl(AWTEvent e) +{ + if (e.id <= ActionEvent.ACTION_LAST + && e.id >= ActionEvent.ACTION_FIRST + && (action_listeners != null + || (eventMask & AWTEvent.ACTION_EVENT_MASK) != 0)) + processEvent(e); + else + super.dispatchEventImpl(e); +} + +/*************************************************************************/ + +/** + * Returns a debugging string for this button. + * + * @return A debugging string for this button. + */ +protected String +paramString() +{ + return getName () + "," + getX () + "," + getY () + "," + + getWidth () + "x" + getHeight () + ",label=" + getLabel (); +} + +/** + * Gets the AccessibleContext associated with this <code>Button</code>. + * The context is created, if necessary. + * + * @return the associated context + */ +public AccessibleContext getAccessibleContext() +{ + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTButton(); + return accessibleContext; +} + + /** + * Generate a unique name for this button. + * + * @return A unique name for this button. + */ + String generateName () + { + return "button" + getUniqueLong (); + } + + private static synchronized long getUniqueLong () + { + return next_button_number++; + } + +} // class Button diff --git a/libjava/classpath/java/awt/Canvas.java b/libjava/classpath/java/awt/Canvas.java new file mode 100644 index 000000000..ab7a8e3fa --- /dev/null +++ b/libjava/classpath/java/awt/Canvas.java @@ -0,0 +1,354 @@ +/* Canvas.java -- + Copyright (C) 1999, 2000, 2002, 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.image.BufferStrategy; +import java.awt.peer.ComponentPeer; +import java.io.Serializable; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; + +/** + * The <code>Canvas</code> component provides a blank rectangular + * area, which the client application can use for drawing and for + * capturing events. By overriding the <code>paint()</code> method, + * the canvas can be used for anything from simple line drawings to + * full-scale custom components. + * + * @author Original author unknown + * @author Tom Tromey (tromey@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.0 + */ + +public class Canvas + extends Component + implements Serializable, Accessible +{ + + /** + * Compatible with Sun's JDK. + */ + private static final long serialVersionUID = -2284879212465893870L; + + /** + * The number used to generate the name returned by getName. + */ + private static transient long next_canvas_number; + + /** + * The buffer strategy associated with this canvas. + */ + transient BufferStrategy bufferStrategy; + + /** + * Initializes a new instance of <code>Canvas</code>. + */ + public Canvas() + { + } + + /** + * Initializes a new instance of <code>Canvas</code> + * with the supplied graphics configuration. + * + * @param graphicsConfiguration the graphics configuration to use + * for this particular canvas. + */ + public Canvas(GraphicsConfiguration graphicsConfiguration) + { + this.graphicsConfig = graphicsConfiguration; + } + + /** + * Creates the native peer for this object. + */ + public void addNotify() + { + if (peer == null) + peer = (ComponentPeer) getToolkit().createCanvas(this); + super.addNotify(); + } + + /** + * Repaints the canvas window. This method should be overridden by + * a subclass to do something useful, as this method simply paints + * the window with the background color. + * + * @param gfx the <code>Graphics</code> to use for painting + */ + public void paint(Graphics gfx) + { + /* This implementation doesn't make much sense since the filling + of background color is guaranteed for heavyweight components + such as this. But there's no need to worry, since paint() is + usually overridden anyway. */ + gfx.setColor(getBackground()); + Dimension size = getSize(); + gfx.fillRect(0, 0, size.width, size.height); + } + + /** + * This class provides accessibility support for the canvas. + */ + protected class AccessibleAWTCanvas + extends AccessibleAWTComponent + { + /** + * For compatability with Sun's JDK + */ + private static final long serialVersionUID = -6325592262103146699L; + + /** + * Constructor for the accessible canvas. + */ + protected AccessibleAWTCanvas() + { + } + + /** + * Returns the accessible role for the canvas. + * + * @return an instance of <code>AccessibleRole</code>, describing + * the role of the canvas. + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.CANVAS; + } + + } + + /** + * Gets the AccessibleContext associated with this <code>Canvas</code>. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTCanvas(); + return accessibleContext; + } + + /** + * A BltBufferStrategy for canvases. + */ + private class CanvasBltBufferStrategy extends BltBufferStrategy + { + /** + * Creates a block transfer strategy for this canvas. + * + * @param numBuffers the number of buffers in this strategy + * @param accelerated true if the buffer should be accelerated, + * false otherwise + */ + CanvasBltBufferStrategy(int numBuffers, boolean accelerated) + { + super(numBuffers, + new BufferCapabilities(new ImageCapabilities(accelerated), + new ImageCapabilities(accelerated), + BufferCapabilities.FlipContents.COPIED)); + } + } + + /** + * A FlipBufferStrategy for canvases. + */ + private class CanvasFlipBufferStrategy extends FlipBufferStrategy + { + /** + * Creates a flip buffer strategy for this canvas. + * + * @param numBuffers the number of buffers in this strategy + * + * @throws AWTException if the requested number of buffers is not + * supported + */ + CanvasFlipBufferStrategy(int numBuffers) + throws AWTException + { + super(numBuffers, + new BufferCapabilities(new ImageCapabilities(true), + new ImageCapabilities(true), + BufferCapabilities.FlipContents.COPIED)); + } + } + + /** + * Creates a buffering strategy that manages how this canvas is + * repainted. This method attempts to create the optimum strategy + * based on the desired number of buffers. Hardware or software + * acceleration may be used. + * + * createBufferStrategy attempts different levels of optimization, + * but guarantees that some strategy with the requested number of + * buffers will be created even if it is not optimal. First it + * attempts to create a page flipping strategy, then an accelerated + * blitting strategy, then an unaccelerated blitting strategy. + * + * Calling this method causes any existing buffer strategy to be + * destroyed. + * + * @param numBuffers the number of buffers in this strategy + * + * @throws IllegalArgumentException if requested number of buffers + * is less than one + * @throws IllegalStateException if this canvas is not displayable + * + * @since 1.4 + */ + public void createBufferStrategy(int numBuffers) + { + if (numBuffers < 1) + throw new IllegalArgumentException("Canvas.createBufferStrategy: number" + + " of buffers is less than one"); + + if (!isDisplayable()) + throw new IllegalStateException("Canvas.createBufferStrategy: canvas is" + + " not displayable"); + + BufferStrategy newStrategy = null; + + // try a flipping strategy + try + { + newStrategy = new CanvasFlipBufferStrategy(numBuffers); + } + catch (AWTException e) + { + } + + // fall back to an accelerated blitting strategy + if (newStrategy == null) + newStrategy = new CanvasBltBufferStrategy(numBuffers, true); + + bufferStrategy = newStrategy; + } + + /** + * Creates a buffering strategy that manages how this canvas is + * repainted. This method attempts to create a strategy based on + * the specified capabilities and throws an exception if the + * requested strategy is not supported. + * + * Calling this method causes any existing buffer strategy to be + * destroyed. + * + * @param numBuffers the number of buffers in this strategy + * @param caps the requested buffering capabilities + * + * @throws AWTException if the requested capabilities are not + * supported + * @throws IllegalArgumentException if requested number of buffers + * is less than one or if caps is null + * + * @since 1.4 + */ + public void createBufferStrategy(int numBuffers, BufferCapabilities caps) + throws AWTException + { + if (numBuffers < 1) + throw new IllegalArgumentException("Canvas.createBufferStrategy: number" + + " of buffers is less than one"); + + if (caps == null) + throw new IllegalArgumentException("Canvas.createBufferStrategy:" + + " capabilities object is null"); + + // a flipping strategy was requested + if (caps.isPageFlipping()) + bufferStrategy = new CanvasFlipBufferStrategy(numBuffers); + else + bufferStrategy = new CanvasBltBufferStrategy(numBuffers, true); + } + + /** + * Returns the buffer strategy used by the canvas. + * + * @return the buffer strategy. + * @since 1.4 + */ + public BufferStrategy getBufferStrategy() + { + return bufferStrategy; + } + + /** + * Updates the canvas in response to a request to + * <code>repaint()</code> it. The canvas is cleared + * with the current background colour, before <code>paint()</code> + * is called to add the new contents. Subclasses + * which override this method should either call this + * method via <code>super.update(graphics)</code> or re-implement + * this behaviour, so as to ensure that the canvas is + * clear before painting takes place. + * + * @param graphics the graphics context. + */ + public void update(Graphics graphics) + { + Dimension size; + + /* Clear the canvas */ + size = getSize(); + graphics.clearRect(0, 0, size.width, size.height); + /* Call the paint method */ + paint(graphics); + } + + /** + * Generate a unique name for this <code>Canvas</code>. + * + * @return A unique name for this <code>Canvas</code>. + */ + String generateName() + { + return "canvas" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_canvas_number++; + } +} diff --git a/libjava/classpath/java/awt/CardLayout.java b/libjava/classpath/java/awt/CardLayout.java new file mode 100644 index 000000000..c36daf482 --- /dev/null +++ b/libjava/classpath/java/awt/CardLayout.java @@ -0,0 +1,501 @@ +/* CardLayout.java -- Card-based layout engine + Copyright (C) 1999, 2000, 2002, 2003, 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.io.Serializable; +import java.util.Enumeration; +import java.util.Hashtable; + +/** + * This class implements a card-based layout scheme. Each included + * component is treated as a card. Only one card can be shown at a + * time. This class includes methods for changing which card is + * shown. + * + * @author Tom Tromey (tromey@redhat.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class CardLayout implements LayoutManager2, Serializable +{ + private static final long serialVersionUID = -4328196481005934313L; + + /** + * Initializes a new instance of <code>CardLayout</code> with horizontal + * and vertical gaps of 0. + */ + public CardLayout () + { + this (0, 0); + } + + /** + * Create a new <code>CardLayout</code> object with the specified + * horizontal and vertical gaps. + * + * @param hgap The horizontal gap + * @param vgap The vertical gap + */ + public CardLayout (int hgap, int vgap) + { + this.hgap = hgap; + this.vgap = vgap; + this.tab = new Hashtable (); + } + + /** + * Add a new component to the layout. The constraint must be a + * string which is used to name the component. This string can + * later be used to refer to the particular component. + * + * @param comp The component to add + * @param constraints The name by which the component can later be called + * + * @exception IllegalArgumentException If `constraints' is not a + * <code>String</code> + */ + public void addLayoutComponent (Component comp, Object constraints) + { + if (! (constraints instanceof String)) + throw new IllegalArgumentException ("Object " + constraints + + " is not a string"); + addLayoutComponent ((String) constraints, comp); + } + + /** + * Add a new component to the layout. The name can be used later + * to refer to the component. + * + * @param name The name by which the component can later be called + * @param comp The component to add + * + * @deprecated This method is deprecated in favor of + * <code>addLayoutComponent(Component, Object)</code>. + */ + public void addLayoutComponent (String name, Component comp) + { + tab.put (name, comp); + // First component added is the default component. + comp.setVisible(tab.size() == 1); + } + + /** + * Cause the first component in the container to be displayed. + * + * @param parent The parent container, not <code>null</code>. + */ + public void first (Container parent) + { + gotoComponent (parent, FIRST); + } + + /** + * Return this layout manager's horizontal gap. + * + * @return the horizontal gap + */ + public int getHgap () + { + return hgap; + } + + /** + * Return this layout manager's x alignment. This method always + * returns Component.CENTER_ALIGNMENT. + * + * @param parent Container using this layout manager instance + * + * @return the x-axis alignment + */ + public float getLayoutAlignmentX (Container parent) + { + return Component.CENTER_ALIGNMENT; + } + + /** + * Returns this layout manager's y alignment. This method always + * returns Component.CENTER_ALIGNMENT. + * + * @param parent Container using this layout manager instance + * + * @return the y-axis alignment + */ + public float getLayoutAlignmentY (Container parent) + { + return Component.CENTER_ALIGNMENT; + } + + /** + * Return this layout manager's vertical gap. + * + * @return the vertical gap + */ + public int getVgap () + { + return vgap; + } + + /** + * Invalidate this layout manager's state. + */ + public void invalidateLayout (Container target) + { + // Do nothing. + } + + /** + * Cause the last component in the container to be displayed. + * + * @param parent The parent container, not <code>null</code>. + */ + public void last (Container parent) + { + gotoComponent (parent, LAST); + } + + /** + * Lays out the container. This is done by resizing the child components + * to be the same size as the parent, less insets and gaps. + * + * @param parent The parent container. + */ + public void layoutContainer (Container parent) + { + synchronized (parent.getTreeLock ()) + { + int width = parent.width; + int height = parent.height; + + Insets ins = parent.getInsets (); + + int num = parent.ncomponents; + Component[] comps = parent.component; + + int x = ins.left + hgap; + int y = ins.top + vgap; + width = width - 2 * hgap - ins.left - ins.right; + height = height - 2 * vgap - ins.top - ins.bottom; + + for (int i = 0; i < num; ++i) + comps[i].setBounds (x, y, width, height); + } + } + + /** + * Get the maximum layout size of the container. + * + * @param target The parent container + * + * @return the maximum layout size + */ + public Dimension maximumLayoutSize (Container target) + { + if (target == null || target.ncomponents == 0) + return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); + // The JCL says that this returns Integer.MAX_VALUE for both + // dimensions. But that just seems wrong to me. + return getSize (target, MAX); + } + + /** + * Get the minimum layout size of the container. + * + * @param target The parent container + * + * @return the minimum layout size + */ + public Dimension minimumLayoutSize (Container target) + { + return getSize (target, MIN); + } + + /** + * Cause the next component in the container to be displayed. If + * this current card is the last one in the deck, the first + * component is displayed. + * + * @param parent The parent container, not <code>null</code>. + */ + public void next (Container parent) + { + gotoComponent (parent, NEXT); + } + + /** + * Get the preferred layout size of the container. + * + * @param parent The parent container + * + * @return the preferred layout size + */ + public Dimension preferredLayoutSize (Container parent) + { + return getSize (parent, PREF); + } + + /** + * Cause the previous component in the container to be displayed. + * If this current card is the first one in the deck, the last + * component is displayed. + * + * @param parent The parent container, not <code>null</code>. + */ + public void previous (Container parent) + { + gotoComponent (parent, PREV); + } + + /** + * Remove the indicated component from this layout manager. + * + * @param comp The component to remove + */ + public void removeLayoutComponent (Component comp) + { + Enumeration e = tab.keys (); + while (e.hasMoreElements ()) + { + Object key = e.nextElement (); + if (tab.get (key) == comp) + { + tab.remove (key); + Container parent = comp.getParent(); + next(parent); + break; + } + } + } + + /** + * Set this layout manager's horizontal gap. + * + * @param hgap The new gap + */ + public void setHgap (int hgap) + { + this.hgap = hgap; + } + + /** + * Set this layout manager's vertical gap. + * + * @param vgap The new gap + */ + public void setVgap (int vgap) + { + this.vgap = vgap; + } + + /** + * Cause the named component to be shown. If the component name is + * unknown or <code>null</code>, this method does nothing. + * + * @param parent The parent container, not <code>null</code>. + * @param name The name of the component to show + */ + public void show (Container parent, String name) + { + if (name == null) + return; + + if (parent.getLayout() != this) + throw new IllegalArgumentException("parent's layout is not this CardLayout"); + + Object target = tab.get (name); + if (target != null) + { + int num = parent.ncomponents; + // This is more efficient than calling getComponents(). + Component[] comps = parent.component; + for (int i = 0; i < num; ++i) + { + if (comps[i].isVisible()) + { + if (target == comps[i]) + return; + comps[i].setVisible (false); + } + } + ((Component) target).setVisible (true); + parent.validate(); + } + } + + /** + * Returns a string representation of this layout manager. + * + * @return A string representation of this object. + */ + public String toString () + { + return getClass ().getName () + "[hgap=" + hgap + ",vgap=" + vgap + "]"; + } + + /** + * This implements first(), last(), next(), and previous(). + * + * @param parent The parent container + * @param what The type of goto: FIRST, LAST, NEXT or PREV + * + * @throws IllegalArgumentException if parent has not this + * CardLayout set as its layout. + */ + private void gotoComponent (Container parent, int what) + { + if (parent.getLayout() != this) + throw new IllegalArgumentException("parent's layout is not this CardLayout"); + + synchronized (parent.getTreeLock ()) + { + int num = parent.ncomponents; + // This is more efficient than calling getComponents(). + Component[] comps = parent.component; + + if (num == 1) + { + comps[0].setVisible(true); + return; + } + + int choice = -1; + + if (what == FIRST) + choice = 0; + else if (what == LAST) + choice = num - 1; + + for (int i = 0; i < num; ++i) + { + if (comps[i].isVisible ()) + { + if (choice == i) + { + // Do nothing if we're already looking at the right + // component. + return; + } + else if (what == PREV) + { + choice = i - 1; + if (choice < 0) + choice = num - 1; + } + else if (what == NEXT) + { + choice = i + 1; + if (choice == num) + choice = 0; + } + comps[i].setVisible (false); + + if (choice >= 0) + break; + } else + { + comps[i].setVisible(true); + } + } + + if (choice >= 0 && choice < num) + comps[choice].setVisible (true); + } + } + + // Compute the size according to WHAT. + private Dimension getSize (Container parent, int what) + { + synchronized (parent.getTreeLock ()) + { + int w = 0, h = 0, num = parent.ncomponents; + Component[] comps = parent.component; + + for (int i = 0; i < num; ++i) + { + Dimension d; + + if (what == MIN) + d = comps[i].getMinimumSize (); + else if (what == MAX) + d = comps[i].getMaximumSize (); + else + d = comps[i].getPreferredSize (); + + w = Math.max (d.width, w); + h = Math.max (d.height, h); + } + + Insets i = parent.getInsets (); + w += 2 * hgap + i.right + i.left; + h += 2 * vgap + i.bottom + i.top; + + // Handle overflow. + if (w < 0) + w = Integer.MAX_VALUE; + if (h < 0) + h = Integer.MAX_VALUE; + + return new Dimension (w, h); + } + } + + /** + * @serial Horizontal gap value. + */ + private int hgap; + + /** + * @serial Vertical gap value. + */ + private int vgap; + + /** + * @serial Table of named components. + */ + private Hashtable tab; + + // These constants are used by the private gotoComponent method. + private static final int FIRST = 0; + private static final int LAST = 1; + private static final int NEXT = 2; + private static final int PREV = 3; + + // These constants are used by the private getSize method. + private static final int MIN = 0; + private static final int MAX = 1; + private static final int PREF = 2; +} diff --git a/libjava/classpath/java/awt/Checkbox.java b/libjava/classpath/java/awt/Checkbox.java new file mode 100644 index 000000000..dffb57da3 --- /dev/null +++ b/libjava/classpath/java/awt/Checkbox.java @@ -0,0 +1,665 @@ +/* Checkbox.java -- An AWT checkbox widget + Copyright (C) 1999, 2000, 2001, 2002, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.peer.CheckboxPeer; +import java.io.Serializable; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; +import javax.accessibility.AccessibleValue; + +/** + * This class implements a component which has an on/off state. Two + * or more Checkboxes can be grouped by a CheckboxGroup. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@redhat.com) + */ +public class Checkbox extends Component + implements ItemSelectable, Accessible, Serializable +{ + +// FIXME: Need readObject/writeObject for this. + +/* + * Static Variables + */ + +// Serialization Constant +private static final long serialVersionUID = 7270714317450821763L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * @serial The checkbox group for this checkbox. + */ +private CheckboxGroup group; + +/** + * @serial The label on this checkbox. + */ +private String label; + +/** + * @serial The state of this checkbox. + * This is package-private to avoid an accessor method. + */ +boolean state; + +// The list of listeners for this object. +private transient ItemListener item_listeners; + + /* + * The number used to generate the name returned by getName. + */ + private static transient long next_checkbox_number; + +/** + * This class provides accessibility support for the + * checkbox. + * + * @author Jerry Quinn (jlquinn@optonline.net) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +protected class AccessibleAWTCheckbox + extends AccessibleAWTComponent + implements ItemListener, AccessibleAction, AccessibleValue +{ + /** + * Serialization constant to match JDK 1.5 + */ + private static final long serialVersionUID = 7881579233144754107L; + + /** + * Default constructor which simply calls the + * super class for generic component accessibility + * handling. + */ + public AccessibleAWTCheckbox() + { + super(); + } + + /** + * Captures changes to the state of the checkbox and + * fires appropriate accessible property change events. + * + * @param event the event fired. + * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent) + */ + public void itemStateChanged(ItemEvent event) + { + firePropertyChange(ACCESSIBLE_STATE_PROPERTY, + state ? null : AccessibleState.CHECKED, + state ? AccessibleState.CHECKED : null); + } + + /** + * Returns an implementation of the <code>AccessibleAction</code> + * interface for this accessible object. In this case, the + * current instance is simply returned (with a more appropriate + * type), as it also implements the accessible action as well as + * the context. + * + * @return the accessible action associated with this context. + * @see javax.accessibility.AccessibleAction + */ + public AccessibleAction getAccessibleAction() + { + return this; + } + + /** + * Returns an implementation of the <code>AccessibleValue</code> + * interface for this accessible object. In this case, the + * current instance is simply returned (with a more appropriate + * type), as it also implements the accessible value as well as + * the context. + * + * @return the accessible value associated with this context. + * @see javax.accessibility.AccessibleValue + */ + public AccessibleValue getAccessibleValue() + { + return this; + } + + /* + * The following methods are implemented in the JDK (up to + * 1.5) as stubs. We do likewise here. + */ + + /** + * Returns the number of actions associated with this accessible + * object. This default implementation returns 0. + * + * @return the number of accessible actions available. + * @see javax.accessibility.AccessibleAction#getAccessibleActionCount() + */ + public int getAccessibleActionCount() + { + // 1.4.1 and 1.5 do this + return 0; + } + + /** + * Returns a description of the action with the supplied id. + * This default implementation always returns null. + * + * @param i the id of the action whose description should be + * retrieved. + * @return a <code>String</code> describing the action. + * @see javax.accessibility.AccessibleAction#getAccessibleActionDescription(int) + */ + public String getAccessibleActionDescription(int i) + { + // 1.5 does this + return null; + } + + /** + * Executes the action with the specified id. This + * default implementation simply returns false. + * + * @param i the id of the action to perform. + * @return true if the action was performed. + * @see javax.accessibility.AccessibleAction#doAccessibleAction(int) + */ + public boolean doAccessibleAction(int i) + { + // 1.5 does this + return false; + } + + /** + * Returns the current value of this accessible object. + * If no value has been set, null is returned. This + * default implementation always returns null, regardless. + * + * @return the numeric value of this object, or null if + * no value has been set. + * @see javax.accessibility.AccessibleValue#getCurrentAccessibleValue() + */ + public Number getCurrentAccessibleValue() + { + // 1.5 does this + return null; + } + + /** + * Sets the current value of this accessible object + * to that supplied. In this default implementation, + * the value is never set and the method always returns + * false. + * + * @param number the new accessible value. + * @return true if the value was set. + * @see javax.accessibility.AccessibleValue#setCurrentAccessibleValue(java.lang.Number) + */ + public boolean setCurrentAccessibleValue(Number number) + { + // 1.5 does this + return false; + } + + /** + * Returns the minimum acceptable accessible value used + * by this object, or null if no minimum value exists. + * This default implementation always returns null. + * + * @return the minimum acceptable accessible value, or null + * if there is no minimum. + * @see javax.accessibility.AccessibleValue#getMinimumAccessibleValue() + */ + public Number getMinimumAccessibleValue() + { + return null; + } + + /** + * Returns the maximum acceptable accessible value used + * by this object, or null if no maximum value exists. + * This default implementation always returns null. + * + * @return the maximum acceptable accessible value, or null + * if there is no maximum. + * @see javax.accessibility.AccessibleValue#getMaximumAccessibleValue() + */ + public Number getMaximumAccessibleValue() + { + return null; + } + + /** + * Returns the role of this accessible object. + * + * @return the instance of <code>AccessibleRole</code>, + * which describes this object. + * @see javax.accessibility.AccessibleRole + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.CHECK_BOX; + } + + /** + * Returns the state set of this accessible object. + * + * @return a set of <code>AccessibleState</code>s + * which represent the current state of the + * accessible object. + * @see javax.accessibility.AccessibleState + * @see javax.accessibility.AccessibleStateSet + */ + public AccessibleStateSet getAccessibleStateSet() + { + AccessibleStateSet set = super.getAccessibleStateSet(); + if (state) + set.add(AccessibleState.CHECKED); + return set; + } + +} + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of <code>Checkbox</code> with no label, + * an initial state of off, and that is not part of any checkbox group. + */ +public +Checkbox() +{ + this("", false, null); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of <code>Checkbox</code> with the specified + * label, an initial state of off, and that is not part of any checkbox + * group. + * + * @param label The label for this checkbox. + */ +public +Checkbox(String label) +{ + this(label, false, null); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of <code>Checkbox</code> with the specified + * label and initial state, and that is not part of any checkbox + * group. + * + * @param label The label for this checkbox. + * @param state The initial state of the checkbox, <code>true</code> for + * on, <code>false</code> for off. + */ +public +Checkbox(String label, boolean state) +{ + this(label, state, null); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of <code>Checkbox</code> with the specified + * label, initial state, and checkbox group. + * + * @param label The label for this checkbox. + * @param group The checkbox group for this box, or <code>null</code> + * if there is no checkbox group. + * @param state The initial state of the checkbox, <code>true</code> for + * on, <code>false</code> for off. + */ +public +Checkbox(String label, CheckboxGroup group, boolean state) +{ + this(label, state, group); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of <code>Checkbox</code> with the specified + * label, initial state, and checkbox group. + * + * @param label The label for this checkbox. + * @param state The initial state of the checkbox, <code>true</code> for + * on, <code>false</code> for off. + * @param group The checkbox group for this box, or <code>null</code> + * if there is no checkbox group. + */ +public +Checkbox(String label, boolean state, CheckboxGroup group) +{ + this.label = label; + this.state = state; + this.group = group; + + if ( state && group != null ) + { + group.setSelectedCheckbox(this); + } +} + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * Returns the label for this checkbox. + * + * @return The label for this checkbox. + */ +public String +getLabel() +{ + return(label); +} + +/*************************************************************************/ + +/** + * Sets the label for this checkbox to the specified value. + * + * @param label The new checkbox label. + */ +public synchronized void +setLabel(String label) +{ + this.label = label; + if (peer != null) + { + CheckboxPeer cp = (CheckboxPeer) peer; + cp.setLabel(label); + } +} + +/*************************************************************************/ + +/** + * Returns the state of this checkbox. + * + * @return The state of this checkbox, which will be <code>true</code> for + * on and <code>false</code> for off. + */ +public boolean +getState() +{ + return(state); +} + +/*************************************************************************/ + +/** + * Sets the state of this checkbox to the specified value. + * + * @param state The new state of the checkbox, which will be <code>true</code> + * for on or <code>false</code> for off. + */ +public synchronized void +setState(boolean state) +{ + if (this.state != state) + { + this.state = state; + if (peer != null) + { + CheckboxPeer cp = (CheckboxPeer) peer; + cp.setState (state); + } + } +} + +/*************************************************************************/ + +/** + * Returns an array of length one containing the checkbox label if this + * checkbox is selected. Otherwise <code>null</code> is returned. + * + * @return The selection state of this checkbox. + */ +public Object[] +getSelectedObjects() +{ + if (state == false) + return(null); + + Object[] objs = new Object[1]; + objs[0] = label; + + return(objs); +} + +/*************************************************************************/ + +/** + * Returns the checkbox group this object is a member of, if any. + * + * @return This object's checkbox group, of <code>null</code> if it is + * not a member of any group. + */ +public CheckboxGroup +getCheckboxGroup() +{ + return(group); +} + +/*************************************************************************/ + +/** + * Sets this object's checkbox group to the specified group. + * + * @param group The new checkbox group, or <code>null</code> to make this + * object part of no checkbox group. + */ +public synchronized void +setCheckboxGroup(CheckboxGroup group) +{ + this.group = group; + if (peer != null) + { + CheckboxPeer cp = (CheckboxPeer) peer; + cp.setCheckboxGroup (group); + } +} + +/*************************************************************************/ + +/** + * Creates this object's native peer. + */ +public void +addNotify() +{ + if (peer == null) + peer = getToolkit ().createCheckbox (this); + super.addNotify (); +} + + public ItemListener[] getItemListeners () + { + return (ItemListener[]) + AWTEventMulticaster.getListeners (item_listeners, ItemListener.class); + } + +/** + * Adds a new listeners to the list of registered listeners for this object. + * + * @param listener The new listener to add. + */ +public synchronized void +addItemListener(ItemListener listener) +{ + item_listeners = AWTEventMulticaster.add(item_listeners, listener); +} + +/*************************************************************************/ + +/** + * Removes a listener from the list of registered listeners for this object. + * + * @param listener The listener to remove. + */ +public synchronized void +removeItemListener(ItemListener listener) +{ + item_listeners = AWTEventMulticaster.remove(item_listeners, listener); +} + +/*************************************************************************/ + +/** + * Processes this event by calling <code>processItemEvent()</code> if it + * is any instance of <code>ItemEvent</code>. Otherwise it is passed to + * the superclass for processing. + * + * @param event The event to process. + */ +protected void +processEvent(AWTEvent event) +{ + if (event instanceof ItemEvent) + processItemEvent((ItemEvent)event); + else + super.processEvent(event); +} + +/*************************************************************************/ + +/** + * Processes this event by dispatching it to any registered listeners. + * + * @param event The <code>ItemEvent</code> to process. + */ +protected void +processItemEvent(ItemEvent event) +{ + if (item_listeners != null) + item_listeners.itemStateChanged(event); +} + +void +dispatchEventImpl(AWTEvent e) +{ + if (e.id <= ItemEvent.ITEM_LAST + && e.id >= ItemEvent.ITEM_FIRST) + { + ItemEvent ie = (ItemEvent) e; + int itemState = ie.getStateChange(); + setState(itemState == ItemEvent.SELECTED ? true : false); + if (item_listeners != null + || (eventMask & AWTEvent.ITEM_EVENT_MASK) != 0) + processEvent(e); + } + else + super.dispatchEventImpl(e); +} + +/*************************************************************************/ + +/** + * Returns a debugging string for this object. + */ +protected String +paramString() +{ + // Note: We cannot add the checkbox group information here because this + // would trigger infinite recursion when CheckboxGroup.toString() is + // called and the box is in its selected state. + return ("label=" + label + ",state=" + state + "," + super.paramString()); +} + +/** + * Gets the AccessibleContext associated with this <code>Checkbox</code>. + * The context is created, if necessary. + * + * @return the associated context + */ +public AccessibleContext getAccessibleContext() +{ + /* Create the context if this is the first request */ + if (accessibleContext == null) + { + AccessibleAWTCheckbox ac = new AccessibleAWTCheckbox(); + accessibleContext = ac; + addItemListener(ac); + } + return accessibleContext; +} + + /** + * Generate a unique name for this checkbox. + * + * @return A unique name for this checkbox. + */ + String generateName() + { + return "checkbox" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_checkbox_number++; + } +} diff --git a/libjava/classpath/java/awt/CheckboxGroup.java b/libjava/classpath/java/awt/CheckboxGroup.java new file mode 100644 index 000000000..30f3e1635 --- /dev/null +++ b/libjava/classpath/java/awt/CheckboxGroup.java @@ -0,0 +1,172 @@ +/* CheckboxGroup.java -- A grouping class for checkboxes. + Copyright (C) 1999, 2000, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +/** + * This class if for combining checkboxes into groups so that only + * one checkbox in the group can be selected at any one time. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@redhat.com) + */ +public class CheckboxGroup implements java.io.Serializable +{ + +/* + * Static Variables + */ + +// Serialization constant +private static final long serialVersionUID = 3729780091441768983L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * @serial The currently selected checkbox. + */ +private Checkbox selectedCheckbox; + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of <code>CheckboxGroup</code>. + */ +public +CheckboxGroup() +{ +} + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * Returns the currently selected checkbox, or <code>null</code> if none + * of the checkboxes in this group are selected. + * + * @return The selected checkbox. + */ +public Checkbox +getSelectedCheckbox() +{ + return getCurrent (); +} + +/*************************************************************************/ + +/** + * Returns the currently selected checkbox, or <code>null</code> if none + * of the checkboxes in this group are selected. + * + * @return The selected checkbox. + * + * @deprecated This method is deprecated in favor of + * <code>getSelectedCheckbox()</code>. + */ +public Checkbox +getCurrent() +{ + return(selectedCheckbox); +} + +/*************************************************************************/ + +/** + * This method sets the specified checkbox to be the selected on in this + * group, and unsets all others. + * + * @param selectedCheckbox The new selected checkbox. + */ +public void +setSelectedCheckbox(Checkbox selectedCheckbox) +{ + setCurrent (selectedCheckbox); +} + +/*************************************************************************/ + +/** + * This method sets the specified checkbox to be the selected on in this + * group, and unsets all others. + * + * @param selectedCheckbox The new selected checkbox. + * + * @deprecated This method is deprecated in favor of + * <code>setSelectedCheckbox()</code>. + */ +public void +setCurrent(Checkbox selectedCheckbox) +{ + if (this.selectedCheckbox != null) + { + if (this.selectedCheckbox.getCheckboxGroup() != this) + return; + + this.selectedCheckbox.setState(false); + } + + this.selectedCheckbox = selectedCheckbox; + if (selectedCheckbox != null) + selectedCheckbox.setState(true); +} + +/*************************************************************************/ + +/** + * Returns a string representation of this checkbox group. + * + * @return A string representation of this checkbox group. + */ +public String +toString() +{ + return(getClass().getName() + "[selectedCheckbox=" + selectedCheckbox + "]"); +} + +} // class CheckboxGroup diff --git a/libjava/classpath/java/awt/CheckboxMenuItem.java b/libjava/classpath/java/awt/CheckboxMenuItem.java new file mode 100644 index 000000000..597e1964b --- /dev/null +++ b/libjava/classpath/java/awt/CheckboxMenuItem.java @@ -0,0 +1,376 @@ +/* CheckboxMenuItem.java -- A menu option with a checkbox on it. + Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.peer.CheckboxMenuItemPeer; +import java.util.EventListener; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleValue; + +/** + * This class implements a menu item that has a checkbox on it indicating + * the selected state of some option. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@redhat.com) + */ +public class CheckboxMenuItem extends MenuItem + implements ItemSelectable, Accessible +{ + +/* + * Static Variables + */ + +/** + * The number used to generate the name returned by getName. + */ +private static transient long next_chkmenuitem_number; + +// Serialization constant +private static final long serialVersionUID = 6190621106981774043L; + +/* + * Instance Variables + */ + +/** + * @serial The state of the checkbox, with <code>true</code> being on and + * <code>false</code> being off. + */ +private boolean state; + +// List of registered ItemListeners +private transient ItemListener item_listeners; + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of <code>CheckboxMenuItem</code> with no + * label and an initial state of off. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ +public +CheckboxMenuItem() +{ + this("", false); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of <code>CheckboxMenuItem</code> with the + * specified label and an initial state of off. + * + * @param label The label of the menu item. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ +public +CheckboxMenuItem(String label) +{ + this(label, false); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of <code>CheckboxMenuItem</code> with the + * specified label and initial state. + * + * @param label The label of the menu item. + * @param state The initial state of the menu item, where <code>true</code> + * is on, and <code>false</code> is off. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ +public +CheckboxMenuItem(String label, boolean state) +{ + super(label); + this.state = state; + + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException (); +} + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * Returns the state of this menu item. + * + * @return The state of this menu item. + */ +public boolean +getState() +{ + return(state); +} + +/*************************************************************************/ + +/** + * Sets the state of this menu item. + * + * @param state The initial state of the menu item, where <code>true</code> + * is on, and <code>false</code> is off. + */ +public synchronized void +setState(boolean state) +{ + this.state = state; + if (peer != null) + { + CheckboxMenuItemPeer cp = (CheckboxMenuItemPeer) peer; + cp.setState (state); + } +} + +/*************************************************************************/ + +/** + * Returns an array of length 1 with the menu item label for this object + * if the state is on. Otherwise <code>null</code> is returned. + * + * @return An array with this menu item's label if it has a state of on, + * or <code>null</code> otherwise. + */ +public Object[] +getSelectedObjects() +{ + if (state == false) + return(null); + + Object[] obj = new Object[1]; + obj[0] = getLabel(); + + return(obj); +} + +/*************************************************************************/ + +/** + * Create's this object's native peer + */ +public synchronized void +addNotify() +{ + if (peer == null) + peer = getToolkit().createCheckboxMenuItem(this); + + super.addNotify (); +} + +/*************************************************************************/ + +/** + * Adds the specified listener to the list of registered item listeners + * for this object. + * + * @param listener The listener to add. + */ +public synchronized void +addItemListener(ItemListener listener) +{ + item_listeners = AWTEventMulticaster.add(item_listeners, listener); + + enableEvents(AWTEvent.ITEM_EVENT_MASK); +} + +/*************************************************************************/ + +/** + * Removes the specified listener from the list of registered item + * listeners for this object. + * + * @param listener The listener to remove. + */ +public synchronized void +removeItemListener(ItemListener listener) +{ + item_listeners = AWTEventMulticaster.remove(item_listeners, listener); +} + +/*************************************************************************/ + +/** + * Processes the specified event by calling <code>processItemEvent()</code> + * if it is an instance of <code>ItemEvent</code> or calling the superclass + * method otherwise. + * + * @param event The event to process. + */ +protected void +processEvent(AWTEvent event) +{ + if (event instanceof ItemEvent) + processItemEvent((ItemEvent)event); + else + super.processEvent(event); +} + +/*************************************************************************/ + +/** + * Processes the specified event by dispatching it to any registered listeners. + * + * @param event The event to process. + */ +protected void +processItemEvent(ItemEvent event) +{ + if (item_listeners != null) + item_listeners.itemStateChanged(event); +} + +void +dispatchEventImpl(AWTEvent e) +{ + if (e instanceof ItemEvent) + { + synchronized (this) + { + state = (((ItemEvent) e).getStateChange() == ItemEvent.SELECTED); + } + } + + if (e.id <= ItemEvent.ITEM_LAST + && e.id >= ItemEvent.ITEM_FIRST + && (item_listeners != null + || (eventMask & AWTEvent.ITEM_EVENT_MASK) != 0)) + processEvent(e); + else + super.dispatchEventImpl(e); +} + +/*************************************************************************/ + +/** + * Returns a debugging string for this object. + * + * @return A debugging string for this object. + */ +public String +paramString() +{ + return ("label=" + getLabel() + ",state=" + state + + "," + super.paramString()); +} + + /** + * Returns an array of all the objects currently registered as FooListeners + * upon this <code>CheckboxMenuItem</code>. FooListeners are registered using + * the addFooListener method. + * + * @exception ClassCastException If listenerType doesn't specify a class or + * interface that implements java.util.EventListener. + */ + public <T extends EventListener> T[] getListeners (Class<T> listenerType) + { + if (listenerType == ItemListener.class) + return AWTEventMulticaster.getListeners (item_listeners, listenerType); + + return super.getListeners (listenerType); + } + + /** + * Returns an aray of all item listeners currently registered to this + * <code>CheckBoxMenuItem</code>. + */ + public ItemListener[] getItemListeners () + { + return (ItemListener[]) getListeners (ItemListener.class); + } + + + protected class AccessibleAWTCheckboxMenuItem extends AccessibleAWTMenuItem + implements AccessibleAction, AccessibleValue + { + // I think the base class provides the necessary implementation + + private static final long serialVersionUID = -1122642964303476L; + } + + /** + * Gets the AccessibleContext associated with this <code>CheckboxMenuItem</code>. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTCheckboxMenuItem(); + return accessibleContext; + } + + /** + * Generate a unique name for this <code>CheckboxMenuItem</code>. + * + * @return A unique name for this <code>CheckboxMenuItem</code>. + */ + String generateName() + { + return "chkmenuitem" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_chkmenuitem_number++; + } + +} // class CheckboxMenuItem diff --git a/libjava/classpath/java/awt/Choice.java b/libjava/classpath/java/awt/Choice.java new file mode 100644 index 000000000..5d2cfaf67 --- /dev/null +++ b/libjava/classpath/java/awt/Choice.java @@ -0,0 +1,569 @@ +/* Choice.java -- Java choice button widget. + Copyright (C) 1999, 2000, 2001, 2002, 2004, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.peer.ChoicePeer; +import java.io.Serializable; +import java.util.EventListener; +import java.util.Vector; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; + +/** + * This class implements a drop down choice list. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class Choice extends Component + implements ItemSelectable, Serializable, Accessible +{ + /** + * The number used to generate the name returned by getName. + */ + private static transient long next_choice_number; + + // Serialization constant + private static final long serialVersionUID = -4075310674757313071L; + + /** + * @serial A list of items for the choice box, which can be <code>null</code>. + * This is package-private to avoid an accessor method. + */ + Vector pItems = new Vector(); + + /** + * @serial The index of the selected item in the choice box. + */ + private int selectedIndex = -1; + + /** + * ItemListener chain + */ + private ItemListener item_listeners; + + /** + * This class provides accessibility support for the + * combo box. + * + * @author Jerry Quinn (jlquinn@optonline.net) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ + protected class AccessibleAWTChoice + extends AccessibleAWTComponent + implements AccessibleAction + { + + /** + * Serialization constant to match JDK 1.5 + */ + private static final long serialVersionUID = 7175603582428509322L; + + /** + * Default constructor which simply calls the + * super class for generic component accessibility + * handling. + */ + public AccessibleAWTChoice() + { + super(); + } + + /** + * Returns an implementation of the <code>AccessibleAction</code> + * interface for this accessible object. In this case, the + * current instance is simply returned (with a more appropriate + * type), as it also implements the accessible action as well as + * the context. + * + * @return the accessible action associated with this context. + * @see javax.accessibility.AccessibleAction + */ + public AccessibleAction getAccessibleAction() + { + return this; + } + + /** + * Returns the role of this accessible object. + * + * @return the instance of <code>AccessibleRole</code>, + * which describes this object. + * @see javax.accessibility.AccessibleRole + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.COMBO_BOX; + } + + /** + * Returns the number of actions associated with this accessible + * object. In this case, it is the number of choices available. + * + * @return the number of choices available. + * @see javax.accessibility.AccessibleAction#getAccessibleActionCount() + */ + public int getAccessibleActionCount() + { + return pItems.size(); + } + + /** + * Returns a description of the action with the supplied id. + * In this case, it is the text used in displaying the particular + * choice on-screen. + * + * @param i the id of the choice whose description should be + * retrieved. + * @return the <code>String</code> used to describe the choice. + * @see javax.accessibility.AccessibleAction#getAccessibleActionDescription(int) + */ + public String getAccessibleActionDescription(int i) + { + return (String) pItems.get(i); + } + + /** + * Executes the action with the specified id. In this case, + * calling this method provides the same behaviour as would + * choosing a choice from the list in a visual manner. + * + * @param i the id of the choice to select. + * @return true if a valid choice was specified. + * @see javax.accessibility.AccessibleAction#doAccessibleAction(int) + */ + public boolean doAccessibleAction(int i) + { + if (i < 0 || i >= pItems.size()) + return false; + + Choice.this.select( i ); + + return true; + } + } + + /** + * Initializes a new instance of <code>Choice</code>. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true + */ + public Choice() + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException (); + } + + /** + * Returns the number of items in the list. + * + * @return The number of items in the list. + */ + public int getItemCount() + { + return countItems (); + } + + /** + * Returns the number of items in the list. + * + * @return The number of items in the list. + * + * @deprecated This method is deprecated in favor of <code>getItemCount</code>. + */ + public int countItems() + { + return pItems.size(); + } + + /** + * Returns the item at the specified index in the list. + * + * @param index The index into the list to return the item from. + * + * @exception ArrayIndexOutOfBoundsException If the index is invalid. + */ + public String getItem(int index) + { + return (String)pItems.elementAt(index); + } + + /** + * Adds the specified item to this choice box. + * + * @param item The item to add. + * + * @exception NullPointerException If the item's value is null + * + * @since 1.1 + */ + public synchronized void add(String item) + { + if (item == null) + throw new NullPointerException ("item must be non-null"); + + pItems.addElement(item); + + if (peer != null) + ((ChoicePeer) peer).add(item, getItemCount() - 1); + + if (selectedIndex == -1) + select( 0 ); + } + + /** + * Adds the specified item to this choice box. + * + * This method is oboslete since Java 2 platform 1.1. Please use + * {@link #add(String)} instead. + * + * @param item The item to add. + * + * @exception NullPointerException If the item's value is equal to null + */ + public synchronized void addItem(String item) + { + add(item); + } + + /** Inserts an item into this Choice. Existing items are shifted + * upwards. If the new item is the only item, then it is selected. + * If the currently selected item is shifted, then the first item is + * selected. If the currently selected item is not shifted, then it + * remains selected. + * + * @param item The item to add. + * @param index The index at which the item should be inserted. + * + * @exception IllegalArgumentException If index is less than 0 + */ + public synchronized void insert(String item, int index) + { + if (index < 0) + throw new IllegalArgumentException ("index may not be less then 0"); + + if (index > getItemCount ()) + index = getItemCount (); + + pItems.insertElementAt(item, index); + + if (peer != null) + ((ChoicePeer) peer).add (item, index); + + if (selectedIndex == -1 || selectedIndex >= index) + select(0); + } + + /** + * Removes the specified item from the choice box. + * + * @param item The item to remove. + * + * @exception IllegalArgumentException If the specified item doesn't exist. + */ + public synchronized void remove(String item) + { + int index = pItems.indexOf(item); + if (index == -1) + throw new IllegalArgumentException ("item \"" + + item + "\" not found in Choice"); + remove(index); + } + + /** + * Removes the item at the specified index from the choice box. + * + * @param index The index of the item to remove. + * + * @exception IndexOutOfBoundsException If the index is not valid. + */ + public synchronized void remove(int index) + { + pItems.removeElementAt(index); + + if (peer != null) + ((ChoicePeer) peer).remove( index ); + + if( getItemCount() == 0 ) + selectedIndex = -1; + else + { + if( selectedIndex > index ) + selectedIndex--; + else if( selectedIndex == index ) + selectedIndex = 0; + + if( peer != null ) + ((ChoicePeer)peer).select( selectedIndex ); + } + } + + /** + * Removes all of the objects from this choice box. + */ + public synchronized void removeAll() + { + if (getItemCount() <= 0) + return; + + pItems.removeAllElements (); + + if (peer != null) + { + ChoicePeer cp = (ChoicePeer) peer; + cp.removeAll (); + } + + selectedIndex = -1; + } + + /** + * Returns the currently selected item, or null if no item is + * selected. + * + * @return The currently selected item. + */ + public synchronized String getSelectedItem() + { + return (selectedIndex == -1 + ? null + : ((String)pItems.elementAt(selectedIndex))); + } + + /** + * Returns an array with one row containing the selected item. + * + * @return An array containing the selected item. + */ + public synchronized Object[] getSelectedObjects() + { + if (selectedIndex == -1) + return null; + + Object[] objs = new Object[1]; + objs[0] = pItems.elementAt(selectedIndex); + + return objs; + } + + /** + * Returns the index of the selected item. + * + * @return The index of the selected item. + */ + public int getSelectedIndex() + { + return selectedIndex; + } + + /** + * Forces the item at the specified index to be selected. + * + * @param index The index of the row to make selected. + * + * @exception IllegalArgumentException If the specified index is invalid. + */ + public synchronized void select(int index) + { + if ((index < 0) || (index >= getItemCount())) + throw new IllegalArgumentException("Bad index: " + index); + + if( selectedIndex == index ) + return; + + selectedIndex = index; + if( peer != null ) + ((ChoicePeer)peer).select( index ); + } + + /** + * Forces the named item to be selected. + * + * @param item The item to be selected. + * + * @exception IllegalArgumentException If the specified item does not exist. + */ + public synchronized void select(String item) + { + int index = pItems.indexOf(item); + if( index >= 0 ) + select( index ); + } + + /** + * Creates the native peer for this object. + */ + public void addNotify() + { + if (peer == null) + peer = getToolkit ().createChoice (this); + super.addNotify (); + } + + /** + * Adds the specified listener to the list of registered listeners for + * this object. + * + * @param listener The listener to add. + */ + public synchronized void addItemListener(ItemListener listener) + { + item_listeners = AWTEventMulticaster.add(item_listeners, listener); + } + + /** + * Removes the specified listener from the list of registered listeners for + * this object. + * + * @param listener The listener to remove. + */ + public synchronized void removeItemListener(ItemListener listener) + { + item_listeners = AWTEventMulticaster.remove(item_listeners, listener); + } + + /** + * Processes this event by invoking <code>processItemEvent()</code> if the + * event is an instance of <code>ItemEvent</code>, otherwise the event + * is passed to the superclass. + * + * @param event The event to process. + */ + protected void processEvent(AWTEvent event) + { + if (event instanceof ItemEvent) + processItemEvent((ItemEvent)event); + else + super.processEvent(event); + } + + void dispatchEventImpl(AWTEvent e) + { + super.dispatchEventImpl(e); + + if( e.id <= ItemEvent.ITEM_LAST && e.id >= ItemEvent.ITEM_FIRST && + ( item_listeners != null || + ( eventMask & AWTEvent.ITEM_EVENT_MASK ) != 0 ) ) + processEvent(e); + } + + /** + * Processes item event by dispatching to any registered listeners. + * + * @param event The event to process. + */ + protected void processItemEvent(ItemEvent event) + { + int index = pItems.indexOf((String) event.getItem()); + if (item_listeners != null) + item_listeners.itemStateChanged(event); + } + + /** + * Returns a debugging string for this object. + * + * @return A debugging string for this object. + */ + protected String paramString() + { + return "selectedIndex=" + selectedIndex + "," + super.paramString(); + } + + /** + * Returns an array of all the objects currently registered as FooListeners + * upon this Choice. FooListeners are registered using the addFooListener + * method. + * + * @exception ClassCastException If listenerType doesn't specify a class or + * interface that implements java.util.EventListener. + * + * @since 1.3 + */ + public <T extends EventListener> T[] getListeners (Class<T> listenerType) + { + if (listenerType == ItemListener.class) + return AWTEventMulticaster.getListeners (item_listeners, listenerType); + + return super.getListeners (listenerType); + } + + /** + * Returns all registered item listeners. + * + * @since 1.4 + */ + public ItemListener[] getItemListeners () + { + return (ItemListener[]) getListeners (ItemListener.class); + } + + /** + * Gets the AccessibleContext associated with this <code>Choice</code>. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTChoice(); + return accessibleContext; + } + + /** + * Generate a unique name for this <code>Choice</code>. + * + * @return A unique name for this <code>Choice</code>. + */ + String generateName() + { + return "choice" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_choice_number++; + } +} // class Choice diff --git a/libjava/classpath/java/awt/Color.java b/libjava/classpath/java/awt/Color.java new file mode 100644 index 000000000..243a5e86f --- /dev/null +++ b/libjava/classpath/java/awt/Color.java @@ -0,0 +1,1025 @@ +/* Color.java -- represents a color in Java + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.color.ColorSpace; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; +import java.io.Serializable; + +/** + * This class represents a color value in the AWT system. It uses the sRGB + * (standard Red-Green-Blue) system, along with an alpha value ranging from + * transparent (0.0f or 0) and opaque (1.0f or 255). The color is not + * pre-multiplied by the alpha value an any of the accessor methods. Further + * information about sRGB can be found at + * <a href="http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html"> + * http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html</a>. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ColorSpace + * @see AlphaComposite + * @since 1.0 + * @status updated to 1.4 + */ +public class Color implements Paint, Serializable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 118526816881161077L; + + /** Constant for the color white: R=255, G=255, B=255. */ + public static final Color white = new Color(0xffffff, false); + + /** + * Constant for the color white: R=255, G=255, B=255. + * + * @since 1.4 + */ + public static final Color WHITE = white; + + /** Constant for the color light gray: R=192, G=192, B=192. */ + public static final Color lightGray = new Color(0xc0c0c0, false); + + /** + * Constant for the color light gray: R=192, G=192, B=192. + * + * @since 1.4 + */ + public static final Color LIGHT_GRAY = lightGray; + + /** Constant for the color gray: R=128, G=128, B=128. */ + public static final Color gray = new Color(0x808080, false); + + /** + * Constant for the color gray: R=128, G=128, B=128. + * + * @since 1.4 + */ + public static final Color GRAY = gray; + + /** Constant for the color dark gray: R=64, G=64, B=64. */ + public static final Color darkGray = new Color(0x404040, false); + + /** + * Constant for the color dark gray: R=64, G=64, B=64. + * + * @since 1.4 + */ + public static final Color DARK_GRAY = darkGray; + + /** Constant for the color black: R=0, G=0, B=0. */ + public static final Color black = new Color(0x000000, false); + + /** + * Constant for the color black: R=0, G=0, B=0. + * + * @since 1.4 + */ + public static final Color BLACK = black; + + /** Constant for the color red: R=255, G=0, B=0. */ + public static final Color red = new Color(0xff0000, false); + + /** + * Constant for the color red: R=255, G=0, B=0. + * + * @since 1.4 + */ + public static final Color RED = red; + + /** Constant for the color pink: R=255, G=175, B=175. */ + public static final Color pink = new Color(0xffafaf, false); + + /** + * Constant for the color pink: R=255, G=175, B=175. + * + * @since 1.4 + */ + public static final Color PINK = pink; + + /** Constant for the color orange: R=255, G=200, B=0. */ + public static final Color orange = new Color(0xffc800, false); + + /** + * Constant for the color orange: R=255, G=200, B=0. + * + * @since 1.4 + */ + public static final Color ORANGE = orange; + + /** Constant for the color yellow: R=255, G=255, B=0. */ + public static final Color yellow = new Color(0xffff00, false); + + /** + * Constant for the color yellow: R=255, G=255, B=0. + * + * @since 1.4 + */ + public static final Color YELLOW = yellow; + + /** Constant for the color green: R=0, G=255, B=0. */ + public static final Color green = new Color(0x00ff00, false); + + /** + * Constant for the color green: R=0, G=255, B=0. + * + * @since 1.4 + */ + public static final Color GREEN = green; + + /** Constant for the color magenta: R=255, G=0, B=255. */ + public static final Color magenta = new Color(0xff00ff, false); + + /** + * Constant for the color magenta: R=255, G=0, B=255. + * + * @since 1.4 + */ + public static final Color MAGENTA = magenta; + + /** Constant for the color cyan: R=0, G=255, B=255. */ + public static final Color cyan = new Color(0x00ffff, false); + + /** + * Constant for the color cyan: R=0, G=255, B=255. + * + * @since 1.4 + */ + public static final Color CYAN = cyan; + + /** Constant for the color blue: R=0, G=0, B=255. */ + public static final Color blue = new Color(0x0000ff, false); + + /** + * Constant for the color blue: R=0, G=0, B=255. + * + * @since 1.4 + */ + public static final Color BLUE = blue; + + /** Internal mask for red. */ + private static final int RED_MASK = 255 << 16; + + /** Internal mask for green. */ + private static final int GREEN_MASK = 255 << 8; + + /** Internal mask for blue. */ + private static final int BLUE_MASK = 255; + + /** Internal mask for alpha. Package visible for use in subclass. */ + static final int ALPHA_MASK = 255 << 24; + + /** Amount to scale a color by when brightening or darkening. */ + private static final float BRIGHT_SCALE = 0.7f; + + /** + * The color value, in sRGB. Note that the actual color may be more + * precise if frgbvalue or fvalue is non-null. This class stores alpha, red, + * green, and blue, each 0-255, packed in an int. However, the subclass + * SystemColor stores an index into an array. Therefore, for serial + * compatibility (and because of poor design on Sun's part), this value + * cannot be used directly; instead you must use <code>getRGB()</code>. + * + * @see #getRGB() + * @serial the value of the color, whether an RGB literal or array index + */ + final int value; + + /** + * The color value, in sRGB. This may be null if the color was constructed + * with ints; and it does not include alpha. This stores red, green, and + * blue, in the range 0.0f - 1.0f. + * + * @see #getRGBColorComponents(float[]) + * @see #getRGBComponents(float[]) + * @serial the rgb components of the value + * @since 1.2 + */ + private float[] frgbvalue; + + /** + * The color value, in the native ColorSpace components. This may be null + * if the color was constructed with ints or in the sRGB color space; and + * it does not include alpha. + * + * @see #getRGBColorComponents(float[]) + * @see #getRGBComponents(float[]) + * @serial the original color space components of the color + * @since 1.2 + */ + private float[] fvalue; + + /** + * The alpha value. This is in the range 0.0f - 1.0f, but is invalid if + * deserialized as 0.0 when frgbvalue is null. + * + * @see #getRGBComponents(float[]) + * @see #getComponents(float[]) + * @serial the alpha component of this color + * @since 1.2 + */ + private final float falpha; + + /** + * The ColorSpace. Null means the default sRGB space. + * + * @see #getColor(String) + * @see #getColorSpace() + * @see #getColorComponents(float[]) + * @serial the color space for this color + * @since 1.2 + */ + private final ColorSpace cs; + + /** + * The paint context for this solid color. Package visible for use in + * subclass. + */ + transient ColorPaintContext context; + + /** + * Initializes a new instance of <code>Color</code> using the specified + * red, green, and blue values, which must be given as integers in the + * range of 0-255. Alpha will default to 255 (opaque). When drawing to + * screen, the actual color may be adjusted to the best match of hardware + * capabilities. + * + * @param red the red component of the RGB value + * @param green the green component of the RGB value + * @param blue the blue component of the RGB value + * @throws IllegalArgumentException if the values are out of range 0-255 + * @see #getRed() + * @see #getGreen() + * @see #getBlue() + * @see #getRGB() + * @see #Color(int, int, int, int) + */ + public Color(int red, int green, int blue) + { + this(red, green, blue, 255); + } + + /** + * Initializes a new instance of <code>Color</code> using the specified + * red, green, blue, and alpha values, which must be given as integers in + * the range of 0-255. When drawing to screen, the actual color may be + * adjusted to the best match of hardware capabilities. + * + * @param red the red component of the RGB value + * @param green the green component of the RGB value + * @param blue the blue component of the RGB value + * @param alpha the alpha value of the color + * @throws IllegalArgumentException if the values are out of range 0-255 + * @see #getRed() + * @see #getGreen() + * @see #getBlue() + * @see #getAlpha() + * @see #getRGB() + */ + public Color(int red, int green, int blue, int alpha) + { + if ((red & 255) != red || (green & 255) != green || (blue & 255) != blue + || (alpha & 255) != alpha) + throw new IllegalArgumentException("Bad RGB values" + +" red=0x"+Integer.toHexString(red) + +" green=0x"+Integer.toHexString(green) + +" blue=0x"+Integer.toHexString(blue) + +" alpha=0x"+Integer.toHexString(alpha) ); + + value = (alpha << 24) | (red << 16) | (green << 8) | blue; + falpha = 1; + cs = null; + } + + /** + * Initializes a new instance of <code>Color</code> using the specified + * RGB value. The blue value is in bits 0-7, green in bits 8-15, and + * red in bits 16-23. The other bits are ignored. The alpha value is set + * to 255 (opaque). When drawing to screen, the actual color may be + * adjusted to the best match of hardware capabilities. + * + * @param value the RGB value + * @see ColorModel#getRGBdefault() + * @see #getRed() + * @see #getGreen() + * @see #getBlue() + * @see #getRGB() + * @see #Color(int, boolean) + */ + public Color(int value) + { + this(value, false); + } + + /** + * Initializes a new instance of <code>Color</code> using the specified + * RGB value. The blue value is in bits 0-7, green in bits 8-15, and + * red in bits 16-23. The alpha value is in bits 24-31, unless hasalpha + * is false, in which case alpha is set to 255. When drawing to screen, the + * actual color may be adjusted to the best match of hardware capabilities. + * + * @param value the RGB value + * @param hasalpha true if value includes the alpha + * @see ColorModel#getRGBdefault() + * @see #getRed() + * @see #getGreen() + * @see #getBlue() + * @see #getAlpha() + * @see #getRGB() + */ + public Color(int value, boolean hasalpha) + { + // Note: SystemColor calls this constructor, setting falpha to 0; but + // code in getRGBComponents correctly reports falpha as 1.0 to the user + // for all instances of SystemColor since frgbvalue is left null here. + if (hasalpha) + falpha = ((value & ALPHA_MASK) >> 24) / 255f; + else + { + value |= ALPHA_MASK; + falpha = 1; + } + this.value = value; + cs = null; + } + + /** + * Initializes a new instance of <code>Color</code> using the specified + * RGB values. These must be in the range of 0.0-1.0. Alpha is assigned + * the value of 1.0 (opaque). When drawing to screen, the actual color may + * be adjusted to the best match of hardware capabilities. + * + * @param red the red component of the RGB value + * @param green the green component of the RGB value + * @param blue the blue component of the RGB value + * @throws IllegalArgumentException tf the values are out of range 0.0f-1.0f + * @see #getRed() + * @see #getGreen() + * @see #getBlue() + * @see #getRGB() + * @see #Color(float, float, float, float) + */ + public Color(float red, float green, float blue) + { + this(red, green, blue, 1.0f); + } + + /** + * Initializes a new instance of <code>Color</code> using the specified + * RGB and alpha values. These must be in the range of 0.0-1.0. When drawing + * to screen, the actual color may be adjusted to the best match of + * hardware capabilities. + * + * @param red the red component of the RGB value + * @param green the green component of the RGB value + * @param blue the blue component of the RGB value + * @param alpha the alpha value of the color + * @throws IllegalArgumentException tf the values are out of range 0.0f-1.0f + * @see #getRed() + * @see #getGreen() + * @see #getBlue() + * @see #getAlpha() + * @see #getRGB() + */ + public Color(float red, float green, float blue, float alpha) + { + value = convert(red, green, blue, alpha); + frgbvalue = new float[] {red, green, blue}; + falpha = alpha; + cs = null; + } + + /** + * Creates a color in the given ColorSpace with the specified alpha. The + * array must be non-null and have enough elements for the color space + * (for example, RGB requires 3 elements, CMYK requires 4). When drawing + * to screen, the actual color may be adjusted to the best match of + * hardware capabilities. + * + * @param space the color space of components + * @param components the color components, except alpha + * @param alpha the alpha value of the color + * @throws NullPointerException if cpsace or components is null + * @throws ArrayIndexOutOfBoundsException if components is too small + * @throws IllegalArgumentException if alpha or any component is out of range + * @see #getComponents(float[]) + * @see #getColorComponents(float[]) + */ + public Color(ColorSpace space, float[] components, float alpha) + { + frgbvalue = space.toRGB(components); + fvalue = components; + falpha = alpha; + cs = space; + value = convert(frgbvalue[0], frgbvalue[1], frgbvalue[2], alpha); + } + + /** + * Returns the red value for this color, as an integer in the range 0-255 + * in the sRGB color space. + * + * @return the red value for this color + * @see #getRGB() + */ + public int getRed() + { + // Do not inline getRGB() to value, because of SystemColor. + return (getRGB() & RED_MASK) >> 16; + } + + /** + * Returns the green value for this color, as an integer in the range 0-255 + * in the sRGB color space. + * + * @return the green value for this color + * @see #getRGB() + */ + public int getGreen() + { + // Do not inline getRGB() to value, because of SystemColor. + return (getRGB() & GREEN_MASK) >> 8; + } + + /** + * Returns the blue value for this color, as an integer in the range 0-255 + * in the sRGB color space. + * + * @return the blue value for this color + * @see #getRGB() + */ + public int getBlue() + { + // Do not inline getRGB() to value, because of SystemColor. + return getRGB() & BLUE_MASK; + } + + /** + * Returns the alpha value for this color, as an integer in the range 0-255. + * + * @return the alpha value for this color + * @see #getRGB() + */ + public int getAlpha() + { + // Do not inline getRGB() to value, because of SystemColor. + return (getRGB() & ALPHA_MASK) >>> 24; + } + + /** + * Returns the RGB value for this color, in the sRGB color space. The blue + * value will be in bits 0-7, green in 8-15, red in 16-23, and alpha value in + * 24-31. + * + * @return the RGB value for this color + * @see ColorModel#getRGBdefault() + * @see #getRed() + * @see #getGreen() + * @see #getBlue() + * @see #getAlpha() + */ + public int getRGB() + { + return value; + } + + /** + * Returns a brighter version of this color. This is done by increasing the + * RGB values by an arbitrary scale factor. The new color is opaque (an + * alpha of 255). Note that this method and the <code>darker()</code> + * method are not necessarily inverses. + * + * @return a brighter version of this color + * @see #darker() + */ + public Color brighter() + { + // Do not inline getRGB() to this.value, because of SystemColor. + int value = getRGB(); + int[] hues = new int[3]; + hues[0] = (value & RED_MASK) >> 16; + hues[1] = (value & GREEN_MASK) >> 8; + hues[2] = value & BLUE_MASK; + + // (0,0,0) is a special case. + if (hues[0] == 0 && hues[1] == 0 && hues[2] ==0) + { + hues[0] = 3; + hues[1] = 3; + hues[2] = 3; + } + else + { + for (int index = 0; index < 3; index++) + { + + if (hues[index] > 2) + hues[index] = (int) Math.min(255, hues[index]/0.7f); + if (hues[index] == 1 || hues[index] == 2) + hues[index] = 4; + } + } + + return new Color(hues[0], hues[1], hues[2], 255); + } + + /** + * Returns a darker version of this color. This is done by decreasing the + * RGB values by an arbitrary scale factor. The new color is opaque (an + * alpha of 255). Note that this method and the <code>brighter()</code> + * method are not necessarily inverses. + * + * @return a darker version of this color + * @see #brighter() + */ + public Color darker() + { + // Do not inline getRGB() to this.value, because of SystemColor. + int value = getRGB(); + return new Color((int) (((value & RED_MASK) >> 16) * BRIGHT_SCALE), + (int) (((value & GREEN_MASK) >> 8) * BRIGHT_SCALE), + (int) ((value & BLUE_MASK) * BRIGHT_SCALE), 255); + } + + /** + * Returns a hash value for this color. This is simply the color in 8-bit + * precision, in the format 0xAARRGGBB (alpha, red, green, blue). + * + * @return a hash value for this color + */ + public int hashCode() + { + return value; + } + + /** + * Tests this object for equality against the specified object. This will + * be true if and only if the specified object is an instance of + * <code>Color</code> and has the same 8-bit integer red, green, and blue + * values as this object. Note that two colors may be slightly different + * as float values, but round to the same integer values. Also note that + * this does not accurately compare SystemColors, since that class does + * not store its internal data in RGB format like regular colors. + * + * @param obj the object to compare to + * @return true if the specified object is semantically equal to this one + */ + public boolean equals(Object obj) + { + return obj instanceof Color && ((Color) obj).value == value; + } + + /** + * Returns a string representation of this object. Subclasses may return + * any desired format, except for null, but this implementation returns + * <code>getClass().getName() + "[r=" + getRed() + ",g=" + getGreen() + * + ",b=" + getBlue() + ']'</code>. + * + * @return a string representation of this object + */ + public String toString() + { + return getClass().getName() + "[r=" + ((value & RED_MASK) >> 16) + + ",g=" + ((value & GREEN_MASK) >> 8) + ",b=" + (value & BLUE_MASK) + + ']'; + } + + /** + * Converts the specified string to a number, using Integer.decode, and + * creates a new instance of <code>Color</code> from the value. The alpha + * value will be 255 (opaque). + * + * @param str the numeric color string + * @return a new instance of <code>Color</code> for the string + * @throws NumberFormatException if the string cannot be parsed + * @throws NullPointerException if the string is null + * @see Integer#decode(String) + * @see #Color(int) + * @since 1.1 + */ + public static Color decode(String str) + { + return new Color(Integer.decode(str).intValue(), false); + } + + /** + * Returns a new instance of <code>Color</code> from the value of the + * system property named by the specified string. If the property does not + * exist, or cannot be parsed, then <code>null</code> will be returned. + * + * @param prop the system property to retrieve + * @throws SecurityException if getting the property is denied + * @see #getColor(String, Color) + * @see Integer#getInteger(String) + */ + public static Color getColor(String prop) + { + return getColor(prop, null); + } + + /** + * Returns a new instance of <code>Color</code> from the value of the + * system property named by the specified string. If the property does + * not exist, or cannot be parsed, then the default color value will be + * returned. + * + * @param prop the system property to retrieve + * @param defcolor the default color + * @throws SecurityException if getting the property is denied + * @see Integer#getInteger(String) + */ + public static Color getColor(String prop, Color defcolor) + { + Integer val = Integer.getInteger(prop, null); + return val == null ? defcolor + : new Color(val.intValue(), false); + } + + /** + * Returns a new instance of <code>Color</code> from the value of the + * system property named by the specified string. If the property does + * not exist, or cannot be parsed, then the default RGB value will be + * used to create a return value. + * + * @param prop the system property to retrieve + * @param defrgb the default RGB value + * @throws SecurityException if getting the property is denied + * @see #getColor(String, Color) + * @see Integer#getInteger(String, int) + */ + public static Color getColor(String prop, int defrgb) + { + Color c = getColor(prop, null); + return c == null ? new Color(defrgb, false) : c; + } + + /** + * Converts from the HSB (hue, saturation, brightness) color model to the + * RGB (red, green, blue) color model. The hue may be any floating point; + * it's fractional portion is used to select the angle in the HSB model. + * The saturation and brightness must be between 0 and 1. The result is + * suitable for creating an RGB color with the one-argument constructor. + * + * @param hue the hue of the HSB value + * @param saturation the saturation of the HSB value + * @param brightness the brightness of the HSB value + * @return the RGB value + * @see #getRGB() + * @see #Color(int) + * @see ColorModel#getRGBdefault() + */ + public static int HSBtoRGB(float hue, float saturation, float brightness) + { + if (saturation == 0) + return convert(brightness, brightness, brightness, 0); + if (saturation < 0 || saturation > 1 || brightness < 0 || brightness > 1) + throw new IllegalArgumentException(); + hue = hue - (float) Math.floor(hue); + int i = (int) (6 * hue); + float f = 6 * hue - i; + float p = brightness * (1 - saturation); + float q = brightness * (1 - saturation * f); + float t = brightness * (1 - saturation * (1 - f)); + switch (i) + { + case 0: + return convert(brightness, t, p, 0); + case 1: + return convert(q, brightness, p, 0); + case 2: + return convert(p, brightness, t, 0); + case 3: + return convert(p, q, brightness, 0); + case 4: + return convert(t, p, brightness, 0); + case 5: + return convert(brightness, p, q, 0); + default: + throw new InternalError("impossible"); + } + } + + /** + * Converts from the RGB (red, green, blue) color model to the HSB (hue, + * saturation, brightness) color model. If the array is null, a new one + * is created, otherwise it is recycled. The results will be in the range + * 0.0-1.0 if the inputs are in the range 0-255. + * + * @param red the red part of the RGB value + * @param green the green part of the RGB value + * @param blue the blue part of the RGB value + * @param array an array for the result (at least 3 elements), or null + * @return the array containing HSB value + * @throws ArrayIndexOutOfBoundsException of array is too small + * @see #getRGB() + * @see #Color(int) + * @see ColorModel#getRGBdefault() + */ + public static float[] RGBtoHSB(int red, int green, int blue, float array[]) + { + if (array == null) + array = new float[3]; + // Calculate brightness. + int min; + int max; + if (red < green) + { + min = red; + max = green; + } + else + { + min = green; + max = red; + } + if (blue > max) + max = blue; + else if (blue < min) + min = blue; + array[2] = max / 255f; + // Calculate saturation. + if (max == 0) + array[1] = 0; + else + array[1] = ((float) (max - min)) / ((float) max); + // Calculate hue. + if (array[1] == 0) + array[0] = 0; + else + { + float delta = (max - min) * 6; + if (red == max) + array[0] = (green - blue) / delta; + else if (green == max) + array[0] = 1f / 3 + (blue - red) / delta; + else + array[0] = 2f / 3 + (red - green) / delta; + if (array[0] < 0) + array[0]++; + } + return array; + } + + /** + * Returns a new instance of <code>Color</code> based on the specified + * HSB values. The hue may be any floating point; it's fractional portion + * is used to select the angle in the HSB model. The saturation and + * brightness must be between 0 and 1. + * + * @param hue the hue of the HSB value + * @param saturation the saturation of the HSB value + * @param brightness the brightness of the HSB value + * @return the new <code>Color</code> object + */ + public static Color getHSBColor(float hue, float saturation, + float brightness) + { + return new Color(HSBtoRGB(hue, saturation, brightness), false); + } + + /** + * Returns a float array with the red, green, and blue components, and the + * alpha value, in the default sRGB space, with values in the range 0.0-1.0. + * If the array is null, a new one is created, otherwise it is recycled. + * + * @param array the array to put results into (at least 4 elements), or null + * @return the RGB components and alpha value + * @throws ArrayIndexOutOfBoundsException if array is too small + */ + public float[] getRGBComponents(float[] array) + { + if (array == null) + array = new float[4]; + getRGBColorComponents(array); + // Stupid serialization issues require this check. + array[3] = (falpha == 0 && frgbvalue == null + ? ((getRGB() & ALPHA_MASK) >> 24) / 255f : falpha); + return array; + } + + /** + * Returns a float array with the red, green, and blue components, in the + * default sRGB space, with values in the range 0.0-1.0. If the array is + * null, a new one is created, otherwise it is recycled. + * + * @param array the array to put results into (at least 3 elements), or null + * @return the RGB components + * @throws ArrayIndexOutOfBoundsException if array is too small + */ + public float[] getRGBColorComponents(float[] array) + { + if (array == null) + array = new float[3]; + else if (array == frgbvalue) + return array; // Optimization for getColorComponents(float[]). + if (frgbvalue == null) + { + // Do not inline getRGB() to this.value, because of SystemColor. + int value = getRGB(); + frgbvalue = new float[] { ((value & RED_MASK) >> 16) / 255f, + ((value & GREEN_MASK) >> 8) / 255f, + (value & BLUE_MASK) / 255f }; + } + array[0] = frgbvalue[0]; + array[1] = frgbvalue[1]; + array[2] = frgbvalue[2]; + return array; + } + + /** + * Returns a float array containing the color and alpha components of this + * color in the ColorSpace it was created with (the constructors which do + * not take a ColorSpace parameter use a default sRGB ColorSpace). If the + * array is null, a new one is created, otherwise it is recycled, and must + * have at least one more position than components used in the color space. + * + * @param array the array to put results into, or null + * @return the original color space components and alpha value + * @throws ArrayIndexOutOfBoundsException if array is too small + */ + public float[] getComponents(float[] array) + { + int numComponents = cs == null ? 3 : cs.getNumComponents(); + if (array == null) + array = new float[1 + numComponents]; + getColorComponents(array); + // Stupid serialization issues require this check. + array[numComponents] = (falpha == 0 && frgbvalue == null + ? ((getRGB() & ALPHA_MASK) >> 24) / 255f : falpha); + return array; + } + + /** + * Returns a float array containing the color components of this color in + * the ColorSpace it was created with (the constructors which do not take + * a ColorSpace parameter use a default sRGB ColorSpace). If the array is + * null, a new one is created, otherwise it is recycled, and must have at + * least as many positions as used in the color space. + * + * @param array the array to put results into, or null + * @return the original color space components + * @throws ArrayIndexOutOfBoundsException if array is too small + */ + public float[] getColorComponents(float[] array) + { + int numComponents = cs == null ? 3 : cs.getNumComponents(); + if (array == null) + array = new float[numComponents]; + if (fvalue == null) // If fvalue is null, cs should be null too. + fvalue = getRGBColorComponents(frgbvalue); + System.arraycopy(fvalue, 0, array, 0, numComponents); + return array; + } + + /** + * Returns a float array containing the color and alpha components of this + * color in the given ColorSpace. If the array is null, a new one is + * created, otherwise it is recycled, and must have at least one more + * position than components used in the color space. + * + * @param space the color space to translate to + * @param array the array to put results into, or null + * @return the color space components and alpha value + * @throws ArrayIndexOutOfBoundsException if array is too small + * @throws NullPointerException if space is null + */ + public float[] getComponents(ColorSpace space, float[] array) + { + int numComponents = space.getNumComponents(); + if (array == null) + array = new float[1 + numComponents]; + getColorComponents(space, array); + // Stupid serialization issues require this check. + array[numComponents] = (falpha == 0 && frgbvalue == null + ? ((getRGB() & ALPHA_MASK) >> 24) / 255f : falpha); + return array; + } + + /** + * Returns a float array containing the color components of this color in + * the given ColorSpace. If the array is null, a new one is created, + * otherwise it is recycled, and must have at least as many positions as + * used in the color space. + * + * @param space the color space to translate to + * @return the color space components + * @throws ArrayIndexOutOfBoundsException if array is too small + * @throws NullPointerException if space is null + */ + public float[] getColorComponents(ColorSpace space, float[] array) + { + float[] components = space.fromRGB(getRGBColorComponents(frgbvalue)); + if (array == null) + return components; + System.arraycopy(components, 0, array, 0, components.length); + return array; + } + + /** + * Returns the color space of this color. Except for the constructor which + * takes a ColorSpace argument, this will be an implementation of + * ColorSpace.CS_sRGB. + * + * @return the color space + */ + public ColorSpace getColorSpace() + { + return cs == null ? ColorSpace.getInstance(ColorSpace.CS_sRGB) : cs; + } + + /** + * Returns a paint context, used for filling areas of a raster scan with + * this color. Since the color is constant across the entire rectangle, and + * since it is always in sRGB space, this implementation returns the same + * object, regardless of the parameters. Subclasses, however, may have a + * mutable result. + * + * @param cm the requested color model + * @param deviceBounds the bounding box in device coordinates, ignored + * @param userBounds the bounding box in user coordinates, ignored + * @param xform the bounds transformation, ignored + * @param hints any rendering hints, ignored + * @return a context for painting this solid color + */ + public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, + Rectangle2D userBounds, + AffineTransform xform, + RenderingHints hints) + { + if (context == null || !context.getColorModel().equals(cm)) + context = new ColorPaintContext(cm,value); + return context; + } + + /** + * Returns the transparency level of this color. + * + * @return one of {@link #OPAQUE}, {@link #BITMASK}, or {@link #TRANSLUCENT} + */ + public int getTransparency() + { + // Do not inline getRGB() to this.value, because of SystemColor. + int alpha = getRGB() & ALPHA_MASK; + return alpha == (255 << 24) ? OPAQUE : alpha == 0 ? BITMASK : TRANSLUCENT; + } + + /** + * Converts float values to integer value. + * + * @param red the red value + * @param green the green value + * @param blue the blue value + * @param alpha the alpha value + * @return the integer value made of 8-bit sections + * @throws IllegalArgumentException if parameters are out of range 0.0-1.0 + */ + private static int convert(float red, float green, float blue, float alpha) + { + if (red < 0 || red > 1 || green < 0 || green > 1 || blue < 0 || blue > 1 + || alpha < 0 || alpha > 1) + throw new IllegalArgumentException("Bad RGB values"); + int redval = Math.round(255 * red); + int greenval = Math.round(255 * green); + int blueval = Math.round(255 * blue); + int alphaval = Math.round(255 * alpha); + return (alphaval << 24) | (redval << 16) | (greenval << 8) | blueval; + } +} // class Color diff --git a/libjava/classpath/java/awt/ColorPaintContext.java b/libjava/classpath/java/awt/ColorPaintContext.java new file mode 100644 index 000000000..5ba688617 --- /dev/null +++ b/libjava/classpath/java/awt/ColorPaintContext.java @@ -0,0 +1,195 @@ +/* ColorPaintContext.java -- context for painting solid colors + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.image.ColorModel; +import java.awt.image.Raster; + +/** + * This class provides a paint context which will fill a rectanglar region of + * a raster scan with the given color. However, it is not yet completely + * implemented. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ +class ColorPaintContext implements PaintContext +{ + /** + * The color to fill any raster with. Package visible for use in + * SystemColor. + */ + final int color; + final ColorModel colorModel; + + private ColorRaster cachedRaster; + + + /** + * Create the context for a given color. + * + * @param colorRGB The solid color to use. + */ + ColorPaintContext(int colorRGB) + { + this(ColorModel.getRGBdefault(), colorRGB); + } + + /** + * Create the context for a given color. + * + * @param cm The color model of this context. + * @param colorRGB The solid color to use. + */ + ColorPaintContext(ColorModel cm,int colorRGB) + { + color = colorRGB; + colorModel = cm; + } + + /** + * Release the resources allocated for the paint. As the color is constant, + * there aren't any resources. + */ + public void dispose() + { + } + + /** + * Return the color model of this context. + * + * @return the context color model + */ + public ColorModel getColorModel() + { + return colorModel; + } + + /** + * Return a raster containing the colors for the graphics operation. + * + * @param x the x-coordinate, in device space + * @param y the y-coordinate, in device space + * @param width the width, in device space + * @param height the height, in device space + * @return a raster for the given area and color + */ + public Raster getRaster(int x, int y, int width, int height) + { + if( cachedRaster == null + || cachedRaster.getWidth() < width + || cachedRaster.getHeight() < height) + { + cachedRaster = new ColorRaster(colorModel, 0, 0, width, height, color); + } + return cachedRaster.createChild(0 ,0 ,width ,height ,0 ,0 , null); + } + + /** + * A ColorRaster is a raster that is completely filled with one color. The + * data layout is taken from the color model given to the constructor. + */ + private class ColorRaster extends Raster + { + + /** + * Create a raster that is compaltible with the given color model and + * filled with the given color. + * @param cm The color model for this raster. + * @param x The smallest horizontal corrdinate in the raster. + * @param y The smallest vertical coordinate in the raster. + * @param width The width of the raster. + * @param height The height of the raster. + * @param rgbPixel The RGB value of the color for this raster. + */ + ColorRaster(ColorModel cm,int x, int y, int width, int height, int rgbPixel) + { + super(cm.createCompatibleSampleModel(width,height),new Point(x,y)); + Object pixel = cm.getDataElements(rgbPixel,null); + int[] pixelComps = cm.getComponents(pixel, null, 0); + int[] d = (int[]) multiplyData(pixelComps,null,width*height); + getSampleModel().setPixels(0, 0, width, height, d, + dataBuffer); + } + + + + private Object multiplyData(Object src, Object dest, int factor) + { + Object from; + int srcLength = 0; + if (src instanceof byte[]) + { + srcLength = ((byte[])src).length; + + if (dest == null) dest = new byte[factor * srcLength]; + } + else if (src instanceof short[]) + { + srcLength = ((short[])src).length; + if (dest == null) dest = new short[factor * srcLength]; + } + else if (src instanceof int[]) + { + srcLength = ((int[]) src).length; + if (dest == null) dest = new int[factor * srcLength]; + } + else + { + throw new ClassCastException("Unknown data buffer type"); + } + + System.arraycopy(src,0,dest,0,srcLength); + + int count = 1; + while(count*2 < factor) + { + System.arraycopy(dest, 0, dest, count * srcLength, count*srcLength); + count *= 2; + } + + if(factor > count) + System.arraycopy(dest,0, dest, count * srcLength, + (factor - count) * srcLength ); + + return dest; + } + + } + +} // class ColorPaintContext diff --git a/libjava/classpath/java/awt/Component.java b/libjava/classpath/java/awt/Component.java new file mode 100644 index 000000000..d2878a9fd --- /dev/null +++ b/libjava/classpath/java/awt/Component.java @@ -0,0 +1,7099 @@ +/* Component.java -- a graphics component + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2006 + Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +//import gnu.java.awt.dnd.peer.gtk.GtkDropTargetContextPeer; + +import gnu.java.awt.ComponentReshapeEvent; + +import gnu.java.lang.CPStringBuilder; + +import java.awt.dnd.DropTarget; +import java.awt.event.ActionEvent; +import java.awt.event.AdjustmentEvent; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.HierarchyBoundsListener; +import java.awt.event.HierarchyEvent; +import java.awt.event.HierarchyListener; +import java.awt.event.InputEvent; +import java.awt.event.InputMethodEvent; +import java.awt.event.InputMethodListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.awt.event.PaintEvent; +import java.awt.event.WindowEvent; +import java.awt.im.InputContext; +import java.awt.im.InputMethodRequests; +import java.awt.image.BufferStrategy; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.VolatileImage; +import java.awt.peer.ComponentPeer; +import java.awt.peer.LightweightPeer; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.Serializable; +import java.lang.reflect.Array; +import java.util.Collections; +import java.util.EventListener; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Locale; +import java.util.Set; +import java.util.Vector; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleComponent; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; + +/** + * The root of all evil. All graphical representations are subclasses of this + * giant class, which is designed for screen display and user interaction. + * This class can be extended directly to build a lightweight component (one + * not associated with a native window); lightweight components must reside + * inside a heavyweight window. + * + * <p>This class is Serializable, which has some big implications. A user can + * save the state of all graphical components in one VM, and reload them in + * another. Note that this class will only save Serializable listeners, and + * ignore the rest, without causing any serialization exceptions. However, by + * making a listener serializable, and adding it to another element, you link + * in that entire element to the state of this component. To get around this, + * use the idiom shown in the example below - make listeners non-serializable + * in inner classes, rather than using this object itself as the listener, if + * external objects do not need to save the state of this object. + * + * <pre> + * import java.awt.*; + * import java.awt.event.*; + * import java.io.Serializable; + * class MyApp implements Serializable + * { + * BigObjectThatShouldNotBeSerializedWithAButton bigOne; + * // Serializing aButton will not suck in an instance of MyApp, with its + * // accompanying field bigOne. + * Button aButton = new Button(); + * class MyActionListener implements ActionListener + * { + * public void actionPerformed(ActionEvent e) + * { + * System.out.println("Hello There"); + * } + * } + * MyApp() + * { + * aButton.addActionListener(new MyActionListener()); + * } + * } + * </pre> + * + * <p>Status: Incomplete. The event dispatch mechanism is implemented. All + * other methods defined in the J2SE 1.3 API javadoc exist, but are mostly + * incomplete or only stubs; except for methods relating to the Drag and + * Drop, Input Method, and Accessibility frameworks: These methods are + * present but commented out. + * + * @author original author unknown + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status still missing 1.4 support + */ +public abstract class Component + implements ImageObserver, MenuContainer, Serializable +{ + // Word to the wise - this file is huge. Search for '\f' (^L) for logical + // sectioning by fields, public API, private API, and nested classes. + + + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -7644114512714619750L; + + /** + * Constant returned by the <code>getAlignmentY</code> method to indicate + * that the component wishes to be aligned to the top relative to + * other components. + * + * @see #getAlignmentY() + */ + public static final float TOP_ALIGNMENT = 0; + + /** + * Constant returned by the <code>getAlignmentY</code> and + * <code>getAlignmentX</code> methods to indicate + * that the component wishes to be aligned to the centdisper relative to + * other components. + * + * @see #getAlignmentX() + * @see #getAlignmentY() + */ + public static final float CENTER_ALIGNMENT = 0.5f; + + /** + * Constant returned by the <code>getAlignmentY</code> method to indicate + * that the component wishes to be aligned to the bottom relative to + * other components. + * + * @see #getAlignmentY() + */ + public static final float BOTTOM_ALIGNMENT = 1; + + /** + * Constant returned by the <code>getAlignmentX</code> method to indicate + * that the component wishes to be aligned to the right relative to + * other components. + * + * @see #getAlignmentX() + */ + public static final float RIGHT_ALIGNMENT = 1; + + /** + * Constant returned by the <code>getAlignmentX</code> method to indicate + * that the component wishes to be aligned to the left relative to + * other components. + * + * @see #getAlignmentX() + */ + public static final float LEFT_ALIGNMENT = 0; + + /** + * Make the treelock a String so that it can easily be identified + * in debug dumps. We clone the String in order to avoid a conflict in + * the unlikely event that some other package uses exactly the same string + * as a lock object. + */ + static final Object treeLock = new String("AWT_TREE_LOCK"); + + /** + * The default maximum size. + */ + private static final Dimension DEFAULT_MAX_SIZE + = new Dimension(Short.MAX_VALUE, Short.MAX_VALUE); + + // Serialized fields from the serialization spec. + + /** + * The x position of the component in the parent's coordinate system. + * + * @see #getLocation() + * @serial the x position + */ + int x; + + /** + * The y position of the component in the parent's coordinate system. + * + * @see #getLocation() + * @serial the y position + */ + int y; + + /** + * The component width. + * + * @see #getSize() + * @serial the width + */ + int width; + + /** + * The component height. + * + * @see #getSize() + * @serial the height + */ + int height; + + /** + * The foreground color for the component. This may be null. + * + * @see #getForeground() + * @see #setForeground(Color) + * @serial the foreground color + */ + Color foreground; + + /** + * The background color for the component. This may be null. + * + * @see #getBackground() + * @see #setBackground(Color) + * @serial the background color + */ + Color background; + + /** + * The default font used in the component. This may be null. + * + * @see #getFont() + * @see #setFont(Font) + * @serial the font + */ + Font font; + + /** + * The font in use by the peer, or null if there is no peer. + * + * @serial the peer's font + */ + Font peerFont; + + /** + * The cursor displayed when the pointer is over this component. This may + * be null. + * + * @see #getCursor() + * @see #setCursor(Cursor) + */ + Cursor cursor; + + /** + * The locale for the component. + * + * @see #getLocale() + * @see #setLocale(Locale) + */ + Locale locale = Locale.getDefault (); + + /** + * True if the object should ignore repaint events (usually because it is + * not showing). + * + * @see #getIgnoreRepaint() + * @see #setIgnoreRepaint(boolean) + * @serial true to ignore repaints + * @since 1.4 + */ + boolean ignoreRepaint; + + /** + * True when the object is visible (although it is only showing if all + * ancestors are likewise visible). For component, this defaults to true. + * + * @see #isVisible() + * @see #setVisible(boolean) + * @serial true if visible + */ + boolean visible = true; + + /** + * True if the object is enabled, meaning it can interact with the user. + * For component, this defaults to true. + * + * @see #isEnabled() + * @see #setEnabled(boolean) + * @serial true if enabled + */ + boolean enabled = true; + + /** + * True if the object is valid. This is set to false any time a size + * adjustment means the component need to be layed out again. + * + * @see #isValid() + * @see #validate() + * @see #invalidate() + * @serial true if layout is valid + */ + boolean valid; + + /** + * The DropTarget for drag-and-drop operations. + * + * @see #getDropTarget() + * @see #setDropTarget(DropTarget) + * @serial the drop target, or null + * @since 1.2 + */ + DropTarget dropTarget; + + /** + * The list of popup menus for this component. + * + * @see #add(PopupMenu) + * @serial the list of popups + */ + Vector popups; + + /** + * The component's name. May be null, in which case a default name is + * generated on the first use. + * + * @see #getName() + * @see #setName(String) + * @serial the name + */ + String name; + + /** + * True once the user has set the name. Note that the user may set the name + * to null. + * + * @see #name + * @see #getName() + * @see #setName(String) + * @serial true if the name has been explicitly set + */ + boolean nameExplicitlySet; + + /** + * Indicates if the object can be focused. Defaults to true for components. + * + * @see #isFocusable() + * @see #setFocusable(boolean) + * @since 1.4 + */ + boolean focusable = true; + + /** + * Tracks whether this component's {@link #isFocusTraversable} + * method has been overridden. + * + * @since 1.4 + */ + int isFocusTraversableOverridden; + + /** + * The focus traversal keys, if not inherited from the parent or + * default keyboard focus manager. These sets will contain only + * AWTKeyStrokes that represent press and release events to use as + * focus control. + * + * @see #getFocusTraversalKeys(int) + * @see #setFocusTraversalKeys(int, Set) + * @since 1.4 + */ + Set[] focusTraversalKeys; + + /** + * True if focus traversal keys are enabled. This defaults to true for + * Component. If this is true, keystrokes in focusTraversalKeys are trapped + * and processed automatically rather than being passed on to the component. + * + * @see #getFocusTraversalKeysEnabled() + * @see #setFocusTraversalKeysEnabled(boolean) + * @since 1.4 + */ + boolean focusTraversalKeysEnabled = true; + + /** + * Cached information on the minimum size. Should have been transient. + * + * @serial ignore + */ + Dimension minSize; + + /** + * Flag indicating whether the minimum size for the component has been set + * by a call to {@link #setMinimumSize(Dimension)} with a non-null value. + */ + boolean minSizeSet; + + /** + * The maximum size for the component. + * @see #setMaximumSize(Dimension) + */ + Dimension maxSize; + + /** + * A flag indicating whether the maximum size for the component has been set + * by a call to {@link #setMaximumSize(Dimension)} with a non-null value. + */ + boolean maxSizeSet; + + /** + * Cached information on the preferred size. Should have been transient. + * + * @serial ignore + */ + Dimension prefSize; + + /** + * Flag indicating whether the preferred size for the component has been set + * by a call to {@link #setPreferredSize(Dimension)} with a non-null value. + */ + boolean prefSizeSet; + + /** + * Set to true if an event is to be handled by this component, false if + * it is to be passed up the hierarcy. + * + * @see #dispatchEvent(AWTEvent) + * @serial true to process event locally + */ + boolean newEventsOnly; + + /** + * Set by subclasses to enable event handling of particular events, and + * left alone when modifying listeners. For component, this defaults to + * enabling only input methods. + * + * @see #enableInputMethods(boolean) + * @see AWTEvent + * @serial the mask of events to process + */ + long eventMask = AWTEvent.INPUT_ENABLED_EVENT_MASK; + + /** + * Describes all registered PropertyChangeListeners. + * + * @see #addPropertyChangeListener(PropertyChangeListener) + * @see #removePropertyChangeListener(PropertyChangeListener) + * @see #firePropertyChange(String, Object, Object) + * @serial the property change listeners + * @since 1.2 + */ + PropertyChangeSupport changeSupport; + + /** + * True if the component has been packed (layed out). + * + * @serial true if this is packed + */ + boolean isPacked; + + /** + * The serialization version for this class. Currently at version 4. + * + * XXX How do we handle prior versions? + * + * @serial the serialization version + */ + int componentSerializedDataVersion = 4; + + /** + * The accessible context associated with this component. This is only set + * by subclasses. + * + * @see #getAccessibleContext() + * @serial the accessibility context + * @since 1.2 + */ + AccessibleContext accessibleContext; + + + // Guess what - listeners are special cased in serialization. See + // readObject and writeObject. + + /** Component listener chain. */ + transient ComponentListener componentListener; + + /** Focus listener chain. */ + transient FocusListener focusListener; + + /** Key listener chain. */ + transient KeyListener keyListener; + + /** Mouse listener chain. */ + transient MouseListener mouseListener; + + /** Mouse motion listener chain. */ + transient MouseMotionListener mouseMotionListener; + + /** + * Mouse wheel listener chain. + * + * @since 1.4 + */ + transient MouseWheelListener mouseWheelListener; + + /** + * Input method listener chain. + * + * @since 1.2 + */ + transient InputMethodListener inputMethodListener; + + /** + * Hierarcy listener chain. + * + * @since 1.3 + */ + transient HierarchyListener hierarchyListener; + + /** + * Hierarcy bounds listener chain. + * + * @since 1.3 + */ + transient HierarchyBoundsListener hierarchyBoundsListener; + + // Anything else is non-serializable, and should be declared "transient". + + /** The parent. */ + transient Container parent; + + /** The associated native peer. */ + transient ComponentPeer peer; + + /** The preferred component orientation. */ + transient ComponentOrientation componentOrientation = ComponentOrientation.UNKNOWN; + + /** + * The associated graphics configuration. + * + * @since 1.4 + */ + transient GraphicsConfiguration graphicsConfig; + + /** + * The buffer strategy for repainting. + * + * @since 1.4 + */ + transient BufferStrategy bufferStrategy; + + /** + * The number of hierarchy listeners of this container plus all of its + * children. This is needed for efficient handling of HierarchyEvents. + * These must be propagated to all child components with HierarchyListeners + * attached. To avoid traversal of the whole subtree, we keep track of + * the number of HierarchyListeners here and only walk the paths that + * actually have listeners. + */ + int numHierarchyListeners; + int numHierarchyBoundsListeners; + + /** + * true if requestFocus was called on this component when its + * top-level ancestor was not focusable. + */ + private transient FocusEvent pendingFocusRequest = null; + + /** + * The system properties that affect image updating. + */ + private static transient boolean incrementalDraw; + private static transient Long redrawRate; + + static + { + incrementalDraw = Boolean.getBoolean ("awt.image.incrementalDraw"); + redrawRate = Long.getLong ("awt.image.redrawrate"); + } + + // Public and protected API. + + /** + * Default constructor for subclasses. When Component is extended directly, + * it forms a lightweight component that must be hosted in an opaque native + * container higher in the tree. + */ + protected Component() + { + // Nothing to do here. + } + + /** + * Returns the name of this component. + * + * @return the name of this component + * @see #setName(String) + * @since 1.1 + */ + public String getName() + { + if (name == null && ! nameExplicitlySet) + name = generateName(); + return name; + } + + /** + * Sets the name of this component to the specified name (this is a bound + * property with the name 'name'). + * + * @param name the new name (<code>null</code> permitted). + * @see #getName() + * @since 1.1 + */ + public void setName(String name) + { + nameExplicitlySet = true; + String old = this.name; + this.name = name; + firePropertyChange("name", old, name); + } + + /** + * Returns the parent of this component. + * + * @return the parent of this component + */ + public Container getParent() + { + return parent; + } + + /** + * Returns the native windowing system peer for this component. Only the + * platform specific implementation code should call this method. + * + * @return the peer for this component + * @deprecated user programs should not directly manipulate peers; use + * {@link #isDisplayable()} instead + */ + // Classpath's Gtk peers rely on this. + public ComponentPeer getPeer() + { + return peer; + } + + /** + * Set the associated drag-and-drop target, which receives events when this + * is enabled. + * + * @param dt the new drop target + * @see #isEnabled() + */ + public void setDropTarget(DropTarget dt) + { + this.dropTarget = dt; + + if (peer != null) + dropTarget.addNotify(peer); + } + + /** + * Gets the associated drag-and-drop target, if there is one. + * + * @return the drop target + */ + public DropTarget getDropTarget() + { + return dropTarget; + } + + /** + * Returns the graphics configuration of this component, if there is one. + * If it has not been set, it is inherited from the parent. + * + * @return the graphics configuration, or null + * @since 1.3 + */ + public GraphicsConfiguration getGraphicsConfiguration() + { + GraphicsConfiguration conf = null; + synchronized (getTreeLock()) + { + if (graphicsConfig != null) + { + conf = graphicsConfig; + } + else + { + Component par = getParent(); + if (par != null) + { + conf = parent.getGraphicsConfiguration(); + } + } + } + return conf; + } + + /** + * Returns the object used for synchronization locks on this component + * when performing tree and layout functions. + * + * @return the synchronization lock for this component + */ + public final Object getTreeLock() + { + return treeLock; + } + + /** + * Returns the toolkit in use for this component. The toolkit is associated + * with the frame this component belongs to. + * + * @return the toolkit for this component + */ + public Toolkit getToolkit() + { + // Only heavyweight peers can handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + Toolkit tk = null; + if (p != null) + { + tk = peer.getToolkit(); + } + if (tk == null) + tk = Toolkit.getDefaultToolkit(); + return tk; + } + + /** + * Tests whether or not this component is valid. A invalid component needs + * to have its layout redone. + * + * @return true if this component is valid + * @see #validate() + * @see #invalidate() + */ + public boolean isValid() + { + // Tests show that components are invalid as long as they are not showing, even after validate() + // has been called on them. + return peer != null && valid; + } + + /** + * Tests if the component is displayable. It must be connected to a native + * screen resource. This reduces to checking that peer is not null. A + * containment hierarchy is made displayable when a window is packed or + * made visible. + * + * @return true if the component is displayable + * @see Container#add(Component) + * @see Container#remove(Component) + * @see Window#pack() + * @see Window#show() + * @see Window#dispose() + * @since 1.2 + */ + public boolean isDisplayable() + { + return peer != null; + } + + /** + * Tests whether or not this component is visible. Except for top-level + * frames, components are initially visible. + * + * @return true if the component is visible + * @see #setVisible(boolean) + */ + public boolean isVisible() + { + return visible; + } + + /** + * Tests whether or not this component is actually being shown on + * the screen. This will be true if and only if it this component is + * visible and its parent components are all visible. + * + * @return true if the component is showing on the screen + * @see #setVisible(boolean) + */ + public boolean isShowing() + { + Component par = parent; + return visible && peer != null && (par == null || par.isShowing()); + } + + /** + * Tests whether or not this component is enabled. Components are enabled + * by default, and must be enabled to receive user input or generate events. + * + * @return true if the component is enabled + * @see #setEnabled(boolean) + */ + public boolean isEnabled() + { + return enabled; + } + + /** + * Enables or disables this component. The component must be enabled to + * receive events (except that lightweight components always receive mouse + * events). + * + * @param enabled true to enable this component + * + * @see #isEnabled() + * @see #isLightweight() + * + * @since 1.1 + */ + public void setEnabled(boolean enabled) + { + enable(enabled); + } + + /** + * Enables this component. + * + * @deprecated use {@link #setEnabled(boolean)} instead + */ + public void enable() + { + if (! enabled) + { + // Need to lock the tree here, because the peers are involved. + synchronized (getTreeLock()) + { + enabled = true; + ComponentPeer p = peer; + if (p != null) + p.enable(); + } + } + } + + /** + * Enables or disables this component. + * + * @param enabled true to enable this component + * + * @deprecated use {@link #setEnabled(boolean)} instead + */ + public void enable(boolean enabled) + { + if (enabled) + enable(); + else + disable(); + } + + /** + * Disables this component. + * + * @deprecated use {@link #setEnabled(boolean)} instead + */ + public void disable() + { + if (enabled) + { + // Need to lock the tree here, because the peers are involved. + synchronized (getTreeLock()) + { + enabled = false; + ComponentPeer p = peer; + if (p != null) + p.disable(); + } + } + } + + /** + * Checks if this image is painted to an offscreen image buffer that is + * later copied to screen (double buffering reduces flicker). This version + * returns false, so subclasses must override it if they provide double + * buffering. + * + * @return true if this is double buffered; defaults to false + */ + public boolean isDoubleBuffered() + { + return false; + } + + /** + * Enables or disables input method support for this component. By default, + * components have this enabled. Input methods are given the opportunity + * to process key events before this component and its listeners. + * + * @param enable true to enable input method processing + * @see #processKeyEvent(KeyEvent) + * @since 1.2 + */ + public void enableInputMethods(boolean enable) + { + if (enable) + eventMask |= AWTEvent.INPUT_ENABLED_EVENT_MASK; + else + eventMask &= ~AWTEvent.INPUT_ENABLED_EVENT_MASK; + } + + /** + * Makes this component visible or invisible. Note that it wtill might + * not show the component, if a parent is invisible. + * + * @param visible true to make this component visible + * + * @see #isVisible() + * + * @since 1.1 + */ + public void setVisible(boolean visible) + { + // Inspection by subclassing shows that Sun's implementation calls + // show(boolean) which then calls show() or hide(). It is the show() + // method that is overriden in subclasses like Window. + show(visible); + } + + /** + * Makes this component visible on the screen. + * + * @deprecated use {@link #setVisible(boolean)} instead + */ + public void show() + { + // We must set visible before showing the peer. Otherwise the + // peer could post paint events before visible is true, in which + // case lightweight components are not initially painted -- + // Container.paint first calls isShowing () before painting itself + // and its children. + if(! visible) + { + // Need to lock the tree here to avoid races and inconsistencies. + synchronized (getTreeLock()) + { + visible = true; + // Avoid NullPointerExceptions by creating a local reference. + ComponentPeer currentPeer = peer; + if (currentPeer != null) + { + currentPeer.show(); + + // Fire HierarchyEvent. + fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, + this, parent, + HierarchyEvent.SHOWING_CHANGED); + + // The JDK repaints the component before invalidating the parent. + // So do we. + if (peer instanceof LightweightPeer) + repaint(); + } + + // Only post an event if this component actually has a listener + // or has this event explicitly enabled. + if (componentListener != null + || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0) + { + ComponentEvent ce = + new ComponentEvent(this,ComponentEvent.COMPONENT_SHOWN); + getToolkit().getSystemEventQueue().postEvent(ce); + } + } + + // Invalidate the parent if we have one. The component itself must + // not be invalidated. We also avoid NullPointerException with + // a local reference here. + Container currentParent = parent; + if (currentParent != null) + currentParent.invalidate(); + + } + } + + /** + * Makes this component visible or invisible. + * + * @param visible true to make this component visible + * + * @deprecated use {@link #setVisible(boolean)} instead + */ + public void show(boolean visible) + { + if (visible) + show(); + else + hide(); + } + + /** + * Hides this component so that it is no longer shown on the screen. + * + * @deprecated use {@link #setVisible(boolean)} instead + */ + public void hide() + { + if (visible) + { + // Need to lock the tree here to avoid races and inconsistencies. + synchronized (getTreeLock()) + { + visible = false; + + // Avoid NullPointerExceptions by creating a local reference. + ComponentPeer currentPeer = peer; + if (currentPeer != null) + { + currentPeer.hide(); + + // Fire hierarchy event. + fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, + this, parent, + HierarchyEvent.SHOWING_CHANGED); + // The JDK repaints the component before invalidating the + // parent. So do we. This only applies for lightweights. + if (peer instanceof LightweightPeer) + repaint(); + } + + // Only post an event if this component actually has a listener + // or has this event explicitly enabled. + if (componentListener != null + || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0) + { + ComponentEvent ce = + new ComponentEvent(this,ComponentEvent.COMPONENT_HIDDEN); + getToolkit().getSystemEventQueue().postEvent(ce); + } + } + + // Invalidate the parent if we have one. The component itself need + // not be invalidated. We also avoid NullPointerException with + // a local reference here. + Container currentParent = parent; + if (currentParent != null) + currentParent.invalidate(); + + } + } + + /** + * Returns this component's foreground color. If not set, this is inherited + * from the parent. + * + * @return this component's foreground color, or null + * @see #setForeground(Color) + */ + public Color getForeground() + { + if (foreground != null) + return foreground; + return parent == null ? null : parent.getForeground(); + } + + /** + * Sets this component's foreground color to the specified color. This is a + * bound property. + * + * @param c the new foreground color + * @see #getForeground() + */ + public void setForeground(Color c) + { + if (peer != null) + peer.setForeground(c); + + Color previous = foreground; + foreground = c; + firePropertyChange("foreground", previous, c); + } + + /** + * Tests if the foreground was explicitly set, or just inherited from the + * parent. + * + * @return true if the foreground has been set + * @since 1.4 + */ + public boolean isForegroundSet() + { + return foreground != null; + } + + /** + * Returns this component's background color. If not set, this is inherited + * from the parent. + * + * @return the background color of the component, or null + * @see #setBackground(Color) + */ + public Color getBackground() + { + if (background != null) + return background; + return parent == null ? null : parent.getBackground(); + } + + /** + * Sets this component's background color to the specified color. The parts + * of the component affected by the background color may by system dependent. + * This is a bound property. + * + * @param c the new background color + * @see #getBackground() + */ + public void setBackground(Color c) + { + // return if the background is already set to that color. + if ((c != null) && c.equals(background)) + return; + + Color previous = background; + background = c; + if (peer != null && c != null) + peer.setBackground(c); + firePropertyChange("background", previous, c); + } + + /** + * Tests if the background was explicitly set, or just inherited from the + * parent. + * + * @return true if the background has been set + * @since 1.4 + */ + public boolean isBackgroundSet() + { + return background != null; + } + + /** + * Returns the font in use for this component. If not set, this is inherited + * from the parent. + * + * @return the font for this component + * @see #setFont(Font) + */ + public Font getFont() + { + return getFontImpl(); + } + + /** + * Implementation of getFont(). This is pulled out of getFont() to prevent + * client programs from overriding this. + * + * @return the font of this component + */ + private final Font getFontImpl() + { + Font f = font; + if (f == null) + { + Component p = parent; + if (p != null) + f = p.getFontImpl(); + else + { + // It is important to return null here and not some kind of default + // font, otherwise the Swing UI would not install its fonts because + // it keeps non-UIResource fonts. + f = null; + } + } + return f; + } + + /** + * Sets the font for this component to the specified font. This is a bound + * property. + * + * @param f the new font for this component + * + * @see #getFont() + */ + public void setFont(Font f) + { + Font oldFont; + Font newFont; + // Synchronize on the tree because getFontImpl() relies on the hierarchy + // not beeing changed. + synchronized (getTreeLock()) + { + // Synchronize on this here to guarantee thread safety wrt to the + // property values. + synchronized (this) + { + oldFont = font; + font = f; + newFont = f; + } + // Create local variable here for thread safety. + ComponentPeer p = peer; + if (p != null) + { + // The peer receives the real font setting, which can depend on + // the parent font when this component's font has been set to null. + f = getFont(); + if (f != null) + { + p.setFont(f); + peerFont = f; + } + } + } + + // Fire property change event. + firePropertyChange("font", oldFont, newFont); + + // Invalidate when necessary as font changes can change the size of the + // component. + if (valid) + invalidate(); + } + + /** + * Tests if the font was explicitly set, or just inherited from the parent. + * + * @return true if the font has been set + * @since 1.4 + */ + public boolean isFontSet() + { + return font != null; + } + + /** + * Returns the locale for this component. If this component does not + * have a locale, the locale of the parent component is returned. + * + * @return the locale for this component + * @throws IllegalComponentStateException if it has no locale or parent + * @see #setLocale(Locale) + * @since 1.1 + */ + public Locale getLocale() + { + if (locale != null) + return locale; + if (parent == null) + throw new IllegalComponentStateException + ("Component has no parent: can't determine Locale"); + return parent.getLocale(); + } + + /** + * Sets the locale for this component to the specified locale. This is a + * bound property. + * + * @param newLocale the new locale for this component + */ + public void setLocale(Locale newLocale) + { + if (locale == newLocale) + return; + + Locale oldLocale = locale; + locale = newLocale; + firePropertyChange("locale", oldLocale, newLocale); + // New writing/layout direction or more/less room for localized labels. + invalidate(); + } + + /** + * Returns the color model of the device this componet is displayed on. + * + * @return this object's color model + * @see Toolkit#getColorModel() + */ + public ColorModel getColorModel() + { + GraphicsConfiguration config = getGraphicsConfiguration(); + return config != null ? config.getColorModel() + : getToolkit().getColorModel(); + } + + /** + * Returns the location of this component's top left corner relative to + * its parent component. This may be outdated, so for synchronous behavior, + * you should use a component listner. + * + * @return the location of this component + * @see #setLocation(int, int) + * @see #getLocationOnScreen() + * @since 1.1 + */ + public Point getLocation() + { + return location (); + } + + /** + * Returns the location of this component's top left corner in screen + * coordinates. + * + * @return the location of this component in screen coordinates + * @throws IllegalComponentStateException if the component is not showing + */ + public Point getLocationOnScreen() + { + if (! isShowing()) + throw new IllegalComponentStateException("component " + + getClass().getName() + + " not showing"); + + // Need to lock the tree here. We get crazy races and explosions when + // the tree changes while we are trying to find the location of this + // component. + synchronized (getTreeLock()) + { + // Only a heavyweight peer can answer the question for the screen + // location. So we are going through the hierarchy until we find + // one and add up the offsets while doing so. + int offsX = 0; + int offsY = 0; + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + offsX += comp.x; + offsY += comp.y; + comp = comp.parent; + p = comp == null ? null: comp.peer; + } + // Now we have a heavyweight component. + assert ! (p instanceof LightweightPeer); + Point loc = p.getLocationOnScreen(); + loc.x += offsX; + loc.y += offsY; + return loc; + } + } + + /** + * Returns the location of this component's top left corner relative to + * its parent component. + * + * @return the location of this component + * @deprecated use {@link #getLocation()} instead + */ + public Point location() + { + return new Point (x, y); + } + + /** + * Moves this component to the specified location, relative to the parent's + * coordinates. The coordinates are the new upper left corner of this + * component. + * + * @param x the new X coordinate of this component + * @param y the new Y coordinate of this component + * @see #getLocation() + * @see #setBounds(int, int, int, int) + */ + public void setLocation(int x, int y) + { + move (x, y); + } + + /** + * Moves this component to the specified location, relative to the parent's + * coordinates. The coordinates are the new upper left corner of this + * component. + * + * @param x the new X coordinate of this component + * @param y the new Y coordinate of this component + * @deprecated use {@link #setLocation(int, int)} instead + */ + public void move(int x, int y) + { + setBounds(x, y, this.width, this.height); + } + + /** + * Moves this component to the specified location, relative to the parent's + * coordinates. The coordinates are the new upper left corner of this + * component. + * + * @param p new coordinates for this component + * @throws NullPointerException if p is null + * @see #getLocation() + * @see #setBounds(int, int, int, int) + * @since 1.1 + */ + public void setLocation(Point p) + { + setLocation(p.x, p.y); + } + + /** + * Returns the size of this object. + * + * @return the size of this object + * @see #setSize(int, int) + * @since 1.1 + */ + public Dimension getSize() + { + return size (); + } + + /** + * Returns the size of this object. + * + * @return the size of this object + * @deprecated use {@link #getSize()} instead + */ + public Dimension size() + { + return new Dimension (width, height); + } + + /** + * Sets the size of this component to the specified width and height. + * + * @param width the new width of this component + * @param height the new height of this component + * @see #getSize() + * @see #setBounds(int, int, int, int) + */ + public void setSize(int width, int height) + { + resize (width, height); + } + + /** + * Sets the size of this component to the specified value. + * + * @param width the new width of the component + * @param height the new height of the component + * @deprecated use {@link #setSize(int, int)} instead + */ + public void resize(int width, int height) + { + setBounds(this.x, this.y, width, height); + } + + /** + * Sets the size of this component to the specified value. + * + * @param d the new size of this component + * @throws NullPointerException if d is null + * @see #setSize(int, int) + * @see #setBounds(int, int, int, int) + * @since 1.1 + */ + public void setSize(Dimension d) + { + resize (d); + } + + /** + * Sets the size of this component to the specified value. + * + * @param d the new size of this component + * @throws NullPointerException if d is null + * @deprecated use {@link #setSize(Dimension)} instead + */ + public void resize(Dimension d) + { + resize (d.width, d.height); + } + + /** + * Returns a bounding rectangle for this component. Note that the + * returned rectange is relative to this component's parent, not to + * the screen. + * + * @return the bounding rectangle for this component + * @see #setBounds(int, int, int, int) + * @see #getLocation() + * @see #getSize() + */ + public Rectangle getBounds() + { + return bounds (); + } + + /** + * Returns a bounding rectangle for this component. Note that the + * returned rectange is relative to this component's parent, not to + * the screen. + * + * @return the bounding rectangle for this component + * @deprecated use {@link #getBounds()} instead + */ + public Rectangle bounds() + { + return new Rectangle (x, y, width, height); + } + + /** + * Sets the bounding rectangle for this component to the specified values. + * Note that these coordinates are relative to the parent, not to the screen. + * + * @param x the X coordinate of the upper left corner of the rectangle + * @param y the Y coordinate of the upper left corner of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @see #getBounds() + * @see #setLocation(int, int) + * @see #setLocation(Point) + * @see #setSize(int, int) + * @see #setSize(Dimension) + * @since 1.1 + */ + public void setBounds(int x, int y, int w, int h) + { + reshape (x, y, w, h); + } + + /** + * Sets the bounding rectangle for this component to the specified values. + * Note that these coordinates are relative to the parent, not to the screen. + * + * @param x the X coordinate of the upper left corner of the rectangle + * @param y the Y coordinate of the upper left corner of the rectangle + * @param width the width of the rectangle + * @param height the height of the rectangle + * @deprecated use {@link #setBounds(int, int, int, int)} instead + */ + public void reshape(int x, int y, int width, int height) + { + // We need to lock the tree here, otherwise we risk races and + // inconsistencies. + synchronized (getTreeLock()) + { + int oldx = this.x; + int oldy = this.y; + int oldwidth = this.width; + int oldheight = this.height; + + boolean resized = oldwidth != width || oldheight != height; + boolean moved = oldx != x || oldy != y; + + if (resized || moved) + { + // Update the fields. + this.x = x; + this.y = y; + this.width = width; + this.height = height; + + if (peer != null) + { + peer.setBounds (x, y, width, height); + if (resized) + invalidate(); + if (parent != null && parent.valid) + parent.invalidate(); + } + + // Send some events to interested listeners. + notifyReshape(resized, moved); + + // Repaint this component and the parent if appropriate. + if (parent != null && peer instanceof LightweightPeer + && isShowing()) + { + // The parent repaints the area that we occupied before. + parent.repaint(oldx, oldy, oldwidth, oldheight); + // This component repaints the area that we occupy now. + repaint(); + } + } + } + } + + /** + * Sends notification to interested listeners about resizing and/or moving + * the component. If this component has interested + * component listeners or the corresponding event mask enabled, then + * COMPONENT_MOVED and/or COMPONENT_RESIZED events are posted to the event + * queue. + * + * @param resized true if the component has been resized, false otherwise + * @param moved true if the component has been moved, false otherwise + */ + void notifyReshape(boolean resized, boolean moved) + { + // Only post an event if this component actually has a listener + // or has this event explicitly enabled. + if (componentListener != null + || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0) + { + // Fire component event on this component. + if (moved) + { + ComponentEvent ce = new ComponentEvent(this, + ComponentEvent.COMPONENT_MOVED); + getToolkit().getSystemEventQueue().postEvent(ce); + } + if (resized) + { + ComponentEvent ce = new ComponentEvent(this, + ComponentEvent.COMPONENT_RESIZED); + getToolkit().getSystemEventQueue().postEvent(ce); + } + } + } + + /** + * Sets the bounding rectangle for this component to the specified + * rectangle. Note that these coordinates are relative to the parent, not + * to the screen. + * + * @param r the new bounding rectangle + * @throws NullPointerException if r is null + * @see #getBounds() + * @see #setLocation(Point) + * @see #setSize(Dimension) + * @since 1.1 + */ + public void setBounds(Rectangle r) + { + setBounds (r.x, r.y, r.width, r.height); + } + + /** + * Gets the x coordinate of the upper left corner. This is more efficient + * than getBounds().x or getLocation().x. + * + * @return the current x coordinate + * @since 1.2 + */ + public int getX() + { + return x; + } + + /** + * Gets the y coordinate of the upper left corner. This is more efficient + * than getBounds().y or getLocation().y. + * + * @return the current y coordinate + * @since 1.2 + */ + public int getY() + { + return y; + } + + /** + * Gets the width of the component. This is more efficient than + * getBounds().width or getSize().width. + * + * @return the current width + * @since 1.2 + */ + public int getWidth() + { + return width; + } + + /** + * Gets the height of the component. This is more efficient than + * getBounds().height or getSize().height. + * + * @return the current width + * @since 1.2 + */ + public int getHeight() + { + return height; + } + + /** + * Returns the bounds of this component. This allows reuse of an existing + * rectangle, if r is non-null. + * + * @param r the rectangle to use, or null + * @return the bounds + */ + public Rectangle getBounds(Rectangle r) + { + if (r == null) + r = new Rectangle(); + r.x = x; + r.y = y; + r.width = width; + r.height = height; + return r; + } + + /** + * Returns the size of this component. This allows reuse of an existing + * dimension, if d is non-null. + * + * @param d the dimension to use, or null + * @return the size + */ + public Dimension getSize(Dimension d) + { + if (d == null) + d = new Dimension(); + d.width = width; + d.height = height; + return d; + } + + /** + * Returns the location of this component. This allows reuse of an existing + * point, if p is non-null. + * + * @param p the point to use, or null + * @return the location + */ + public Point getLocation(Point p) + { + if (p == null) + p = new Point(); + p.x = x; + p.y = y; + return p; + } + + /** + * Tests if this component is opaque. All "heavyweight" (natively-drawn) + * components are opaque. A component is opaque if it draws all pixels in + * the bounds; a lightweight component is partially transparent if it lets + * pixels underneath show through. Subclasses that guarantee that all pixels + * will be drawn should override this. + * + * @return true if this is opaque + * @see #isLightweight() + * @since 1.2 + */ + public boolean isOpaque() + { + return ! isLightweight(); + } + + /** + * Return whether the component is lightweight. That means the component has + * no native peer, but is displayable. This applies to subclasses of + * Component not in this package, such as javax.swing. + * + * @return true if the component has a lightweight peer + * @see #isDisplayable() + * @since 1.2 + */ + public boolean isLightweight() + { + return peer instanceof LightweightPeer; + } + + /** + * Returns the component's preferred size. + * + * @return the component's preferred size + * @see #getMinimumSize() + * @see #setPreferredSize(Dimension) + * @see LayoutManager + */ + public Dimension getPreferredSize() + { + return preferredSize(); + } + + /** + * Sets the preferred size that will be returned by + * {@link #getPreferredSize()} always, and sends a + * {@link PropertyChangeEvent} (with the property name 'preferredSize') to + * all registered listeners. + * + * @param size the preferred size (<code>null</code> permitted). + * + * @since 1.5 + * + * @see #getPreferredSize() + */ + public void setPreferredSize(Dimension size) + { + Dimension old = prefSizeSet ? prefSize : null; + prefSize = size; + prefSizeSet = (size != null); + firePropertyChange("preferredSize", old, size); + } + + /** + * Returns <code>true</code> if the current preferred size is not + * <code>null</code> and was set by a call to + * {@link #setPreferredSize(Dimension)}, otherwise returns <code>false</code>. + * + * @return A boolean. + * + * @since 1.5 + */ + public boolean isPreferredSizeSet() + { + return prefSizeSet; + } + + /** + * Returns the component's preferred size. + * + * @return the component's preferred size + * @deprecated use {@link #getPreferredSize()} instead + */ + public Dimension preferredSize() + { + // Create a new Dimension object, so that the application doesn't mess + // with the actual values. + return new Dimension(preferredSizeImpl()); + } + + /** + * The actual calculation is pulled out of preferredSize() so that + * we can call it from Container.preferredSize() and avoid creating a + * new intermediate Dimension object. + * + * @return the preferredSize of the component + */ + Dimension preferredSizeImpl() + { + Dimension size = prefSize; + // Try to use a cached value. + if (size == null || !(valid || prefSizeSet)) + { + // We need to lock here, because the calculation depends on the + // component structure not changing. + synchronized (getTreeLock()) + { + ComponentPeer p = peer; + if (p != null) + size = peer.preferredSize(); + else + size = minimumSizeImpl(); + } + } + return size; + } + + /** + * Returns the component's minimum size. + * + * @return the component's minimum size + * @see #getPreferredSize() + * @see #setMinimumSize(Dimension) + * @see LayoutManager + */ + public Dimension getMinimumSize() + { + return minimumSize(); + } + + /** + * Sets the minimum size that will be returned by {@link #getMinimumSize()} + * always, and sends a {@link PropertyChangeEvent} (with the property name + * 'minimumSize') to all registered listeners. + * + * @param size the minimum size (<code>null</code> permitted). + * + * @since 1.5 + * + * @see #getMinimumSize() + */ + public void setMinimumSize(Dimension size) + { + Dimension old = minSizeSet ? minSize : null; + minSize = size; + minSizeSet = (size != null); + firePropertyChange("minimumSize", old, size); + } + + /** + * Returns <code>true</code> if the current minimum size is not + * <code>null</code> and was set by a call to + * {@link #setMinimumSize(Dimension)}, otherwise returns <code>false</code>. + * + * @return A boolean. + * + * @since 1.5 + */ + public boolean isMinimumSizeSet() + { + return minSizeSet; + } + + /** + * Returns the component's minimum size. + * + * @return the component's minimum size + * @deprecated use {@link #getMinimumSize()} instead + */ + public Dimension minimumSize() + { + // Create a new Dimension object, so that the application doesn't mess + // with the actual values. + return new Dimension(minimumSizeImpl()); + } + + /** + * The actual calculation is pulled out of minimumSize() so that + * we can call it from Container.preferredSize() and + * Component.preferredSizeImpl and avoid creating a + * new intermediate Dimension object. + * + * @return the minimum size of the component + */ + Dimension minimumSizeImpl() + { + Dimension size = minSize; + if (size == null || !(valid || minSizeSet)) + { + // We need to lock here, because the calculation depends on the + // component structure not changing. + synchronized (getTreeLock()) + { + ComponentPeer p = peer; + if (p != null) + size = peer.minimumSize(); + else + size = size(); + } + } + return size; + } + + /** + * Returns the component's maximum size. + * + * @return the component's maximum size + * @see #getMinimumSize() + * @see #setMaximumSize(Dimension) + * @see #getPreferredSize() + * @see LayoutManager + */ + public Dimension getMaximumSize() + { + return new Dimension(maximumSizeImpl()); + } + + /** + * This is pulled out from getMaximumSize(), so that we can access it + * from Container.getMaximumSize() without creating an additional + * intermediate Dimension object. + * + * @return the maximum size of the component + */ + Dimension maximumSizeImpl() + { + Dimension size; + if (maxSizeSet) + size = maxSize; + else + size = DEFAULT_MAX_SIZE; + return size; + } + + /** + * Sets the maximum size that will be returned by {@link #getMaximumSize()} + * always, and sends a {@link PropertyChangeEvent} (with the property name + * 'maximumSize') to all registered listeners. + * + * @param size the maximum size (<code>null</code> permitted). + * + * @since 1.5 + * + * @see #getMaximumSize() + */ + public void setMaximumSize(Dimension size) + { + Dimension old = maxSizeSet ? maxSize : null; + maxSize = size; + maxSizeSet = (size != null); + firePropertyChange("maximumSize", old, size); + } + + /** + * Returns <code>true</code> if the current maximum size is not + * <code>null</code> and was set by a call to + * {@link #setMaximumSize(Dimension)}, otherwise returns <code>false</code>. + * + * @return A boolean. + * + * @since 1.5 + */ + public boolean isMaximumSizeSet() + { + return maxSizeSet; + } + + /** + * Returns the preferred horizontal alignment of this component. The value + * returned will be between {@link #LEFT_ALIGNMENT} and + * {@link #RIGHT_ALIGNMENT}, inclusive. + * + * @return the preferred horizontal alignment of this component + */ + public float getAlignmentX() + { + return CENTER_ALIGNMENT; + } + + /** + * Returns the preferred vertical alignment of this component. The value + * returned will be between {@link #TOP_ALIGNMENT} and + * {@link #BOTTOM_ALIGNMENT}, inclusive. + * + * @return the preferred vertical alignment of this component + */ + public float getAlignmentY() + { + return CENTER_ALIGNMENT; + } + + /** + * Calls the layout manager to re-layout the component. This is called + * during validation of a container in most cases. + * + * @see #validate() + * @see LayoutManager + */ + public void doLayout() + { + layout (); + } + + /** + * Calls the layout manager to re-layout the component. This is called + * during validation of a container in most cases. + * + * @deprecated use {@link #doLayout()} instead + */ + public void layout() + { + // Nothing to do unless we're a container. + } + + /** + * Called to ensure that the layout for this component is valid. This is + * usually called on containers. + * + * @see #invalidate() + * @see #doLayout() + * @see LayoutManager + * @see Container#validate() + */ + public void validate() + { + if (! valid) + { + // Synchronize on the tree here as this might change the layout + // of the hierarchy. + synchronized (getTreeLock()) + { + // Create local variables for thread safety. + ComponentPeer p = peer; + if (p != null) + { + // Possibly update the peer's font. + Font newFont = getFont(); + Font oldFont = peerFont; + // Only update when the font really changed. + if (newFont != oldFont + && (oldFont == null || ! oldFont.equals(newFont))) + { + p.setFont(newFont); + peerFont = newFont; + } + // Let the peer perform any layout. + p.layout(); + } + } + valid = true; + } + } + + /** + * Invalidates this component and all of its parent components. This will + * cause them to have their layout redone. This is called frequently, so + * make it fast. + */ + public void invalidate() + { + // Need to lock here, to avoid races and other ugly stuff when doing + // layout or structure changes in other threads. + synchronized (getTreeLock()) + { + // Invalidate. + valid = false; + + // Throw away cached layout information. + if (! minSizeSet) + minSize = null; + if (! prefSizeSet) + prefSize = null; + if (! maxSizeSet) + maxSize = null; + + // Also invalidate the parent, if it hasn't already been invalidated. + if (parent != null && parent.isValid()) + parent.invalidate(); + } + } + + /** + * Returns a graphics object for this component. Returns <code>null</code> + * if this component is not currently displayed on the screen. + * + * @return a graphics object for this component + * @see #paint(Graphics) + */ + public Graphics getGraphics() + { + // Only heavyweight peers can handle this. + ComponentPeer p = peer; + Graphics g = null; + if (p instanceof LightweightPeer) + { + if (parent != null) + { + g = parent.getGraphics(); + if (g != null) + { + g.translate(x, y); + g.setClip(0, 0, width, height); + g.setFont(getFont()); + } + } + } + else + { + if (p != null) + g = p.getGraphics(); + } + return g; + } + + /** + * Returns the font metrics for the specified font in this component. + * + * @param font the font to retrieve metrics for + * @return the font metrics for the specified font + * @throws NullPointerException if font is null + * @see #getFont() + * @see Toolkit#getFontMetrics(Font) + */ + public FontMetrics getFontMetrics(Font font) + { + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + return p == null ? getToolkit().getFontMetrics(font) + : p.getFontMetrics(font); + } + + /** + * Sets the cursor for this component to the specified cursor. The cursor + * is displayed when the point is contained by the component, and the + * component is visible, displayable, and enabled. This is inherited by + * subcomponents unless they set their own cursor. + * + * @param cursor the new cursor for this component + * @see #isEnabled() + * @see #isShowing() + * @see #getCursor() + * @see #contains(int, int) + * @see Toolkit#createCustomCursor(Image, Point, String) + */ + public void setCursor(Cursor cursor) + { + this.cursor = cursor; + + // Only heavyweight peers handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + if (p != null) + p.setCursor(cursor); + } + + /** + * Returns the cursor for this component. If not set, this is inherited + * from the parent, or from Cursor.getDefaultCursor(). + * + * @return the cursor for this component + */ + public Cursor getCursor() + { + if (cursor != null) + return cursor; + return parent != null ? parent.getCursor() : Cursor.getDefaultCursor(); + } + + /** + * Tests if the cursor was explicitly set, or just inherited from the parent. + * + * @return true if the cursor has been set + * @since 1.4 + */ + public boolean isCursorSet() + { + return cursor != null; + } + + /** + * Paints this component on the screen. The clipping region in the graphics + * context will indicate the region that requires painting. This is called + * whenever the component first shows, or needs to be repaired because + * something was temporarily drawn on top. It is not necessary for + * subclasses to call <code>super.paint(g)</code>. Components with no area + * are not painted. + * + * @param g the graphics context for this paint job + * @see #update(Graphics) + */ + public void paint(Graphics g) + { + // This is a callback method and is meant to be overridden by subclasses + // that want to perform custom painting. + } + + /** + * Updates this component. This is called for heavyweight components in + * response to {@link #repaint()}. The default implementation simply forwards + * to {@link #paint(Graphics)}. The coordinates of the graphics are + * relative to this component. Subclasses should call either + * <code>super.update(g)</code> or <code>paint(g)</code>. + * + * @param g the graphics context for this update + * + * @see #paint(Graphics) + * @see #repaint() + */ + public void update(Graphics g) + { + // Note 1: We used to clear the background here for lightweights and + // toplevel components. Tests show that this is not what the JDK does + // here. Note that there is some special handling and background + // clearing code in Container.update(Graphics). + + // Note 2 (for peer implementors): The JDK doesn't seem call update() for + // toplevel components, even when an UPDATE event is sent (as a result + // of repaint). + paint(g); + } + + /** + * Paints this entire component, including any sub-components. + * + * @param g the graphics context for this paint job + * + * @see #paint(Graphics) + */ + public void paintAll(Graphics g) + { + if (isShowing()) + { + validate(); + if (peer instanceof LightweightPeer) + paint(g); + else + peer.paint(g); + } + } + + /** + * Repaint this entire component. The <code>update()</code> method + * on this component will be called as soon as possible. + * + * @see #update(Graphics) + * @see #repaint(long, int, int, int, int) + */ + public void repaint() + { + repaint(0, 0, 0, width, height); + } + + /** + * Repaint this entire component. The <code>update()</code> method on this + * component will be called in approximate the specified number of + * milliseconds. + * + * @param tm milliseconds before this component should be repainted + * @see #paint(Graphics) + * @see #repaint(long, int, int, int, int) + */ + public void repaint(long tm) + { + repaint(tm, 0, 0, width, height); + } + + /** + * Repaints the specified rectangular region within this component. The + * <code>update</code> method on this component will be called as soon as + * possible. The coordinates are relative to this component. + * + * @param x the X coordinate of the upper left of the region to repaint + * @param y the Y coordinate of the upper left of the region to repaint + * @param w the width of the region to repaint + * @param h the height of the region to repaint + * @see #update(Graphics) + * @see #repaint(long, int, int, int, int) + */ + public void repaint(int x, int y, int w, int h) + { + repaint(0, x, y, w, h); + } + + /** + * Repaints the specified rectangular region within this component. The + * <code>update</code> method on this component will be called in + * approximately the specified number of milliseconds. The coordinates + * are relative to this component. + * + * @param tm milliseconds before this component should be repainted + * @param x the X coordinate of the upper left of the region to repaint + * @param y the Y coordinate of the upper left of the region to repaint + * @param width the width of the region to repaint + * @param height the height of the region to repaint + * @see #update(Graphics) + */ + public void repaint(long tm, int x, int y, int width, int height) + { + // The repaint() call has previously been delegated to + // {@link ComponentPeer.repaint()}. Testing on the JDK using some + // dummy peers show that this methods is never called. I think it makes + // sense to actually perform the tasks below here, since it's pretty + // much peer independent anyway, and makes sure only heavyweights are + // bothered by this. + ComponentPeer p = peer; + + // Let the nearest heavyweight parent handle repainting for lightweight + // components. + // We need to recursivly call repaint() on the parent here, since + // a (lightweight) parent component might have overridden repaint() + // to perform additional custom tasks. + + if (p instanceof LightweightPeer) + { + // We perform some boundary checking to restrict the paint + // region to this component. + if (parent != null) + { + int px = this.x + Math.max(0, x); + int py = this.y + Math.max(0, y); + int pw = Math.min(this.width, width); + int ph = Math.min(this.height, height); + parent.repaint(tm, px, py, pw, ph); + } + } + else + { + // Now send an UPDATE event to the heavyweight component that we've found. + if (isVisible() && p != null && width > 0 && height > 0) + { + PaintEvent pe = new PaintEvent(this, PaintEvent.UPDATE, + new Rectangle(x, y, width, height)); + getToolkit().getSystemEventQueue().postEvent(pe); + } + } + } + + /** + * Prints this component. This method is provided so that printing can be + * done in a different manner from painting. However, the implementation + * in this class simply calls the <code>paint()</code> method. + * + * @param g the graphics context of the print device + * + * @see #paint(Graphics) + */ + public void print(Graphics g) + { + paint(g); + } + + /** + * Prints this component, including all sub-components. + * + * @param g the graphics context of the print device + * + * @see #paintAll(Graphics) + */ + public void printAll(Graphics g) + { + if( peer != null ) + peer.print( g ); + paintAll( g ); + } + + /** + * Called when an image has changed so that this component is repainted. + * This incrementally draws an image as more bits are available, when + * possible. Incremental drawing is enabled if the system property + * <code>awt.image.incrementalDraw</code> is not present or is true, in which + * case the redraw rate is set to 100ms or the value of the system property + * <code>awt.image.redrawrate</code>. + * + * <p>The coordinate system used depends on the particular flags. + * + * @param img the image that has been updated + * @param flags tlags as specified in <code>ImageObserver</code> + * @param x the X coordinate + * @param y the Y coordinate + * @param w the width + * @param h the height + * @return false if the image is completely loaded, loading has been + * aborted, or an error has occurred. true if more updates are + * required. + * @see ImageObserver + * @see Graphics#drawImage(Image, int, int, Color, ImageObserver) + * @see Graphics#drawImage(Image, int, int, ImageObserver) + * @see Graphics#drawImage(Image, int, int, int, int, Color, ImageObserver) + * @see Graphics#drawImage(Image, int, int, int, int, ImageObserver) + * @see ImageObserver#imageUpdate(Image, int, int, int, int, int) + */ + public boolean imageUpdate(Image img, int flags, int x, int y, int w, int h) + { + if ((flags & (FRAMEBITS | ALLBITS)) != 0) + repaint(); + else if ((flags & SOMEBITS) != 0) + { + if (incrementalDraw) + { + if (redrawRate != null) + { + long tm = redrawRate.longValue(); + if (tm < 0) + tm = 0; + repaint(tm); + } + else + repaint(100); + } + } + return (flags & (ALLBITS | ABORT | ERROR)) == 0; + } + + /** + * Creates an image from the specified producer. + * + * @param producer the image procedure to create the image from + * @return the resulting image + */ + public Image createImage(ImageProducer producer) + { + // Only heavyweight peers can handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + // Sun allows producer to be null. + Image im; + if (p != null) + im = p.createImage(producer); + else + im = getToolkit().createImage(producer); + return im; + } + + /** + * Creates an image with the specified width and height for use in + * double buffering. Headless environments do not support images. + * + * @param width the width of the image + * @param height the height of the image + * @return the requested image, or null if it is not supported + */ + public Image createImage (int width, int height) + { + Image returnValue = null; + if (!GraphicsEnvironment.isHeadless ()) + { + // Only heavyweight peers can handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + if (p != null) + returnValue = p.createImage(width, height); + } + return returnValue; + } + + /** + * Creates an image with the specified width and height for use in + * double buffering. Headless environments do not support images. + * + * @param width the width of the image + * @param height the height of the image + * @return the requested image, or null if it is not supported + * @since 1.4 + */ + public VolatileImage createVolatileImage(int width, int height) + { + // Only heavyweight peers can handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + VolatileImage im = null; + if (p != null) + im = p.createVolatileImage(width, height); + return im; + } + + /** + * Creates an image with the specified width and height for use in + * double buffering. Headless environments do not support images. The image + * will support the specified capabilities. + * + * @param width the width of the image + * @param height the height of the image + * @param caps the requested capabilities + * @return the requested image, or null if it is not supported + * @throws AWTException if a buffer with the capabilities cannot be created + * @since 1.4 + */ + public VolatileImage createVolatileImage(int width, int height, + ImageCapabilities caps) + throws AWTException + { + // Only heavyweight peers can handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + VolatileImage im = null; + if (p != null) + im = peer.createVolatileImage(width, height); + return im; + } + + /** + * Prepares the specified image for rendering on this component. + * + * @param image the image to prepare for rendering + * @param observer the observer to notify of image preparation status + * @return true if the image is already fully prepared + * @throws NullPointerException if image is null + */ + public boolean prepareImage(Image image, ImageObserver observer) + { + return prepareImage(image, image.getWidth(observer), + image.getHeight(observer), observer); + } + + /** + * Prepares the specified image for rendering on this component at the + * specified scaled width and height + * + * @param image the image to prepare for rendering + * @param width the scaled width of the image + * @param height the scaled height of the image + * @param observer the observer to notify of image preparation status + * @return true if the image is already fully prepared + */ + public boolean prepareImage(Image image, int width, int height, + ImageObserver observer) + { + // Only heavyweight peers handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + boolean retval; + if (p != null) + retval = p.prepareImage(image, width, height, observer); + else + retval = getToolkit().prepareImage(image, width, height, observer); + return retval; + } + + /** + * Returns the status of the loading of the specified image. The value + * returned will be those flags defined in <code>ImageObserver</code>. + * + * @param image the image to check on + * @param observer the observer to notify of image loading progress + * @return the image observer flags indicating the status of the load + * @see #prepareImage(Image, int, int, ImageObserver) + * @see Toolkit#checkImage(Image, int, int, ImageObserver) + * @throws NullPointerException if image is null + */ + public int checkImage(Image image, ImageObserver observer) + { + return checkImage(image, -1, -1, observer); + } + + /** + * Returns the status of the loading of the specified image. The value + * returned will be those flags defined in <code>ImageObserver</code>. + * + * @param image the image to check on + * @param width the scaled image width + * @param height the scaled image height + * @param observer the observer to notify of image loading progress + * @return the image observer flags indicating the status of the load + * @see #prepareImage(Image, int, int, ImageObserver) + * @see Toolkit#checkImage(Image, int, int, ImageObserver) + */ + public int checkImage(Image image, int width, int height, + ImageObserver observer) + { + // Only heavyweight peers handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + int retval; + if (p != null) + retval = p.checkImage(image, width, height, observer); + else + retval = getToolkit().checkImage(image, width, height, observer); + return retval; + } + + /** + * Sets whether paint messages delivered by the operating system should be + * ignored. This does not affect messages from AWT, except for those + * triggered by OS messages. Setting this to true can allow faster + * performance in full-screen mode or page-flipping. + * + * @param ignoreRepaint the new setting for ignoring repaint events + * @see #getIgnoreRepaint() + * @see BufferStrategy + * @see GraphicsDevice#setFullScreenWindow(Window) + * @since 1.4 + */ + public void setIgnoreRepaint(boolean ignoreRepaint) + { + this.ignoreRepaint = ignoreRepaint; + } + + /** + * Test whether paint events from the operating system are ignored. + * + * @return the status of ignoring paint events + * @see #setIgnoreRepaint(boolean) + * @since 1.4 + */ + public boolean getIgnoreRepaint() + { + return ignoreRepaint; + } + + /** + * Tests whether or not the specified point is contained within this + * component. Coordinates are relative to this component. + * + * @param x the X coordinate of the point to test + * @param y the Y coordinate of the point to test + * @return true if the point is within this component + * @see #getComponentAt(int, int) + */ + public boolean contains(int x, int y) + { + return inside (x, y); + } + + /** + * Tests whether or not the specified point is contained within this + * component. Coordinates are relative to this component. + * + * @param x the X coordinate of the point to test + * @param y the Y coordinate of the point to test + * @return true if the point is within this component + * @deprecated use {@link #contains(int, int)} instead + */ + public boolean inside(int x, int y) + { + return x >= 0 && y >= 0 && x < width && y < height; + } + + /** + * Tests whether or not the specified point is contained within this + * component. Coordinates are relative to this component. + * + * @param p the point to test + * @return true if the point is within this component + * @throws NullPointerException if p is null + * @see #getComponentAt(Point) + * @since 1.1 + */ + public boolean contains(Point p) + { + return contains (p.x, p.y); + } + + /** + * Returns the component occupying the position (x,y). This will either + * be this component, an immediate child component, or <code>null</code> + * if neither of the first two occupies the specified location. + * + * @param x the X coordinate to search for components at + * @param y the Y coordinate to search for components at + * @return the component at the specified location, or null + * @see #contains(int, int) + */ + public Component getComponentAt(int x, int y) + { + return locate (x, y); + } + + /** + * Returns the component occupying the position (x,y). This will either + * be this component, an immediate child component, or <code>null</code> + * if neither of the first two occupies the specified location. + * + * @param x the X coordinate to search for components at + * @param y the Y coordinate to search for components at + * @return the component at the specified location, or null + * @deprecated use {@link #getComponentAt(int, int)} instead + */ + public Component locate(int x, int y) + { + return contains (x, y) ? this : null; + } + + /** + * Returns the component occupying the position (x,y). This will either + * be this component, an immediate child component, or <code>null</code> + * if neither of the first two occupies the specified location. + * + * @param p the point to search for components at + * @return the component at the specified location, or null + * @throws NullPointerException if p is null + * @see #contains(Point) + * @since 1.1 + */ + public Component getComponentAt(Point p) + { + return getComponentAt (p.x, p.y); + } + + /** + * AWT 1.0 event delivery. + * + * Deliver an AWT 1.0 event to this Component. This method simply + * calls {@link #postEvent}. + * + * @param e the event to deliver + * @deprecated use {@link #dispatchEvent (AWTEvent)} instead + */ + public void deliverEvent (Event e) + { + postEvent (e); + } + + /** + * Forwards AWT events to processEvent() if:<ul> + * <li>Events have been enabled for this type of event via + * <code>enableEvents()</code></li>, + * <li>There is at least one registered listener for this type of event</li> + * </ul> + * + * @param e the event to dispatch + */ + public final void dispatchEvent(AWTEvent e) + { + // Some subclasses in the AWT package need to override this behavior, + // hence the use of dispatchEventImpl(). + dispatchEventImpl(e); + } + + /** + * By default, no old mouse events should be ignored. + * This can be overridden by subclasses. + * + * @return false, no mouse events are ignored. + */ + static boolean ignoreOldMouseEvents() + { + return false; + } + + /** + * AWT 1.0 event handler. + * + * This method simply calls handleEvent and returns the result. + * + * @param e the event to handle + * @return true if the event was handled, false otherwise + * @deprecated use {@link #dispatchEvent(AWTEvent)} instead + */ + public boolean postEvent (Event e) + { + boolean handled = handleEvent (e); + + if (!handled && getParent() != null) + // FIXME: need to translate event coordinates to parent's + // coordinate space. + handled = getParent ().postEvent (e); + + return handled; + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see ComponentEvent + * @see #removeComponentListener(ComponentListener) + * @see #getComponentListeners() + * @since 1.1 + */ + public synchronized void addComponentListener(ComponentListener listener) + { + if (listener != null) + { + componentListener = AWTEventMulticaster.add(componentListener, + listener); + newEventsOnly = true; + } + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see ComponentEvent + * @see #addComponentListener(ComponentListener) + * @see #getComponentListeners() + * @since 1.1 + */ + public synchronized void removeComponentListener(ComponentListener listener) + { + componentListener = AWTEventMulticaster.remove(componentListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addComponentListener(ComponentListener) + * @see #removeComponentListener(ComponentListener) + * @since 1.4 + */ + public synchronized ComponentListener[] getComponentListeners() + { + return (ComponentListener[]) + AWTEventMulticaster.getListeners(componentListener, + ComponentListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see FocusEvent + * @see #removeFocusListener(FocusListener) + * @see #getFocusListeners() + * @since 1.1 + */ + public synchronized void addFocusListener(FocusListener listener) + { + if (listener != null) + { + focusListener = AWTEventMulticaster.add(focusListener, listener); + newEventsOnly = true; + } + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see FocusEvent + * @see #addFocusListener(FocusListener) + * @see #getFocusListeners() + * @since 1.1 + */ + public synchronized void removeFocusListener(FocusListener listener) + { + focusListener = AWTEventMulticaster.remove(focusListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addFocusListener(FocusListener) + * @see #removeFocusListener(FocusListener) + * @since 1.4 + */ + public synchronized FocusListener[] getFocusListeners() + { + return (FocusListener[]) + AWTEventMulticaster.getListeners(focusListener, FocusListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see HierarchyEvent + * @see #removeHierarchyListener(HierarchyListener) + * @see #getHierarchyListeners() + * @since 1.3 + */ + public synchronized void addHierarchyListener(HierarchyListener listener) + { + if (listener != null) + { + hierarchyListener = AWTEventMulticaster.add(hierarchyListener, + listener); + newEventsOnly = true; + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyListeners++; + if (parent != null) + parent.updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK, + 1); + } + } + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see HierarchyEvent + * @see #addHierarchyListener(HierarchyListener) + * @see #getHierarchyListeners() + * @since 1.3 + */ + public synchronized void removeHierarchyListener(HierarchyListener listener) + { + hierarchyListener = AWTEventMulticaster.remove(hierarchyListener, listener); + + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyListeners--; + if (parent != null) + parent.updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK, + -1); + } + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addHierarchyListener(HierarchyListener) + * @see #removeHierarchyListener(HierarchyListener) + * @since 1.4 + */ + public synchronized HierarchyListener[] getHierarchyListeners() + { + return (HierarchyListener[]) + AWTEventMulticaster.getListeners(hierarchyListener, + HierarchyListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see HierarchyEvent + * @see #removeHierarchyBoundsListener(HierarchyBoundsListener) + * @see #getHierarchyBoundsListeners() + * @since 1.3 + */ + public synchronized void + addHierarchyBoundsListener(HierarchyBoundsListener listener) + { + if (listener != null) + { + hierarchyBoundsListener = + AWTEventMulticaster.add(hierarchyBoundsListener, listener); + newEventsOnly = true; + + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyBoundsListeners++; + if (parent != null) + parent.updateHierarchyListenerCount + (AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, 1); + } + } + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see HierarchyEvent + * @see #addHierarchyBoundsListener(HierarchyBoundsListener) + * @see #getHierarchyBoundsListeners() + * @since 1.3 + */ + public synchronized void + removeHierarchyBoundsListener(HierarchyBoundsListener listener) + { + hierarchyBoundsListener = + AWTEventMulticaster.remove(hierarchyBoundsListener, listener); + + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyBoundsListeners--; + if (parent != null) + parent.updateHierarchyListenerCount + (AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, + -1); + } + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addHierarchyBoundsListener(HierarchyBoundsListener) + * @see #removeHierarchyBoundsListener(HierarchyBoundsListener) + * @since 1.4 + */ + public synchronized HierarchyBoundsListener[] getHierarchyBoundsListeners() + { + return (HierarchyBoundsListener[]) + AWTEventMulticaster.getListeners(hierarchyBoundsListener, + HierarchyBoundsListener.class); + } + + /** + * Fires a HierarchyEvent or HierarchyChangeEvent on this component. + * + * @param id the event id + * @param changed the changed component + * @param parent the parent + * @param flags the event flags + */ + void fireHierarchyEvent(int id, Component changed, Container parent, + long flags) + { + boolean enabled = false; + switch (id) + { + case HierarchyEvent.HIERARCHY_CHANGED: + enabled = hierarchyListener != null + || (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) != 0; + break; + case HierarchyEvent.ANCESTOR_MOVED: + case HierarchyEvent.ANCESTOR_RESIZED: + enabled = hierarchyBoundsListener != null + || (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0; + break; + default: + assert false : "Should not reach here"; + } + if (enabled) + { + HierarchyEvent ev = new HierarchyEvent(this, id, changed, parent, + flags); + dispatchEvent(ev); + } + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see KeyEvent + * @see #removeKeyListener(KeyListener) + * @see #getKeyListeners() + * @since 1.1 + */ + public synchronized void addKeyListener(KeyListener listener) + { + if (listener != null) + { + keyListener = AWTEventMulticaster.add(keyListener, listener); + newEventsOnly = true; + } + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see KeyEvent + * @see #addKeyListener(KeyListener) + * @see #getKeyListeners() + * @since 1.1 + */ + public synchronized void removeKeyListener(KeyListener listener) + { + keyListener = AWTEventMulticaster.remove(keyListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addKeyListener(KeyListener) + * @see #removeKeyListener(KeyListener) + * @since 1.4 + */ + public synchronized KeyListener[] getKeyListeners() + { + return (KeyListener[]) + AWTEventMulticaster.getListeners(keyListener, KeyListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see MouseEvent + * @see #removeMouseListener(MouseListener) + * @see #getMouseListeners() + * @since 1.1 + */ + public synchronized void addMouseListener(MouseListener listener) + { + if (listener != null) + { + mouseListener = AWTEventMulticaster.add(mouseListener, listener); + newEventsOnly = true; + } + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see MouseEvent + * @see #addMouseListener(MouseListener) + * @see #getMouseListeners() + * @since 1.1 + */ + public synchronized void removeMouseListener(MouseListener listener) + { + mouseListener = AWTEventMulticaster.remove(mouseListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addMouseListener(MouseListener) + * @see #removeMouseListener(MouseListener) + * @since 1.4 + */ + public synchronized MouseListener[] getMouseListeners() + { + return (MouseListener[]) + AWTEventMulticaster.getListeners(mouseListener, MouseListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see MouseEvent + * @see #removeMouseMotionListener(MouseMotionListener) + * @see #getMouseMotionListeners() + * @since 1.1 + */ + public synchronized void addMouseMotionListener(MouseMotionListener listener) + { + if (listener != null) + { + mouseMotionListener = AWTEventMulticaster.add(mouseMotionListener, + listener); + newEventsOnly = true; + } + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see MouseEvent + * @see #addMouseMotionListener(MouseMotionListener) + * @see #getMouseMotionListeners() + * @since 1.1 + */ + public synchronized void removeMouseMotionListener(MouseMotionListener listener) + { + mouseMotionListener = AWTEventMulticaster.remove(mouseMotionListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addMouseMotionListener(MouseMotionListener) + * @see #removeMouseMotionListener(MouseMotionListener) + * @since 1.4 + */ + public synchronized MouseMotionListener[] getMouseMotionListeners() + { + return (MouseMotionListener[]) + AWTEventMulticaster.getListeners(mouseMotionListener, + MouseMotionListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see MouseEvent + * @see MouseWheelEvent + * @see #removeMouseWheelListener(MouseWheelListener) + * @see #getMouseWheelListeners() + * @since 1.4 + */ + public synchronized void addMouseWheelListener(MouseWheelListener listener) + { + if (listener != null) + { + mouseWheelListener = AWTEventMulticaster.add(mouseWheelListener, + listener); + newEventsOnly = true; + } + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see MouseEvent + * @see MouseWheelEvent + * @see #addMouseWheelListener(MouseWheelListener) + * @see #getMouseWheelListeners() + * @since 1.4 + */ + public synchronized void removeMouseWheelListener(MouseWheelListener listener) + { + mouseWheelListener = AWTEventMulticaster.remove(mouseWheelListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addMouseWheelListener(MouseWheelListener) + * @see #removeMouseWheelListener(MouseWheelListener) + * @since 1.4 + */ + public synchronized MouseWheelListener[] getMouseWheelListeners() + { + return (MouseWheelListener[]) + AWTEventMulticaster.getListeners(mouseWheelListener, + MouseWheelListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see InputMethodEvent + * @see #removeInputMethodListener(InputMethodListener) + * @see #getInputMethodListeners() + * @see #getInputMethodRequests() + * @since 1.2 + */ + public synchronized void addInputMethodListener(InputMethodListener listener) + { + if (listener != null) + { + inputMethodListener = AWTEventMulticaster.add(inputMethodListener, + listener); + newEventsOnly = true; + } + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see InputMethodEvent + * @see #addInputMethodListener(InputMethodListener) + * @see #getInputMethodRequests() + * @since 1.2 + */ + public synchronized void removeInputMethodListener(InputMethodListener listener) + { + inputMethodListener = AWTEventMulticaster.remove(inputMethodListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addInputMethodListener(InputMethodListener) + * @see #removeInputMethodListener(InputMethodListener) + * @since 1.4 + */ + public synchronized InputMethodListener[] getInputMethodListeners() + { + return (InputMethodListener[]) + AWTEventMulticaster.getListeners(inputMethodListener, + InputMethodListener.class); + } + + /** + * Returns all registered {@link EventListener}s of the given + * <code>listenerType</code>. + * + * @param listenerType the class of listeners to filter (<code>null</code> + * not permitted). + * + * @return An array of registered listeners. + * + * @throws ClassCastException if <code>listenerType</code> does not implement + * the {@link EventListener} interface. + * @throws NullPointerException if <code>listenerType</code> is + * <code>null</code>. + * + * @see #getComponentListeners() + * @see #getFocusListeners() + * @see #getHierarchyListeners() + * @see #getHierarchyBoundsListeners() + * @see #getKeyListeners() + * @see #getMouseListeners() + * @see #getMouseMotionListeners() + * @see #getMouseWheelListeners() + * @see #getInputMethodListeners() + * @see #getPropertyChangeListeners() + * @since 1.3 + */ + public <T extends EventListener> T[] getListeners(Class<T> listenerType) + { + if (listenerType == ComponentListener.class) + return (T[]) getComponentListeners(); + if (listenerType == FocusListener.class) + return (T[]) getFocusListeners(); + if (listenerType == HierarchyListener.class) + return (T[]) getHierarchyListeners(); + if (listenerType == HierarchyBoundsListener.class) + return (T[]) getHierarchyBoundsListeners(); + if (listenerType == KeyListener.class) + return (T[]) getKeyListeners(); + if (listenerType == MouseListener.class) + return (T[]) getMouseListeners(); + if (listenerType == MouseMotionListener.class) + return (T[]) getMouseMotionListeners(); + if (listenerType == MouseWheelListener.class) + return (T[]) getMouseWheelListeners(); + if (listenerType == InputMethodListener.class) + return (T[]) getInputMethodListeners(); + if (listenerType == PropertyChangeListener.class) + return (T[]) getPropertyChangeListeners(); + return (T[]) Array.newInstance(listenerType, 0); + } + + /** + * Returns the input method request handler, for subclasses which support + * on-the-spot text input. By default, input methods are handled by AWT, + * and this returns null. + * + * @return the input method handler, null by default + * @since 1.2 + */ + public InputMethodRequests getInputMethodRequests() + { + return null; + } + + /** + * Gets the input context of this component, which is inherited from the + * parent unless this is overridden. + * + * @return the text input context + * @since 1.2 + */ + public InputContext getInputContext() + { + return parent == null ? null : parent.getInputContext(); + } + + /** + * Enables the specified events. The events to enable are specified + * by OR-ing together the desired masks from <code>AWTEvent</code>. + * + * <p>Events are enabled by default when a listener is attached to the + * component for that event type. This method can be used by subclasses + * to ensure the delivery of a specified event regardless of whether + * or not a listener is attached. + * + * @param eventsToEnable the desired events to enable + * @see #processEvent(AWTEvent) + * @see #disableEvents(long) + * @see AWTEvent + * @since 1.1 + */ + protected final void enableEvents(long eventsToEnable) + { + // Update the counter for hierarchy (bounds) listeners. + if ((eventsToEnable & AWTEvent.HIERARCHY_EVENT_MASK) != 0 + && (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) == 0) + { + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyListeners++; + if (parent != null) + parent.updateHierarchyListenerCount + (AWTEvent.HIERARCHY_EVENT_MASK, + 1); + } + } + if ((eventsToEnable & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0 + && (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) == 0) + { + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyBoundsListeners++; + if (parent != null) + parent.updateHierarchyListenerCount + (AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, + 1); + } + } + + eventMask |= eventsToEnable; + newEventsOnly = true; + + // Only heavyweight peers handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + if (p != null) + p.setEventMask(eventMask); + + } + + /** + * Disables the specified events. The events to disable are specified + * by OR-ing together the desired masks from <code>AWTEvent</code>. + * + * @param eventsToDisable the desired events to disable + * @see #enableEvents(long) + * @since 1.1 + */ + protected final void disableEvents(long eventsToDisable) + { + // Update the counter for hierarchy (bounds) listeners. + if ((eventsToDisable & AWTEvent.HIERARCHY_EVENT_MASK) != 0 + && (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) != 0) + { + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyListeners--; + if (parent != null) + parent.updateHierarchyListenerCount + (AWTEvent.HIERARCHY_EVENT_MASK, + -1); + } + } + if ((eventsToDisable & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0 + && (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0) + { + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyBoundsListeners--; + if (parent != null) + parent.updateHierarchyListenerCount + (AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, + -1); + } + } + + eventMask &= ~eventsToDisable; + + // Only heavyweight peers handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + if (p != null) + p.setEventMask(eventMask); + + } + + /** + * This is called by the EventQueue if two events with the same event id + * and owner component are queued. Returns a new combined event, or null if + * no combining is done. The coelesced events are currently mouse moves + * (intermediate ones are discarded) and paint events (a merged paint is + * created in place of the two events). + * + * @param existingEvent the event on the queue + * @param newEvent the new event that might be entered on the queue + * @return null if both events are kept, or the replacement coelesced event + */ + protected AWTEvent coalesceEvents(AWTEvent existingEvent, AWTEvent newEvent) + { + AWTEvent coalesced = null; + switch (existingEvent.id) + { + case MouseEvent.MOUSE_MOVED: + case MouseEvent.MOUSE_DRAGGED: + // Just drop the old (intermediate) event and return the new one. + MouseEvent me1 = (MouseEvent) existingEvent; + MouseEvent me2 = (MouseEvent) newEvent; + if (me1.getModifiers() == me2.getModifiers()) + coalesced = newEvent; + break; + case PaintEvent.PAINT: + case PaintEvent.UPDATE: + // For heavyweights the EventQueue should ask the peer. + if (peer == null || peer instanceof LightweightPeer) + { + PaintEvent pe1 = (PaintEvent) existingEvent; + PaintEvent pe2 = (PaintEvent) newEvent; + Rectangle r1 = pe1.getUpdateRect(); + Rectangle r2 = pe2.getUpdateRect(); + if (r1.contains(r2)) + coalesced = existingEvent; + else if (r2.contains(r1)) + coalesced = newEvent; + } + else + { + // Replace the event and let the heavyweight figure out the expanding + // of the repaint area. + coalesced = newEvent; + } + break; + default: + coalesced = null; + } + return coalesced; + } + + /** + * Processes the specified event. In this class, this method simply + * calls one of the more specific event handlers. + * + * @param e the event to process + * @throws NullPointerException if e is null + * @see #processComponentEvent(ComponentEvent) + * @see #processFocusEvent(FocusEvent) + * @see #processKeyEvent(KeyEvent) + * @see #processMouseEvent(MouseEvent) + * @see #processMouseMotionEvent(MouseEvent) + * @see #processInputMethodEvent(InputMethodEvent) + * @see #processHierarchyEvent(HierarchyEvent) + * @see #processMouseWheelEvent(MouseWheelEvent) + * @since 1.1 + */ + protected void processEvent(AWTEvent e) + { + /* Note: the order of these if statements are + important. Subclasses must be checked first. Eg. MouseEvent + must be checked before ComponentEvent, since a MouseEvent + object is also an instance of a ComponentEvent. */ + + if (e instanceof FocusEvent) + processFocusEvent((FocusEvent) e); + else if (e instanceof MouseWheelEvent) + processMouseWheelEvent((MouseWheelEvent) e); + else if (e instanceof MouseEvent) + { + if (e.id == MouseEvent.MOUSE_MOVED + || e.id == MouseEvent.MOUSE_DRAGGED) + processMouseMotionEvent((MouseEvent) e); + else + processMouseEvent((MouseEvent) e); + } + else if (e instanceof KeyEvent) + processKeyEvent((KeyEvent) e); + else if (e instanceof InputMethodEvent) + processInputMethodEvent((InputMethodEvent) e); + else if (e instanceof ComponentEvent) + processComponentEvent((ComponentEvent) e); + else if (e instanceof HierarchyEvent) + { + if (e.id == HierarchyEvent.HIERARCHY_CHANGED) + processHierarchyEvent((HierarchyEvent) e); + else + processHierarchyBoundsEvent((HierarchyEvent) e); + } + } + + /** + * Called when a component event is dispatched and component events are + * enabled. This method passes the event along to any listeners + * that are attached. + * + * @param e the <code>ComponentEvent</code> to process + * @throws NullPointerException if e is null + * @see ComponentListener + * @see #addComponentListener(ComponentListener) + * @see #enableEvents(long) + * @since 1.1 + */ + protected void processComponentEvent(ComponentEvent e) + { + if (componentListener == null) + return; + switch (e.id) + { + case ComponentEvent.COMPONENT_HIDDEN: + componentListener.componentHidden(e); + break; + case ComponentEvent.COMPONENT_MOVED: + componentListener.componentMoved(e); + break; + case ComponentEvent.COMPONENT_RESIZED: + componentListener.componentResized(e); + break; + case ComponentEvent.COMPONENT_SHOWN: + componentListener.componentShown(e); + break; + } + } + + /** + * Called when a focus event is dispatched and component events are + * enabled. This method passes the event along to any listeners + * that are attached. + * + * @param e the <code>FocusEvent</code> to process + * @throws NullPointerException if e is null + * @see FocusListener + * @see #addFocusListener(FocusListener) + * @see #enableEvents(long) + * @since 1.1 + */ + protected void processFocusEvent(FocusEvent e) + { + if (focusListener == null) + return; + + switch (e.id) + { + case FocusEvent.FOCUS_GAINED: + focusListener.focusGained(e); + break; + case FocusEvent.FOCUS_LOST: + focusListener.focusLost(e); + break; + } + } + + /** + * Called when a key event is dispatched and component events are + * enabled. This method passes the event along to any listeners + * that are attached. + * + * @param e the <code>KeyEvent</code> to process + * @throws NullPointerException if e is null + * @see KeyListener + * @see #addKeyListener(KeyListener) + * @see #enableEvents(long) + * @since 1.1 + */ + protected void processKeyEvent(KeyEvent e) + { + if (keyListener == null) + return; + switch (e.id) + { + case KeyEvent.KEY_PRESSED: + keyListener.keyPressed(e); + break; + case KeyEvent.KEY_RELEASED: + keyListener.keyReleased(e); + break; + case KeyEvent.KEY_TYPED: + keyListener.keyTyped(e); + break; + } + } + + /** + * Called when a regular mouse event is dispatched and component events are + * enabled. This method passes the event along to any listeners + * that are attached. + * + * @param e the <code>MouseEvent</code> to process + * @throws NullPointerException if e is null + * @see MouseListener + * @see #addMouseListener(MouseListener) + * @see #enableEvents(long) + * @since 1.1 + */ + protected void processMouseEvent(MouseEvent e) + { + if (mouseListener == null) + return; + switch (e.id) + { + case MouseEvent.MOUSE_CLICKED: + mouseListener.mouseClicked(e); + break; + case MouseEvent.MOUSE_ENTERED: + if( isLightweight() ) + setCursor( getCursor() ); + mouseListener.mouseEntered(e); + break; + case MouseEvent.MOUSE_EXITED: + mouseListener.mouseExited(e); + break; + case MouseEvent.MOUSE_PRESSED: + mouseListener.mousePressed(e); + break; + case MouseEvent.MOUSE_RELEASED: + mouseListener.mouseReleased(e); + break; + } + } + + /** + * Called when a mouse motion event is dispatched and component events are + * enabled. This method passes the event along to any listeners + * that are attached. + * + * @param e the <code>MouseMotionEvent</code> to process + * @throws NullPointerException if e is null + * @see MouseMotionListener + * @see #addMouseMotionListener(MouseMotionListener) + * @see #enableEvents(long) + * @since 1.1 + */ + protected void processMouseMotionEvent(MouseEvent e) + { + if (mouseMotionListener == null) + return; + switch (e.id) + { + case MouseEvent.MOUSE_DRAGGED: + mouseMotionListener.mouseDragged(e); + break; + case MouseEvent.MOUSE_MOVED: + mouseMotionListener.mouseMoved(e); + break; + } + e.consume(); + } + + /** + * Called when a mouse wheel event is dispatched and component events are + * enabled. This method passes the event along to any listeners that are + * attached. + * + * @param e the <code>MouseWheelEvent</code> to process + * @throws NullPointerException if e is null + * @see MouseWheelListener + * @see #addMouseWheelListener(MouseWheelListener) + * @see #enableEvents(long) + * @since 1.4 + */ + protected void processMouseWheelEvent(MouseWheelEvent e) + { + if (mouseWheelListener != null + && e.id == MouseEvent.MOUSE_WHEEL) + { + mouseWheelListener.mouseWheelMoved(e); + e.consume(); + } + } + + /** + * Called when an input method event is dispatched and component events are + * enabled. This method passes the event along to any listeners that are + * attached. + * + * @param e the <code>InputMethodEvent</code> to process + * @throws NullPointerException if e is null + * @see InputMethodListener + * @see #addInputMethodListener(InputMethodListener) + * @see #enableEvents(long) + * @since 1.2 + */ + protected void processInputMethodEvent(InputMethodEvent e) + { + if (inputMethodListener == null) + return; + switch (e.id) + { + case InputMethodEvent.CARET_POSITION_CHANGED: + inputMethodListener.caretPositionChanged(e); + break; + case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED: + inputMethodListener.inputMethodTextChanged(e); + break; + } + } + + /** + * Called when a hierarchy change event is dispatched and component events + * are enabled. This method passes the event along to any listeners that are + * attached. + * + * @param e the <code>HierarchyEvent</code> to process + * @throws NullPointerException if e is null + * @see HierarchyListener + * @see #addHierarchyListener(HierarchyListener) + * @see #enableEvents(long) + * @since 1.3 + */ + protected void processHierarchyEvent(HierarchyEvent e) + { + if (hierarchyListener == null) + return; + if (e.id == HierarchyEvent.HIERARCHY_CHANGED) + hierarchyListener.hierarchyChanged(e); + } + + /** + * Called when a hierarchy bounds event is dispatched and component events + * are enabled. This method passes the event along to any listeners that are + * attached. + * + * @param e the <code>HierarchyEvent</code> to process + * @throws NullPointerException if e is null + * @see HierarchyBoundsListener + * @see #addHierarchyBoundsListener(HierarchyBoundsListener) + * @see #enableEvents(long) + * @since 1.3 + */ + protected void processHierarchyBoundsEvent(HierarchyEvent e) + { + if (hierarchyBoundsListener == null) + return; + switch (e.id) + { + case HierarchyEvent.ANCESTOR_MOVED: + hierarchyBoundsListener.ancestorMoved(e); + break; + case HierarchyEvent.ANCESTOR_RESIZED: + hierarchyBoundsListener.ancestorResized(e); + break; + } + } + + /** + * AWT 1.0 event handler. + * + * This method calls one of the event-specific handler methods. For + * example for key events, either {@link #keyDown(Event,int)} + * or {@link #keyUp(Event,int)} is called. A derived + * component can override one of these event-specific methods if it + * only needs to handle certain event types. Otherwise it can + * override handleEvent itself and handle any event. + * + * @param evt the event to handle + * @return true if the event was handled, false otherwise + * @deprecated use {@link #processEvent(AWTEvent)} instead + */ + public boolean handleEvent (Event evt) + { + switch (evt.id) + { + // Handle key events. + case Event.KEY_ACTION: + case Event.KEY_PRESS: + return keyDown (evt, evt.key); + case Event.KEY_ACTION_RELEASE: + case Event.KEY_RELEASE: + return keyUp (evt, evt.key); + + // Handle mouse events. + case Event.MOUSE_DOWN: + return mouseDown (evt, evt.x, evt.y); + case Event.MOUSE_UP: + return mouseUp (evt, evt.x, evt.y); + case Event.MOUSE_MOVE: + return mouseMove (evt, evt.x, evt.y); + case Event.MOUSE_DRAG: + return mouseDrag (evt, evt.x, evt.y); + case Event.MOUSE_ENTER: + return mouseEnter (evt, evt.x, evt.y); + case Event.MOUSE_EXIT: + return mouseExit (evt, evt.x, evt.y); + + // Handle focus events. + case Event.GOT_FOCUS: + return gotFocus (evt, evt.arg); + case Event.LOST_FOCUS: + return lostFocus (evt, evt.arg); + + // Handle action event. + case Event.ACTION_EVENT: + return action (evt, evt.arg); + } + // Unknown event. + return false; + } + + /** + * AWT 1.0 MOUSE_DOWN event handler. This method is meant to be + * overridden by components providing their own MOUSE_DOWN handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param x the x coordinate, ignored + * @param y the y coordinate, ignored + * @return false + * @deprecated use {@link #processMouseEvent(MouseEvent)} instead + */ + public boolean mouseDown(Event evt, int x, int y) + { + return false; + } + + /** + * AWT 1.0 MOUSE_DRAG event handler. This method is meant to be + * overridden by components providing their own MOUSE_DRAG handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param x the x coordinate, ignored + * @param y the y coordinate, ignored + * @return false + * @deprecated use {@link #processMouseMotionEvent(MouseEvent)} instead + */ + public boolean mouseDrag(Event evt, int x, int y) + { + return false; + } + + /** + * AWT 1.0 MOUSE_UP event handler. This method is meant to be + * overridden by components providing their own MOUSE_UP handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param x the x coordinate, ignored + * @param y the y coordinate, ignored + * @return false + * @deprecated use {@link #processMouseEvent(MouseEvent)} instead + */ + public boolean mouseUp(Event evt, int x, int y) + { + return false; + } + + /** + * AWT 1.0 MOUSE_MOVE event handler. This method is meant to be + * overridden by components providing their own MOUSE_MOVE handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param x the x coordinate, ignored + * @param y the y coordinate, ignored + * @return false + * @deprecated use {@link #processMouseMotionEvent(MouseEvent)} instead + */ + public boolean mouseMove(Event evt, int x, int y) + { + return false; + } + + /** + * AWT 1.0 MOUSE_ENTER event handler. This method is meant to be + * overridden by components providing their own MOUSE_ENTER handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param x the x coordinate, ignored + * @param y the y coordinate, ignored + * @return false + * @deprecated use {@link #processMouseEvent(MouseEvent)} instead + */ + public boolean mouseEnter(Event evt, int x, int y) + { + return false; + } + + /** + * AWT 1.0 MOUSE_EXIT event handler. This method is meant to be + * overridden by components providing their own MOUSE_EXIT handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param x the x coordinate, ignored + * @param y the y coordinate, ignored + * @return false + * @deprecated use {@link #processMouseEvent(MouseEvent)} instead + */ + public boolean mouseExit(Event evt, int x, int y) + { + return false; + } + + /** + * AWT 1.0 KEY_PRESS and KEY_ACTION event handler. This method is + * meant to be overridden by components providing their own key + * press handler. The default implementation simply returns false. + * + * @param evt the event to handle + * @param key the key pressed, ignored + * @return false + * @deprecated use {@link #processKeyEvent(KeyEvent)} instead + */ + public boolean keyDown(Event evt, int key) + { + return false; + } + + /** + * AWT 1.0 KEY_RELEASE and KEY_ACTION_RELEASE event handler. This + * method is meant to be overridden by components providing their + * own key release handler. The default implementation simply + * returns false. + * + * @param evt the event to handle + * @param key the key pressed, ignored + * @return false + * @deprecated use {@link #processKeyEvent(KeyEvent)} instead + */ + public boolean keyUp(Event evt, int key) + { + return false; + } + + /** + * AWT 1.0 ACTION_EVENT event handler. This method is meant to be + * overridden by components providing their own action event + * handler. The default implementation simply returns false. + * + * @param evt the event to handle + * @param what the object acted on, ignored + * @return false + * @deprecated in classes which support actions, use + * <code>processActionEvent(ActionEvent)</code> instead + */ + public boolean action(Event evt, Object what) + { + return false; + } + + /** + * Called when the parent of this Component is made visible or when + * the Component is added to an already visible Container and needs + * to be shown. A native peer - if any - is created at this + * time. This method is called automatically by the AWT system and + * should not be called by user level code. + * + * @see #isDisplayable() + * @see #removeNotify() + */ + public void addNotify() + { + // We need to lock the tree here to avoid races and inconsistencies. + synchronized (getTreeLock()) + { + if (peer == null) + peer = getToolkit().createComponent(this); + else if (parent != null && parent.isLightweight()) + new HeavyweightInLightweightListener(parent); + // Now that all the children has gotten their peers, we should + // have the event mask needed for this component and its + //lightweight subcomponents. + peer.setEventMask(eventMask); + + // We used to leave the invalidate() to the peer. However, I put it + // back here for 2 reasons: 1) The RI does call invalidate() from + // addNotify(); 2) The peer shouldn't be bother with validation too + // much. + invalidate(); + + if (dropTarget != null) + dropTarget.addNotify(peer); + + // Fetch the peerFont for later installation in validate(). + peerFont = getFont(); + + // Notify hierarchy listeners. + long flags = HierarchyEvent.DISPLAYABILITY_CHANGED; + if (isHierarchyVisible()) + flags |= HierarchyEvent.SHOWING_CHANGED; + fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, this, parent, + flags); + } + } + + /** + * Called to inform this component is has been removed from its + * container. Its native peer - if any - is destroyed at this time. + * This method is called automatically by the AWT system and should + * not be called by user level code. + * + * @see #isDisplayable() + * @see #addNotify() + */ + public void removeNotify() + { + // We need to lock the tree here to avoid races and inconsistencies. + synchronized (getTreeLock()) + { + // We null our peer field before disposing of it, such that if we're + // not the event dispatch thread and the dispatch thread is awoken by + // the dispose call, there will be no race checking the peer's null + // status. + + ComponentPeer tmp = peer; + peer = null; + peerFont = null; + if (tmp != null) + { + tmp.hide(); + tmp.dispose(); + } + + // Notify hierarchy listeners. + long flags = HierarchyEvent.DISPLAYABILITY_CHANGED; + if (isHierarchyVisible()) + flags |= HierarchyEvent.SHOWING_CHANGED; + fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, this, parent, + flags); + } + } + + /** + * AWT 1.0 GOT_FOCUS event handler. This method is meant to be + * overridden by components providing their own GOT_FOCUS handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param what the Object focused, ignored + * @return false + * @deprecated use {@link #processFocusEvent(FocusEvent)} instead + */ + public boolean gotFocus(Event evt, Object what) + { + return false; + } + + /** + * AWT 1.0 LOST_FOCUS event handler. This method is meant to be + * overridden by components providing their own LOST_FOCUS handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param what the Object focused, ignored + * @return false + * @deprecated use {@link #processFocusEvent(FocusEvent)} instead + */ + public boolean lostFocus(Event evt, Object what) + { + return false; + } + + /** + * Tests whether or not this component is in the group that can be + * traversed using the keyboard traversal mechanism (such as the TAB key). + * + * @return true if the component is traversed via the TAB key + * @see #setFocusable(boolean) + * @since 1.1 + * @deprecated use {@link #isFocusable()} instead + */ + public boolean isFocusTraversable() + { + return enabled && visible && (peer == null || isLightweight() || peer.isFocusTraversable()); + } + + /** + * Tests if this component can receive focus. + * + * @return true if this component can receive focus + * @since 1.4 + */ + public boolean isFocusable() + { + return focusable; + } + + /** + * Specify whether this component can receive focus. This method also + * sets the {@link #isFocusTraversableOverridden} field to 1, which + * appears to be the undocumented way {@link + * DefaultFocusTraversalPolicy#accept(Component)} determines whether to + * respect the {@link #isFocusable()} method of the component. + * + * @param focusable the new focusable status + * @since 1.4 + */ + public void setFocusable(boolean focusable) + { + firePropertyChange("focusable", this.focusable, focusable); + this.focusable = focusable; + this.isFocusTraversableOverridden = 1; + } + + /** + * Sets the focus traversal keys for one of the three focus + * traversal directions supported by Components: + * {@link KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS}, + * {@link KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS}, or + * {@link KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS}. Normally, the + * default values should match the operating system's native + * choices. To disable a given traversal, use + * <code>Collections.EMPTY_SET</code>. The event dispatcher will + * consume PRESSED, RELEASED, and TYPED events for the specified + * key, although focus can only transfer on PRESSED or RELEASED. + * + * <p>The defaults are: + * <table> + * <th><td>Identifier</td><td>Meaning</td><td>Default</td></th> + * <tr><td>KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS</td> + * <td>Normal forward traversal</td> + * <td>TAB on KEY_PRESSED, Ctrl-TAB on KEY_PRESSED</td></tr> + * <tr><td>KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS</td> + * <td>Normal backward traversal</td> + * <td>Shift-TAB on KEY_PRESSED, Ctrl-Shift-TAB on KEY_PRESSED</td></tr> + * <tr><td>KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS</td> + * <td>Go up a traversal cycle</td><td>None</td></tr> + * </table> + * + * If keystrokes is null, this component's focus traversal key set + * is inherited from one of its ancestors. If none of its ancestors + * has its own set of focus traversal keys, the focus traversal keys + * are set to the defaults retrieved from the current + * KeyboardFocusManager. If not null, the set must contain only + * AWTKeyStrokes that are not already focus keys and are not + * KEY_TYPED events. + * + * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, or + * UP_CYCLE_TRAVERSAL_KEYS + * @param keystrokes a set of keys, or null + * @throws IllegalArgumentException if id or keystrokes is invalid + * @see #getFocusTraversalKeys(int) + * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS + * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS + * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS + * @since 1.4 + */ + public void setFocusTraversalKeys(int id, + Set<? extends AWTKeyStroke> keystrokes) + { + if (keystrokes == null) + { + Container parent = getParent (); + + while (parent != null) + { + if (parent.areFocusTraversalKeysSet (id)) + { + keystrokes = parent.getFocusTraversalKeys (id); + break; + } + parent = parent.getParent (); + } + + if (keystrokes == null) + keystrokes = KeyboardFocusManager.getCurrentKeyboardFocusManager (). + getDefaultFocusTraversalKeys (id); + } + + Set sa; + Set sb; + String name; + switch (id) + { + case KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS: + sa = getFocusTraversalKeys + (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + sb = getFocusTraversalKeys + (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); + name = "forwardFocusTraversalKeys"; + break; + case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS: + sa = getFocusTraversalKeys + (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + sb = getFocusTraversalKeys + (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); + name = "backwardFocusTraversalKeys"; + break; + case KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS: + sa = getFocusTraversalKeys + (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + sb = getFocusTraversalKeys + (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + name = "upCycleFocusTraversalKeys"; + break; + default: + throw new IllegalArgumentException (); + } + + int i = keystrokes.size (); + Iterator iter = keystrokes.iterator (); + + while (--i >= 0) + { + Object o = iter.next (); + if (!(o instanceof AWTKeyStroke) + || sa.contains (o) || sb.contains (o) + || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED) + throw new IllegalArgumentException (); + } + + if (focusTraversalKeys == null) + focusTraversalKeys = new Set[3]; + + keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes)); + firePropertyChange (name, focusTraversalKeys[id], keystrokes); + + focusTraversalKeys[id] = keystrokes; + } + + /** + * Returns the set of keys for a given focus traversal action, as + * defined in <code>setFocusTraversalKeys</code>. If not set, this + * is inherited from the parent component, which may have gotten it + * from the KeyboardFocusManager. + * + * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, + * or UP_CYCLE_TRAVERSAL_KEYS + * + * @return set of traversal keys + * + * @throws IllegalArgumentException if id is invalid + * + * @see #setFocusTraversalKeys (int, Set) + * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS + * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS + * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS + * + * @since 1.4 + */ + public Set<AWTKeyStroke> getFocusTraversalKeys (int id) + { + if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS) + throw new IllegalArgumentException(); + + Set<AWTKeyStroke> s = null; + + if (focusTraversalKeys != null) + s = focusTraversalKeys[id]; + + if (s == null && parent != null) + s = parent.getFocusTraversalKeys (id); + + return s == null ? (KeyboardFocusManager.getCurrentKeyboardFocusManager() + .getDefaultFocusTraversalKeys(id)) : s; + } + + /** + * Tests whether the focus traversal keys for a given action are explicitly + * set or inherited. + * + * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, + * or UP_CYCLE_TRAVERSAL_KEYS + * @return true if that set is explicitly specified + * @throws IllegalArgumentException if id is invalid + * @see #getFocusTraversalKeys (int) + * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS + * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS + * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS + * @since 1.4 + */ + public boolean areFocusTraversalKeysSet (int id) + { + if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS) + throw new IllegalArgumentException (); + + return focusTraversalKeys != null && focusTraversalKeys[id] != null; + } + + /** + * Enable or disable focus traversal keys on this Component. If + * they are, then the keyboard focus manager consumes and acts on + * key press and release events that trigger focus traversal, and + * discards the corresponding key typed events. If focus traversal + * keys are disabled, then all key events that would otherwise + * trigger focus traversal are sent to this Component. + * + * @param focusTraversalKeysEnabled the new value of the flag + * @see #getFocusTraversalKeysEnabled () + * @see #setFocusTraversalKeys (int, Set) + * @see #getFocusTraversalKeys (int) + * @since 1.4 + */ + public void setFocusTraversalKeysEnabled (boolean focusTraversalKeysEnabled) + { + firePropertyChange ("focusTraversalKeysEnabled", + this.focusTraversalKeysEnabled, + focusTraversalKeysEnabled); + this.focusTraversalKeysEnabled = focusTraversalKeysEnabled; + } + + /** + * Check whether or not focus traversal keys are enabled on this + * Component. If they are, then the keyboard focus manager consumes + * and acts on key press and release events that trigger focus + * traversal, and discards the corresponding key typed events. If + * focus traversal keys are disabled, then all key events that would + * otherwise trigger focus traversal are sent to this Component. + * + * @return true if focus traversal keys are enabled + * @see #setFocusTraversalKeysEnabled (boolean) + * @see #setFocusTraversalKeys (int, Set) + * @see #getFocusTraversalKeys (int) + * @since 1.4 + */ + public boolean getFocusTraversalKeysEnabled () + { + return focusTraversalKeysEnabled; + } + + /** + * Request that this Component be given the keyboard input focus and + * that its top-level ancestor become the focused Window. + * + * For the request to be granted, the Component must be focusable, + * displayable and showing and the top-level Window to which it + * belongs must be focusable. If the request is initially denied on + * the basis that the top-level Window is not focusable, the request + * will be remembered and granted when the Window does become + * focused. + * + * Never assume that this Component is the focus owner until it + * receives a FOCUS_GAINED event. + * + * The behaviour of this method is platform-dependent. + * {@link #requestFocusInWindow()} should be used instead. + * + * @see #requestFocusInWindow () + * @see FocusEvent + * @see #addFocusListener (FocusListener) + * @see #isFocusable () + * @see #isDisplayable () + * @see KeyboardFocusManager#clearGlobalFocusOwner () + */ + public void requestFocus () + { + requestFocusImpl(false, true); + } + + /** + * Request that this Component be given the keyboard input focus and + * that its top-level ancestor become the focused Window. + * + * For the request to be granted, the Component must be focusable, + * displayable and showing and the top-level Window to which it + * belongs must be focusable. If the request is initially denied on + * the basis that the top-level Window is not focusable, the request + * will be remembered and granted when the Window does become + * focused. + * + * Never assume that this Component is the focus owner until it + * receives a FOCUS_GAINED event. + * + * The behaviour of this method is platform-dependent. + * {@link #requestFocusInWindow()} should be used instead. + * + * If the return value is false, the request is guaranteed to fail. + * If the return value is true, the request will succeed unless it + * is vetoed or something in the native windowing system intervenes, + * preventing this Component's top-level ancestor from becoming + * focused. This method is meant to be called by derived + * lightweight Components that want to avoid unnecessary repainting + * when they know a given focus transfer need only be temporary. + * + * @param temporary true if the focus request is temporary + * @return true if the request has a chance of success + * @see #requestFocusInWindow () + * @see FocusEvent + * @see #addFocusListener (FocusListener) + * @see #isFocusable () + * @see #isDisplayable () + * @see KeyboardFocusManager#clearGlobalFocusOwner () + * @since 1.4 + */ + protected boolean requestFocus (boolean temporary) + { + return requestFocusImpl(temporary, true); + } + + /** + * Request that this component be given the keyboard input focus, if + * its top-level ancestor is the currently focused Window. A + * <code>FOCUS_GAINED</code> event will be fired if and only if this + * request is successful. To be successful, the component must be + * displayable, showing, and focusable, and its ancestor top-level + * Window must be focused. + * + * If the return value is false, the request is guaranteed to fail. + * If the return value is true, the request will succeed unless it + * is vetoed or something in the native windowing system intervenes, + * preventing this Component's top-level ancestor from becoming + * focused. + * + * @return true if the request has a chance of success + * @see #requestFocus () + * @see FocusEvent + * @see #addFocusListener (FocusListener) + * @see #isFocusable () + * @see #isDisplayable () + * @see KeyboardFocusManager#clearGlobalFocusOwner () + * @since 1.4 + */ + public boolean requestFocusInWindow () + { + return requestFocusImpl(false, false); + } + + /** + * Request that this component be given the keyboard input focus, if + * its top-level ancestor is the currently focused Window. A + * <code>FOCUS_GAINED</code> event will be fired if and only if this + * request is successful. To be successful, the component must be + * displayable, showing, and focusable, and its ancestor top-level + * Window must be focused. + * + * If the return value is false, the request is guaranteed to fail. + * If the return value is true, the request will succeed unless it + * is vetoed or something in the native windowing system intervenes, + * preventing this Component's top-level ancestor from becoming + * focused. This method is meant to be called by derived + * lightweight Components that want to avoid unnecessary repainting + * when they know a given focus transfer need only be temporary. + * + * @param temporary true if the focus request is temporary + * @return true if the request has a chance of success + * @see #requestFocus () + * @see FocusEvent + * @see #addFocusListener (FocusListener) + * @see #isFocusable () + * @see #isDisplayable () + * @see KeyboardFocusManager#clearGlobalFocusOwner () + * @since 1.4 + */ + protected boolean requestFocusInWindow (boolean temporary) + { + return requestFocusImpl(temporary, false); + } + + /** + * Helper method for all 4 requestFocus variants. + * + * @param temporary indicates if the focus change is temporary + * @param focusWindow indicates if the window focus may be changed + * + * @return <code>false</code> if the request has been definitely denied, + * <code>true</code> otherwise + */ + private boolean requestFocusImpl(boolean temporary, boolean focusWindow) + { + boolean retval = false; + + // Don't try to focus non-focusable and non-visible components. + if (isFocusable() && isVisible()) + { + ComponentPeer myPeer = peer; + if (peer != null) + { + // Find Window ancestor and find out if we're showing while + // doing this. + boolean showing = true; + Component window = this; + while (! (window instanceof Window)) + { + if (! window.isVisible()) + showing = false; + window = window.parent; + } + // Don't allow focus when there is no window or the window + // is not focusable. + if (window != null && ((Window) window).isFocusableWindow() + && showing) + { + // Search for nearest heavy ancestor (including this + // component). + Component heavyweightParent = this; + while (heavyweightParent.peer instanceof LightweightPeer) + heavyweightParent = heavyweightParent.parent; + + // Don't allow focus on lightweight components without + // visible heavyweight ancestor + if (heavyweightParent != null && heavyweightParent.isVisible()) + { + // Don't allow focus when heavyweightParent has no peer. + myPeer = heavyweightParent.peer; + if (myPeer != null) + { + // Register lightweight focus request. + if (heavyweightParent != this) + { + KeyboardFocusManager + .addLightweightFocusRequest(heavyweightParent, + this); + } + + // Try to focus the component. + long time = EventQueue.getMostRecentEventTime(); + boolean success = myPeer.requestFocus(this, temporary, + focusWindow, + time); + if (! success) + { + // Dequeue key events if focus request failed. + KeyboardFocusManager kfm = + KeyboardFocusManager.getCurrentKeyboardFocusManager(); + kfm.dequeueKeyEvents(time, this); + } + retval = success; + } + } + } + } + } + return retval; + } + + /** + * Transfers focus to the next component in the focus traversal + * order, as though this were the current focus owner. + * + * @see #requestFocus() + * @since 1.1 + */ + public void transferFocus () + { + nextFocus (); + } + + /** + * Returns the root container that owns the focus cycle where this + * component resides. A focus cycle root is in two cycles, one as + * the ancestor, and one as the focusable element; this call always + * returns the ancestor. + * + * @return the ancestor container that owns the focus cycle + * @since 1.4 + */ + public Container getFocusCycleRootAncestor () + { + Container parent = getParent (); + + while (parent != null && !parent.isFocusCycleRoot()) + parent = parent.getParent (); + + return parent; + } + + /** + * Tests if the container is the ancestor of the focus cycle that + * this component belongs to. + * + * @param c the container to test + * @return true if c is the focus cycle root + * @since 1.4 + */ + public boolean isFocusCycleRoot (Container c) + { + return c == getFocusCycleRootAncestor (); + } + + /** + * AWT 1.0 focus event processor. Transfers focus to the next + * component in the focus traversal order, as though this were the + * current focus owner. + * + * @deprecated use {@link #transferFocus ()} instead + */ + public void nextFocus () + { + // Find the nearest valid (== showing && focusable && enabled) focus + // cycle root ancestor and the focused component in it. + Container focusRoot = getFocusCycleRootAncestor(); + Component focusComp = this; + while (focusRoot != null + && ! (focusRoot.isShowing() && focusRoot.isFocusable() + && focusRoot.isEnabled())) + { + focusComp = focusRoot; + focusRoot = focusComp.getFocusCycleRootAncestor(); + } + + if (focusRoot != null) + { + // First try to get the componentBefore from the policy. + FocusTraversalPolicy policy = focusRoot.getFocusTraversalPolicy(); + Component nextFocus = policy.getComponentAfter(focusRoot, focusComp); + + // If this fails, then ask for the defaultComponent. + if (nextFocus == null) + nextFocus = policy.getDefaultComponent(focusRoot); + + // Request focus on this component, if not null. + if (nextFocus != null) + nextFocus.requestFocus(); + } + } + + /** + * Transfers focus to the previous component in the focus traversal + * order, as though this were the current focus owner. + * + * @see #requestFocus () + * @since 1.4 + */ + public void transferFocusBackward () + { + // Find the nearest valid (== showing && focusable && enabled) focus + // cycle root ancestor and the focused component in it. + Container focusRoot = getFocusCycleRootAncestor(); + Component focusComp = this; + while (focusRoot != null + && ! (focusRoot.isShowing() && focusRoot.isFocusable() + && focusRoot.isEnabled())) + { + focusComp = focusRoot; + focusRoot = focusComp.getFocusCycleRootAncestor(); + } + + if (focusRoot != null) + { + // First try to get the componentBefore from the policy. + FocusTraversalPolicy policy = focusRoot.getFocusTraversalPolicy(); + Component nextFocus = policy.getComponentBefore(focusRoot, focusComp); + + // If this fails, then ask for the defaultComponent. + if (nextFocus == null) + nextFocus = policy.getDefaultComponent(focusRoot); + + // Request focus on this component, if not null. + if (nextFocus != null) + nextFocus.requestFocus(); + } + } + + /** + * Transfers focus to the focus cycle root of this component. + * However, if this is a Window, the default focus owner in the + * window in the current focus cycle is focused instead. + * + * @see #requestFocus() + * @see #isFocusCycleRoot(Container) + * @since 1.4 + */ + public void transferFocusUpCycle () + { + // Find the nearest focus cycle root ancestor that is itself + // focusable, showing and enabled. + Container focusCycleRoot = getFocusCycleRootAncestor(); + while (focusCycleRoot != null && + ! (focusCycleRoot.isShowing() && focusCycleRoot.isFocusable() + && focusCycleRoot.isEnabled())) + { + focusCycleRoot = focusCycleRoot.getFocusCycleRootAncestor(); + } + + KeyboardFocusManager fm = + KeyboardFocusManager.getCurrentKeyboardFocusManager(); + + if (focusCycleRoot != null) + { + // If we found a focus cycle root, then we make this the new + // focused component, and make it's focus cycle root the new + // global focus cycle root. If the found root has no focus cycle + // root ancestor itself, then the component will be both the focused + // component and the new global focus cycle root. + Container focusCycleAncestor = + focusCycleRoot.getFocusCycleRootAncestor(); + Container globalFocusCycleRoot; + if (focusCycleAncestor == null) + globalFocusCycleRoot = focusCycleRoot; + else + globalFocusCycleRoot = focusCycleAncestor; + + fm.setGlobalCurrentFocusCycleRoot(globalFocusCycleRoot); + focusCycleRoot.requestFocus(); + } + else + { + // If this component has no applicable focus cycle root, we try + // find the nearest window and set this as the new global focus cycle + // root and the default focus component of this window the new focused + // component. + Container cont; + if (this instanceof Container) + cont = (Container) this; + else + cont = getParent(); + + while (cont != null && !(cont instanceof Window)) + cont = cont.getParent(); + + if (cont != null) + { + FocusTraversalPolicy policy = cont.getFocusTraversalPolicy(); + Component focusComp = policy.getDefaultComponent(cont); + if (focusComp != null) + { + fm.setGlobalCurrentFocusCycleRoot(cont); + focusComp.requestFocus(); + } + } + } + } + + /** + * Tests if this component is the focus owner. Use {@link + * #isFocusOwner ()} instead. + * + * @return true if this component owns focus + * @since 1.2 + */ + public boolean hasFocus () + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + Component focusOwner = manager.getFocusOwner (); + + return this == focusOwner; + } + + /** + * Tests if this component is the focus owner. + * + * @return true if this component owns focus + * @since 1.4 + */ + public boolean isFocusOwner() + { + return hasFocus (); + } + + /** + * Adds the specified popup menu to this component. + * + * @param popup the popup menu to be added + * + * @see #remove(MenuComponent) + * + * @since 1.1 + */ + public synchronized void add(PopupMenu popup) + { + if (popups == null) + popups = new Vector(); + popups.add(popup); + + if (popup.parent != null) + popup.parent.remove(popup); + popup.parent = this; + if (peer != null) + popup.addNotify(); + } + + /** + * Removes the specified popup menu from this component. + * + * @param popup the popup menu to remove + * @see #add(PopupMenu) + * @since 1.1 + */ + public synchronized void remove(MenuComponent popup) + { + if (popups != null) + popups.remove(popup); + } + + /** + * Returns a debugging string representing this component. The string may + * be empty but not null. + * + * @return a string representing this component + */ + protected String paramString() + { + CPStringBuilder param = new CPStringBuilder(); + String name = getName(); + if (name != null) + param.append(name).append(","); + param.append(x).append(",").append(y).append(",").append(width) + .append("x").append(height); + if (! isValid()) + param.append(",invalid"); + if (! isVisible()) + param.append(",invisible"); + if (! isEnabled()) + param.append(",disabled"); + if (! isOpaque()) + param.append(",translucent"); + if (isDoubleBuffered()) + param.append(",doublebuffered"); + if (parent == null) + param.append(",parent=null"); + else + param.append(",parent=").append(parent.getName()); + return param.toString(); + } + + /** + * Returns a string representation of this component. This is implemented + * as <code>getClass().getName() + '[' + paramString() + ']'</code>. + * + * @return a string representation of this component + */ + public String toString() + { + return getClass().getName() + '[' + paramString() + ']'; + } + + /** + * Prints a listing of this component to <code>System.out</code>. + * + * @see #list(PrintStream) + */ + public void list() + { + list(System.out, 0); + } + + /** + * Prints a listing of this component to the specified print stream. + * + * @param out the <code>PrintStream</code> to print to + */ + public void list(PrintStream out) + { + list(out, 0); + } + + /** + * Prints a listing of this component to the specified print stream, + * starting at the specified indentation point. + * + * @param out the <code>PrintStream</code> to print to + * @param indent the indentation point + */ + public void list(PrintStream out, int indent) + { + for (int i = 0; i < indent; ++i) + out.print(' '); + out.println(toString()); + } + + /** + * Prints a listing of this component to the specified print writer. + * + * @param out the <code>PrintWrinter</code> to print to + * @since 1.1 + */ + public void list(PrintWriter out) + { + list(out, 0); + } + + /** + * Prints a listing of this component to the specified print writer, + * starting at the specified indentation point. + * + * @param out the <code>PrintWriter</code> to print to + * @param indent the indentation point + * @since 1.1 + */ + public void list(PrintWriter out, int indent) + { + for (int i = 0; i < indent; ++i) + out.print(' '); + out.println(toString()); + } + + /** + * Adds the specified property listener to this component. This is harmless + * if the listener is null, but if the listener has already been registered, + * it will now be registered twice. The property listener ignores inherited + * properties. Recognized properties include:<br> + * <ul> + * <li>the font (<code>"font"</code>)</li> + * <li>the background color (<code>"background"</code>)</li> + * <li>the foreground color (<code>"foreground"</code>)</li> + * <li>the focusability (<code>"focusable"</code>)</li> + * <li>the focus key traversal enabled state + * (<code>"focusTraversalKeysEnabled"</code>)</li> + * <li>the set of forward traversal keys + * (<code>"forwardFocusTraversalKeys"</code>)</li> + * <li>the set of backward traversal keys + * (<code>"backwardFocusTraversalKeys"</code>)</li> + * <li>the set of up-cycle traversal keys + * (<code>"upCycleFocusTraversalKeys"</code>)</li> + * </ul> + * + * @param listener the new listener to add + * @see #removePropertyChangeListener(PropertyChangeListener) + * @see #getPropertyChangeListeners() + * @see #addPropertyChangeListener(String, PropertyChangeListener) + * @since 1.1 + */ + public void addPropertyChangeListener(PropertyChangeListener listener) + { + if (changeSupport == null) + changeSupport = new PropertyChangeSupport(this); + changeSupport.addPropertyChangeListener(listener); + } + + /** + * Removes the specified property listener from the component. This is + * harmless if the listener was not previously registered. + * + * @param listener the listener to remove + * @see #addPropertyChangeListener(PropertyChangeListener) + * @see #getPropertyChangeListeners() + * @see #removePropertyChangeListener(String, PropertyChangeListener) + * @since 1.1 + */ + public void removePropertyChangeListener(PropertyChangeListener listener) + { + if (changeSupport != null) + changeSupport.removePropertyChangeListener(listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addPropertyChangeListener(PropertyChangeListener) + * @see #removePropertyChangeListener(PropertyChangeListener) + * @see #getPropertyChangeListeners(String) + * @since 1.4 + */ + public PropertyChangeListener[] getPropertyChangeListeners() + { + return changeSupport == null ? new PropertyChangeListener[0] + : changeSupport.getPropertyChangeListeners(); + } + + /** + * Adds the specified property listener to this component. This is harmless + * if the listener is null, but if the listener has already been registered, + * it will now be registered twice. The property listener ignores inherited + * properties. The listener is keyed to a single property. Recognized + * properties include:<br> + * <ul> + * <li>the font (<code>"font"</code>)</li> + * <li>the background color (<code>"background"</code>)</li> + * <li>the foreground color (<code>"foreground"</code>)</li> + * <li>the focusability (<code>"focusable"</code>)</li> + * <li>the focus key traversal enabled state + * (<code>"focusTraversalKeysEnabled"</code>)</li> + * <li>the set of forward traversal keys + * (<code>"forwardFocusTraversalKeys"</code>)</li> +p * <li>the set of backward traversal keys + * (<code>"backwardFocusTraversalKeys"</code>)</li> + * <li>the set of up-cycle traversal keys + * (<code>"upCycleFocusTraversalKeys"</code>)</li> + * </ul> + * + * @param propertyName the property name to filter on + * @param listener the new listener to add + * @see #removePropertyChangeListener(String, PropertyChangeListener) + * @see #getPropertyChangeListeners(String) + * @see #addPropertyChangeListener(PropertyChangeListener) + * @since 1.1 + */ + public void addPropertyChangeListener(String propertyName, + PropertyChangeListener listener) + { + if (changeSupport == null) + changeSupport = new PropertyChangeSupport(this); + changeSupport.addPropertyChangeListener(propertyName, listener); + } + + /** + * Removes the specified property listener on a particular property from + * the component. This is harmless if the listener was not previously + * registered. + * + * @param propertyName the property name to filter on + * @param listener the listener to remove + * @see #addPropertyChangeListener(String, PropertyChangeListener) + * @see #getPropertyChangeListeners(String) + * @see #removePropertyChangeListener(PropertyChangeListener) + * @since 1.1 + */ + public void removePropertyChangeListener(String propertyName, + PropertyChangeListener listener) + { + if (changeSupport != null) + changeSupport.removePropertyChangeListener(propertyName, listener); + } + + /** + * Returns an array of all specified listeners on the named property that + * are registered on this component. + * + * @return an array of listeners + * @see #addPropertyChangeListener(String, PropertyChangeListener) + * @see #removePropertyChangeListener(String, PropertyChangeListener) + * @see #getPropertyChangeListeners() + * @since 1.4 + */ + public PropertyChangeListener[] getPropertyChangeListeners(String property) + { + return changeSupport == null ? new PropertyChangeListener[0] + : changeSupport.getPropertyChangeListeners(property); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + */ + protected void firePropertyChange(String propertyName, Object oldValue, + Object newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, oldValue, newValue); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + */ + protected void firePropertyChange(String propertyName, boolean oldValue, + boolean newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, oldValue, newValue); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + */ + protected void firePropertyChange(String propertyName, int oldValue, + int newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, oldValue, newValue); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + * + * @since 1.5 + */ + public void firePropertyChange(String propertyName, byte oldValue, + byte newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Byte(oldValue), + new Byte(newValue)); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + * + * @since 1.5 + */ + public void firePropertyChange(String propertyName, char oldValue, + char newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Character(oldValue), + new Character(newValue)); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + * + * @since 1.5 + */ + public void firePropertyChange(String propertyName, short oldValue, + short newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Short(oldValue), + new Short(newValue)); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + * + * @since 1.5 + */ + public void firePropertyChange(String propertyName, long oldValue, + long newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Long(oldValue), + new Long(newValue)); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + * + * @since 1.5 + */ + public void firePropertyChange(String propertyName, float oldValue, + float newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Float(oldValue), + new Float(newValue)); + } + + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + * + * @since 1.5 + */ + public void firePropertyChange(String propertyName, double oldValue, + double newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Double(oldValue), + new Double(newValue)); + } + + /** + * Sets the text layout orientation of this component. New components default + * to UNKNOWN (which behaves like LEFT_TO_RIGHT). This method affects only + * the current component, while + * {@link #applyComponentOrientation(ComponentOrientation)} affects the + * entire hierarchy. + * + * @param o the new orientation (<code>null</code> is accepted) + * @see #getComponentOrientation() + */ + public void setComponentOrientation(ComponentOrientation o) + { + + ComponentOrientation oldOrientation = componentOrientation; + componentOrientation = o; + firePropertyChange("componentOrientation", oldOrientation, o); + } + + /** + * Determines the text layout orientation used by this component. + * + * @return the component orientation (this can be <code>null</code>) + * @see #setComponentOrientation(ComponentOrientation) + */ + public ComponentOrientation getComponentOrientation() + { + return componentOrientation; + } + + /** + * Sets the text layout orientation of this component. New components default + * to UNKNOWN (which behaves like LEFT_TO_RIGHT). This method affects the + * entire hierarchy, while + * {@link #setComponentOrientation(ComponentOrientation)} affects only the + * current component. + * + * @param o the new orientation + * @throws NullPointerException if o is null + * @see #getComponentOrientation() + * @since 1.4 + */ + public void applyComponentOrientation(ComponentOrientation o) + { + setComponentOrientation(o); + } + + /** + * Returns the accessibility framework context of this class. Component is + * not accessible, so the default implementation returns null. Subclasses + * must override this behavior, and return an appropriate subclass of + * {@link AccessibleAWTComponent}. + * + * @return the accessibility context + */ + public AccessibleContext getAccessibleContext() + { + return null; + } + + + // Helper methods; some are package visible for use by subclasses. + + /** + * Subclasses should override this to return unique component names like + * "menuitem0". + * + * @return the generated name for this component + */ + String generateName() + { + // Component is abstract. + return null; + } + + /** + * Sets the peer for this component. + * + * @param peer the new peer + */ + final void setPeer(ComponentPeer peer) + { + this.peer = peer; + } + + /** + * Translate an AWT 1.1 event ({@link AWTEvent}) into an AWT 1.0 + * event ({@link Event}). + * + * @param e an AWT 1.1 event to translate + * + * @return an AWT 1.0 event representing e + */ + static Event translateEvent (AWTEvent e) + { + Object target = e.getSource (); + Event translated = null; + + if (e instanceof WindowEvent) + { + WindowEvent we = (WindowEvent) e; + int id = we.id; + int newId = 0; + + switch (id) + { + case WindowEvent.WINDOW_DEICONIFIED: + newId = Event.WINDOW_DEICONIFY; + break; + case WindowEvent.WINDOW_CLOSED: + case WindowEvent.WINDOW_CLOSING: + newId = Event.WINDOW_DESTROY; + break; + case WindowEvent.WINDOW_ICONIFIED: + newId = Event.WINDOW_ICONIFY; + break; + case WindowEvent.WINDOW_GAINED_FOCUS: + newId = Event.GOT_FOCUS; + break; + case WindowEvent.WINDOW_LOST_FOCUS: + newId = Event.LOST_FOCUS; + break; + default: + return null; + } + + translated = new Event(target, 0, newId, 0, 0, 0, 0); + } + else if (e instanceof InputEvent) + { + InputEvent ie = (InputEvent) e; + long when = ie.getWhen (); + + int oldID = 0; + int id = e.getID (); + + int oldMods = 0; + int mods = ie.getModifiersEx (); + + if ((mods & InputEvent.BUTTON2_DOWN_MASK) != 0) + oldMods |= Event.META_MASK; + else if ((mods & InputEvent.BUTTON3_DOWN_MASK) != 0) + oldMods |= Event.ALT_MASK; + + if ((mods & InputEvent.SHIFT_DOWN_MASK) != 0) + oldMods |= Event.SHIFT_MASK; + + if ((mods & InputEvent.CTRL_DOWN_MASK) != 0) + oldMods |= Event.CTRL_MASK; + + if ((mods & InputEvent.META_DOWN_MASK) != 0) + oldMods |= Event.META_MASK; + + if ((mods & InputEvent.ALT_DOWN_MASK) != 0) + oldMods |= Event.ALT_MASK; + + if (e instanceof MouseEvent && !ignoreOldMouseEvents()) + { + if (id == MouseEvent.MOUSE_PRESSED) + oldID = Event.MOUSE_DOWN; + else if (id == MouseEvent.MOUSE_RELEASED) + oldID = Event.MOUSE_UP; + else if (id == MouseEvent.MOUSE_MOVED) + oldID = Event.MOUSE_MOVE; + else if (id == MouseEvent.MOUSE_DRAGGED) + oldID = Event.MOUSE_DRAG; + else if (id == MouseEvent.MOUSE_ENTERED) + oldID = Event.MOUSE_ENTER; + else if (id == MouseEvent.MOUSE_EXITED) + oldID = Event.MOUSE_EXIT; + else + // No analogous AWT 1.0 mouse event. + return null; + + MouseEvent me = (MouseEvent) e; + + translated = new Event (target, when, oldID, + me.getX (), me.getY (), 0, oldMods); + } + else if (e instanceof KeyEvent) + { + if (id == KeyEvent.KEY_PRESSED) + oldID = Event.KEY_PRESS; + else if (e.getID () == KeyEvent.KEY_RELEASED) + oldID = Event.KEY_RELEASE; + else + // No analogous AWT 1.0 key event. + return null; + + int oldKey = 0; + int newKey = ((KeyEvent) e).getKeyCode (); + switch (newKey) + { + case KeyEvent.VK_BACK_SPACE: + oldKey = Event.BACK_SPACE; + break; + case KeyEvent.VK_CAPS_LOCK: + oldKey = Event.CAPS_LOCK; + break; + case KeyEvent.VK_DELETE: + oldKey = Event.DELETE; + break; + case KeyEvent.VK_DOWN: + case KeyEvent.VK_KP_DOWN: + oldKey = Event.DOWN; + break; + case KeyEvent.VK_END: + oldKey = Event.END; + break; + case KeyEvent.VK_ENTER: + oldKey = Event.ENTER; + break; + case KeyEvent.VK_ESCAPE: + oldKey = Event.ESCAPE; + break; + case KeyEvent.VK_F1: + oldKey = Event.F1; + break; + case KeyEvent.VK_F10: + oldKey = Event.F10; + break; + case KeyEvent.VK_F11: + oldKey = Event.F11; + break; + case KeyEvent.VK_F12: + oldKey = Event.F12; + break; + case KeyEvent.VK_F2: + oldKey = Event.F2; + break; + case KeyEvent.VK_F3: + oldKey = Event.F3; + break; + case KeyEvent.VK_F4: + oldKey = Event.F4; + break; + case KeyEvent.VK_F5: + oldKey = Event.F5; + break; + case KeyEvent.VK_F6: + oldKey = Event.F6; + break; + case KeyEvent.VK_F7: + oldKey = Event.F7; + break; + case KeyEvent.VK_F8: + oldKey = Event.F8; + break; + case KeyEvent.VK_F9: + oldKey = Event.F9; + break; + case KeyEvent.VK_HOME: + oldKey = Event.HOME; + break; + case KeyEvent.VK_INSERT: + oldKey = Event.INSERT; + break; + case KeyEvent.VK_LEFT: + case KeyEvent.VK_KP_LEFT: + oldKey = Event.LEFT; + break; + case KeyEvent.VK_NUM_LOCK: + oldKey = Event.NUM_LOCK; + break; + case KeyEvent.VK_PAUSE: + oldKey = Event.PAUSE; + break; + case KeyEvent.VK_PAGE_DOWN: + oldKey = Event.PGDN; + break; + case KeyEvent.VK_PAGE_UP: + oldKey = Event.PGUP; + break; + case KeyEvent.VK_PRINTSCREEN: + oldKey = Event.PRINT_SCREEN; + break; + case KeyEvent.VK_RIGHT: + case KeyEvent.VK_KP_RIGHT: + oldKey = Event.RIGHT; + break; + case KeyEvent.VK_SCROLL_LOCK: + oldKey = Event.SCROLL_LOCK; + break; + case KeyEvent.VK_TAB: + oldKey = Event.TAB; + break; + case KeyEvent.VK_UP: + case KeyEvent.VK_KP_UP: + oldKey = Event.UP; + break; + default: + oldKey = ((KeyEvent) e).getKeyChar(); + } + + translated = new Event (target, when, oldID, + 0, 0, oldKey, oldMods); + } + } + else if (e instanceof AdjustmentEvent) + { + AdjustmentEvent ae = (AdjustmentEvent) e; + int type = ae.getAdjustmentType(); + int oldType; + if (type == AdjustmentEvent.BLOCK_DECREMENT) + oldType = Event.SCROLL_PAGE_UP; + else if (type == AdjustmentEvent.BLOCK_INCREMENT) + oldType = Event.SCROLL_PAGE_DOWN; + else if (type == AdjustmentEvent.TRACK) + oldType = Event.SCROLL_ABSOLUTE; + else if (type == AdjustmentEvent.UNIT_DECREMENT) + oldType = Event.SCROLL_LINE_UP; + else if (type == AdjustmentEvent.UNIT_INCREMENT) + oldType = Event.SCROLL_LINE_DOWN; + else + oldType = type; + translated = new Event(target, oldType, new Integer(ae.getValue())); + } + else if (e instanceof ActionEvent) + translated = new Event (target, Event.ACTION_EVENT, + ((ActionEvent) e).getActionCommand ()); + + return translated; + } + + /** + * Implementation of dispatchEvent. Allows trusted package classes + * to dispatch additional events first. This implementation first + * translates <code>e</code> to an AWT 1.0 event and sends the + * result to {@link #postEvent}. If the AWT 1.0 event is not + * handled, and events of type <code>e</code> are enabled for this + * component, e is passed on to {@link #processEvent}. + * + * @param e the event to dispatch + */ + void dispatchEventImpl(AWTEvent e) + { + // Update the component's knowledge about the size. + // Important: Please look at the big comment in ComponentReshapeEvent + // to learn why we did it this way. If you change this code, make + // sure that the peer->AWT bounds update still works. + // (for instance: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29448 ) + if (e instanceof ComponentReshapeEvent) + { + ComponentReshapeEvent reshape = (ComponentReshapeEvent) e; + x = reshape.x; + y = reshape.y; + width = reshape.width; + height = reshape.height; + return; + } + + // Retarget focus events before dispatching it to the KeyboardFocusManager + // in order to handle lightweight components properly. + boolean dispatched = false; + if (! e.isFocusManagerEvent) + { + e = KeyboardFocusManager.retargetFocusEvent(e); + dispatched = KeyboardFocusManager.getCurrentKeyboardFocusManager() + .dispatchEvent(e); + } + + if (! dispatched) + { + // Give toolkit a chance to dispatch the event + // to globally registered listeners. + Toolkit.getDefaultToolkit().globalDispatchEvent(e); + + if (newEventsOnly) + { + if (eventTypeEnabled(e.id)) + processEvent(e); + } + else + { + Event oldEvent = translateEvent(e); + if (oldEvent != null) + postEvent (oldEvent); + } + if (peer != null) + peer.handleEvent(e); + } + } + + /** + * Tells whether or not an event type is enabled. + */ + boolean eventTypeEnabled (int type) + { + if (type > AWTEvent.RESERVED_ID_MAX) + return true; + + switch (type) + { + case HierarchyEvent.HIERARCHY_CHANGED: + return (hierarchyListener != null + || (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) != 0); + + case HierarchyEvent.ANCESTOR_MOVED: + case HierarchyEvent.ANCESTOR_RESIZED: + return (hierarchyBoundsListener != null + || (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0); + + case ComponentEvent.COMPONENT_HIDDEN: + case ComponentEvent.COMPONENT_MOVED: + case ComponentEvent.COMPONENT_RESIZED: + case ComponentEvent.COMPONENT_SHOWN: + return (componentListener != null + || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0); + + case KeyEvent.KEY_PRESSED: + case KeyEvent.KEY_RELEASED: + case KeyEvent.KEY_TYPED: + return (keyListener != null + || (eventMask & AWTEvent.KEY_EVENT_MASK) != 0); + + case MouseEvent.MOUSE_CLICKED: + case MouseEvent.MOUSE_ENTERED: + case MouseEvent.MOUSE_EXITED: + case MouseEvent.MOUSE_PRESSED: + case MouseEvent.MOUSE_RELEASED: + return (mouseListener != null + || (eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0); + case MouseEvent.MOUSE_MOVED: + case MouseEvent.MOUSE_DRAGGED: + return (mouseMotionListener != null + || (eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0); + case MouseEvent.MOUSE_WHEEL: + return (mouseWheelListener != null + || (eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0); + + case FocusEvent.FOCUS_GAINED: + case FocusEvent.FOCUS_LOST: + return (focusListener != null + || (eventMask & AWTEvent.FOCUS_EVENT_MASK) != 0); + + case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED: + case InputMethodEvent.CARET_POSITION_CHANGED: + return (inputMethodListener != null + || (eventMask & AWTEvent.INPUT_METHOD_EVENT_MASK) != 0); + + case PaintEvent.PAINT: + case PaintEvent.UPDATE: + return (eventMask & AWTEvent.PAINT_EVENT_MASK) != 0; + + default: + return false; + } + } + + /** + * Returns <code>true</code> when this component and all of its ancestors + * are visible, <code>false</code> otherwise. + * + * @return <code>true</code> when this component and all of its ancestors + * are visible, <code>false</code> otherwise + */ + boolean isHierarchyVisible() + { + boolean visible = isVisible(); + Component comp = parent; + while (comp != null && visible) + { + comp = comp.parent; + if (comp != null) + visible = visible && comp.isVisible(); + } + return visible; + } + + /** + * Returns the mouse pointer position relative to this Component's + * top-left corner. + * + * @return relative mouse pointer position + * + * @throws HeadlessException if in a headless environment + */ + public Point getMousePosition() throws HeadlessException + { + return getMousePositionHelper(true); + } + + Point getMousePositionHelper(boolean allowChildren) throws HeadlessException + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException("can't get mouse position" + + " in headless environment"); + if (!isShowing()) + return null; + + Component parent = this; + int windowRelativeXOffset = 0; + int windowRelativeYOffset = 0; + while (parent != null && !(parent instanceof Window)) + { + windowRelativeXOffset += parent.getX(); + windowRelativeYOffset += parent.getY(); + parent = parent.getParent(); + } + if (parent == null) + return null; + + Window window = (Window) parent; + if (!Toolkit.getDefaultToolkit() + .getMouseInfoPeer().isWindowUnderMouse(window)) + return null; + + PointerInfo info = MouseInfo.getPointerInfo(); + Point mouseLocation = info.getLocation(); + Point windowLocation = window.getLocationOnScreen(); + + int x = mouseLocation.x - windowLocation.x; + int y = mouseLocation.y - windowLocation.y; + + if (!mouseOverComponent(window.getComponentAt(x, y), allowChildren)) + return null; + + return new Point(x - windowRelativeXOffset, y - windowRelativeYOffset); + } + + boolean mouseOverComponent(Component component, boolean allowChildren) + { + return component == this; + } + + /** + * This method is used to implement transferFocus(). CHILD is the child + * making the request. This is overridden by Container; when called for an + * ordinary component there is no child and so we always return null. + * + * FIXME: is this still needed, in light of focus traversal policies? + * + * @param child the component making the request + * @return the next component to focus on + */ + Component findNextFocusComponent(Component child) + { + return null; + } + + /** + * Deserializes this component. This regenerates all serializable listeners + * which were registered originally. + * + * @param s the stream to read from + * @throws ClassNotFoundException if deserialization fails + * @throws IOException if the stream fails + */ + private void readObject(ObjectInputStream s) + throws ClassNotFoundException, IOException + { + s.defaultReadObject(); + String key = (String) s.readObject(); + while (key != null) + { + Object listener = s.readObject(); + if ("componentL".equals(key)) + addComponentListener((ComponentListener) listener); + else if ("focusL".equals(key)) + addFocusListener((FocusListener) listener); + else if ("keyL".equals(key)) + addKeyListener((KeyListener) listener); + else if ("mouseL".equals(key)) + addMouseListener((MouseListener) listener); + else if ("mouseMotionL".equals(key)) + addMouseMotionListener((MouseMotionListener) listener); + else if ("inputMethodL".equals(key)) + addInputMethodListener((InputMethodListener) listener); + else if ("hierarchyL".equals(key)) + addHierarchyListener((HierarchyListener) listener); + else if ("hierarchyBoundsL".equals(key)) + addHierarchyBoundsListener((HierarchyBoundsListener) listener); + else if ("mouseWheelL".equals(key)) + addMouseWheelListener((MouseWheelListener) listener); + key = (String) s.readObject(); + } + } + + /** + * Serializes this component. This ignores all listeners which do not + * implement Serializable, but includes those that do. + * + * @param s the stream to write to + * @throws IOException if the stream fails + */ + private void writeObject(ObjectOutputStream s) throws IOException + { + s.defaultWriteObject(); + AWTEventMulticaster.save(s, "componentL", componentListener); + AWTEventMulticaster.save(s, "focusL", focusListener); + AWTEventMulticaster.save(s, "keyL", keyListener); + AWTEventMulticaster.save(s, "mouseL", mouseListener); + AWTEventMulticaster.save(s, "mouseMotionL", mouseMotionListener); + AWTEventMulticaster.save(s, "inputMethodL", inputMethodListener); + AWTEventMulticaster.save(s, "hierarchyL", hierarchyListener); + AWTEventMulticaster.save(s, "hierarchyBoundsL", hierarchyBoundsListener); + AWTEventMulticaster.save(s, "mouseWheelL", mouseWheelListener); + s.writeObject(null); + } + + + // Nested classes. + + /** + * This class fixes the bounds for a Heavyweight component that + * is placed inside a Lightweight container. When the lightweight is + * moved or resized, setBounds for the lightweight peer does nothing. + * Therefore, it was never moved on the screen. This class is + * attached to the lightweight, and it adjusts the position and size + * of the peer when notified. + * This is the same for show and hide. + */ + class HeavyweightInLightweightListener + implements ComponentListener + { + + /** + * Constructor. Adds component listener to lightweight parent. + * + * @param parent - the lightweight container. + */ + public HeavyweightInLightweightListener(Container parent) + { + parent.addComponentListener(this); + } + + /** + * This method is called when the component is resized. + * + * @param event the <code>ComponentEvent</code> indicating the resize + */ + public void componentResized(ComponentEvent event) + { + // Nothing to do here, componentMoved will be called. + } + + /** + * This method is called when the component is moved. + * + * @param event the <code>ComponentEvent</code> indicating the move + */ + public void componentMoved(ComponentEvent event) + { + if (peer != null) + peer.setBounds(x, y, width, height); + } + + /** + * This method is called when the component is made visible. + * + * @param event the <code>ComponentEvent</code> indicating the visibility + */ + public void componentShown(ComponentEvent event) + { + if (isShowing()) + peer.show(); + } + + /** + * This method is called when the component is hidden. + * + * @param event the <code>ComponentEvent</code> indicating the visibility + */ + public void componentHidden(ComponentEvent event) + { + if (isShowing()) + peer.hide(); + } + } + + /** + * This class provides accessibility support for subclasses of container. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + * @status updated to 1.4 + */ + protected abstract class AccessibleAWTComponent extends AccessibleContext + implements Serializable, AccessibleComponent + { + /** + * Compatible with JDK 1.3+. + */ + private static final long serialVersionUID = 642321655757800191L; + + /** + * Converts show/hide events to PropertyChange events, and is registered + * as a component listener on this component. + * + * @serial the component handler + */ + protected ComponentListener accessibleAWTComponentHandler + = new AccessibleAWTComponentHandler(); + + /** + * Converts focus events to PropertyChange events, and is registered + * as a focus listener on this component. + * + * @serial the focus handler + */ + protected FocusListener accessibleAWTFocusHandler + = new AccessibleAWTFocusHandler(); + + /** + * The default constructor. + */ + protected AccessibleAWTComponent() + { + Component.this.addComponentListener(accessibleAWTComponentHandler); + Component.this.addFocusListener(accessibleAWTFocusHandler); + } + + /** + * Adds a global property change listener to the accessible component. + * + * @param l the listener to add + * @see #ACCESSIBLE_NAME_PROPERTY + * @see #ACCESSIBLE_DESCRIPTION_PROPERTY + * @see #ACCESSIBLE_STATE_PROPERTY + * @see #ACCESSIBLE_VALUE_PROPERTY + * @see #ACCESSIBLE_SELECTION_PROPERTY + * @see #ACCESSIBLE_TEXT_PROPERTY + * @see #ACCESSIBLE_VISIBLE_DATA_PROPERTY + */ + public void addPropertyChangeListener(PropertyChangeListener l) + { + Component.this.addPropertyChangeListener(l); + super.addPropertyChangeListener(l); + } + + /** + * Removes a global property change listener from this accessible + * component. + * + * @param l the listener to remove + */ + public void removePropertyChangeListener(PropertyChangeListener l) + { + Component.this.removePropertyChangeListener(l); + super.removePropertyChangeListener(l); + } + + /** + * Returns the accessible name of this component. It is almost always + * wrong to return getName(), since it is not localized. In fact, for + * things like buttons, this should be the text of the button, not the + * name of the object. The tooltip text might also be appropriate. + * + * @return the name + * @see #setAccessibleName(String) + */ + public String getAccessibleName() + { + return accessibleName; + } + + /** + * Returns a brief description of this accessible context. This should + * be localized. + * + * @return a description of this component + * @see #setAccessibleDescription(String) + */ + public String getAccessibleDescription() + { + return accessibleDescription; + } + + /** + * Returns the role of this component. + * + * @return the accessible role + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.AWT_COMPONENT; + } + + /** + * Returns a state set describing this component's state. + * + * @return a new state set + * @see AccessibleState + */ + public AccessibleStateSet getAccessibleStateSet() + { + AccessibleStateSet s = new AccessibleStateSet(); + if (Component.this.isEnabled()) + s.add(AccessibleState.ENABLED); + if (isFocusable()) + s.add(AccessibleState.FOCUSABLE); + if (isFocusOwner()) + s.add(AccessibleState.FOCUSED); + // Note: While the java.awt.Component has an 'opaque' property, it + // seems that it is not added to the accessible state set here, even + // if this property is true. However, it is handled for + // javax.swing.JComponent, so we add it there. + if (Component.this.isShowing()) + s.add(AccessibleState.SHOWING); + if (Component.this.isVisible()) + s.add(AccessibleState.VISIBLE); + return s; + } + + /** + * Returns the parent of this component, if it is accessible. + * + * @return the accessible parent + */ + public Accessible getAccessibleParent() + { + if (accessibleParent == null) + { + Container parent = getParent(); + accessibleParent = parent instanceof Accessible + ? (Accessible) parent : null; + } + return accessibleParent; + } + + /** + * Returns the index of this component in its accessible parent. + * + * @return the index, or -1 if the parent is not accessible + * @see #getAccessibleParent() + */ + public int getAccessibleIndexInParent() + { + if (getAccessibleParent() == null) + return -1; + AccessibleContext context + = ((Component) accessibleParent).getAccessibleContext(); + if (context == null) + return -1; + for (int i = context.getAccessibleChildrenCount(); --i >= 0; ) + if (context.getAccessibleChild(i) == Component.this) + return i; + return -1; + } + + /** + * Returns the number of children of this component which implement + * Accessible. Subclasses must override this if they can have children. + * + * @return the number of accessible children, default 0 + */ + public int getAccessibleChildrenCount() + { + return 0; + } + + /** + * Returns the ith accessible child. Subclasses must override this if + * they can have children. + * + * @return the ith accessible child, or null + * @see #getAccessibleChildrenCount() + */ + public Accessible getAccessibleChild(int i) + { + return null; + } + + /** + * Returns the locale of this component. + * + * @return the locale + * @throws IllegalComponentStateException if the locale is unknown + */ + public Locale getLocale() + { + return Component.this.getLocale(); + } + + /** + * Returns this, since it is an accessible component. + * + * @return the accessible component + */ + public AccessibleComponent getAccessibleComponent() + { + return this; + } + + /** + * Gets the background color. + * + * @return the background color + * @see #setBackground(Color) + */ + public Color getBackground() + { + return Component.this.getBackground(); + } + + /** + * Sets the background color. + * + * @param c the background color + * @see #getBackground() + * @see #isOpaque() + */ + public void setBackground(Color c) + { + Component.this.setBackground(c); + } + + /** + * Gets the foreground color. + * + * @return the foreground color + * @see #setForeground(Color) + */ + public Color getForeground() + { + return Component.this.getForeground(); + } + + /** + * Sets the foreground color. + * + * @param c the foreground color + * @see #getForeground() + */ + public void setForeground(Color c) + { + Component.this.setForeground(c); + } + + /** + * Gets the cursor. + * + * @return the cursor + * @see #setCursor(Cursor) + */ + public Cursor getCursor() + { + return Component.this.getCursor(); + } + + /** + * Sets the cursor. + * + * @param cursor the cursor + * @see #getCursor() + */ + public void setCursor(Cursor cursor) + { + Component.this.setCursor(cursor); + } + + /** + * Gets the font. + * + * @return the font + * @see #setFont(Font) + */ + public Font getFont() + { + return Component.this.getFont(); + } + + /** + * Sets the font. + * + * @param f the font + * @see #getFont() + */ + public void setFont(Font f) + { + Component.this.setFont(f); + } + + /** + * Gets the font metrics for a font. + * + * @param f the font to look up + * @return its metrics + * @throws NullPointerException if f is null + * @see #getFont() + */ + public FontMetrics getFontMetrics(Font f) + { + return Component.this.getFontMetrics(f); + } + + /** + * Tests if the component is enabled. + * + * @return true if the component is enabled + * @see #setEnabled(boolean) + * @see #getAccessibleStateSet() + * @see AccessibleState#ENABLED + */ + public boolean isEnabled() + { + return Component.this.isEnabled(); + } + + /** + * Set whether the component is enabled. + * + * @param b the new enabled status + * @see #isEnabled() + */ + public void setEnabled(boolean b) + { + Component.this.setEnabled(b); + } + + /** + * Test whether the component is visible (not necesarily showing). + * + * @return true if it is visible + * @see #setVisible(boolean) + * @see #getAccessibleStateSet() + * @see AccessibleState#VISIBLE + */ + public boolean isVisible() + { + return Component.this.isVisible(); + } + + /** + * Sets the visibility of this component. + * + * @param b the desired visibility + * @see #isVisible() + */ + public void setVisible(boolean b) + { + Component.this.setVisible(b); + } + + /** + * Tests if the component is showing. + * + * @return true if this is showing + */ + public boolean isShowing() + { + return Component.this.isShowing(); + } + + /** + * Tests if the point is contained in this component. + * + * @param p the point to check + * @return true if it is contained + * @throws NullPointerException if p is null + */ + public boolean contains(Point p) + { + return Component.this.contains(p.x, p.y); + } + + /** + * Returns the location of this object on the screen, or null if it is + * not showing. + * + * @return the location relative to screen coordinates, if showing + * @see #getBounds() + * @see #getLocation() + */ + public Point getLocationOnScreen() + { + return Component.this.isShowing() ? Component.this.getLocationOnScreen() + : null; + } + + /** + * Returns the location of this object relative to its parent's coordinate + * system, or null if it is not showing. + * + * @return the location + * @see #getBounds() + * @see #getLocationOnScreen() + */ + public Point getLocation() + { + return Component.this.getLocation(); + } + + /** + * Sets the location of this relative to its parent's coordinate system. + * + * @param p the location + * @throws NullPointerException if p is null + * @see #getLocation() + */ + public void setLocation(Point p) + { + Component.this.setLocation(p.x, p.y); + } + + /** + * Gets the bounds of this component, or null if it is not on screen. + * + * @return the bounds + * @see #contains(Point) + * @see #setBounds(Rectangle) + */ + public Rectangle getBounds() + { + return Component.this.getBounds(); + } + + /** + * Sets the bounds of this component. + * + * @param r the bounds + * @throws NullPointerException if r is null + * @see #getBounds() + */ + public void setBounds(Rectangle r) + { + Component.this.setBounds(r.x, r.y, r.width, r.height); + } + + /** + * Gets the size of this component, or null if it is not showing. + * + * @return the size + * @see #setSize(Dimension) + */ + public Dimension getSize() + { + return Component.this.getSize(); + } + + /** + * Sets the size of this component. + * + * @param d the size + * @throws NullPointerException if d is null + * @see #getSize() + */ + public void setSize(Dimension d) + { + Component.this.setSize(d.width, d.height); + } + + /** + * Returns the Accessible child at a point relative to the coordinate + * system of this component, if one exists, or null. Since components + * have no children, subclasses must override this to get anything besides + * null. + * + * @param p the point to check + * @return the accessible child at that point + * @throws NullPointerException if p is null + */ + public Accessible getAccessibleAt(Point p) + { + return null; + } + + /** + * Tests whether this component can accept focus. + * + * @return true if this is focus traversable + * @see #getAccessibleStateSet () + * @see AccessibleState#FOCUSABLE + * @see AccessibleState#FOCUSED + */ + public boolean isFocusTraversable () + { + return Component.this.isFocusTraversable (); + } + + /** + * Requests focus for this component. + * + * @see #isFocusTraversable () + */ + public void requestFocus () + { + Component.this.requestFocus (); + } + + /** + * Adds a focus listener. + * + * @param l the listener to add + */ + public void addFocusListener(FocusListener l) + { + Component.this.addFocusListener(l); + } + + /** + * Removes a focus listener. + * + * @param l the listener to remove + */ + public void removeFocusListener(FocusListener l) + { + Component.this.removeFocusListener(l); + } + + /** + * Converts component changes into property changes. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + * @status updated to 1.4 + */ + protected class AccessibleAWTComponentHandler implements ComponentListener + { + /** + * Default constructor. + */ + protected AccessibleAWTComponentHandler() + { + // Nothing to do here. + } + + /** + * Convert a component hidden to a property change. + * + * @param e the event to convert + */ + public void componentHidden(ComponentEvent e) + { + AccessibleAWTComponent.this.firePropertyChange + (ACCESSIBLE_STATE_PROPERTY, AccessibleState.VISIBLE, null); + } + + /** + * Convert a component shown to a property change. + * + * @param e the event to convert + */ + public void componentShown(ComponentEvent e) + { + AccessibleAWTComponent.this.firePropertyChange + (ACCESSIBLE_STATE_PROPERTY, null, AccessibleState.VISIBLE); + } + + /** + * Moving a component does not affect properties. + * + * @param e ignored + */ + public void componentMoved(ComponentEvent e) + { + // Nothing to do here. + } + + /** + * Resizing a component does not affect properties. + * + * @param e ignored + */ + public void componentResized(ComponentEvent e) + { + // Nothing to do here. + } + } // class AccessibleAWTComponentHandler + + /** + * Converts focus changes into property changes. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + * @status updated to 1.4 + */ + protected class AccessibleAWTFocusHandler implements FocusListener + { + /** + * Default constructor. + */ + protected AccessibleAWTFocusHandler() + { + // Nothing to do here. + } + + /** + * Convert a focus gained to a property change. + * + * @param e the event to convert + */ + public void focusGained(FocusEvent e) + { + AccessibleAWTComponent.this.firePropertyChange + (ACCESSIBLE_STATE_PROPERTY, null, AccessibleState.FOCUSED); + } + + /** + * Convert a focus lost to a property change. + * + * @param e the event to convert + */ + public void focusLost(FocusEvent e) + { + AccessibleAWTComponent.this.firePropertyChange + (ACCESSIBLE_STATE_PROPERTY, AccessibleState.FOCUSED, null); + } + } // class AccessibleAWTComponentHandler + } // class AccessibleAWTComponent + + /** + * This class provides support for blitting offscreen surfaces to a + * component. + * + * @see BufferStrategy + * + * @since 1.4 + */ + protected class BltBufferStrategy extends BufferStrategy + { + /** + * The capabilities of the image buffer. + */ + protected BufferCapabilities caps; + + /** + * The back buffers used in this strategy. + */ + protected VolatileImage[] backBuffers; + + /** + * Whether or not the image buffer resources are allocated and + * ready to be drawn into. + */ + protected boolean validatedContents; + + /** + * The width of the back buffers. + */ + protected int width; + + /** + * The height of the back buffers. + */ + protected int height; + + /** + * The front buffer. + */ + private VolatileImage frontBuffer; + + /** + * Creates a blitting buffer strategy. + * + * @param numBuffers the number of buffers, including the front + * buffer + * @param caps the capabilities of this strategy + */ + protected BltBufferStrategy(int numBuffers, BufferCapabilities caps) + { + this.caps = caps; + createBackBuffers(numBuffers - 1); + width = getWidth(); + height = getHeight(); + } + + /** + * Initializes the backBuffers field with an array of numBuffers + * VolatileImages. + * + * @param numBuffers the number of backbuffers to create + */ + protected void createBackBuffers(int numBuffers) + { + GraphicsConfiguration c = + GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + + backBuffers = new VolatileImage[numBuffers]; + + for (int i = 0; i < numBuffers; i++) + backBuffers[i] = c.createCompatibleVolatileImage(width, height); + } + + /** + * Retrieves the capabilities of this buffer strategy. + * + * @return the capabilities of this buffer strategy + */ + public BufferCapabilities getCapabilities() + { + return caps; + } + + /** + * Retrieves a graphics object that can be used to draw into this + * strategy's image buffer. + * + * @return a graphics object + */ + public Graphics getDrawGraphics() + { + // Return the backmost buffer's graphics. + return backBuffers[0].getGraphics(); + } + + /** + * Bring the contents of the back buffer to the front buffer. + */ + public void show() + { + GraphicsConfiguration c = + GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + + // draw the front buffer. + getGraphics().drawImage(backBuffers[backBuffers.length - 1], + width, height, null); + + BufferCapabilities.FlipContents f = getCapabilities().getFlipContents(); + + // blit the back buffers. + for (int i = backBuffers.length - 1; i > 0 ; i--) + backBuffers[i] = backBuffers[i - 1]; + + // create new backmost buffer. + if (f == BufferCapabilities.FlipContents.UNDEFINED) + backBuffers[0] = c.createCompatibleVolatileImage(width, height); + + // create new backmost buffer and clear it to the background + // color. + if (f == BufferCapabilities.FlipContents.BACKGROUND) + { + backBuffers[0] = c.createCompatibleVolatileImage(width, height); + backBuffers[0].getGraphics().clearRect(0, 0, width, height); + } + + // FIXME: set the backmost buffer to the prior contents of the + // front buffer. How do we retrieve the contents of the front + // buffer? + // + // if (f == BufferCapabilities.FlipContents.PRIOR) + + // set the backmost buffer to a copy of the new front buffer. + if (f == BufferCapabilities.FlipContents.COPIED) + backBuffers[0] = backBuffers[backBuffers.length - 1]; + } + + /** + * Re-create the image buffer resources if they've been lost. + */ + protected void revalidate() + { + GraphicsConfiguration c = + GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + + for (int i = 0; i < backBuffers.length; i++) + { + int result = backBuffers[i].validate(c); + if (result == VolatileImage.IMAGE_INCOMPATIBLE) + backBuffers[i] = c.createCompatibleVolatileImage(width, height); + } + validatedContents = true; + } + + /** + * Returns whether or not the image buffer resources have been + * lost. + * + * @return true if the resources have been lost, false otherwise + */ + public boolean contentsLost() + { + for (int i = 0; i < backBuffers.length; i++) + { + if (backBuffers[i].contentsLost()) + { + validatedContents = false; + return true; + } + } + // we know that the buffer resources are valid now because we + // just checked them + validatedContents = true; + return false; + } + + /** + * Returns whether or not the image buffer resources have been + * restored. + * + * @return true if the resources have been restored, false + * otherwise + */ + public boolean contentsRestored() + { + GraphicsConfiguration c = + GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + + boolean imageRestored = false; + + for (int i = 0; i < backBuffers.length; i++) + { + int result = backBuffers[i].validate(c); + if (result == VolatileImage.IMAGE_RESTORED) + imageRestored = true; + else if (result == VolatileImage.IMAGE_INCOMPATIBLE) + return false; + } + // we know that the buffer resources are valid now because we + // just checked them + validatedContents = true; + return imageRestored; + } + } + + /** + * This class provides support for flipping component buffers. It + * can only be used on Canvases and Windows. + * + * @since 1.4 + */ + protected class FlipBufferStrategy extends BufferStrategy + { + /** + * The number of buffers. + */ + protected int numBuffers; + + /** + * The capabilities of this buffering strategy. + */ + protected BufferCapabilities caps; + + /** + * An Image reference to the drawing buffer. + */ + protected Image drawBuffer; + + /** + * A VolatileImage reference to the drawing buffer. + */ + protected VolatileImage drawVBuffer; + + /** + * Whether or not the image buffer resources are allocated and + * ready to be drawn into. + */ + protected boolean validatedContents; + + /** + * The width of the back buffer. + */ + private int width; + + /** + * The height of the back buffer. + */ + private int height; + + /** + * Creates a flipping buffer strategy. The only supported + * strategy for FlipBufferStrategy itself is a double-buffer page + * flipping strategy. It forms the basis for more complex derived + * strategies. + * + * @param numBuffers the number of buffers + * @param caps the capabilities of this buffering strategy + * + * @throws AWTException if the requested + * number-of-buffers/capabilities combination is not supported + */ + protected FlipBufferStrategy(int numBuffers, BufferCapabilities caps) + throws AWTException + { + this.caps = caps; + width = getWidth(); + height = getHeight(); + + if (numBuffers > 1) + createBuffers(numBuffers, caps); + else + { + drawVBuffer = peer.createVolatileImage(width, height); + drawBuffer = drawVBuffer; + } + } + + /** + * Creates a multi-buffer flipping strategy. The number of + * buffers must be greater than one and the buffer capabilities + * must specify page flipping. + * + * @param numBuffers the number of flipping buffers; must be + * greater than one + * @param caps the buffering capabilities; caps.isPageFlipping() + * must return true + * + * @throws IllegalArgumentException if numBuffers is not greater + * than one or if the page flipping capability is not requested + * + * @throws AWTException if the requested flipping strategy is not + * supported + */ + protected void createBuffers(int numBuffers, BufferCapabilities caps) + throws AWTException + { + if (numBuffers <= 1) + throw new IllegalArgumentException("FlipBufferStrategy.createBuffers:" + + " numBuffers must be greater than" + + " one."); + + if (!caps.isPageFlipping()) + throw new IllegalArgumentException("FlipBufferStrategy.createBuffers:" + + " flipping must be a specified" + + " capability."); + + peer.createBuffers(numBuffers, caps); + } + + /** + * Return a direct reference to the back buffer image. + * + * @return a direct reference to the back buffer image. + */ + protected Image getBackBuffer() + { + return peer.getBackBuffer(); + } + + /** + * Perform a flip operation to transfer the contents of the back + * buffer to the front buffer. + */ + protected void flip(BufferCapabilities.FlipContents flipAction) + { + peer.flip(flipAction); + } + + /** + * Release the back buffer's resources. + */ + protected void destroyBuffers() + { + peer.destroyBuffers(); + } + + /** + * Retrieves the capabilities of this buffer strategy. + * + * @return the capabilities of this buffer strategy + */ + public BufferCapabilities getCapabilities() + { + return caps; + } + + /** + * Retrieves a graphics object that can be used to draw into this + * strategy's image buffer. + * + * @return a graphics object + */ + public Graphics getDrawGraphics() + { + return drawVBuffer.getGraphics(); + } + + /** + * Re-create the image buffer resources if they've been lost. + */ + protected void revalidate() + { + GraphicsConfiguration c = + GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + + if (drawVBuffer.validate(c) == VolatileImage.IMAGE_INCOMPATIBLE) + drawVBuffer = peer.createVolatileImage(width, height); + validatedContents = true; + } + + /** + * Returns whether or not the image buffer resources have been + * lost. + * + * @return true if the resources have been lost, false otherwise + */ + public boolean contentsLost() + { + if (drawVBuffer.contentsLost()) + { + validatedContents = false; + return true; + } + // we know that the buffer resources are valid now because we + // just checked them + validatedContents = true; + return false; + } + + /** + * Returns whether or not the image buffer resources have been + * restored. + * + * @return true if the resources have been restored, false + * otherwise + */ + public boolean contentsRestored() + { + GraphicsConfiguration c = + GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + + int result = drawVBuffer.validate(c); + + boolean imageRestored = false; + + if (result == VolatileImage.IMAGE_RESTORED) + imageRestored = true; + else if (result == VolatileImage.IMAGE_INCOMPATIBLE) + return false; + + // we know that the buffer resources are valid now because we + // just checked them + validatedContents = true; + return imageRestored; + } + + /** + * Bring the contents of the back buffer to the front buffer. + */ + public void show() + { + flip(caps.getFlipContents()); + } + } +} diff --git a/libjava/classpath/java/awt/ComponentOrientation.java b/libjava/classpath/java/awt/ComponentOrientation.java new file mode 100644 index 000000000..69b14c755 --- /dev/null +++ b/libjava/classpath/java/awt/ComponentOrientation.java @@ -0,0 +1,215 @@ +/* ComponentOrientation.java -- describes a component's orientation + Copyright (C) 2000, 2001, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.io.Serializable; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * This class is used to differentiate different orientations for text layout. + * It controls whether text flows left-to-right or right-to-left, and whether + * lines are horizontal or vertical, as in this table:<br> + * <pre> + * LT RT TL TR + * A B C C B A A D G G D A + * D E F F E D B E H H E B + * G H I I H G C F I I F C + * </pre> + * <b>LT</b> languages are most common (left-to-right lines, top-to-bottom). + * This includes Western European languages, and optionally includes Japanese, + * Chinese, and Korean. <b>RT</b> languages (right-to-left lines, + * top-to-bottom) are mainly middle eastern, such as Hebrew and Arabic. + * <b>TR</b> languages flow top-to-bottom in a line, right-to-left, and are + * the basis of Japanese, Chinese, and Korean. Finally, <b>TL</b> languages + * flow top-to-bottom in a line, left-to-right, as in Mongolian. + * + * <p>This is a pretty poor excuse for a type-safe enum, since it is not + * guaranteed that orientation objects are unique (thanks to serialization), + * yet there is no equals() method. You would be wise to compare the output + * of isHorizontal() and isLeftToRight() rather than comparing objects with + * ==, especially since more constants may be added in the future. + * + * @author Bryce McKinlay (bryce@albatross.co.nz) + * @since 1.0 + * @status updated to 1.4 + */ +public final class ComponentOrientation implements Serializable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -4113291392143563828L; + + /** Constant for unknown orientation. */ + private static final int UNKNOWN_ID = 1; + + /** Constant for horizontal line orientation. */ + private static final int HORIZONTAL_ID = 2; + + /** Constant for left-to-right orientation. */ + private static final int LEFT_TO_RIGHT_ID = 4; + + /** + * Items run left to right, and lines flow top to bottom. Examples: English, + * French. + */ + public static final ComponentOrientation LEFT_TO_RIGHT + = new ComponentOrientation(HORIZONTAL_ID | LEFT_TO_RIGHT_ID); + + /** + * Items run right to left, and lines flow top to bottom. Examples: Arabic, + * Hebrew. + */ + public static final ComponentOrientation RIGHT_TO_LEFT + = new ComponentOrientation(HORIZONTAL_ID); + + /** + * The orientation is unknown for the locale. For backwards compatibility, + * this behaves like LEFT_TO_RIGHT in the instance methods. + */ + public static final ComponentOrientation UNKNOWN + = new ComponentOrientation(UNKNOWN_ID | HORIZONTAL_ID | LEFT_TO_RIGHT_ID); + + /** + * The orientation of this object; bitwise-or of unknown (1), horizontal (2), + * and left-to-right (4). + * + * @serial the orientation + */ + private final int orientation; + + /** + * Construct a given orientation. + * + * @param orientation the orientation + */ + private ComponentOrientation(int orientation) + { + this.orientation = orientation; + } + + /** + * Returns true if the lines are horizontal, in which case lines flow + * top-to-bottom. For example, English, Hebrew. Counterexamples: Japanese, + * Chinese, Korean, Mongolian. + * + * @return true if this orientation has horizontal lines + */ + public boolean isHorizontal() + { + return (orientation & HORIZONTAL_ID) != 0; + } + + /** + * If isHorizontal() returns true, then this determines whether items in + * the line flow left-to-right. If isHorizontal() returns false, items in + * a line flow top-to-bottom, and this determines if lines flow + * left-to-right. + * + * @return true if this orientation flows left-to-right + */ + public boolean isLeftToRight() + { + return (orientation & LEFT_TO_RIGHT_ID) != 0; + } + + /** + * Gets an orientation appropriate for the locale. + * + * @param locale the locale + * @return the orientation for that locale + * @throws NullPointerException if locale is null + */ + public static ComponentOrientation getOrientation(Locale locale) + { + // Based on iterating over all languages defined in JDK 1.4, this behavior + // matches Sun's. However, it makes me wonder if any non-horizontal + // orientations even exist, as it sure contradicts their documentation. + String language = locale.getLanguage(); + if ("ar".equals(language) || "fa".equals(language) || "iw".equals(language) + || "ur".equals(language)) + return RIGHT_TO_LEFT; + return LEFT_TO_RIGHT; + } + + /** + * Gets an orientation from a resource bundle. This tries the following: + * + * <ul> + * <li>Use the key "Orientation" to find an instance of ComponentOrientation + * in the bundle.</li> + * <li>Get the locale of the resource bundle, and get the orientation of + * that locale.</li> + * <li>Give up and get the orientation of the default locale.</li> + * </ul> + * + * @param bdl the bundle to use + * @return the orientation + * @throws NullPointerException if bdl is null + * @deprecated use {@link #getOrientation(Locale)} instead + */ + public static ComponentOrientation getOrientation(ResourceBundle bdl) + { + ComponentOrientation r; + try + { + r = (ComponentOrientation) bdl.getObject("Orientation"); + if (r != null) + return r; + } + catch (MissingResourceException ignored) + { + } + catch (ClassCastException ignored) + { + } + try + { + r = getOrientation(bdl.getLocale()); + if (r != null) + return r; + } + catch (Exception ignored) + { + } + return getOrientation(Locale.getDefault()); + } +} // class ComponentOrientation diff --git a/libjava/classpath/java/awt/Composite.java b/libjava/classpath/java/awt/Composite.java new file mode 100644 index 000000000..ca3abe4d1 --- /dev/null +++ b/libjava/classpath/java/awt/Composite.java @@ -0,0 +1,73 @@ +/* Composite.java -- graphics formed from composite layers + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.image.ColorModel; + +/** + * This interface is for graphics which are formed as composites of others. + * It combines {@link Graphics2D} shapes according to defined rules to form + * the new image. Implementations of this interface must be immutable, because + * they are not cloned when a Graphics2D container is cloned. + * + * <p>Since this can expose pixels to untrusted code, there is a security + * check on custom objects, <code>readDisplayPixels</code>, to prevent leaking + * restricted information graphically. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see AlphaComposite + * @see CompositeContext + * @see Graphics2D#setComposite(Composite) + * @since 1.2 + * @status updated to 1.4 + */ +public interface Composite +{ + /** + * Create a context state for performing the compositing operation. Several + * contexts may exist for this object, in a multi-threaded environment. + * + * @param srcColorModel the color model of the source + * @param dstColorModel the color model of the destination + * @param hints hints for choosing between rendering alternatives + */ + CompositeContext createContext(ColorModel srcColorModel, + ColorModel dstColorModel, + RenderingHints hints); +} // interface Composite diff --git a/libjava/classpath/java/awt/CompositeContext.java b/libjava/classpath/java/awt/CompositeContext.java new file mode 100644 index 000000000..018a27071 --- /dev/null +++ b/libjava/classpath/java/awt/CompositeContext.java @@ -0,0 +1,71 @@ +/* Composite.java -- the context for compositing graphics layers + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.image.Raster; +import java.awt.image.WritableRaster; + +/** + * This interface provides an optimized environment for compositing graphics. + * Several such contexts may exist for a given <code>Composite</code> object. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see Composite + * @since 1.2 + * @status updated to 1.4 + */ +public interface CompositeContext +{ + /** + * Release resources allocated for the compositing. + */ + void dispose(); + + /** + * Compose the two source images into the composite image. The destination + * can be the same as one of the two inputs, and the destination must be + * compatible with the ColorModel chosen in {@link Composite#createContext}. + * + * @param src the lower image source in compositing + * @param dstIn the upper image source in compositing + * @param dstOut the destination for the composite + * @see Composite + */ + void compose(Raster src, Raster dstIn, WritableRaster dstOut); +} // interface CompositeContext diff --git a/libjava/classpath/java/awt/Container.java b/libjava/classpath/java/awt/Container.java new file mode 100644 index 000000000..7e596f10a --- /dev/null +++ b/libjava/classpath/java/awt/Container.java @@ -0,0 +1,2370 @@ +/* Container.java -- parent container class in AWT + Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import gnu.java.lang.CPStringBuilder; + +import java.awt.event.ContainerEvent; +import java.awt.event.ContainerListener; +import java.awt.event.HierarchyEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.peer.ComponentPeer; +import java.awt.peer.ContainerPeer; +import java.awt.peer.LightweightPeer; +import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.Serializable; +import java.util.Collections; +import java.util.EventListener; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import javax.accessibility.Accessible; + +/** + * A generic window toolkit object that acts as a container for other objects. + * Components are tracked in a list, and new elements are at the end of the + * list or bottom of the stacking order. + * + * @author original author unknown + * @author Eric Blake (ebb9@email.byu.edu) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * + * @since 1.0 + * + * @status still missing 1.4 support, some generics from 1.5 + */ +public class Container extends Component +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 4613797578919906343L; + + /* Serialized fields from the serialization spec. */ + int ncomponents; + Component[] component; + LayoutManager layoutMgr; + + /** + * @since 1.4 + */ + boolean focusCycleRoot; + + /** + * Indicates if this container provides a focus traversal policy. + * + * @since 1.5 + */ + private boolean focusTraversalPolicyProvider; + + int containerSerializedDataVersion; + + /* Anything else is non-serializable, and should be declared "transient". */ + transient ContainerListener containerListener; + + /** The focus traversal policy that determines how focus is + transferred between this Container and its children. */ + private FocusTraversalPolicy focusTraversalPolicy; + + /** + * The focus traversal keys, if not inherited from the parent or default + * keyboard manager. These sets will contain only AWTKeyStrokes that + * represent press and release events to use as focus control. + * + * @see #getFocusTraversalKeys(int) + * @see #setFocusTraversalKeys(int, Set) + * @since 1.4 + */ + transient Set[] focusTraversalKeys; + + /** + * Default constructor for subclasses. + */ + public Container() + { + // Nothing to do here. + } + + /** + * Returns the number of components in this container. + * + * @return The number of components in this container. + */ + public int getComponentCount() + { + return countComponents (); + } + + /** + * Returns the number of components in this container. + * + * @return The number of components in this container. + * + * @deprecated use {@link #getComponentCount()} instead + */ + public int countComponents() + { + return ncomponents; + } + + /** + * Returns the component at the specified index. + * + * @param n The index of the component to retrieve. + * + * @return The requested component. + * + * @throws ArrayIndexOutOfBoundsException If the specified index is invalid + */ + public Component getComponent(int n) + { + synchronized (getTreeLock ()) + { + if (n < 0 || n >= ncomponents) + throw new ArrayIndexOutOfBoundsException("no such component"); + + return component[n]; + } + } + + /** + * Returns an array of the components in this container. + * + * @return The components in this container. + */ + public Component[] getComponents() + { + synchronized (getTreeLock ()) + { + Component[] result = new Component[ncomponents]; + + if (ncomponents > 0) + System.arraycopy(component, 0, result, 0, ncomponents); + + return result; + } + } + + /** + * Returns the insets for this container, which is the space used for + * borders, the margin, etc. + * + * @return The insets for this container. + */ + public Insets getInsets() + { + return insets (); + } + + /** + * Returns the insets for this container, which is the space used for + * borders, the margin, etc. + * + * @return The insets for this container. + * @deprecated use {@link #getInsets()} instead + */ + public Insets insets() + { + Insets i; + if (peer == null || peer instanceof LightweightPeer) + i = new Insets (0, 0, 0, 0); + else + i = ((ContainerPeer) peer).getInsets (); + return i; + } + + /** + * Adds the specified component to this container at the end of the + * component list. + * + * @param comp The component to add to the container. + * + * @return The same component that was added. + */ + public Component add(Component comp) + { + addImpl(comp, null, -1); + return comp; + } + + /** + * Adds the specified component to the container at the end of the + * component list. This method should not be used. Instead, use + * <code>add(Component, Object)</code>. + * + * @param name The name of the component to be added. + * @param comp The component to be added. + * + * @return The same component that was added. + * + * @see #add(Component,Object) + */ + public Component add(String name, Component comp) + { + addImpl(comp, name, -1); + return comp; + } + + /** + * Adds the specified component to this container at the specified index + * in the component list. + * + * @param comp The component to be added. + * @param index The index in the component list to insert this child + * at, or -1 to add at the end of the list. + * + * @return The same component that was added. + * + * @throws ArrayIndexOutOfBoundsException If the specified index is invalid. + */ + public Component add(Component comp, int index) + { + addImpl(comp, null, index); + return comp; + } + + /** + * Adds the specified component to this container at the end of the + * component list. The layout manager will use the specified constraints + * when laying out this component. + * + * @param comp The component to be added to this container. + * @param constraints The layout constraints for this component. + */ + public void add(Component comp, Object constraints) + { + addImpl(comp, constraints, -1); + } + + /** + * Adds the specified component to this container at the specified index + * in the component list. The layout manager will use the specified + * constraints when layout out this component. + * + * @param comp The component to be added. + * @param constraints The layout constraints for this component. + * @param index The index in the component list to insert this child + * at, or -1 to add at the end of the list. + * + * @throws ArrayIndexOutOfBoundsException If the specified index is invalid. + */ + public void add(Component comp, Object constraints, int index) + { + addImpl(comp, constraints, index); + } + + /** + * This method is called by all the <code>add()</code> methods to perform + * the actual adding of the component. Subclasses who wish to perform + * their own processing when a component is added should override this + * method. Any subclass doing this must call the superclass version of + * this method in order to ensure proper functioning of the container. + * + * @param comp The component to be added. + * @param constraints The layout constraints for this component, or + * <code>null</code> if there are no constraints. + * @param index The index in the component list to insert this child + * at, or -1 to add at the end of the list. + * + * @throws ArrayIndexOutOfBoundsException If the specified index is invalid. + */ + protected void addImpl(Component comp, Object constraints, int index) + { + synchronized (getTreeLock ()) + { + if (index > ncomponents + || (index < 0 && index != -1) + || comp instanceof Window + || (comp instanceof Container + && ((Container) comp).isAncestorOf(this))) + throw new IllegalArgumentException(); + + // Reparent component, and make sure component is instantiated if + // we are. + if (comp.parent != null) + comp.parent.remove(comp); + + if (component == null) + component = new Component[4]; // FIXME, better initial size? + + // This isn't the most efficient implementation. We could do less + // copying when growing the array. It probably doesn't matter. + if (ncomponents >= component.length) + { + int nl = component.length * 2; + Component[] c = new Component[nl]; + System.arraycopy(component, 0, c, 0, ncomponents); + component = c; + } + + if (index == -1) + component[ncomponents++] = comp; + else + { + System.arraycopy(component, index, component, index + 1, + ncomponents - index); + component[index] = comp; + ++ncomponents; + } + + // Give the new component a parent. + comp.parent = this; + + // Update the counter for Hierarchy(Bounds)Listeners. + int childHierarchyListeners = comp.numHierarchyListeners; + if (childHierarchyListeners > 0) + updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK, + childHierarchyListeners); + int childHierarchyBoundsListeners = comp.numHierarchyBoundsListeners; + if (childHierarchyBoundsListeners > 0) + updateHierarchyListenerCount(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, + childHierarchyListeners); + + // Invalidate the layout of this container. + if (valid) + invalidate(); + + // Create the peer _after_ the component has been added, so that + // the peer gets to know about the component hierarchy. + if (peer != null) + { + // Notify the component that it has a new parent. + comp.addNotify(); + } + + // Notify the layout manager. + if (layoutMgr != null) + { + // If we have a LayoutManager2 the constraints are "real", + // otherwise they are the "name" of the Component to add. + if (layoutMgr instanceof LayoutManager2) + { + LayoutManager2 lm2 = (LayoutManager2) layoutMgr; + lm2.addLayoutComponent(comp, constraints); + } + else if (constraints instanceof String) + layoutMgr.addLayoutComponent((String) constraints, comp); + else + layoutMgr.addLayoutComponent("", comp); + } + + // We previously only sent an event when this container is showing. + // Also, the event was posted to the event queue. A Mauve test shows + // that this event is not delivered using the event queue and it is + // also sent when the container is not showing. + if (containerListener != null + || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0) + { + ContainerEvent ce = new ContainerEvent(this, + ContainerEvent.COMPONENT_ADDED, + comp); + dispatchEvent(ce); + } + + // Notify hierarchy listeners. + comp.fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, comp, + this, HierarchyEvent.PARENT_CHANGED); + } + } + + /** + * Removes the component at the specified index from this container. + * + * @param index The index of the component to remove. + */ + public void remove(int index) + { + synchronized (getTreeLock ()) + { + if (index < 0 || index >= ncomponents) + throw new ArrayIndexOutOfBoundsException(); + + Component r = component[index]; + if (peer != null) + r.removeNotify(); + + if (layoutMgr != null) + layoutMgr.removeLayoutComponent(r); + + // Update the counter for Hierarchy(Bounds)Listeners. + int childHierarchyListeners = r.numHierarchyListeners; + if (childHierarchyListeners > 0) + updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK, + -childHierarchyListeners); + int childHierarchyBoundsListeners = r.numHierarchyBoundsListeners; + if (childHierarchyBoundsListeners > 0) + updateHierarchyListenerCount(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, + -childHierarchyListeners); + + r.parent = null; + + System.arraycopy(component, index + 1, component, index, + ncomponents - index - 1); + component[--ncomponents] = null; + + if (valid) + invalidate(); + + if (containerListener != null + || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0) + { + // Post event to notify of removing the component. + ContainerEvent ce = new ContainerEvent(this, + ContainerEvent.COMPONENT_REMOVED, + r); + dispatchEvent(ce); + } + + // Notify hierarchy listeners. + r.fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, r, + this, HierarchyEvent.PARENT_CHANGED); + } + } + + /** + * Removes the specified component from this container. + * + * @param comp The component to remove from this container. + */ + public void remove(Component comp) + { + synchronized (getTreeLock ()) + { + for (int i = 0; i < ncomponents; ++i) + { + if (component[i] == comp) + { + remove(i); + break; + } + } + } + } + + /** + * Removes all components from this container. + */ + public void removeAll() + { + synchronized (getTreeLock ()) + { + // In order to allow the same bad tricks to be used as in RI + // this code has to stay exactly that way: In a real-life app + // a Container subclass implemented its own vector for + // subcomponents, supplied additional addXYZ() methods + // and overrode remove(int) and removeAll (the latter calling + // super.removeAll() ). + // By doing it this way, user code cannot prevent the correct + // removal of components. + while (ncomponents > 0) + { + ncomponents--; + Component r = component[ncomponents]; + component[ncomponents] = null; + + if (peer != null) + r.removeNotify(); + + if (layoutMgr != null) + layoutMgr.removeLayoutComponent(r); + + r.parent = null; + + // Send ContainerEvent if necessary. + if (containerListener != null + || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0) + { + // Post event to notify of removing the component. + ContainerEvent ce + = new ContainerEvent(this, + ContainerEvent.COMPONENT_REMOVED, + r); + dispatchEvent(ce); + } + + // Update the counter for Hierarchy(Bounds)Listeners. + int childHierarchyListeners = r.numHierarchyListeners; + if (childHierarchyListeners > 0) + updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK, + -childHierarchyListeners); + int childHierarchyBoundsListeners = r.numHierarchyBoundsListeners; + if (childHierarchyBoundsListeners > 0) + updateHierarchyListenerCount(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, + -childHierarchyListeners); + + + // Send HierarchyEvent if necessary. + fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, r, this, + HierarchyEvent.PARENT_CHANGED); + + } + + if (valid) + invalidate(); + } + } + + /** + * Returns the current layout manager for this container. + * + * @return The layout manager for this container. + */ + public LayoutManager getLayout() + { + return layoutMgr; + } + + /** + * Sets the layout manager for this container to the specified layout + * manager. + * + * @param mgr The new layout manager for this container. + */ + public void setLayout(LayoutManager mgr) + { + layoutMgr = mgr; + if (valid) + invalidate(); + } + + /** + * Layout the components in this container. + */ + public void doLayout() + { + layout (); + } + + /** + * Layout the components in this container. + * + * @deprecated use {@link #doLayout()} instead + */ + public void layout() + { + if (layoutMgr != null) + layoutMgr.layoutContainer (this); + } + + /** + * Invalidates this container to indicate that it (and all parent + * containers) need to be laid out. + */ + public void invalidate() + { + super.invalidate(); + if (layoutMgr != null && layoutMgr instanceof LayoutManager2) + { + LayoutManager2 lm2 = (LayoutManager2) layoutMgr; + lm2.invalidateLayout(this); + } + } + + /** + * Re-lays out the components in this container. + */ + public void validate() + { + ComponentPeer p = peer; + if (! valid && p != null) + { + ContainerPeer cPeer = null; + if (p instanceof ContainerPeer) + cPeer = (ContainerPeer) peer; + synchronized (getTreeLock ()) + { + if (cPeer != null) + cPeer.beginValidate(); + validateTree(); + valid = true; + if (cPeer != null) + cPeer.endValidate(); + } + } + } + + /** + * Recursively invalidates the container tree. + */ + private final void invalidateTree() + { + synchronized (getTreeLock()) + { + for (int i = 0; i < ncomponents; i++) + { + Component comp = component[i]; + if (comp instanceof Container) + ((Container) comp).invalidateTree(); + else if (comp.valid) + comp.invalidate(); + } + if (valid) + invalidate(); + } + } + + /** + * Recursively validates the container tree, recomputing any invalid + * layouts. + */ + protected void validateTree() + { + if (!valid) + { + ContainerPeer cPeer = null; + if (peer instanceof ContainerPeer) + { + cPeer = (ContainerPeer) peer; + cPeer.beginLayout(); + } + + doLayout (); + for (int i = 0; i < ncomponents; ++i) + { + Component comp = component[i]; + + if (comp instanceof Container && ! (comp instanceof Window) + && ! comp.valid) + { + ((Container) comp).validateTree(); + } + else + { + comp.validate(); + } + } + + if (cPeer != null) + { + cPeer = (ContainerPeer) peer; + cPeer.endLayout(); + } + } + + /* children will call invalidate() when they are layed out. It + is therefore important that valid is not set to true + until after the children have been layed out. */ + valid = true; + + } + + public void setFont(Font f) + { + Font oldFont = getFont(); + super.setFont(f); + Font newFont = getFont(); + if (newFont != oldFont && (oldFont == null || ! oldFont.equals(newFont))) + { + invalidateTree(); + } + } + + /** + * Returns the preferred size of this container. + * + * @return The preferred size of this container. + */ + public Dimension getPreferredSize() + { + return preferredSize (); + } + + /** + * Returns the preferred size of this container. + * + * @return The preferred size of this container. + * + * @deprecated use {@link #getPreferredSize()} instead + */ + public Dimension preferredSize() + { + Dimension size = prefSize; + // Try to return cached value if possible. + if (size == null || !(prefSizeSet || valid)) + { + // Need to lock here. + synchronized (getTreeLock()) + { + LayoutManager l = layoutMgr; + if (l != null) + prefSize = l.preferredLayoutSize(this); + else + prefSize = super.preferredSizeImpl(); + size = prefSize; + } + } + if (size != null) + return new Dimension(size); + else + return size; + } + + /** + * Returns the minimum size of this container. + * + * @return The minimum size of this container. + */ + public Dimension getMinimumSize() + { + return minimumSize (); + } + + /** + * Returns the minimum size of this container. + * + * @return The minimum size of this container. + * + * @deprecated use {@link #getMinimumSize()} instead + */ + public Dimension minimumSize() + { + Dimension size = minSize; + // Try to return cached value if possible. + if (size == null || !(minSizeSet || valid)) + { + // Need to lock here. + synchronized (getTreeLock()) + { + LayoutManager l = layoutMgr; + if (l != null) + minSize = l.minimumLayoutSize(this); + else + minSize = super.minimumSizeImpl(); + size = minSize; + } + } + if (size != null) + return new Dimension(size); + else + return size; + } + + /** + * Returns the maximum size of this container. + * + * @return The maximum size of this container. + */ + public Dimension getMaximumSize() + { + Dimension size = maxSize; + // Try to return cached value if possible. + if (size == null || !(maxSizeSet || valid)) + { + // Need to lock here. + synchronized (getTreeLock()) + { + LayoutManager l = layoutMgr; + if (l instanceof LayoutManager2) + maxSize = ((LayoutManager2) l).maximumLayoutSize(this); + else { + maxSize = super.maximumSizeImpl(); + } + size = maxSize; + } + } + if (size != null) + return new Dimension(size); + else + return size; + } + + /** + * Returns the preferred alignment along the X axis. This is a value + * between 0 and 1 where 0 represents alignment flush left and + * 1 means alignment flush right, and 0.5 means centered. + * + * @return The preferred alignment along the X axis. + */ + public float getAlignmentX() + { + LayoutManager layout = getLayout(); + float alignmentX = 0.0F; + if (layout != null && layout instanceof LayoutManager2) + { + synchronized (getTreeLock()) + { + LayoutManager2 lm2 = (LayoutManager2) layout; + alignmentX = lm2.getLayoutAlignmentX(this); + } + } + else + alignmentX = super.getAlignmentX(); + return alignmentX; + } + + /** + * Returns the preferred alignment along the Y axis. This is a value + * between 0 and 1 where 0 represents alignment flush top and + * 1 means alignment flush bottom, and 0.5 means centered. + * + * @return The preferred alignment along the Y axis. + */ + public float getAlignmentY() + { + LayoutManager layout = getLayout(); + float alignmentY = 0.0F; + if (layout != null && layout instanceof LayoutManager2) + { + synchronized (getTreeLock()) + { + LayoutManager2 lm2 = (LayoutManager2) layout; + alignmentY = lm2.getLayoutAlignmentY(this); + } + } + else + alignmentY = super.getAlignmentY(); + return alignmentY; + } + + /** + * Paints this container. The implementation of this method in this + * class forwards to any lightweight components in this container. If + * this method is subclassed, this method should still be invoked as + * a superclass method so that lightweight components are properly + * drawn. + * + * @param g - The graphics context for this paint job. + */ + public void paint(Graphics g) + { + if (isShowing()) + { + visitChildren(g, GfxPaintVisitor.INSTANCE, true); + } + } + + /** + * Updates this container. The implementation of this method in this + * class forwards to any lightweight components in this container. If + * this method is subclassed, this method should still be invoked as + * a superclass method so that lightweight components are properly + * drawn. + * + * @param g The graphics context for this update. + * + * @specnote The specification suggests that this method forwards the + * update() call to all its lightweight children. Tests show + * that this is not done either in the JDK. The exact behaviour + * seems to be that the background is cleared in heavyweight + * Containers, and all other containers + * directly call paint(), causing the (lightweight) children to + * be painted. + */ + public void update(Graphics g) + { + // It seems that the JDK clears the background of containers like Panel + // and Window (within this method) but not of 'plain' Containers or + // JComponents. This could + // lead to the assumption that it only clears heavyweight containers. + // However that is not quite true. In a test with a custom Container + // that overrides isLightweight() to return false, the background is + // also not cleared. So we do a check on !(peer instanceof LightweightPeer) + // instead. + if (isShowing()) + { + ComponentPeer p = peer; + if (! (p instanceof LightweightPeer)) + { + g.clearRect(0, 0, getWidth(), getHeight()); + } + paint(g); + } + } + + /** + * Prints this container. The implementation of this method in this + * class forwards to any lightweight components in this container. If + * this method is subclassed, this method should still be invoked as + * a superclass method so that lightweight components are properly + * drawn. + * + * @param g The graphics context for this print job. + */ + public void print(Graphics g) + { + super.print(g); + visitChildren(g, GfxPrintVisitor.INSTANCE, true); + } + + /** + * Paints all of the components in this container. + * + * @param g The graphics context for this paint job. + */ + public void paintComponents(Graphics g) + { + if (isShowing()) + visitChildren(g, GfxPaintAllVisitor.INSTANCE, false); + } + + /** + * Prints all of the components in this container. + * + * @param g The graphics context for this print job. + */ + public void printComponents(Graphics g) + { + super.paint(g); + visitChildren(g, GfxPrintAllVisitor.INSTANCE, true); + } + + /** + * Adds the specified container listener to this object's list of + * container listeners. + * + * @param listener The listener to add. + */ + public synchronized void addContainerListener(ContainerListener listener) + { + if (listener != null) + { + containerListener = AWTEventMulticaster.add(containerListener, + listener); + newEventsOnly = true; + } + } + + /** + * Removes the specified container listener from this object's list of + * container listeners. + * + * @param listener The listener to remove. + */ + public synchronized void removeContainerListener(ContainerListener listener) + { + containerListener = AWTEventMulticaster.remove(containerListener, listener); + } + + /** + * @since 1.4 + */ + public synchronized ContainerListener[] getContainerListeners() + { + return (ContainerListener[]) + AWTEventMulticaster.getListeners(containerListener, + ContainerListener.class); + } + + /** + * Returns all registered {@link EventListener}s of the given + * <code>listenerType</code>. + * + * @param listenerType the class of listeners to filter (<code>null</code> + * not permitted). + * + * @return An array of registered listeners. + * + * @throws ClassCastException if <code>listenerType</code> does not implement + * the {@link EventListener} interface. + * @throws NullPointerException if <code>listenerType</code> is + * <code>null</code>. + * + * @see #getContainerListeners() + * + * @since 1.3 + */ + public <T extends EventListener> T[] getListeners(Class<T> listenerType) + { + if (listenerType == ContainerListener.class) + return (T[]) getContainerListeners(); + return super.getListeners(listenerType); + } + + /** + * Processes the specified event. This method calls + * <code>processContainerEvent()</code> if this method is a + * <code>ContainerEvent</code>, otherwise it calls the superclass + * method. + * + * @param e The event to be processed. + */ + protected void processEvent(AWTEvent e) + { + if (e instanceof ContainerEvent) + processContainerEvent((ContainerEvent) e); + else + super.processEvent(e); + } + + /** + * Called when a container event occurs if container events are enabled. + * This method calls any registered listeners. + * + * @param e The event that occurred. + */ + protected void processContainerEvent(ContainerEvent e) + { + if (containerListener == null) + return; + switch (e.id) + { + case ContainerEvent.COMPONENT_ADDED: + containerListener.componentAdded(e); + break; + + case ContainerEvent.COMPONENT_REMOVED: + containerListener.componentRemoved(e); + break; + } + } + + /** + * AWT 1.0 event processor. + * + * @param e The event that occurred. + * + * @deprecated use {@link #dispatchEvent(AWTEvent)} instead + */ + public void deliverEvent(Event e) + { + if (!handleEvent (e)) + { + synchronized (getTreeLock ()) + { + Component parent = getParent (); + + if (parent != null) + parent.deliverEvent (e); + } + } + } + + /** + * Returns the component located at the specified point. This is done + * by checking whether or not a child component claims to contain this + * point. The first child component that does is returned. If no + * child component claims the point, the container itself is returned, + * unless the point does not exist within this container, in which + * case <code>null</code> is returned. + * + * When components overlap, the first component is returned. The component + * that is closest to (x, y), containing that location, is returned. + * Heavyweight components take precedence of lightweight components. + * + * This function does not ignore invisible components. If there is an invisible + * component at (x,y), it will be returned. + * + * @param x The X coordinate of the point. + * @param y The Y coordinate of the point. + * + * @return The component containing the specified point, or + * <code>null</code> if there is no such point. + */ + public Component getComponentAt(int x, int y) + { + return locate (x, y); + } + + /** + * Returns the mouse pointer position relative to this Container's + * top-left corner. If allowChildren is false, the mouse pointer + * must be directly over this container. If allowChildren is true, + * the mouse pointer may be over this container or any of its + * descendents. + * + * @param allowChildren true to allow descendents, false if pointer + * must be directly over Container. + * + * @return relative mouse pointer position + * + * @throws HeadlessException if in a headless environment + */ + public Point getMousePosition(boolean allowChildren) throws HeadlessException + { + return super.getMousePositionHelper(allowChildren); + } + + boolean mouseOverComponent(Component component, boolean allowChildren) + { + if (allowChildren) + return isAncestorOf(component); + else + return component == this; + } + + /** + * Returns the component located at the specified point. This is done + * by checking whether or not a child component claims to contain this + * point. The first child component that does is returned. If no + * child component claims the point, the container itself is returned, + * unless the point does not exist within this container, in which + * case <code>null</code> is returned. + * + * When components overlap, the first component is returned. The component + * that is closest to (x, y), containing that location, is returned. + * Heavyweight components take precedence of lightweight components. + * + * This function does not ignore invisible components. If there is an invisible + * component at (x,y), it will be returned. + * + * @param x The x position of the point to return the component at. + * @param y The y position of the point to return the component at. + * + * @return The component containing the specified point, or <code>null</code> + * if there is no such point. + * + * @deprecated use {@link #getComponentAt(int, int)} instead + */ + public Component locate(int x, int y) + { + synchronized (getTreeLock ()) + { + if (!contains (x, y)) + return null; + + // First find the component closest to (x,y) that is a heavyweight. + for (int i = 0; i < ncomponents; ++i) + { + Component comp = component[i]; + int x2 = x - comp.x; + int y2 = y - comp.y; + if (comp.contains (x2, y2) && !comp.isLightweight()) + return comp; + } + + // if a heavyweight component is not found, look for a lightweight + // closest to (x,y). + for (int i = 0; i < ncomponents; ++i) + { + Component comp = component[i]; + int x2 = x - comp.x; + int y2 = y - comp.y; + if (comp.contains (x2, y2) && comp.isLightweight()) + return comp; + } + + return this; + } + } + + /** + * Returns the component located at the specified point. This is done + * by checking whether or not a child component claims to contain this + * point. The first child component that does is returned. If no + * child component claims the point, the container itself is returned, + * unless the point does not exist within this container, in which + * case <code>null</code> is returned. + * + * The top-most child component is returned in the case where components overlap. + * This is determined by finding the component closest to (x,y) and contains + * that location. Heavyweight components take precedence of lightweight components. + * + * This function does not ignore invisible components. If there is an invisible + * component at (x,y), it will be returned. + * + * @param p The point to return the component at. + * @return The component containing the specified point, or <code>null</code> + * if there is no such point. + */ + public Component getComponentAt(Point p) + { + return getComponentAt (p.x, p.y); + } + + /** + * Locates the visible child component that contains the specified position. + * The top-most child component is returned in the case where there is overlap + * in the components. If the containing child component is a Container, + * this method will continue searching for the deepest nested child + * component. Components which are not visible are ignored during the search. + * + * findComponentAt differs from getComponentAt, because it recursively + * searches a Container's children. + * + * @param x - x coordinate + * @param y - y coordinate + * @return null if the component does not contain the position. + * If there is no child component at the requested point and the point is + * within the bounds of the container the container itself is returned. + */ + public Component findComponentAt(int x, int y) + { + synchronized (getTreeLock ()) + { + if (! contains(x, y)) + return null; + + for (int i = 0; i < ncomponents; ++i) + { + // Ignore invisible children... + if (!component[i].isVisible()) + continue; + + int x2 = x - component[i].x; + int y2 = y - component[i].y; + // We don't do the contains() check right away because + // findComponentAt would redundantly do it first thing. + if (component[i] instanceof Container) + { + Container k = (Container) component[i]; + Component r = k.findComponentAt(x2, y2); + if (r != null) + return r; + } + else if (component[i].contains(x2, y2)) + return component[i]; + } + + return this; + } + } + + /** + * Locates the visible child component that contains the specified position. + * The top-most child component is returned in the case where there is overlap + * in the components. If the containing child component is a Container, + * this method will continue searching for the deepest nested child + * component. Components which are not visible are ignored during the search. + * + * findComponentAt differs from getComponentAt, because it recursively + * searches a Container's children. + * + * @param p - the component's location + * @return null if the component does not contain the position. + * If there is no child component at the requested point and the point is + * within the bounds of the container the container itself is returned. + */ + public Component findComponentAt(Point p) + { + return findComponentAt(p.x, p.y); + } + + /** + * Called when this container is added to another container to inform it + * to create its peer. Peers for any child components will also be + * created. + */ + public void addNotify() + { + synchronized (getTreeLock()) + { + super.addNotify(); + addNotifyContainerChildren(); + } + } + + /** + * Called when this container is removed from its parent container to + * inform it to destroy its peer. This causes the peers of all child + * component to be destroyed as well. + */ + public void removeNotify() + { + synchronized (getTreeLock ()) + { + int ncomps = ncomponents; + Component[] comps = component; + for (int i = ncomps - 1; i >= 0; --i) + { + Component comp = comps[i]; + if (comp != null) + comp.removeNotify(); + } + super.removeNotify(); + } + } + + /** + * Tests whether or not the specified component is contained within + * this components subtree. + * + * @param comp The component to test. + * + * @return <code>true</code> if this container is an ancestor of the + * specified component, <code>false</code> otherwise. + */ + public boolean isAncestorOf(Component comp) + { + synchronized (getTreeLock ()) + { + while (true) + { + if (comp == null) + return false; + comp = comp.getParent(); + if (comp == this) + return true; + } + } + } + + /** + * Returns a string representing the state of this container for + * debugging purposes. + * + * @return A string representing the state of this container. + */ + protected String paramString() + { + if (layoutMgr == null) + return super.paramString(); + + CPStringBuilder sb = new CPStringBuilder(); + sb.append(super.paramString()); + sb.append(",layout="); + sb.append(layoutMgr.getClass().getName()); + return sb.toString(); + } + + /** + * Writes a listing of this container to the specified stream starting + * at the specified indentation point. + * + * @param out The <code>PrintStream</code> to write to. + * @param indent The indentation point. + */ + public void list(PrintStream out, int indent) + { + synchronized (getTreeLock ()) + { + super.list(out, indent); + for (int i = 0; i < ncomponents; ++i) + component[i].list(out, indent + 2); + } + } + + /** + * Writes a listing of this container to the specified stream starting + * at the specified indentation point. + * + * @param out The <code>PrintWriter</code> to write to. + * @param indent The indentation point. + */ + public void list(PrintWriter out, int indent) + { + synchronized (getTreeLock ()) + { + super.list(out, indent); + for (int i = 0; i < ncomponents; ++i) + component[i].list(out, indent + 2); + } + } + + /** + * Sets the focus traversal keys for a given traversal operation for this + * Container. + * + * @exception IllegalArgumentException If id is not one of + * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, + * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, + * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, + * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS, + * or if keystrokes contains null, or if any Object in keystrokes is not an + * AWTKeyStroke, or if any keystroke represents a KEY_TYPED event, or if any + * keystroke already maps to another focus traversal operation for this + * Container. + * + * @since 1.4 + */ + public void setFocusTraversalKeys(int id, + Set<? extends AWTKeyStroke> keystrokes) + { + if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && + id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) + throw new IllegalArgumentException (); + + if (keystrokes == null) + { + Container parent = getParent (); + + while (parent != null) + { + if (parent.areFocusTraversalKeysSet (id)) + { + keystrokes = parent.getFocusTraversalKeys (id); + break; + } + parent = parent.getParent (); + } + + if (keystrokes == null) + keystrokes = KeyboardFocusManager.getCurrentKeyboardFocusManager (). + getDefaultFocusTraversalKeys (id); + } + + Set sa; + Set sb; + Set sc; + String name; + switch (id) + { + case KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS: + sa = getFocusTraversalKeys + (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + sb = getFocusTraversalKeys + (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); + sc = getFocusTraversalKeys + (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); + name = "forwardFocusTraversalKeys"; + break; + case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS: + sa = getFocusTraversalKeys + (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + sb = getFocusTraversalKeys + (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); + sc = getFocusTraversalKeys + (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); + name = "backwardFocusTraversalKeys"; + break; + case KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS: + sa = getFocusTraversalKeys + (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + sb = getFocusTraversalKeys + (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + sc = getFocusTraversalKeys + (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); + name = "upCycleFocusTraversalKeys"; + break; + case KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS: + sa = getFocusTraversalKeys + (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + sb = getFocusTraversalKeys + (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + sc = getFocusTraversalKeys + (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); + name = "downCycleFocusTraversalKeys"; + break; + default: + throw new IllegalArgumentException (); + } + + int i = keystrokes.size (); + Iterator iter = keystrokes.iterator (); + + while (--i >= 0) + { + Object o = iter.next (); + if (!(o instanceof AWTKeyStroke) + || sa.contains (o) || sb.contains (o) || sc.contains (o) + || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED) + throw new IllegalArgumentException (); + } + + if (focusTraversalKeys == null) + focusTraversalKeys = new Set[4]; + + keystrokes = + Collections.unmodifiableSet(new HashSet<AWTKeyStroke>(keystrokes)); + firePropertyChange (name, focusTraversalKeys[id], keystrokes); + + focusTraversalKeys[id] = keystrokes; + } + + /** + * Returns the Set of focus traversal keys for a given traversal operation for + * this Container. + * + * @exception IllegalArgumentException If id is not one of + * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, + * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, + * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, + * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS. + * + * @since 1.4 + */ + public Set<AWTKeyStroke> getFocusTraversalKeys (int id) + { + if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && + id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) + throw new IllegalArgumentException (); + + Set s = null; + + if (focusTraversalKeys != null) + s = focusTraversalKeys[id]; + + if (s == null && parent != null) + s = parent.getFocusTraversalKeys (id); + + return s == null ? (KeyboardFocusManager.getCurrentKeyboardFocusManager() + .getDefaultFocusTraversalKeys(id)) : s; + } + + /** + * Returns whether the Set of focus traversal keys for the given focus + * traversal operation has been explicitly defined for this Container. + * If this method returns false, this Container is inheriting the Set from + * an ancestor, or from the current KeyboardFocusManager. + * + * @exception IllegalArgumentException If id is not one of + * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, + * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, + * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, + * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS. + * + * @since 1.4 + */ + public boolean areFocusTraversalKeysSet (int id) + { + if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && + id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) + throw new IllegalArgumentException (); + + return focusTraversalKeys != null && focusTraversalKeys[id] != null; + } + + /** + * Check whether the given Container is the focus cycle root of this + * Container's focus traversal cycle. If this Container is a focus + * cycle root itself, then it will be in two different focus cycles + * -- it's own, and that of its ancestor focus cycle root's. In + * that case, if <code>c</code> is either of those containers, this + * method will return true. + * + * @param c the candidate Container + * + * @return true if c is the focus cycle root of the focus traversal + * cycle to which this Container belongs, false otherwise + * + * @since 1.4 + */ + public boolean isFocusCycleRoot (Container c) + { + if (this == c + && isFocusCycleRoot ()) + return true; + + Container ancestor = getFocusCycleRootAncestor (); + + if (c == ancestor) + return true; + + return false; + } + + /** + * If this Container is a focus cycle root, set the focus traversal + * policy that determines the focus traversal order for its + * children. If non-null, this policy will be inherited by all + * inferior focus cycle roots. If <code>policy</code> is null, this + * Container will inherit its policy from the closest ancestor focus + * cycle root that's had its policy set. + * + * @param policy the new focus traversal policy for this Container or null + * + * @since 1.4 + */ + public void setFocusTraversalPolicy (FocusTraversalPolicy policy) + { + focusTraversalPolicy = policy; + } + + /** + * Return the focus traversal policy that determines the focus + * traversal order for this Container's children. This method + * returns null if this Container is not a focus cycle root. If the + * focus traversal policy has not been set explicitly, then this + * method will return an ancestor focus cycle root's policy instead. + * + * @return this Container's focus traversal policy or null + * + * @since 1.4 + */ + public FocusTraversalPolicy getFocusTraversalPolicy () + { + if (!isFocusCycleRoot ()) + return null; + + if (focusTraversalPolicy == null) + { + Container ancestor = getFocusCycleRootAncestor (); + + if (ancestor != this && ancestor != null) + return ancestor.getFocusTraversalPolicy (); + else + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + return manager.getDefaultFocusTraversalPolicy (); + } + } + else + return focusTraversalPolicy; + } + + /** + * Check whether this Container's focus traversal policy has been + * explicitly set. If it has not, then this Container will inherit + * its focus traversal policy from one of its ancestor focus cycle + * roots. + * + * @return true if focus traversal policy is set, false otherwise + */ + public boolean isFocusTraversalPolicySet () + { + return focusTraversalPolicy == null; + } + + /** + * Set whether or not this Container is the root of a focus + * traversal cycle. This Container's focus traversal policy + * determines the order of focus traversal. Some policies prevent + * the focus from being transferred between two traversal cycles + * until an up or down traversal operation is performed. In that + * case, normal traversal (not up or down) is limited to this + * Container and all of this Container's descendents that are not + * descendents of inferior focus cycle roots. In the default case + * however, ContainerOrderFocusTraversalPolicy is in effect, and it + * supports implicit down-cycle traversal operations. + * + * @param focusCycleRoot true if this is a focus cycle root, false otherwise + * + * @since 1.4 + */ + public void setFocusCycleRoot (boolean focusCycleRoot) + { + this.focusCycleRoot = focusCycleRoot; + } + + /** + * Set to <code>true</code> if this container provides a focus traversal + * policy, <code>false</code> when the root container's focus + * traversal policy should be used. + * + * @return <code>true</code> if this container provides a focus traversal + * policy, <code>false</code> when the root container's focus + * traversal policy should be used + * + * @see #setFocusTraversalPolicyProvider(boolean) + * + * @since 1.5 + */ + public final boolean isFocusTraversalPolicyProvider() + { + return focusTraversalPolicyProvider; + } + + /** + * Set to <code>true</code> if this container provides a focus traversal + * policy, <code>false</code> when the root container's focus + * traversal policy should be used. + * + * @param b <code>true</code> if this container provides a focus traversal + * policy, <code>false</code> when the root container's focus + * traversal policy should be used + * + * @see #isFocusTraversalPolicyProvider() + * + * @since 1.5 + */ + public final void setFocusTraversalPolicyProvider(boolean b) + { + focusTraversalPolicyProvider = b; + } + + /** + * Check whether this Container is a focus cycle root. + * + * @return true if this is a focus cycle root, false otherwise + * + * @since 1.4 + */ + public boolean isFocusCycleRoot () + { + return focusCycleRoot; + } + + /** + * Transfer focus down one focus traversal cycle. If this Container + * is a focus cycle root, then its default component becomes the + * focus owner, and this Container becomes the current focus cycle + * root. No traversal will occur if this Container is not a focus + * cycle root. + * + * @since 1.4 + */ + public void transferFocusDownCycle () + { + if (isFocusCycleRoot()) + { + KeyboardFocusManager fm = + KeyboardFocusManager.getCurrentKeyboardFocusManager(); + fm.setGlobalCurrentFocusCycleRoot(this); + FocusTraversalPolicy policy = getFocusTraversalPolicy(); + Component defaultComponent = policy.getDefaultComponent(this); + if (defaultComponent != null) + defaultComponent.requestFocus(); + } + } + + /** + * Sets the ComponentOrientation property of this container and all components + * contained within it. + * + * @exception NullPointerException If orientation is null + * + * @since 1.4 + */ + public void applyComponentOrientation (ComponentOrientation orientation) + { + if (orientation == null) + throw new NullPointerException(); + + setComponentOrientation(orientation); + for (int i = 0; i < ncomponents; i++) + { + if (component[i] instanceof Container) + ((Container) component[i]).applyComponentOrientation(orientation); + else + component[i].setComponentOrientation(orientation); + } + } + + public void addPropertyChangeListener (PropertyChangeListener listener) + { + // TODO: Why is this overridden? + super.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener (String propertyName, + PropertyChangeListener listener) + { + // TODO: Why is this overridden? + super.addPropertyChangeListener(propertyName, listener); + } + + + /** + * Sets the Z ordering for the component <code>comp</code> to + * <code>index</code>. Components with lower Z order paint above components + * with higher Z order. + * + * @param comp the component for which to change the Z ordering + * @param index the index to set + * + * @throws NullPointerException if <code>comp == null</code> + * @throws IllegalArgumentException if comp is an ancestor of this container + * @throws IllegalArgumentException if <code>index</code> is not in + * <code>[0, getComponentCount()]</code> for moving between + * containers or <code>[0, getComponentCount() - 1]</code> for moving + * inside this container + * @throws IllegalArgumentException if <code>comp == this</code> + * @throws IllegalArgumentException if <code>comp</code> is a + * <code>Window</code> + * + * @see #getComponentZOrder(Component) + * + * @since 1.5 + */ + public final void setComponentZOrder(Component comp, int index) + { + if (comp == null) + throw new NullPointerException("comp must not be null"); + if (comp instanceof Container && ((Container) comp).isAncestorOf(this)) + throw new IllegalArgumentException("comp must not be an ancestor of " + + "this"); + if (comp instanceof Window) + throw new IllegalArgumentException("comp must not be a Window"); + + if (comp == this) + throw new IllegalArgumentException("cannot add component to itself"); + + synchronized (getTreeLock()) + { + // FIXME: Implement reparenting. + if ( comp.getParent() != this) + throw new AssertionError("Reparenting is not implemented yet"); + else + { + // Find current component index. + int currentIndex = getComponentZOrder(comp); + if (currentIndex < index) + { + System.arraycopy(component, currentIndex + 1, component, + currentIndex, index - currentIndex); + } + else + { + System.arraycopy(component, index, component, index + 1, + currentIndex - index); + } + component[index] = comp; + } + } + } + + /** + * Returns the Z ordering index of <code>comp</code>. If <code>comp</code> + * is not a child component of this Container, this returns <code>-1</code>. + * + * @param comp the component for which to query the Z ordering + * + * @return the Z ordering index of <code>comp</code> or <code>-1</code> if + * <code>comp</code> is not a child of this Container + * + * @see #setComponentZOrder(Component, int) + * + * @since 1.5 + */ + public final int getComponentZOrder(Component comp) + { + synchronized (getTreeLock()) + { + int index = -1; + if (component != null) + { + for (int i = 0; i < ncomponents; i++) + { + if (component[i] == comp) + { + index = i; + break; + } + } + } + return index; + } + } + + // Hidden helper methods. + + /** + * Perform a graphics operation on the children of this container. + * For each applicable child, the visitChild() method will be called + * to perform the graphics operation. + * + * @param gfx The graphics object that will be used to derive new + * graphics objects for the children. + * + * @param visitor Object encapsulating the graphics operation that + * should be performed. + * + * @param lightweightOnly If true, only lightweight components will + * be visited. + */ + private void visitChildren(Graphics gfx, GfxVisitor visitor, + boolean lightweightOnly) + { + synchronized (getTreeLock()) + { + for (int i = ncomponents - 1; i >= 0; --i) + { + Component comp = component[i]; + boolean applicable = comp.isVisible() + && (comp.isLightweight() || ! lightweightOnly); + + if (applicable) + visitChild(gfx, visitor, comp); + } + } + } + + /** + * Perform a graphics operation on a child. A translated and clipped + * graphics object will be created, and the visit() method of the + * visitor will be called to perform the operation. + * + * @param gfx The graphics object that will be used to derive new + * graphics objects for the child. + * + * @param visitor Object encapsulating the graphics operation that + * should be performed. + * + * @param comp The child component that should be visited. + */ + private void visitChild(Graphics gfx, GfxVisitor visitor, + Component comp) + { + Rectangle bounds = comp.getBounds(); + + if(!gfx.hitClip(bounds.x,bounds.y, bounds.width, bounds.height)) + return; + Graphics g2 = gfx.create(bounds.x, bounds.y, bounds.width, + bounds.height); + try + { + g2.setFont(comp.getFont()); + visitor.visit(comp, g2); + } + finally + { + g2.dispose(); + } + } + + /** + * Overridden to dispatch events to lightweight descendents. + * + * @param e the event to dispatch. + */ + void dispatchEventImpl(AWTEvent e) + { + LightweightDispatcher dispatcher = LightweightDispatcher.getInstance(); + if (! isLightweight() && dispatcher.dispatchEvent(e)) + { + // Some lightweight descendent got this event dispatched. Consume + // it and let the peer handle it. + e.consume(); + ComponentPeer p = peer; + if (p != null) + p.handleEvent(e); + } + else + { + super.dispatchEventImpl(e); + } + } + + /** + * This is called by the lightweight dispatcher to avoid recursivly + * calling into the lightweight dispatcher. + * + * @param e the event to dispatch + * + * @see LightweightDispatcher#redispatch(MouseEvent, Component, int) + */ + void dispatchNoLightweight(AWTEvent e) + { + super.dispatchEventImpl(e); + } + + /** + * Tests if this container has an interest in the given event id. + * + * @param eventId The event id to check. + * + * @return <code>true</code> if a listener for the event id exists or + * if the eventMask is set for the event id. + * + * @see java.awt.Component#eventTypeEnabled(int) + */ + boolean eventTypeEnabled(int eventId) + { + if(eventId <= ContainerEvent.CONTAINER_LAST + && eventId >= ContainerEvent.CONTAINER_FIRST) + return containerListener != null + || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0; + else + return super.eventTypeEnabled(eventId); + } + + // This is used to implement Component.transferFocus. + Component findNextFocusComponent(Component child) + { + synchronized (getTreeLock ()) + { + int start, end; + if (child != null) + { + for (start = 0; start < ncomponents; ++start) + { + if (component[start] == child) + break; + } + end = start; + // This special case lets us be sure to terminate. + if (end == 0) + end = ncomponents; + ++start; + } + else + { + start = 0; + end = ncomponents; + } + + for (int j = start; j != end; ++j) + { + if (j >= ncomponents) + { + // The JCL says that we should wrap here. However, that + // seems wrong. To me it seems that focus order should be + // global within in given window. So instead if we reach + // the end we try to look in our parent, if we have one. + if (parent != null) + return parent.findNextFocusComponent(this); + j -= ncomponents; + } + if (component[j] instanceof Container) + { + Component c = component[j]; + c = c.findNextFocusComponent(null); + if (c != null) + return c; + } + else if (component[j].isFocusTraversable()) + return component[j]; + } + + return null; + } + } + + /** + * Fires hierarchy events to the children of this container and this + * container itself. This overrides {@link Component#fireHierarchyEvent} + * in order to forward this event to all children. + */ + void fireHierarchyEvent(int id, Component changed, Container parent, + long flags) + { + // Only propagate event if there is actually a listener waiting for it. + if ((id == HierarchyEvent.HIERARCHY_CHANGED && numHierarchyListeners > 0) + || ((id == HierarchyEvent.ANCESTOR_MOVED + || id == HierarchyEvent.ANCESTOR_RESIZED) + && numHierarchyBoundsListeners > 0)) + { + for (int i = 0; i < ncomponents; i++) + component[i].fireHierarchyEvent(id, changed, parent, flags); + super.fireHierarchyEvent(id, changed, parent, flags); + } + } + + /** + * Adjusts the number of hierarchy listeners of this container and all of + * its parents. This is called by the add/remove listener methods and + * structure changing methods in Container. + * + * @param type the type, either {@link AWTEvent#HIERARCHY_BOUNDS_EVENT_MASK} + * or {@link AWTEvent#HIERARCHY_EVENT_MASK} + * @param delta the number of listeners added or removed + */ + void updateHierarchyListenerCount(long type, int delta) + { + if (type == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) + numHierarchyBoundsListeners += delta; + else if (type == AWTEvent.HIERARCHY_EVENT_MASK) + numHierarchyListeners += delta; + else + assert false : "Should not reach here"; + + if (parent != null) + parent.updateHierarchyListenerCount(type, delta); + } + + /** + * Notifies interested listeners about resizing or moving the container. + * This performs the super behaviour (sending component events) and + * additionally notifies any hierarchy bounds listeners on child components. + * + * @param resized true if the component has been resized, false otherwise + * @param moved true if the component has been moved, false otherwise + */ + void notifyReshape(boolean resized, boolean moved) + { + // Notify component listeners. + super.notifyReshape(resized, moved); + + if (ncomponents > 0) + { + // Notify hierarchy bounds listeners. + if (resized) + { + for (int i = 0; i < getComponentCount(); i++) + { + Component child = getComponent(i); + child.fireHierarchyEvent(HierarchyEvent.ANCESTOR_RESIZED, + this, parent, 0); + } + } + if (moved) + { + for (int i = 0; i < getComponentCount(); i++) + { + Component child = getComponent(i); + child.fireHierarchyEvent(HierarchyEvent.ANCESTOR_MOVED, + this, parent, 0); + } + } + } + } + + private void addNotifyContainerChildren() + { + synchronized (getTreeLock ()) + { + for (int i = ncomponents; --i >= 0; ) + { + component[i].addNotify(); + } + } + } + + /** + * Deserialize this Container: + * <ol> + * <li>Read from the stream the default serializable fields.</li> + * <li>Read a list of serializable ContainerListeners as optional + * data. If the list is null, no listeners will be registered.</li> + * <li>Read this Container's FocusTraversalPolicy as optional data. + * If this is null, then this Container will use a + * DefaultFocusTraversalPolicy.</li> + * </ol> + * + * @param s the stream to read from + * @throws ClassNotFoundException if deserialization fails + * @throws IOException if the stream fails + */ + private void readObject (ObjectInputStream s) + throws ClassNotFoundException, IOException + { + s.defaultReadObject (); + String key = (String) s.readObject (); + while (key != null) + { + Object object = s.readObject (); + if ("containerL".equals (key)) + addContainerListener((ContainerListener) object); + // FIXME: under what key is the focus traversal policy stored? + else if ("focusTraversalPolicy".equals (key)) + setFocusTraversalPolicy ((FocusTraversalPolicy) object); + + key = (String) s.readObject(); + } + } + + /** + * Serialize this Container: + * <ol> + * <li>Write to the stream the default serializable fields.</li> + * <li>Write the list of serializable ContainerListeners as optional + * data.</li> + * <li>Write this Container's FocusTraversalPolicy as optional data.</li> + * </ol> + * + * @param s the stream to write to + * @throws IOException if the stream fails + */ + private void writeObject (ObjectOutputStream s) throws IOException + { + s.defaultWriteObject (); + AWTEventMulticaster.save (s, "containerL", containerListener); + if (focusTraversalPolicy instanceof Serializable) + s.writeObject (focusTraversalPolicy); + else + s.writeObject (null); + } + + // Nested classes. + + /* The following classes are used in concert with the + visitChildren() method to implement all the graphics operations + that requires traversal of the containment hierarchy. */ + + abstract static class GfxVisitor + { + public abstract void visit(Component c, Graphics gfx); + } + + static class GfxPaintVisitor extends GfxVisitor + { + public static final GfxVisitor INSTANCE = new GfxPaintVisitor(); + + public void visit(Component c, Graphics gfx) + { + c.paint(gfx); + } + } + + static class GfxPrintVisitor extends GfxVisitor + { + public static final GfxVisitor INSTANCE = new GfxPrintVisitor(); + + public void visit(Component c, Graphics gfx) + { + c.print(gfx); + } + } + + static class GfxPaintAllVisitor extends GfxVisitor + { + public static final GfxVisitor INSTANCE = new GfxPaintAllVisitor(); + + public void visit(Component c, Graphics gfx) + { + c.paintAll(gfx); + } + } + + static class GfxPrintAllVisitor extends GfxVisitor + { + public static final GfxVisitor INSTANCE = new GfxPrintAllVisitor(); + + public void visit(Component c, Graphics gfx) + { + c.printAll(gfx); + } + } + + /** + * This class provides accessibility support for subclasses of container. + * + * @author Eric Blake (ebb9@email.byu.edu) + * + * @since 1.3 + */ + protected class AccessibleAWTContainer extends AccessibleAWTComponent + { + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = 5081320404842566097L; + + /** + * The handler to fire PropertyChange when children are added or removed. + * + * @serial the handler for property changes + */ + protected ContainerListener accessibleContainerHandler + = new AccessibleContainerHandler(); + + /** + * The default constructor. + */ + protected AccessibleAWTContainer() + { + Container.this.addContainerListener(accessibleContainerHandler); + } + + /** + * Return the number of accessible children of the containing accessible + * object (at most the total number of its children). + * + * @return the number of accessible children + */ + public int getAccessibleChildrenCount() + { + synchronized (getTreeLock ()) + { + int count = 0; + int i = component == null ? 0 : component.length; + while (--i >= 0) + if (component[i] instanceof Accessible) + count++; + return count; + } + } + + /** + * Return the nth accessible child of the containing accessible object. + * + * @param i the child to grab, zero-based + * @return the accessible child, or null + */ + public Accessible getAccessibleChild(int i) + { + synchronized (getTreeLock ()) + { + if (component == null) + return null; + int index = -1; + while (i >= 0 && ++index < component.length) + if (component[index] instanceof Accessible) + i--; + if (i < 0) + return (Accessible) component[index]; + return null; + } + } + + /** + * Return the accessible child located at point (in the parent's + * coordinates), if one exists. + * + * @param p the point to look at + * + * @return an accessible object at that point, or null + * + * @throws NullPointerException if p is null + */ + public Accessible getAccessibleAt(Point p) + { + Component c = getComponentAt(p.x, p.y); + return c != Container.this && c instanceof Accessible ? (Accessible) c + : null; + } + + /** + * This class fires a <code>PropertyChange</code> listener, if registered, + * when children are added or removed from the enclosing accessible object. + * + * @author Eric Blake (ebb9@email.byu.edu) + * + * @since 1.3 + */ + protected class AccessibleContainerHandler implements ContainerListener + { + /** + * Default constructor. + */ + protected AccessibleContainerHandler() + { + // Nothing to do here. + } + + /** + * Fired when a component is added; forwards to the PropertyChange + * listener. + * + * @param e the container event for adding + */ + public void componentAdded(ContainerEvent e) + { + AccessibleAWTContainer.this.firePropertyChange + (ACCESSIBLE_CHILD_PROPERTY, null, e.getChild()); + } + + /** + * Fired when a component is removed; forwards to the PropertyChange + * listener. + * + * @param e the container event for removing + */ + public void componentRemoved(ContainerEvent e) + { + AccessibleAWTContainer.this.firePropertyChange + (ACCESSIBLE_CHILD_PROPERTY, e.getChild(), null); + } + } // class AccessibleContainerHandler + } // class AccessibleAWTContainer +} // class Container diff --git a/libjava/classpath/java/awt/ContainerOrderFocusTraversalPolicy.java b/libjava/classpath/java/awt/ContainerOrderFocusTraversalPolicy.java new file mode 100644 index 000000000..3fa437db7 --- /dev/null +++ b/libjava/classpath/java/awt/ContainerOrderFocusTraversalPolicy.java @@ -0,0 +1,482 @@ +/* ContainerOrderFocusTraversalPolicy.java -- + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.io.Serializable; + +/** + * ContainerOrderFocusTraversalPolicy defines a focus traversal order + * based on the order in which Components were packed in a Container. + * This policy performs a pre-order traversal of the Component + * hierarchy starting from a given focus cycle root. Portions of the + * hierarchy that are not visible and displayable are skipped. + * + * By default, this policy transfers focus down-cycle implicitly. + * That is, if a forward traversal is requested on a focus cycle root + * and the focus cycle root has focusable children, the focus will + * automatically be transfered down to the lower focus cycle. + * + * The default implementation of accept accepts only Components that + * are visible, displayable, enabled and focusable. Derived classes + * can override these acceptance criteria by overriding accept. + * + * @author Michael Koch + * @author Thomas Fitzsimmons (fitzsim@redhat.com) + * @since 1.4 + */ +public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy + implements Serializable +{ + /** + * Compatible to JDK 1.4+ + */ + static final long serialVersionUID = 486933713763926351L; + + /** + * True if implicit down cycling is enabled. + */ + private boolean implicitDownCycleTraversal = true; + + /** + * Creates the <code>ContainerOrderFocusTraversalPolicy</code> object. + */ + public ContainerOrderFocusTraversalPolicy () + { + // Nothing to do here + } + + /** + * Returns the Component that should receive the focus after current. + * root must be a focus cycle root of current. + * + * @param root a focus cycle root of current + * @param current a (possibly indirect) child of root, or root itself + * + * @return the next Component in the focus traversal order for root, + * or null if no acceptable Component exists. + * + * @exception IllegalArgumentException If root is not a focus cycle + * root of current, or if either root or current is null. + */ + public Component getComponentAfter (Container root, Component current) + { + if (root == null) + throw new IllegalArgumentException ("focus cycle root is null"); + if (current == null) + throw new IllegalArgumentException ("current component is null"); + + if (!root.isFocusCycleRoot ()) + throw new IllegalArgumentException ("root is not a focus cycle root"); + + Container ancestor = current.getFocusCycleRootAncestor (); + Container prevAncestor = ancestor; + while (ancestor != root) + { + ancestor = current.getFocusCycleRootAncestor (); + if (ancestor == prevAncestor) + { + // We've reached the top focus cycle root ancestor. Check + // if it is root. + if (ancestor == null) + ancestor = root; + else if (ancestor != root) + throw new IllegalArgumentException ("the given container is not" + + " a focus cycle root of the" + + " current component"); + else + break; + } + prevAncestor = ancestor; + } + + // FIXME: is this the right thing to do here? It moves the context + // for traversal up one focus traversal cycle. We'll need a test + // for this. + if ((Component) root == current) + root = current.getFocusCycleRootAncestor (); + + // Check if we've reached the top of the component hierarchy. If + // so then we want to loop around to the first component in the + // focus traversal cycle. + if (current instanceof Window) + return getFirstComponent ((Container) current); + + Container parent = current.getParent (); + synchronized (parent.getTreeLock ()) + { + Component[] components = parent.getComponents (); + int componentIndex = 0; + int numComponents = parent.getComponentCount (); + + // Find component's index. + for (int i = 0; i < numComponents; i++) + { + if (components[i].equals(current)) + componentIndex = i; + } + + // Search forward for the next acceptable component. + // Search through all components at least one time + // i.e. start at componentIndex + 1 --> nComponents -1 --> 0 ---> componentIndex + int i = componentIndex + 1; + int end = numComponents - 1; + Component next = getNextAvailableComponent(components, i, end); + if (next != null) + return next; + + // Now check remainder of components from 0 to componentIndex + i = 0; + end = componentIndex; + next = getNextAvailableComponent(components, i, end); + if (next != null) + return next; + + // No focusable components after current in its Container. So go + // to the next Component after current's Container (parent). + Component result = getComponentAfter (root, parent); + return result; + } + } + + /** + * Gets the next available component in the array between the given range. + * + * @param components - the array of components. + * @param start - where to start + * @param end - where to end + * @return next component if found + */ + private Component getNextAvailableComponent(Component[] components, int start, int end) + { + while (start <= end) + { + Component c = components[start]; + + if (c.visible && c.isDisplayable() && c.enabled && c.focusable) + return c; + + if (c instanceof Container) + { + Component result = getFirstComponent((Container) c); + + if (result != null && implicitDownCycleTraversal && result.visible + && result.isDisplayable() && result.enabled && result.focusable) + return result; + } + start++; + } + + return null; + } + + /** + * Gets the previous available component in the array between the given range. + * + * @param components - the array of components. + * @param start - where to start + * @param end - where to end + * @return previous component if found + */ + Component getPrevAvailableComponent(Component[] components, int start, int end) + { + while (start >= end) + { + Component c = components[start]; + if (c.visible && c.isDisplayable() && c.enabled && c.focusable) + return c; + + if (c instanceof Container) + { + Component result = getLastComponent((Container) c); + + if (result != null + && (result.visible && result.isDisplayable() && result.enabled && result.focusable)) + return result; + } + start--; + } + return null; + } + + /** + * Returns the Component that should receive the focus before + * <code>current</code>. <code>root</code> must be a focus cycle root of + * current. + * + * @param root a focus cycle root of current + * @param current a (possibly indirect) child of root, or root itself + * @return the previous Component in the focus traversal order for root, or + * null if no acceptable Component exists. + * @exception IllegalArgumentException If root is not a focus cycle root of + * current, or if either root or current is null. + */ + public Component getComponentBefore (Container root, Component current) + { + if (root == null) + throw new IllegalArgumentException ("focus cycle root is null"); + if (current == null) + throw new IllegalArgumentException ("current component is null"); + + if (!root.isFocusCycleRoot ()) + throw new IllegalArgumentException ("root is not a focus cycle root"); + + Container ancestor = current.getFocusCycleRootAncestor (); + Container prevAncestor = ancestor; + while (ancestor != root) + { + ancestor = current.getFocusCycleRootAncestor (); + if (ancestor == prevAncestor) + { + // We've reached the top focus cycle root ancestor. Check + // if it is root. + if (ancestor == null) + ancestor = root; + else if (ancestor != root) + throw new IllegalArgumentException ("the given container is not" + + " a focus cycle root of the" + + " current component"); + else + break; + } + prevAncestor = ancestor; + } + + // FIXME: is this the right thing to do here? It moves the context + // for traversal up one focus traversal cycle. We'll need a test + // for this. + if ((Component) root == current) + root = current.getFocusCycleRootAncestor (); + + // Check if we've reached the top of the component hierarchy. If + // so then we want to loop around to the last component in the + // focus traversal cycle. + if (current instanceof Window) + return getLastComponent ((Container) current); + + Container parent = current.getParent (); + + synchronized (parent.getTreeLock ()) + { + Component[] components = parent.getComponents (); + int componentIndex = 0; + int numComponents = parent.getComponentCount (); + + // Find component's index. + for (int i = 0; i < numComponents; i++) + { + if (components[i] == current) + componentIndex = i; + } + + // Search through all components at least one time + // i.e. start at componentIndex - 1 --> 0 --> numComponents -1 ---> componentIndex + int i = componentIndex - 1; + int end = 0; + Component prev = getPrevAvailableComponent(components, i, end); + if (prev != null) + return prev; + + // Now check remainder of components + i = numComponents -1; + end = componentIndex; + prev = getPrevAvailableComponent(components, i, end); + if (prev != null) + return prev; + + // No focusable components before current in its Container. So go + // to the previous Component before current's Container (parent). + Component result = getComponentBefore (root, parent); + + return result; + } + } + + /** + * Returns the first Component of root that should receive the focus. + * + * @param root a focus cycle root + * + * @return the first Component in the focus traversal order for + * root, or null if no acceptable Component exists. + * + * @exception IllegalArgumentException If root is null. + */ + public Component getFirstComponent(Container root) + { + if (root == null) + throw new IllegalArgumentException (); + + if (!root.isVisible () + || !root.isDisplayable ()) + return null; + + if (accept(root)) + return root; + + int ncomponents = root.getComponentCount(); + for (int i = 0; i < ncomponents; i++) + { + Component component = root.getComponent(i); + if (component instanceof Container + && !((Container) component).isFocusCycleRoot()) + { + Component first = null; + Container cont = (Container) component; + if (cont.isFocusTraversalPolicyProvider()) + { + FocusTraversalPolicy childPol = cont.getFocusTraversalPolicy(); + first = childPol.getFirstComponent(cont); + } + else + first = getFirstComponent(cont); + if (first != null) + return first; + } + else if (accept(component)) + return component; + } + + return null; + } + + /** + * Returns the last Component of root that should receive the focus. + * + * @param root a focus cycle root + * + * @return the last Component in the focus traversal order for + * root, or null if no acceptable Component exists. + * + * @exception IllegalArgumentException If root is null. + */ + public Component getLastComponent (Container root) + { + if (root == null) + throw new IllegalArgumentException (); + + if (!root.isVisible () + || !root.isDisplayable ()) + return null; + + if (root.visible && root.isDisplayable() && root.enabled + && root.focusable) + return root; + + Component[] componentArray = root.getComponents (); + + for (int i = componentArray.length - 1; i >= 0; i--) + { + Component component = componentArray [i]; + + if (component.visible && component.isDisplayable() && component.enabled + && component.focusable) + return component; + + if (component instanceof Container) + { + Component result = getLastComponent ((Container) component); + + if (result != null && + result.visible && result.isDisplayable() && result.enabled + && result.focusable) + return result; + } + } + + return null; + } + + /** + * Returns the default Component of root that should receive the focus. + * + * @param root a focus cycle root + * + * @return the default Component in the focus traversal order for + * root, or null if no acceptable Component exists. + * + * @exception IllegalArgumentException If root is null. + */ + public Component getDefaultComponent (Container root) + { + return getFirstComponent (root); + } + + /** + * Set whether or not implicit down cycling is enabled. If it is, + * then initiating a forward focus traversal operation onto a focus + * cycle root, the focus will be implicitly transferred into the + * root container's focus cycle. + * + * @param value the setting for implicit down cycling + */ + public void setImplicitDownCycleTraversal (boolean value) + { + implicitDownCycleTraversal = value; + } + + /** + * Check whether or not implicit down cycling is enabled. If it is, + * then initiating a forward focus traversal operation onto a focus + * cycle root, the focus will be implicitly transferred into the + * root container's focus cycle. + * + * @return true if the focus will be transferred down-cycle + * implicitly + */ + public boolean getImplicitDownCycleTraversal () + { + return implicitDownCycleTraversal; + } + + /** + * Check whether the given Component is an acceptable target for the + * keyboard input focus. + * + * @param current the Component to check + * + * @return true if current is acceptable, false otherwise + */ + protected boolean accept (Component current) + { + return (current.visible + && current.isDisplayable () + && current.enabled + && current.focusable); + } +} diff --git a/libjava/classpath/java/awt/Cursor.java b/libjava/classpath/java/awt/Cursor.java new file mode 100644 index 000000000..69d0e87f5 --- /dev/null +++ b/libjava/classpath/java/awt/Cursor.java @@ -0,0 +1,239 @@ +/* Copyright (C) 1999, 2000, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +/** + * This class represents various predefined cursor types. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class Cursor implements java.io.Serializable +{ + static final long serialVersionUID = 8028237497568985504L; + + /** + * Constant for the system default cursor type + */ + public static final int DEFAULT_CURSOR = 0; + + /** + * Constant for a cross-hair cursor. + */ + public static final int CROSSHAIR_CURSOR = 1; + + /** + * Constant for a cursor over a text field. + */ + public static final int TEXT_CURSOR = 2; + + /** + * Constant for a cursor to display while waiting for an action to complete. + */ + public static final int WAIT_CURSOR = 3; + + /** + * Cursor used over SW corner of window decorations. + */ + public static final int SW_RESIZE_CURSOR = 4; + + /** + * Cursor used over SE corner of window decorations. + */ + public static final int SE_RESIZE_CURSOR = 5; + + /** + * Cursor used over NW corner of window decorations. + */ + public static final int NW_RESIZE_CURSOR = 6; + + /** + * Cursor used over NE corner of window decorations. + */ + public static final int NE_RESIZE_CURSOR = 7; + + /** + * Cursor used over N edge of window decorations. + */ + public static final int N_RESIZE_CURSOR = 8; + + /** + * Cursor used over S edge of window decorations. + */ + public static final int S_RESIZE_CURSOR = 9; + + /** + * Cursor used over W edge of window decorations. + */ + public static final int W_RESIZE_CURSOR = 10; + + /** + * Cursor used over E edge of window decorations. + */ + public static final int E_RESIZE_CURSOR = 11; + + /** + * Constant for a hand cursor. + */ + public static final int HAND_CURSOR = 12; + + /** + * Constant for a cursor used during window move operations. + */ + public static final int MOVE_CURSOR = 13; + + private static String[] NAMES = { "Default Cursor", "Crosshair Cursor", + "Text Cursor", "Wait Cursor", + "Southwest Resize Cursor", + "Southeast Resize Cursor", + "Northwest Resize Cursor", + "Northeast Resize Cursor", + "North Resize Cursor", "South Resize Cursor", + "West Resize Cursor", "East Resize Cursor", + "Hand Cursor", "Move Cursor" }; + + public static final int CUSTOM_CURSOR = 0xFFFFFFFF; + + private static final int PREDEFINED_COUNT = 14; + + protected static Cursor[] predefined = new Cursor[PREDEFINED_COUNT]; + protected String name; + + /** + * @serial The numeric id of this cursor. + */ + int type; + + /** + * Initializes a new instance of <code>Cursor</code> with the specified + * type. + * + * @param type The cursor type. + * + * @exception IllegalArgumentException If the specified cursor type is invalid + */ + public Cursor(int type) + { + if (type < 0 || type >= PREDEFINED_COUNT) + throw new IllegalArgumentException ("invalid cursor " + type); + + this.type = type; + + name = NAMES[type]; + + // FIXME: lookup? + } + + /** This constructor is used internally only. + * Application code should call Toolkit.createCustomCursor(). + */ + protected Cursor(String name) + { + this.name = name; + this.type = CUSTOM_CURSOR; + } + + /** + * Returns an instance of <code>Cursor</code> for one of the specified + * predetermined types. + * + * @param type The type contant from this class. + * + * @return The requested predefined cursor. + * + * @exception IllegalArgumentException If the constant is not one of the + * predefined cursor type constants from this class. + */ + public static Cursor getPredefinedCursor(int type) + { + if (type < 0 || type >= PREDEFINED_COUNT) + throw new IllegalArgumentException ("invalid cursor " + type); + if (predefined[type] == null) + predefined[type] = new Cursor(type); + return predefined[type]; + } + + /** + * Retrieves the system specific custom Cursor named Cursor names are, + * for example: "Invalid.16x16". + * + * @exception AWTException + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ + public static Cursor getSystemCustomCursor(String name) + throws AWTException + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException (); + + // FIXME + return null; + } + + /** + * Returns an instance of the system default cursor type. + * + * @return The system default cursor. + */ + public static Cursor getDefaultCursor() + { + return getPredefinedCursor(DEFAULT_CURSOR); + } + + /** + * Returns the numeric type identifier for this cursor. + * + * @return The cursor id. + */ + public int getType() + { + return type; + } + + public String getName() + { + return name; + } + + public String toString() + { + return (this.getClass() + + "[type=" + getType() + + ",name=" + getName() + "]"); + } +} diff --git a/libjava/classpath/java/awt/DefaultFocusTraversalPolicy.java b/libjava/classpath/java/awt/DefaultFocusTraversalPolicy.java new file mode 100644 index 000000000..3f017c5a5 --- /dev/null +++ b/libjava/classpath/java/awt/DefaultFocusTraversalPolicy.java @@ -0,0 +1,111 @@ +/* DefaultFocusTraversalPolicy.java -- + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +/** + * DefaultFocusTraversalPolicy is the default focus traversal policy + * used by Containers. + * + * This policy sharpens ContainerOrderFocusTraversalPolicy's + * acceptance criteria, to reject those Components that have + * unfocusable peers. Despite this extra strictness, this policy will + * always accept a Component that has explicitly been set focusable by + * any means. + * + * This AWT implementation assumes that the peers of the following + * Components are not focusable: Canvas, Panel, Label, ScrollPane, + * Scrollbar, Window, and any lightweight Component. + * + * A Component's focusability is independent of the focusability of + * its peer. + * + * @author Thomas Fitzsimmons (fitzsim@redhat.com) + * @since 1.4 + */ +public class DefaultFocusTraversalPolicy + extends ContainerOrderFocusTraversalPolicy +{ + private static final long serialVersionUID = 8876966522510157497L; + + /** + * Construct a default focus traversal policy. + */ + public DefaultFocusTraversalPolicy () + { + } + + /** + * Check whether a given Component would be acceptable as a focus + * owner. The Component must be displayable, visible and enabled to + * be acceptable. If the Component's focus traversability has been + * overridden, by overriding Component.isFocusTraversable or + * Component.isFocusable, or by calling Component.setFocusable, then + * the Component will be accepted if it is focusable. If the + * Component uses the default focus traversable behaviour, then + * <code>comp</code> will always be rejected if it is a Canvas, + * Panel, Label, ScrollPane, Scrollbar, Window or lightweight + * Component. + * + * @param comp the Component to check + * + * @return true if the Component is an acceptable target for + * keyboard input focus, false otherwise + */ + protected boolean accept (Component comp) + { + if (comp.visible + && comp.isDisplayable () + && comp.enabled) + { + if (comp.isFocusTraversableOverridden != 0 + && (comp.isFocusTraversable () || comp.isFocusable())) + return true; + + if (!(comp instanceof Canvas + || comp instanceof Panel + || comp instanceof Label + || comp instanceof ScrollPane + || comp instanceof Scrollbar + || comp instanceof Window + || comp.isLightweight ())) + return true; + } + return false; + } +} diff --git a/libjava/classpath/java/awt/DefaultKeyboardFocusManager.java b/libjava/classpath/java/awt/DefaultKeyboardFocusManager.java new file mode 100644 index 000000000..f62e6e53e --- /dev/null +++ b/libjava/classpath/java/awt/DefaultKeyboardFocusManager.java @@ -0,0 +1,566 @@ +/* DefaultKeyboardFocusManager.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.ActionEvent; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.awt.event.WindowEvent; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +// FIXME: finish documentation +public class DefaultKeyboardFocusManager extends KeyboardFocusManager +{ + /** + * This class models a request to delay the dispatch of events that + * arrive after a certain time, until a certain component becomes + * the focus owner. + */ + private class EventDelayRequest implements Comparable + { + /** A {@link java.util.List} of {@link java.awt.event.KeyEvent}s + that are being delayed, pending this request's {@link + Component} receiving the keyboard focus. */ + private LinkedList enqueuedKeyEvents = new LinkedList (); + + /** An event timestamp. All events that arrive after this time + should be queued in the {@link #enqueuedKeyEvents} {@link + java.util.List}. */ + public long timestamp; + /** When this {@link Component} becomes focused, all events + between this EventDelayRequest and the next one in will be + dispatched from {@link #enqueuedKeyEvents}. */ + public Component focusedComp; + + /** + * Construct a new EventDelayRequest. + * + * @param timestamp events that arrive after this time will be + * delayed + * @param focusedComp the Component that needs to receive focus + * before events are dispatched + */ + public EventDelayRequest (long timestamp, Component focusedComp) + { + this.timestamp = timestamp; + this.focusedComp = focusedComp; + } + + public int compareTo (Object o) + { + if (!(o instanceof EventDelayRequest)) + throw new ClassCastException (); + + EventDelayRequest request = (EventDelayRequest) o; + + if (request.timestamp < timestamp) + return -1; + else if (request.timestamp == timestamp) + return 0; + else + return 1; + } + + public boolean equals (Object o) + { + if (!(o instanceof EventDelayRequest) || o == null) + return false; + + EventDelayRequest request = (EventDelayRequest) o; + + return (request.timestamp == timestamp + && request.focusedComp == focusedComp); + } + + public void enqueueEvent (KeyEvent e) + { + KeyEvent last = (KeyEvent) enqueuedKeyEvents.getLast (); + if (last != null && e.getWhen () < last.getWhen ()) + throw new RuntimeException ("KeyEvents enqueued out-of-order"); + + if (e.getWhen () <= timestamp) + throw new RuntimeException ("KeyEvents enqueued before starting timestamp"); + + enqueuedKeyEvents.add (e); + } + + public void dispatchEvents () + { + int size = enqueuedKeyEvents.size (); + for (int i = 0; i < size; i++) + { + KeyEvent e = (KeyEvent) enqueuedKeyEvents.remove (0); + dispatchKeyEvent (e); + } + } + + public void discardEvents () + { + enqueuedKeyEvents.clear (); + } + } + + /** + * This flag indicates for which focus traversal key release event we + * possibly wait, before letting any more KEY_TYPED events through. + */ + private AWTKeyStroke waitForKeyStroke = null; + + /** The {@link java.util.SortedSet} of current + * {@link EventDelayRequest}s. */ + private SortedSet delayRequests = new TreeSet (); + + public DefaultKeyboardFocusManager () + { + } + + public boolean dispatchEvent (AWTEvent e) + { + if (e instanceof WindowEvent) + { + Window target = (Window) e.getSource (); + + if (e.id == WindowEvent.WINDOW_ACTIVATED) + setGlobalActiveWindow (target); + else if (e.id == WindowEvent.WINDOW_GAINED_FOCUS) + { + setGlobalFocusedWindow (target); + FocusTraversalPolicy p = target.getFocusTraversalPolicy(); + Component toFocus = p.getInitialComponent(target); + if (toFocus != null) + toFocus.requestFocusInWindow(); + } + else if (e.id != WindowEvent.WINDOW_LOST_FOCUS + && e.id != WindowEvent.WINDOW_DEACTIVATED) + return false; + + redispatchEvent(target, e); + return true; + } + else if (e instanceof FocusEvent) + { + FocusEvent fe = (FocusEvent) e; + Component target = fe.getComponent (); + + boolean retval = false; + if (e.id == FocusEvent.FOCUS_GAINED) + { + retval = handleFocusGained(fe); + } + else if (e.id == FocusEvent.FOCUS_LOST) + { + retval = handleFocusLost(fe); + } + return true; + } + else if (e instanceof KeyEvent) + { + // Loop through all registered KeyEventDispatchers, giving + // each a chance to handle this event. + Iterator i = getKeyEventDispatchers().iterator(); + + while (i.hasNext ()) + { + KeyEventDispatcher dispatcher = (KeyEventDispatcher) i.next (); + if (dispatcher.dispatchKeyEvent ((KeyEvent) e)) + return true; + } + + // processKeyEvent checks if this event represents a focus + // traversal key stroke. + Component focusOwner = getGlobalPermanentFocusOwner (); + + if (focusOwner != null) + processKeyEvent (focusOwner, (KeyEvent) e); + + if (e.isConsumed ()) + return true; + + if (enqueueKeyEvent ((KeyEvent) e)) + // This event was enqueued for dispatch at a later time. + return true; + else + // This event wasn't handled by any of the registered + // KeyEventDispatchers, and wasn't enqueued for dispatch + // later, so send it to the default dispatcher. + return dispatchKeyEvent ((KeyEvent) e); + } + + return false; + } + + /** + * Handles FOCUS_GAINED events in {@link #dispatchEvent(AWTEvent)}. + * + * @param fe the focus event + */ + private boolean handleFocusGained(FocusEvent fe) + { + Component target = fe.getComponent (); + + // If old focus owner != new focus owner, notify old focus + // owner that it has lost focus. + Component oldFocusOwner = getGlobalFocusOwner(); + if (oldFocusOwner != null && oldFocusOwner != target) + { + FocusEvent lost = new FocusEvent(oldFocusOwner, + FocusEvent.FOCUS_LOST, + fe.isTemporary(), target); + oldFocusOwner.dispatchEvent(lost); + } + + setGlobalFocusOwner (target); + if (target != getGlobalFocusOwner()) + { + // Focus transfer was rejected, like when the target is not + // focusable. + dequeueKeyEvents(-1, target); + // FIXME: Restore focus somehow. + } + else + { + if (! fe.isTemporary()) + { + setGlobalPermanentFocusOwner (target); + if (target != getGlobalPermanentFocusOwner()) + { + // Focus transfer was rejected, like when the target is not + // focusable. + dequeueKeyEvents(-1, target); + // FIXME: Restore focus somehow. + } + else + { + redispatchEvent(target, fe); + } + } + } + + return true; + } + + /** + * Handles FOCUS_LOST events for {@link #dispatchEvent(AWTEvent)}. + * + * @param fe the focus event + * + * @return if the event has been handled + */ + private boolean handleFocusLost(FocusEvent fe) + { + Component currentFocus = getGlobalFocusOwner(); + if (currentFocus != fe.getOppositeComponent()) + { + setGlobalFocusOwner(null); + if (getGlobalFocusOwner() != null) + { + // TODO: Is this possible? If so, then we should try to restore + // the focus. + } + else + { + if (! fe.isTemporary()) + { + setGlobalPermanentFocusOwner(null); + if (getGlobalPermanentFocusOwner() != null) + { + // TODO: Is this possible? If so, then we should try to + // restore the focus. + } + else + { + fe.setSource(currentFocus); + redispatchEvent(currentFocus, fe); + } + } + } + } + return true; + } + + private boolean enqueueKeyEvent (KeyEvent e) + { + Iterator i = delayRequests.iterator (); + boolean oneEnqueued = false; + while (i.hasNext ()) + { + EventDelayRequest request = (EventDelayRequest) i.next (); + if (e.getWhen () > request.timestamp) + { + request.enqueueEvent (e); + oneEnqueued = true; + } + } + return oneEnqueued; + } + + public boolean dispatchKeyEvent (KeyEvent e) + { + Component focusOwner = getFocusOwner(); + if (focusOwner == null) + focusOwner = getFocusedWindow(); + + if (focusOwner != null) + redispatchEvent(focusOwner, e); + + // Loop through all registered KeyEventPostProcessors, giving + // each a chance to process this event. + Iterator i = getKeyEventPostProcessors().iterator(); + + while (i.hasNext ()) + { + KeyEventPostProcessor processor = (KeyEventPostProcessor) i.next (); + if (processor.postProcessKeyEvent (e)) + return true; + } + + // The event hasn't been consumed yet. Check if it is an + // MenuShortcut. + if (postProcessKeyEvent (e)) + return true; + + // Always return true. + return true; + } + + public boolean postProcessKeyEvent (KeyEvent e) + { + // Check if this event represents a menu shortcut. + + // MenuShortcuts are activated by Ctrl- KeyEvents, only on KEY_PRESSED. + int modifiers = e.getModifiersEx (); + if (e.getID() == KeyEvent.KEY_PRESSED + && (modifiers & KeyEvent.CTRL_DOWN_MASK) != 0) + { + Window focusedWindow = getGlobalFocusedWindow (); + if (focusedWindow instanceof Frame) + { + MenuBar menubar = ((Frame) focusedWindow).getMenuBar (); + + if (menubar != null) + { + // If there's a menubar, loop through all menu items, + // checking whether each one has a shortcut, and if + // so, whether this key event should activate it. + int numMenus = menubar.getMenuCount (); + + for (int i = 0; i < numMenus; i++) + { + Menu menu = menubar.getMenu (i); + int numItems = menu.getItemCount (); + + for (int j = 0; j < numItems; j++) + { + MenuItem item = menu.getItem (j); + MenuShortcut shortcut = item.getShortcut (); + + if (item.isEnabled() && shortcut != null) + { + // Dispatch a new ActionEvent if: + // + // a) this is a Shift- KeyEvent, and the + // shortcut requires the Shift modifier + // + // or, b) this is not a Shift- KeyEvent, and the + // shortcut does not require the Shift + // modifier. + if (shortcut.getKey () == e.getKeyCode () + && ((shortcut.usesShiftModifier () + && (modifiers & KeyEvent.SHIFT_DOWN_MASK) != 0) + || (! shortcut.usesShiftModifier () + && (modifiers & KeyEvent.SHIFT_DOWN_MASK) == 0))) + { + item.dispatchEvent (new ActionEvent (item, + ActionEvent.ACTION_PERFORMED, + item.getActionCommand (), + modifiers)); + // The event was dispatched. + return true; + } + } + } + } + } + } + } + return false; + } + + public void processKeyEvent (Component comp, KeyEvent e) + { + AWTKeyStroke eventKeystroke = AWTKeyStroke.getAWTKeyStrokeForEvent (e); + // For every focus traversal keystroke, we need to also consume + // the other two key event types for the same key (e.g. if + // KEY_PRESSED TAB is a focus traversal keystroke, we also need to + // consume KEY_RELEASED and KEY_TYPED TAB key events). + // consuming KEY_RELEASED is easy, because their keyCodes matches + // the KEY_PRESSED event. Consuming the intermediate KEY_TYPED is + // very difficult because their is no clean way that we can know + // which KEY_TYPED belongs to a focusTraversalKey and which not. + // To address this problem we swallow every KEY_TYPE between the + // KEY_PRESSED event that matches a focusTraversalKey and the + // corresponding KEY_RELEASED. + AWTKeyStroke oppositeKeystroke = AWTKeyStroke.getAWTKeyStroke (e.getKeyCode (), + e.getModifiersEx (), + !(e.id == KeyEvent.KEY_RELEASED)); + + // Here we check if we are currently waiting for a KEY_RELEASED and + // swallow all KeyEvents that are to be delivered in between. This + // should only be the KEY_TYPED events that correspond to the + // focusTraversalKey's KEY_PRESSED event + if (waitForKeyStroke != null) + { + if (eventKeystroke.equals(waitForKeyStroke)) + // release this lock + waitForKeyStroke = null; + + // as long as we are waiting for the KEY_RELEASED, we swallow every + // KeyEvent, including the KEY_RELEASED + e.consume(); + return; + } + + Set forwardKeystrokes = comp.getFocusTraversalKeys (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + Set backwardKeystrokes = comp.getFocusTraversalKeys (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + Set upKeystrokes = comp.getFocusTraversalKeys (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); + Set downKeystrokes = null; + if (comp instanceof Container) + downKeystrokes = comp.getFocusTraversalKeys (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); + + if (forwardKeystrokes.contains (eventKeystroke)) + { + waitForKeyStroke = oppositeKeystroke; + focusNextComponent (comp); + e.consume (); + } + else if (backwardKeystrokes.contains (eventKeystroke)) + { + waitForKeyStroke = oppositeKeystroke; + focusPreviousComponent (comp); + e.consume (); + } + else if (upKeystrokes.contains (eventKeystroke)) + { + waitForKeyStroke = oppositeKeystroke; + upFocusCycle (comp); + e.consume (); + } + else if (comp instanceof Container + && downKeystrokes.contains (eventKeystroke)) + { + waitForKeyStroke = oppositeKeystroke; + downFocusCycle ((Container) comp); + e.consume (); + } + } + + protected void enqueueKeyEvents (long after, Component untilFocused) + { + delayRequests.add (new EventDelayRequest (after, untilFocused)); + } + + protected void dequeueKeyEvents (long after, Component untilFocused) + { + // FIXME: need synchronization on delayRequests and enqueuedKeyEvents. + + // Remove the KeyEvent with the oldest timestamp, which should be + // the first element in the SortedSet. + if (after < 0) + { + int size = delayRequests.size (); + if (size > 0) + delayRequests.remove (delayRequests.first ()); + } + else + { + EventDelayRequest template = new EventDelayRequest (after, untilFocused); + if (delayRequests.contains (template)) + { + EventDelayRequest actual = (EventDelayRequest) delayRequests.tailSet (template).first (); + delayRequests.remove (actual); + actual.dispatchEvents (); + } + } + } + + protected void discardKeyEvents (Component comp) + { + // FIXME: need synchronization on delayRequests and enqueuedKeyEvents. + + Iterator i = delayRequests.iterator (); + + while (i.hasNext ()) + { + EventDelayRequest request = (EventDelayRequest) i.next (); + + if (request.focusedComp == comp + || (comp instanceof Container + && ((Container) comp).isAncestorOf (request.focusedComp))) + request.discardEvents (); + } + } + + public void focusPreviousComponent (Component comp) + { + if (comp != null) + comp.transferFocusBackward(); + } + + public void focusNextComponent (Component comp) + { + if (comp != null) + comp.transferFocus(); + } + + public void upFocusCycle (Component comp) + { + if (comp != null) + comp.transferFocusUpCycle(); + } + + public void downFocusCycle (Container cont) + { + if (cont != null) + cont.transferFocusDownCycle(); + } +} // class DefaultKeyboardFocusManager diff --git a/libjava/classpath/java/awt/Desktop.java b/libjava/classpath/java/awt/Desktop.java new file mode 100644 index 000000000..1b4078823 --- /dev/null +++ b/libjava/classpath/java/awt/Desktop.java @@ -0,0 +1,268 @@ +/* Desktop.java -- enable desktop integration between java programs and system + programs. + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package java.awt; + +import java.awt.peer.DesktopPeer; +import java.io.File; +import java.io.IOException; +import java.net.URI; + +/** + * This class enables Java application to access system commands to perform + * desktop oriented operations, like writing and sending emails, or surfing + * webpages with the system browser or editing/printing files with a default + * editor. Methods are provided to handle these common operations, plus an + * <code>open</code> command selects a default registered application for the + * specified file type. For example, opening an odf file results in launching + * OpenOffice. If an operation is not supported, or the application fails to + * launch, an exception is generated. + * + * <strong>Implementation note: </strong>As this class is used to manage Desktop + * integration, we provide some extension to configure the behaviour of this + * class depending on the type of dektop that is detected.<br /> + * + * First of all, we support 5 system properties that can be used to define + * the application to launch in any given case. These properties are:<br /> + * <br /> + * <code>gnu.java.awt.peer.Desktop.html.command</code><br /> + * <code>gnu.java.awt.peer.Desktop.mail.command</code><br /> + * <code>gnu.java.awt.peer.Desktop.edit.command</code><br /> + * <code>gnu.java.awt.peer.Desktop.print.command</code><br /> + * <code>gnu.java.awt.peer.Desktop.open.command</code><br /> + * <br /> + * <br /> + * These can be specified from the command line and have priority on every + * other setting.<br /> + * <br /> + * The second method supported is defining a Java preference.<br /> + * The main preference node is a <strong>user node</strong> relative to the + * class <code>gnu.java.awt.peer.ClasspathDesktopPeer</code>. This node + * contains a child for each supported operation. The key for each type is + * always <code>command</code>: + * <br /><br /> + * <code>gnu.java.awt.peer.Desktop.html.command</code><br /> + * <code>gnu.java.awt.peer.Desktop.mail.command</code><br /> + * <code>gnu.java.awt.peer.Desktop.edit.command</code><br /> + * <code>gnu.java.awt.peer.Desktop.print.command</code><br /> + * <code>gnu.java.awt.peer.Desktop.open.command</code><br /> + * <br /> + * <br /> + * The access to these keys is done with the Preference API or, if outside + * of the java scope, is done in a backend dependent way. For example, + * with the GConf backend, you can access these properties + * with (may not be accurate on your system): + * <br /><br /> + * <code> + * gconftool-2 -g /apps/classpath/gnu/java/awt/peer/Desktop/html/command + * </code> + * + * @author Mario Torre <neugens@limasoftware.net> + * @since 1.6 + */ +public class Desktop +{ + /** + * Represents an action type supported by a platform. + * + * To determine if a given action is supported by the platform, + * use the <code>Desktop.isSupported(java.awt.Desktop.Action)</code> + * method. + * + * @author Mario Torre <neugens@limasoftware.net> + */ + public enum Action + { + BROWSE, EDIT, MAIL, OPEN, PRINT + } + + private DesktopPeer peer; + + private Desktop() + { + /* nothing to be done */ + } + + /** + * Returns an instance of the Desktop Class. + * + * If this implementation does not support Desktop, an + * UnsupportedOperationException will be thrown. + * Also, an HeadlessException will be generated if + * GraphicsEnvironment.isHeadless() returns true. + * + * @throws UnsupportedOperationException + * @throws HeadlessException + */ + public static Desktop getDesktop() throws UnsupportedOperationException, + HeadlessException + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException(); + + if (!Desktop.isDesktopSupported()) + throw new UnsupportedOperationException(); + + Desktop desktop = new Desktop(); + desktop.peer = Toolkit.getDefaultToolkit().createDesktopPeer(desktop); + + return desktop; + } + + /** + * Check if this implementation supports Desktop. + * If true, use getDesktop to get an instance of this class. + * + * This implementation will return false when GraphicsEnvironment.isHeadless + * returns true. + * + * @return true if this class is supported on the current platform; + * false otherwise + */ + public static boolean isDesktopSupported() + { + if (GraphicsEnvironment.isHeadless()) + return false; + + return true; + } + + /** + * Check if the given Action is supported by this implementation. + * + * @param action + * @return + */ + public boolean isSupported(Desktop.Action action) + { + return peer.isSupported(action); + } + + /** + * Launches the Desktop default browser to open the given <code>uri</code>. + * + * If a security manager exists and denies + * AWTPermission("showWindowWithoutWarningBanner"),a SecurityException will + * be generated. + * + * @param uri + * @throws IOException + */ + public void browse(URI uri) + throws IOException + { + peer.browse(uri); + } + + /** + * Launch the edit command to edit this file. + * File should already exist before the editing starts. + * + * If a security manager exists and + * SecurityManager.checkRead(java.lang.String) method denies read access to + * the file, or SecurityManager.checkPrintJobAccess() method denies the + * permission to print the file, a SecurityException will be generated. + * + * @param file + * @throws IOException + */ + public void edit(File file) + throws IOException + { + peer.edit(file); + } + + /** + * Launches the Desktop default mailer. + * + * If a security manager exists and denies + * AWTPermission("showWindowWithoutWarningBanner"), a SecurityException will + * be generated. + * + * @throws IOException + */ + public void mail() + throws IOException + { + peer.mail(); + } + + /** + * Launches the Desktop default mailer, with the given mailtoURI + * as agrument. The <code>mailtoURI</code> must conform to the + * {@link http://www.ietf.org/rfc/rfc2368.txt The mailto URL scheme (RFC 2368)} + * + * If a security manager exists and denies + * AWTPermission("showWindowWithoutWarningBanner"), a SecurityException will + * be generated. + * + * @param mailtoURI + * @throws IOException + */ + public void mail(URI mailtoURI) + throws IOException + { + peer.mail(mailtoURI); + } + + /** + * Launches the Desktop default application to open the given File. + * If <code>file</code> is a directory, a file manager is launched. + * + * @param file + * @throws IOException + */ + public void open(File file) + throws IOException + { + peer.open(file); + } + + /** + * Launch the print program to print this file. + * + * @param file + * @throws IOException + */ + public void print(File file) + throws IOException + { + peer.print(file); + } +} diff --git a/libjava/classpath/java/awt/Dialog.java b/libjava/classpath/java/awt/Dialog.java new file mode 100644 index 000000000..d12e1eb12 --- /dev/null +++ b/libjava/classpath/java/awt/Dialog.java @@ -0,0 +1,570 @@ +/* Dialog.java -- An AWT dialog box + Copyright (C) 1999, 2000, 2001, 2002, 2005, 2006 + Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package java.awt; + +import java.awt.peer.DialogPeer; + +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; + +/** + * <code>Dialog</code> provides a top-level window normally used to receive + * user input in applications. + * <p> + * A dialog always has another top-level window as owner and is only visible + * if this owner is visible to the user. The default layout of dialogs is the + * <code>BorderLayout</code>. Dialogs can be modal (blocks user input to other + * components) or non-modal (user input in other components are allowed). + * </p> + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@redhat.com) + */ +public class Dialog extends Window +{ + public enum ModalExclusionType + { + APPLICATION_EXCLUDE, + NO_EXCLUDE, + TOOLKIT_EXCLUDE + } + + public enum ModalityType + { + APPLICATION_MODAL, + DOCUMENT_MODAL, + MODELESS, + TOOLKIT_MODAL + } + + // Serialization constant + private static final long serialVersionUID = 5920926903803293709L; + + /** + * @serial Indicates whether or not this dialog box is modal. + */ + private boolean modal; + + /** + * @serial Indicates whether or not this dialog box is resizable. + */ + private boolean resizable = true; + + /** + * @serial The title string for this dialog box, which can be + * <code>null</code>. + */ + private String title; + + /** + * This field indicates whether the dialog is undecorated or not. + */ + private boolean undecorated = false; + + /** + * Indicates that we are blocked for modality in show + */ + private boolean blocked = false; + + /** + * Secondary EventQueue to handle AWT events while we are blocked for + * modality in show. + */ + private EventQueue eq2 = null; + + /** + * The number used to generate the name returned by getName. + */ + private static transient long next_dialog_number; + + /** + * Initializes a new instance of <code>Dialog</code> with the specified + * parent, that is resizable and not modal, and which has no title. + * + * @param parent The parent frame of this dialog box. + * @exception IllegalArgumentException If the owner's GraphicsConfiguration + * is not from a screen device, or if owner is null. This exception is + * always thrown when GraphicsEnvironment.isHeadless() returns true. + */ + public Dialog(Frame parent) + { + this(parent, "", false); + } + + /** + * Initializes a new instance of <code>Dialog</code> with the specified + * parent and modality, that is resizable and which has no title. + * + * @param parent The parent frame of this dialog box. + * @param modal <code>true</code> if this dialog box is modal, + * <code>false</code> otherwise. + * + * @exception IllegalArgumentException If the owner's GraphicsConfiguration + * is not from a screen device, or if owner is null. This exception is + * always thrown when GraphicsEnvironment.isHeadless() returns true. + */ + public Dialog(Frame parent, boolean modal) + { + this(parent, "", modal); + } + + /** + * Initializes a new instance of <code>Dialog</code> with the specified + * parent, that is resizable and not modal, and which has the specified + * title. + * + * @param parent The parent frame of this dialog box. + * @param title The title string for this dialog box. + * + * @exception IllegalArgumentException If the owner's GraphicsConfiguration + * is not from a screen device, or if owner is null. This exceptionnis + * always thrown when GraphicsEnvironment.isHeadless() returns true. + */ + public Dialog(Frame parent, String title) + { + this(parent, title, false); + } + + /** + * Initializes a new instance of <code>Dialog</code> with the specified, + * parent, title, and modality, that is resizable. + * + * @param parent The parent frame of this dialog box. + * @param title The title string for this dialog box. + * @param modal <code>true</code> if this dialog box is modal, + * <code>false</code> otherwise. + * + * @exception IllegalArgumentException If owner is null or + * GraphicsEnvironment.isHeadless() returns true. + */ + public Dialog(Frame parent, String title, boolean modal) + { + this(parent, title, modal, parent.getGraphicsConfiguration()); + } + + /** + * Initializes a new instance of <code>Dialog</code> with the specified, + * parent, title, modality and <code>GraphicsConfiguration</code>, that is + * resizable. + * + * @param parent The parent frame of this dialog box. + * @param title The title string for this dialog box. + * @param modal <code>true</code> if this dialog box is modal, + * <code>false</code> otherwise. + * @param gc The <code>GraphicsConfiguration</code> object to use. If + * <code>null</code> the <code>GraphicsConfiguration</code> of the target + * frame is used. + * + * @exception IllegalArgumentException If owner is null, the + * GraphicsConfiguration is not a screen device or + * GraphicsEnvironment.isHeadless() returns true. + * @since 1.4 + */ + public Dialog(Frame parent, String title, boolean modal, + GraphicsConfiguration gc) + { + super(parent, (gc == null) ? parent.getGraphicsConfiguration() : gc); + + // A null title is equivalent to an empty title + this.title = (title != null) ? title : ""; + this.modal = modal; + visible = false; + + setLayout(new BorderLayout()); + setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + } + + /** + * Initializes a new instance of <code>Dialog</code> with the specified, + * parent, that is resizable. + * + * @param owner The parent frame of this dialog box. + * + * @exception IllegalArgumentException If parent is null. This exception is + * always thrown when GraphicsEnvironment.isHeadless() returns true. + * + * @since 1.2 + */ + public Dialog(Dialog owner) + { + this(owner, "", false, owner.getGraphicsConfiguration()); + } + + /** + * Initializes a new instance of <code>Dialog</code> with the specified, + * parent and title, that is resizable. + * + * @param owner The parent frame of this dialog box. + * @param title The title string for this dialog box. + * + * @exception IllegalArgumentException If parent is null. This exception is + * always thrown when GraphicsEnvironment.isHeadless() returns + * true. + * @since 1.2 + */ + public Dialog(Dialog owner, String title) + { + this(owner, title, false, owner.getGraphicsConfiguration()); + } + + /** + * Initializes a new instance of <code>Dialog</code> with the specified, + * parent, title and modality, that is resizable. + * + * @param owner The parent frame of this dialog box. + * @param title The title string for this dialog box. + * @param modal <code>true</code> if this dialog box is modal, + * <code>false</code> otherwise. + * + * @exception IllegalArgumentException If parent is null. This exception is + * always thrown when GraphicsEnvironment.isHeadless() returns true. + * @since 1.2 + */ + public Dialog(Dialog owner, String title, boolean modal) + { + this(owner, title, modal, owner.getGraphicsConfiguration()); + } + + /** + * Initializes a new instance of <code>Dialog</code> with the specified, + * parent, title, modality and <code>GraphicsConfiguration</code>, that is + * resizable. + * + * @param parent The parent frame of this dialog box. + * @param title The title string for this dialog box. + * @param modal <code>true</code> if this dialog box is modal, + * <code>false</code> otherwise. + * @param gc The <code>GraphicsConfiguration</code> object to use. If + * <code>null</code> the <code>GraphicsConfiguration</code> of the target + * frame is used. + * + * @exception IllegalArgumentException If parent is null, the + * GraphicsConfiguration is not a screen device or + * GraphicsEnvironment.isHeadless() returns true. + * + * @since 1.4 + */ + public Dialog(Dialog parent, String title, boolean modal, + GraphicsConfiguration gc) + { + super(parent, (gc == null) ? parent.getGraphicsConfiguration() : gc); + + // A null title is equivalent to an empty title + this.title = (title != null) ? title : ""; + this.modal = modal; + visible = false; + + setLayout(new BorderLayout()); + setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + } + + /** + * Returns the title of this dialog box. + * + * @return The title of this dialog box. + */ + public String getTitle() + { + return title; + } + + /** + * Sets the title of this dialog box to the specified string. + * + * @param title the new title. If <code>null</code> an empty + * title will be set. + */ + public synchronized void setTitle(String title) + { + // A null title is equivalent to an empty title + this.title = (title != null) ? title : ""; + + if (peer != null) + { + DialogPeer d = (DialogPeer) peer; + d.setTitle(title); + } + } + + /** + * Tests whether or not this dialog box is modal. + * + * @return <code>true</code> if this dialog box is modal, <code>false</code> + * otherwise. + */ + public boolean isModal() + { + return modal; + } + + /** + * Changes the modality of this dialog box. This can only be done before the + * peer is created. + * + * @param modal <code>true</code> to make this dialog box modal, + * <code>false</code> to make it non-modal. + */ + public void setModal(boolean modal) + { + this.modal = modal; + } + + /** + * Tests whether or not this dialog box is resizable. + * + * @return <code>true</code> if this dialog is resizable, + * <code>false</code> otherwise. + */ + public boolean isResizable() + { + return resizable; + } + + /** + * Changes the resizability of this dialog box. + * + * @param resizable <code>true</code> to make this dialog resizable, + * <code>false</code> to make it non-resizable. + */ + public synchronized void setResizable(boolean resizable) + { + this.resizable = resizable; + if (peer != null) + { + DialogPeer d = (DialogPeer) peer; + d.setResizable(resizable); + } + } + + /** + * Creates this object's native peer. + */ + public synchronized void addNotify() + { + if (peer == null) + peer = getToolkit().createDialog(this); + super.addNotify(); + } + + /** + * Makes this dialog visible and brings it to the front. If the dialog is + * modal and is not already visible, this call will not return until the + * dialog is hidden by someone calling hide or dispose. If this is the event + * dispatching thread we must ensure that another event thread runs while the + * one which invoked this method is blocked. + * + * @deprecated Use {@link Component#setVisible(boolean)} instead. + */ + public synchronized void show() + { + super.show(); + + if (isModal()) + { + // If already shown (and blocked) just return + if (blocked) + return; + + /* + * If show is called in the dispatch thread for a modal dialog it will + * block so we must run another thread so the events keep being + * dispatched. + */ + if (EventQueue.isDispatchThread()) + { + EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); + eq2 = new EventQueue(); + eq.push(eq2); + } + + try + { + blocked = true; + wait(); + blocked = false; + } + catch (InterruptedException e) + { + blocked = false; + } + + if (eq2 != null) + { + eq2.pop(); + eq2 = null; + } + } + } + + /** + * Hides the Dialog and then causes show() to return if it is currently + * blocked. + * + * @deprecated Use {@link Component#setVisible(boolean)} instead. + */ + public synchronized void hide() + { + if (blocked) + { + notifyAll(); + } + + super.hide(); + } + + /** + * Disposes the Dialog and then causes show() to return if it is currently + * blocked. + */ + public synchronized void dispose() + { + if (blocked) + { + notifyAll(); + } + + super.dispose(); + } + + /** + * Returns a debugging string for this component. + * + * @return A debugging string for this component. + */ + protected String paramString() + { + return "title+" + title + ",modal=" + modal + ",resizable=" + resizable + + "," + super.paramString(); + } + + /** + * Returns whether this frame is undecorated or not. + * + * @return <code>true</code> if this dialog is undecorated, + * <code>false</code> otherwise. + * + * @since 1.4 + */ + public boolean isUndecorated() + { + return undecorated; + } + + /** + * Disables or enables decorations for this frame. This method can only be + * called while the frame is not displayable. + * + * @param undecorated <code>true</code> to disable dialog decorations, + * <code>false</code> otherwise. + * + * @exception IllegalComponentStateException If this frame is displayable. + * @since 1.4 + */ + public void setUndecorated(boolean undecorated) + { + if (isDisplayable()) + throw new IllegalComponentStateException(); + + this.undecorated = undecorated; + } + + /** + * Accessibility support for <code>Dialog</code>. + */ + protected class AccessibleAWTDialog + extends AccessibleAWTWindow + { + private static final long serialVersionUID = 4837230331833941201L; + + /** + * Gets the role of this object. + * @return AccessibleRole.DIALOG + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.DIALOG; + } + + /** + * Gets the state set of this object. + * @return The current state of this dialog. + */ + public AccessibleStateSet getAccessibleStateSet() + { + AccessibleStateSet states = super.getAccessibleStateSet(); + if (isResizable()) + states.add(AccessibleState.RESIZABLE); + if (isModal()) + states.add(AccessibleState.MODAL); + return states; + } + } + + /** + * Gets the AccessibleContext associated with this <code>Dialog</code>. The + * context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTDialog(); + return accessibleContext; + } + + /** + * Generate a unique name for this <code>Dialog</code>. + * + * @return A unique name for this <code>Dialog</code>. + */ + String generateName() + { + return "dialog" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_dialog_number++; + } +} diff --git a/libjava/classpath/java/awt/Dimension.java b/libjava/classpath/java/awt/Dimension.java new file mode 100644 index 000000000..4c1a07bf9 --- /dev/null +++ b/libjava/classpath/java/awt/Dimension.java @@ -0,0 +1,234 @@ +/* Dimension.java -- represents a 2-dimensional span + Copyright (C) 1999, 2000, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.geom.Dimension2D; +import java.io.Serializable; + +/** + * This class holds a width and height value pair. This is used in plenty + * of windowing classes, but also has geometric meaning. + * + * <p>It is valid for a dimension to have negative width or height; but it + * is considered to have no area. Therefore, the behavior in various methods + * is undefined in such a case. + * + * <p>There are some public fields; if you mess with them in an inconsistent + * manner, it is your own fault when you get invalid results. Also, this + * class is not threadsafe. + * + * @author Per Bothner (bothner@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see Component + * @see LayoutManager + * @since 1.0 + * @status updated to 1.14 + */ +public class Dimension extends Dimension2D implements Serializable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 4723952579491349524L; + + /** + * The width of this object. + * + * @see #getSize() + * @see #setSize(double, double) + * @serial the width + */ + public int width; + + /** + * The height of this object. + * + * @see #getSize() + * @see #setSize(double, double) + * @serial the height + */ + public int height; + + /** + * Create a new Dimension with a width and height of zero. + */ + public Dimension() + { + } + + /** + * Create a new Dimension with width and height identical to that of the + * specified dimension. + * + * @param d the Dimension to copy + * @throws NullPointerException if d is null + */ + public Dimension(Dimension d) + { + width = d.width; + height = d.height; + } + + /** + * Create a new Dimension with the specified width and height. + * + * @param w the width of this object + * @param h the height of this object + */ + public Dimension(int w, int h) + { + width = w; + height = h; + } + + /** + * Gets the width of this dimension. + * + * @return the width, as a double + */ + public double getWidth() + { + return width; + } + + /** + * Gets the height of this dimension. + * + * @return the height, as a double + */ + public double getHeight() + { + return height; + } + + /** + * Sets the size of this dimension. The values are rounded to int. + * + * @param w the new width + * @param h the new height + * @since 1.2 + */ + public void setSize(double w, double h) + { + width = (int) w; + height = (int) h; + } + + /** + * Returns the size of this dimension. A pretty useless method, as this is + * already a dimension. + * + * @return a copy of this dimension + * @see #setSize(Dimension) + * @since 1.1 + */ + public Dimension getSize() + { + return new Dimension(width, height); + } + + /** + * Sets the width and height of this object to match that of the + * specified object. + * + * @param d the Dimension to get the new width and height from + * @throws NullPointerException if d is null + * @see #getSize() + * @since 1.1 + */ + public void setSize(Dimension d) + { + width = d.width; + height = d.height; + } + + /** + * Sets the width and height of this object to the specified values. + * + * @param w the new width value + * @param h the new height value + */ + public void setSize(int w, int h) + { + width = w; + height = h; + } + + /** + * Tests this object for equality against the specified object. This will + * be true if and only if the specified object is an instance of + * Dimension2D, and has the same width and height. + * + * @param obj the object to test against + * @return true if the object is equal to this + */ + public boolean equals(Object obj) + { + if (! (obj instanceof Dimension)) + return false; + Dimension dim = (Dimension) obj; + return height == dim.height && width == dim.width; + } + + /** + * Return the hashcode for this object. It is not documented, but appears + * to be <code>((width + height) * (width + height + 1) / 2) + width</code>. + * + * @return the hashcode + */ + public int hashCode() + { + // Reverse engineering this was fun! + return (width + height) * (width + height + 1) / 2 + width; + } + + /** + * Returns a string representation of this object. The format is: + * <code>getClass().getName() + "[width=" + width + ",height=" + height + * + ']'</code>. + * + * @return a string representation of this object + */ + public String toString() + { + return getClass().getName() + + "[width=" + width + ",height=" + height + ']'; + } +} // class Dimension diff --git a/libjava/classpath/java/awt/DisplayMode.java b/libjava/classpath/java/awt/DisplayMode.java new file mode 100644 index 000000000..be2a1d118 --- /dev/null +++ b/libjava/classpath/java/awt/DisplayMode.java @@ -0,0 +1,164 @@ +/* DisplayMode.java -- a description of display mode configurations + Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +/** + * This encapsulates information about the display mode for a graphics + * device configuration. They are device dependent, and may not always be + * available. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see GraphicsDevice + * @since 1.4 + * @status updated to 1.4 + */ +public final class DisplayMode +{ + /** + * Value of the bit depth if multiple depths are supported. + * + * @see #getBitDepth() + */ + public static final int BIT_DEPTH_MULTI = -1; + + /** + * Value of an unknown refresh rate. + * + * @see #getRefreshRate() + */ + public static final int REFRESH_RATE_UNKNOWN = 0; + + /** The width. */ + private final int width; + + /** The height. */ + private final int height; + + /** The bit depth. */ + private final int bitDepth; + + /** The refresh rate. */ + private final int refreshRate; + + /** + * Create a mode with the given parameters. + * + * @param width the width + * @param height the height + * @param bitDepth the bitDepth + * @param refreshRate the refreshRate + * @see #BIT_DEPTH_MULTI + * @see #REFRESH_RATE_UNKNOWN + */ + public DisplayMode(int width, int height, int bitDepth, int refreshRate) + { + this.width = width; + this.height = height; + this.bitDepth = bitDepth; + this.refreshRate = refreshRate; + } + + /** + * Returns the height, in pixels. + * + * @return the height + */ + public int getHeight() + { + return height; + } + + /** + * Returns the width, in pixels. + * + * @return the width + */ + public int getWidth() + { + return width; + } + + /** + * Returns the bit depth, in bits per pixel. This may be BIT_DEPTH_MULTI. + * + * @return the bit depth + * @see #BIT_DEPTH_MULTI + */ + public int getBitDepth() + { + return bitDepth; + } + + /** + * Returns the refresh rate, in hertz. This may be REFRESH_RATE_UNKNOWN. + * + * @return the refresh rate + * @see #REFRESH_RATE_UNKNOWN + */ + public int getRefreshRate() + { + return refreshRate; + } + + /** + * Test for equality. This returns true for two modes with identical + * parameters. + * + * @param dm The display mode to compare to + * + * @return true if it is equal + */ + public boolean equals (DisplayMode dm) + { + return (width == dm.width + && height == dm.height + && bitDepth == dm.bitDepth + && refreshRate == dm.refreshRate); + } + + /** + * Returns a hash code for the display mode. + * + * @return the hash code + */ + public int hashCode() + { + return width + height + bitDepth + refreshRate; + } +} // class DisplayMode diff --git a/libjava/classpath/java/awt/Event.java b/libjava/classpath/java/awt/Event.java new file mode 100644 index 000000000..f2c98b9b0 --- /dev/null +++ b/libjava/classpath/java/awt/Event.java @@ -0,0 +1,185 @@ +/* Copyright (C) 1999, 2000, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +/** + * Written using on-line Java Platform 1.2 API Specification, as well + * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). + * Status: Believed complete and correct. + */ + +public class Event implements java.io.Serializable +{ + static final long serialVersionUID = 5488922509400504703L; + + public static final int SHIFT_MASK = 1; + public static final int CTRL_MASK = 2; + public static final int META_MASK = 4; + public static final int ALT_MASK = 8; + + public static final int ACTION_EVENT = 1001; + public static final int BACK_SPACE = 8; + public static final int CAPS_LOCK = 1022; + public static final int DELETE = 127; + public static final int DOWN = 1005; + public static final int END = 1001; + public static final int ENTER = 10; + public static final int ESCAPE = 27; + public static final int F1 = 1008; + public static final int F10 = 1017; + public static final int F11 = 1018; + public static final int F12 = 1019; + public static final int F2 = 1009; + public static final int F3 = 1010; + public static final int F4 = 1011; + public static final int F5 = 1012; + public static final int F6 = 1013; + public static final int F7 = 1014; + public static final int F8 = 1015; + public static final int F9 = 1016; + public static final int GOT_FOCUS = 1004; + public static final int HOME = 1000; + public static final int INSERT = 1025; + public static final int KEY_ACTION = 403; + public static final int KEY_ACTION_RELEASE = 404; + public static final int KEY_PRESS = 401; + public static final int KEY_RELEASE = 402; + public static final int LEFT = 1006; + public static final int LIST_DESELECT = 702; + public static final int LIST_SELECT = 701; + public static final int LOAD_FILE = 1002; + public static final int LOST_FOCUS = 1005; + public static final int MOUSE_DOWN = 501; + public static final int MOUSE_DRAG = 506; + public static final int MOUSE_ENTER = 504; + public static final int MOUSE_EXIT = 505; + public static final int MOUSE_MOVE = 503; + public static final int MOUSE_UP = 502; + public static final int NUM_LOCK = 1023; + public static final int PAUSE = 1024; + public static final int PGDN = 1003; + public static final int PGUP = 1002; + public static final int PRINT_SCREEN = 1020; + public static final int RIGHT = 1007; + public static final int SAVE_FILE = 1003; + public static final int SCROLL_ABSOLUTE = 605; + public static final int SCROLL_BEGIN = 606; + public static final int SCROLL_END = 607; + public static final int SCROLL_LINE_DOWN = 602; + public static final int SCROLL_LINE_UP = 601; + public static final int SCROLL_LOCK = 1021; + public static final int SCROLL_PAGE_DOWN = 604; + public static final int SCROLL_PAGE_UP = 603; + public static final int TAB = 9; + public static final int UP = 1004; + public static final int WINDOW_DEICONIFY = 204; + public static final int WINDOW_DESTROY = 201; + public static final int WINDOW_EXPOSE = 202; + public static final int WINDOW_ICONIFY = 203; + public static final int WINDOW_MOVED = 205; + + public Object arg; + public int clickCount; + boolean consumed; // Required by serialization spec. + public Event evt; + public int id; + public int key; + public int modifiers; + public Object target; + public long when; + public int x; + public int y; + + public Event (Object target, int id, Object arg) + { + this.id = id; + this.target = target; + this.arg = arg; + } + + public Event (Object target, long when, int id, int x, int y, int key, + int modifiers) + { + this.target = target; + this.when = when; + this.id = id; + this.x = x; + this.y = y; + this.key = key; + this.modifiers = modifiers; + } + + public Event (Object target, long when, int id, int x, int y, int key, + int modifiers, Object arg) + { + this (target, when, id, x, y, key, modifiers); + this.arg = arg; + } + + public boolean controlDown () + { + return ((modifiers & CTRL_MASK) == 0 ? false : true); + } + + public boolean metaDown () + { + return ((modifiers & META_MASK) == 0 ? false : true); + } + + protected String paramString () + { + return "id=" + id + ",x=" + x + ",y=" + y + + ",target=" + target + ",arg=" + arg; + } + + public boolean shiftDown() + { + return ((modifiers & SHIFT_MASK) == 0 ? false : true); + } + + public String toString() + { + return getClass().getName() + "[" + paramString() + "]"; + } + + public void translate (int x, int y) + { + this.x += x; + this.y += y; + } +} diff --git a/libjava/classpath/java/awt/EventDispatchThread.java b/libjava/classpath/java/awt/EventDispatchThread.java new file mode 100644 index 000000000..c2147f4c0 --- /dev/null +++ b/libjava/classpath/java/awt/EventDispatchThread.java @@ -0,0 +1,107 @@ +/* EventDispatchThread.java - + Copyright (C) 2000, 2002, 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt; + +/** + * @author Bryce McKinlay + * @status believed complete, but untested. + */ +class EventDispatchThread extends Thread +{ + /** + * The default priority when no property has been set. + */ + private static final int DEFAULT_PRIORITY = NORM_PRIORITY + 1; + + private static int dispatchThreadNum; + + private EventQueue queue; + + EventDispatchThread(EventQueue queue) + { + super(); + setName("AWT-EventQueue-" + ++dispatchThreadNum); + this.queue = queue; + + int priority = DEFAULT_PRIORITY; + try + { + String priorityString = + System.getProperty("gnu.awt.dispatchthread.priority"); + if (priorityString != null) + { + priority = Integer.parseInt(priorityString); + } + } + catch (NumberFormatException ex) + { + // Ignore and use default. + } + setPriority(priority); + + // Make sure that an event dispatch thread is never a daemon thread. + setDaemon(false); + } + + public void run() + { + while (true) + { + try + { + AWTEvent evt = queue.getNextEvent(); + queue.dispatchEvent(evt); + } + catch (ThreadDeath death) + { + // If someone wants to kill us, let them. + return; + } + catch (InterruptedException ie) + { + // We are interrupted when we should finish executing + return; + } + catch (Throwable x) + { + System.err.println("Exception during event dispatch:"); + x.printStackTrace(System.err); + } + } + } +} diff --git a/libjava/classpath/java/awt/EventQueue.java b/libjava/classpath/java/awt/EventQueue.java new file mode 100644 index 000000000..cb52ae013 --- /dev/null +++ b/libjava/classpath/java/awt/EventQueue.java @@ -0,0 +1,658 @@ +/* EventQueue.java -- + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import gnu.java.awt.LowPriorityEvent; +import gnu.java.awt.peer.NativeEventLoopRunningEvent; + +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.InputMethodEvent; +import java.awt.event.InvocationEvent; +import java.awt.event.PaintEvent; +import java.awt.peer.ComponentPeer; +import java.awt.peer.LightweightPeer; +import java.lang.reflect.InvocationTargetException; +import java.util.EmptyStackException; + +/* Written using on-line Java 2 Platform Standard Edition v1.3 API + * Specification, as well as "The Java Class Libraries", 2nd edition + * (Addison-Wesley, 1998). + * Status: Believed complete, but untested. + */ + +/** + * This class manages a queue of <code>AWTEvent</code> objects that + * are posted to it. The AWT system uses only one event queue for all + * events. + * + * @author Bryce McKinlay + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class EventQueue +{ + /** + * Indicates events that are processed with normal priority. This is normally + * all events except PaintEvents. + */ + private static final int NORM_PRIORITY = 0; + + /** + * Indicates events that are processed with lowes priority. This is normally + * all PaintEvents and LowPriorityEvents. + */ + private static final int LOW_PRIORITY = 1; + + /** + * Implements the actual queue. EventQueue has 2 internal queues for + * different priorities: + * 1 PaintEvents are always dispatched with low priority. + * 2. All other events are dispatched with normal priority. + * + * This makes sure that the actual painting (output) is performed _after_ all + * available input has been processed and that the paint regions are + * coalesced as much as possible. + */ + private class Queue + { + /** + * The first item in the queue. This is where events are popped from. + */ + AWTEvent queueHead; + + /** + * The last item. This is where events are posted to. + */ + AWTEvent queueTail; + } + + /** + * The three internal event queues. + * + * @see Queue + */ + private Queue[] queues; + + private EventQueue next; + private EventQueue prev; + private AWTEvent currentEvent; + private long lastWhen = System.currentTimeMillis(); + + private EventDispatchThread dispatchThread = new EventDispatchThread(this); + private boolean nativeLoopRunning = false; + + private boolean isShutdown () + { + // This is the exact self-shutdown condition specified in J2SE: + // http://java.sun.com/j2se/1.4.2/docs/api/java/awt/doc-files/AWTThreadIssues.html + + if (nativeLoopRunning) + return false; + + if (peekEvent() != null) + return false; + + if (Frame.hasDisplayableFrames()) + return false; + + return true; + } + + /** + * Initializes a new instance of <code>EventQueue</code>. + */ + public EventQueue() + { + queues = new Queue[2]; + queues[NORM_PRIORITY] = new Queue(); + queues[LOW_PRIORITY] = new Queue(); + } + + /** + * Returns the next event in the queue. This method will block until + * an event is available or until the thread is interrupted. + * + * @return The next event in the queue. + * + * @exception InterruptedException If this thread is interrupted while + * waiting for an event to be posted to the queue. + */ + public synchronized AWTEvent getNextEvent() + throws InterruptedException + { + if (next != null) + return next.getNextEvent(); + + AWTEvent res = getNextEventImpl(true); + + while (res == null) + { + if (isShutdown()) + { + // Explicitly set dispathThread to null. If we don't do + // this, there is a race condition where dispatchThread + // can be != null even after the event dispatch thread has + // stopped running. If that happens, then the + // dispatchThread == null check in postEventImpl will + // fail, and a new event dispatch thread will not be + // created, leaving invokeAndWaits waiting indefinitely. + dispatchThread = null; + + // Interrupt the event dispatch thread. + throw new InterruptedException(); + } + + wait(); + res = getNextEventImpl(true); + } + + return res; + } + + /** + * Fetches and possibly removes the next event from the internal queues. + * This method returns immediately. When all queues are empty, this returns + * <code>null</code>: + * + * @param remove <true> when the event should be removed from the queue, + * <code>false</code> otherwise + * + * @return the next event or <code>null</code> when all internal queues + * are empty + */ + private AWTEvent getNextEventImpl(boolean remove) + { + AWTEvent next = null; + for (int i = 0; i < queues.length && next == null; i++) + { + Queue q = queues[i]; + if (q.queueHead != null) + { + // Got an event, remove it. + next = q.queueHead; + if (remove) + { + // Unlink event from the queue. + q.queueHead = next.queueNext; + if (q.queueHead == null) + q.queueTail = null; + next.queueNext = null; + } + } + } + return next; + } + + /** + * Returns the next event in the queue without removing it from the queue. + * This method will block until an event is available or until the thread + * is interrupted. + * + * @return The next event in the queue. + * @specnote Does not block. Returns null if there are no events on the + * queue. + */ + public synchronized AWTEvent peekEvent() + { + if (next != null) + return next.peekEvent(); + + return getNextEventImpl(false); + } + + /** + * Returns the next event in the queue that has the specified id + * without removing it from the queue. + * This method will block until an event is available or until the thread + * is interrupted. + * + * @param id The event id to return. + * + * @return The next event in the queue. + * + * @specnote Does not block. Returns null if there are no matching events + * on the queue. + */ + public synchronized AWTEvent peekEvent(int id) + { + if (next != null) + return next.peekEvent(id); + + AWTEvent evt = null; + for (int i = 0; i < queues.length && evt == null; i++) + { + Queue q = queues[i]; + evt = q.queueHead; + while (evt != null && evt.id != id) + evt = evt.queueNext; + // At this point we either have found an event (evt != null -> exit + // for loop), or we have found no event (evt == null -> search next + // internal queue). + } + return evt; + } + + /** + * Posts a new event to the queue. + * + * @param evt The event to post to the queue. + * + * @exception NullPointerException If event is null. + */ + public void postEvent(AWTEvent evt) + { + postEventImpl(evt); + } + + /** + * Sorts events to their priority and calls + * {@link #postEventImpl(AWTEvent, int)}. + * + * @param evt the event to post + */ + private synchronized final void postEventImpl(AWTEvent evt) + { + int priority = NORM_PRIORITY; + if (evt instanceof PaintEvent || evt instanceof LowPriorityEvent) + priority = LOW_PRIORITY; + // TODO: Maybe let Swing RepaintManager events also be processed with + // low priority. + if (evt instanceof NativeEventLoopRunningEvent) + { + nativeLoopRunning = ((NativeEventLoopRunningEvent) evt).isRunning(); + notify(); + return; + } + postEventImpl(evt, priority); + } + + /** + * Actually performs the event posting. This is needed because the + * RI doesn't use the public postEvent() method when transferring events + * between event queues in push() and pop(). + * + * @param evt the event to post + * @param priority the priority of the event + */ + private final void postEventImpl(AWTEvent evt, int priority) + { + if (evt == null) + throw new NullPointerException(); + + if (next != null) + { + next.postEvent(evt); + return; + } + + Object source = evt.getSource(); + + Queue q = queues[priority]; + if (source instanceof Component) + { + // For PaintEvents, ask the ComponentPeer to coalesce the event + // when the component is heavyweight. + Component comp = (Component) source; + ComponentPeer peer = comp.peer; + if (peer != null && evt instanceof PaintEvent + && ! (peer instanceof LightweightPeer)) + peer.coalescePaintEvent((PaintEvent) evt); + + // Check for any events already on the queue with the same source + // and ID. + AWTEvent previous = null; + for (AWTEvent qevt = q.queueHead; qevt != null; qevt = qevt.queueNext) + { + Object src = qevt.getSource(); + if (qevt.id == evt.id && src == comp) + { + // If there are, call coalesceEvents on the source component + // to see if they can be combined. + Component srccmp = (Component) src; + AWTEvent coalescedEvt = srccmp.coalesceEvents(qevt, evt); + if (coalescedEvt != null) + { + // Yes. Replace the existing event with the combined event. + if (qevt != coalescedEvt) + { + if (previous != null) + { + assert previous.queueNext == qevt; + previous.queueNext = coalescedEvt; + } + else + { + assert q.queueHead == qevt; + q.queueHead = coalescedEvt; + } + coalescedEvt.queueNext = qevt.queueNext; + if (q.queueTail == qevt) + q.queueTail = coalescedEvt; + qevt.queueNext = null; + } + return; + } + } + previous = qevt; + } + } + + if (q.queueHead == null) + { + // We have an empty queue. Set this event both as head and as tail. + q.queueHead = evt; + q.queueTail = evt; + } + else + { + // Note: queueTail should not be null here. + q.queueTail.queueNext = evt; + q.queueTail = evt; + } + + if (dispatchThread == null || !dispatchThread.isAlive()) + { + dispatchThread = new EventDispatchThread(this); + dispatchThread.start(); + } + + notify(); + } + + /** + * Causes runnable to have its run method called in the dispatch thread of the + * EventQueue. This will happen after all pending events are processed. The + * call blocks until this has happened. This method will throw an Error if + * called from the event dispatcher thread. + * + * @exception InterruptedException If another thread has interrupted + * this thread. + * @exception InvocationTargetException If an exception is thrown when running + * runnable. + * + * @since 1.2 + */ + public static void invokeAndWait(Runnable runnable) + throws InterruptedException, InvocationTargetException + { + if (isDispatchThread ()) + throw new Error("Can't call invokeAndWait from event dispatch thread"); + + EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); + Object notifyObject = new Object(); + + InvocationEvent ie = + new InvocationEvent(eq, runnable, notifyObject, true); + + synchronized (notifyObject) + { + eq.postEvent(ie); + notifyObject.wait(); + } + + Exception exception; + + if ((exception = ie.getException()) != null) + throw new InvocationTargetException(exception); + } + + /** + * This arranges for runnable to have its run method called in the + * dispatch thread of the EventQueue. This will happen after all + * pending events are processed. + * + * @since 1.2 + */ + public static void invokeLater(Runnable runnable) + { + EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); + + InvocationEvent ie = + new InvocationEvent(eq, runnable, null, false); + + eq.postEvent(ie); + } + + /** + * Return true if the current thread is the current AWT event dispatch + * thread. + */ + public static boolean isDispatchThread() + { + EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); + + /* Find last EventQueue in chain */ + while (eq.next != null) + eq = eq.next; + + return (Thread.currentThread() == eq.dispatchThread); + } + + /** + * Return the event currently being dispatched by the event + * dispatch thread. If the current thread is not the event + * dispatch thread, this method returns null. + * + * @since 1.4 + */ + public static AWTEvent getCurrentEvent() + { + EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); + Thread ct = Thread.currentThread(); + + /* Find out if this thread is the dispatch thread for any of the + EventQueues in the chain */ + while (ct != eq.dispatchThread) + { + // Try next EventQueue, if any + if (eq.next == null) + return null; // Not an event dispatch thread + eq = eq.next; + } + + return eq.currentEvent; + } + + /** + * Allows a custom EventQueue implementation to replace this one. + * All pending events are transferred to the new queue. Calls to postEvent, + * getNextEvent, and peekEvent and others are forwarded to the pushed queue + * until it is removed with a pop(). + * + * @exception NullPointerException if newEventQueue is null. + */ + public synchronized void push(EventQueue newEventQueue) + { + if (newEventQueue == null) + throw new NullPointerException (); + + /* Make sure we are at the top of the stack because callers can + only get a reference to the one at the bottom using + Toolkit.getDefaultToolkit().getSystemEventQueue() */ + if (next != null) + { + next.push (newEventQueue); + return; + } + + /* Make sure we have a live dispatch thread to drive the queue */ + if (dispatchThread == null) + dispatchThread = new EventDispatchThread(this); + + synchronized (newEventQueue) + { + // The RI transfers the events without calling the new eventqueue's + // push(), but using getNextEvent(). + while (peekEvent() != null) + { + try + { + newEventQueue.postEventImpl(getNextEvent()); + } + catch (InterruptedException ex) + { + // What should we do with this? + ex.printStackTrace(); + } + } + newEventQueue.prev = this; + } + + next = newEventQueue; + } + + /** Transfer any pending events from this queue back to the parent queue that + * was previously push()ed. Event dispatch from this queue is suspended. + * + * @exception EmptyStackException If no previous push was made on this + * EventQueue. + */ + protected void pop() throws EmptyStackException + { + /* The order is important here, we must get the prev lock first, + or deadlock could occur as callers usually get here following + prev's next pointer, and thus obtain prev's lock before trying + to get this lock. */ + EventQueue previous = prev; + if (previous == null) + throw new EmptyStackException(); + synchronized (previous) + { + synchronized (this) + { + EventQueue nextQueue = next; + if (nextQueue != null) + { + nextQueue.pop(); + } + else + { + previous.next = null; + + // The RI transfers the events without calling the new eventqueue's + // push(), so this should be OK and most effective. + while (peekEvent() != null) + { + try + { + previous.postEventImpl(getNextEvent()); + } + catch (InterruptedException ex) + { + // What should we do with this? + ex.printStackTrace(); + } + } + prev = null; + // Tell our EventDispatchThread that it can end + // execution. + if (dispatchThread != null) + { + dispatchThread.interrupt(); + dispatchThread = null; + } + } + } + } + } + + /** + * Dispatches an event. The manner in which the event is dispatched depends + * upon the type of the event and the type of the event's source object. + * + * @exception NullPointerException If event is null. + */ + protected void dispatchEvent(AWTEvent evt) + { + currentEvent = evt; + + if (evt instanceof InputEvent) + lastWhen = ((InputEvent) evt).getWhen(); + else if (evt instanceof ActionEvent) + lastWhen = ((ActionEvent) evt).getWhen(); + else if (evt instanceof InvocationEvent) + lastWhen = ((InvocationEvent) evt).getWhen(); + + if (evt instanceof ActiveEvent) + { + ActiveEvent active_evt = (ActiveEvent) evt; + active_evt.dispatch(); + } + else + { + Object source = evt.getSource(); + + if (source instanceof Component) + { + Component srccmp = (Component) source; + srccmp.dispatchEvent(evt); + } + else if (source instanceof MenuComponent) + { + MenuComponent srccmp = (MenuComponent) source; + srccmp.dispatchEvent(evt); + } + } + } + + /** + * Returns the timestamp of the most recent event that had a timestamp, or + * the initialization time of the event queue if no events have been fired. + * At present, only <code>InputEvent</code>s, <code>ActionEvent</code>s, + * <code>InputMethodEvent</code>s, and <code>InvocationEvent</code>s have + * timestamps, but this may be added to other events in future versions. + * If this is called by the event dispatching thread, it can be any + * (sequential) value, but to other threads, the safest bet is to return + * System.currentTimeMillis(). + * + * @return the most recent timestamp + * @see InputEvent#getWhen() + * @see ActionEvent#getWhen() + * @see InvocationEvent#getWhen() + * @see InputMethodEvent#getWhen() + * @since 1.4 + */ + public static long getMostRecentEventTime() + { + EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); + if (Thread.currentThread() != eq.dispatchThread) + return System.currentTimeMillis(); + return eq.lastWhen; + } +} diff --git a/libjava/classpath/java/awt/FileDialog.java b/libjava/classpath/java/awt/FileDialog.java new file mode 100644 index 000000000..c1bd08264 --- /dev/null +++ b/libjava/classpath/java/awt/FileDialog.java @@ -0,0 +1,395 @@ +/* FileDialog.java -- A filename selection dialog box + Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.peer.FileDialogPeer; +import java.io.FilenameFilter; +import java.io.Serializable; + +/** + * This class implements a file selection dialog box widget. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@redhat.com) + */ +public class FileDialog extends Dialog implements Serializable +{ + +/* + * Static Variables + */ + +/** + * Indicates that the purpose of the dialog is for opening a file. + */ +public static final int LOAD = 0; + +/** + * Indicates that the purpose of the dialog is for saving a file. + */ +public static final int SAVE = 1; + +// Serialization constant +private static final long serialVersionUID = 5035145889651310422L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * @serial The directory for this file dialog. + */ +private String dir; + +/** + * @serial The filename for this file dialog + */ +private String file; + +/** + * @serial The filter for selecting filenames to display + */ +private FilenameFilter filter; + +/** + * @serial The mode of this dialog, either <code>LOAD</code> or + * <code>SAVE</code>. + */ +private int mode; + +/** + * The number used to generate the name returned by getName. + */ +private static transient long next_file_dialog_number; + +/*************************************************************************/ + +/* + * Constructors + */ + + /** + * Initializes a new instance of <code>FileDialog</code> with the specified + * parent. This dialog will have no title and will be for loading a file. + * + * @param parent The parent dialog for this. + * + * @since 1.5 + */ + public FileDialog(Dialog parent) + { + this(parent, "", LOAD); + } + + /** + * Initialized a new instance of <code>FileDialog</code> with the + * specified parent and title. This dialog will be for opening a file. + * + * @param parent The parent dialog for this. + * @param title The title for this dialog. + * + * @since 1.5 + */ + public FileDialog(Dialog parent, String title) + { + this(parent, title, LOAD); + } + + /** + * Initialized a new instance of <code>FileDialog</code> with the specified + * parent, title, and mode. + * + * @param parent The parent dialog for this. + * @param title The title for this dialog. + * @param mode The mode of the dialog, either <code>LOAD</code> or + * <code>SAVE</code>. + * @throws IllegalArgumentException - if illegal mode, if + * GraphicsEnvironment.isHeadless or if parent is null. + * + * @since 1.5 + */ + public FileDialog(Dialog parent, String title, int mode) + { + super(parent, title, true); + + // Other IllegalArgumentException cases are taken care of in Window.java + if (mode != LOAD && mode != SAVE) + throw new IllegalArgumentException ( + "Mode argument must be either LOAD or SAVE"); + + setMode(mode); + } + +/** + * Initializes a new instance of <code>FileDialog</code> with the + * specified parent. This dialog will have no title and will be for + * loading a file. + * + * @param parent The parent frame for this dialog. + */ +public +FileDialog(Frame parent) +{ + this(parent, "", LOAD); +} + +/*************************************************************************/ + +/** + * Initialized a new instance of <code>FileDialog</code> with the + * specified parent and title. This dialog will be for opening a file. + * + * @param parent The parent frame for this dialog. + * @param title The title for this dialog. + */ +public +FileDialog(Frame parent, String title) +{ + this(parent, title, LOAD); +} + +/*************************************************************************/ + +/** + * Initialized a new instance of <code>FileDialog</code> with the + * specified parent, title, and mode. + * + * @param parent The parent frame for this dialog. + * @param title The title for this dialog. + * @param mode The mode of the dialog, either <code>LOAD</code> or + * <code>SAVE</code>. + * + * @exception IllegalArgumentException If an illegal file dialog mode + * is supplied. + */ +public +FileDialog(Frame parent, String title, int mode) +{ + super(parent, title, true); + + if ((mode != LOAD) && (mode != SAVE)) + throw new IllegalArgumentException ( + "Mode argument must be either LOAD or SAVE"); + + setMode (mode); +} + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * Returns the mode of this dialog, either <code>LOAD</code> or + * <code>SAVE</code>. + * + * @return The mode of this dialog. + */ +public int +getMode() +{ + return(mode); +} + +/*************************************************************************/ + +/** + * Sets the mode of this dialog to either <code>LOAD</code> or + * <code>SAVE</code>. This method is only effective before the native + * peer is created. + * + * @param mode The new mode of this file dialog. + * + * @exception IllegalArgumentException If an illegal file dialog mode + * is supplied. + */ +public void +setMode(int mode) +{ + if ((mode != LOAD) && (mode != SAVE)) + throw new IllegalArgumentException("Bad mode: " + mode); + + this.mode = mode; +} + +/*************************************************************************/ + +/** + * Returns the directory for this file dialog. + * + * @return The directory for this file dialog. + */ +public String +getDirectory() +{ + return(dir); +} + +/*************************************************************************/ + +/** + * Sets the directory for this file dialog. + * + * @param dir The new directory for this file dialog. + */ +public synchronized void +setDirectory(String dir) +{ + this.dir = dir; + if (peer != null) + { + FileDialogPeer f = (FileDialogPeer) peer; + f.setDirectory (dir); + } +} + +/*************************************************************************/ + +/** + * Returns the file that is selected in this dialog. + * + * @return The file that is selected in this dialog. + */ +public String +getFile() +{ + return(file); +} + +/*************************************************************************/ + +/** + * Sets the selected file for this dialog. + * + * @param file The selected file for this dialog. + */ +public synchronized void +setFile(String file) +{ + if ("".equals(file)) + this.file = null; + else + this.file = file; + + if (peer != null) + { + FileDialogPeer f = (FileDialogPeer) peer; + f.setFile (file); + } +} + +/*************************************************************************/ + +/** + * Returns the filename filter being used by this dialog. + * + * @return The filename filter being used by this dialog. + */ +public FilenameFilter +getFilenameFilter() +{ + return(filter); +} + +/*************************************************************************/ + +/** + * Sets the filename filter used by this dialog. + * + * @param filter The new filename filter for this file dialog box. + */ +public synchronized void +setFilenameFilter(FilenameFilter filter) +{ + this.filter = filter; + if (peer != null) + { + FileDialogPeer f = (FileDialogPeer) peer; + f.setFilenameFilter (filter); + } +} + +/*************************************************************************/ + +/** + * Creates the native peer for this file dialog box. + */ +public void +addNotify() +{ + if (peer == null) + peer = getToolkit ().createFileDialog (this); + super.addNotify (); +} + +/*************************************************************************/ + +/** + * Returns a debugging string for this object. + * + * @return A debugging string for this object. + */ +protected String +paramString() +{ + return ("dir=" + dir + ",file=" + file + + ",mode=" + mode + "," + super.paramString()); +} + +/** + * Generate a unique name for this <code>FileDialog</code>. + * + * @return A unique name for this <code>FileDialog</code>. + */ +String +generateName() +{ + return "filedlg" + getUniqueLong(); +} + +private static synchronized long +getUniqueLong() +{ + return next_file_dialog_number++; +} + +} // class FileDialog diff --git a/libjava/classpath/java/awt/FlowLayout.java b/libjava/classpath/java/awt/FlowLayout.java new file mode 100644 index 000000000..231d041b1 --- /dev/null +++ b/libjava/classpath/java/awt/FlowLayout.java @@ -0,0 +1,365 @@ +/* FlowLayout.java -- Grid-based layout engine + Copyright (C) 1999, 2000, 2001, 2002, 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.io.Serializable; + +/** This class implements a flow-based layout. Components are laid + * out in order from left to right. When a component cannot be placed + * without horizontal clipping, a new row is started. This class + * supports horizontal and vertical gaps. These are used for spacing + * between components. + * + * @author Tom Tromey (tromey@redhat.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class FlowLayout implements LayoutManager, Serializable +{ + /** Constant that specifies left alignment. */ + public static final int LEFT = 0; + /** Constant that specifies center alignment. */ + public static final int CENTER = 1; + /** Constant that specifies right alignment. */ + public static final int RIGHT = 2; + + /** Constant that specifies alignment to leading edge of container's + * orientation. */ + public static final int LEADING = 3; + /** Constant that specifies alignment to trailing edge of container's + * orientation. */ + public static final int TRAILING = 4; + + // Serialization constant + private static final long serialVersionUID = -7262534875583282631L; + + /** + * Add a new component to the layout. This particular implementation + * does nothing. + * + * @param name the name + * @param comp the component + */ + public void addLayoutComponent (String name, Component comp) + { + // Nothing. + } + + /** + * Returns the current justification value for this object. + * + * @return The current justification value for this object. + */ + public int getAlignment () + { + return align; + } + + /** + * Returns the horizontal gap between components. + * + * @return The horizontal gap between components. + */ + public int getHgap () + { + return hgap; + } + + /** + * Returns the vertical gap between lines of components. + * + * @return The vertical gap between lines of components. + */ + public int getVgap () + { + return vgap; + } + + /** + * Initializes a new instance of <code>FlowLayout</code> with a center + * justification and a default horizontal and vertical gap of 5. + */ + public FlowLayout () + { + this (CENTER, 5, 5); + } + + /** + * Initializes a new instance of <code>FlowLayout</code> with the specified + * justification and a default horizontal and vertical gap of 5. + * + * @param align The justification setting, which should be one of the + * contants in this class. + */ + public FlowLayout (int align) + { + this (align, 5, 5); + } + + /** + * Initializes a new instance of <code>FlowLayout</code> with the specified + * justification and gap values + * @param align Alignment + * @param hgap The horizontal gap + * @param vgap The vertical gap + * @exception IllegalArgumentException If either gap is negative + */ + public FlowLayout (int align, int hgap, int vgap) + { + // Use methods to set fields so that we can have all the checking + // in one place. + setVgap (vgap); + setHgap (hgap); + setAlignment (align); + } + + /** Lay out the container's components based on current settings. + * @param parent The parent container + */ + public void layoutContainer (Container parent) + { + synchronized (parent.getTreeLock ()) + { + int num = parent.getComponentCount (); + // This is more efficient than calling getComponents(). + Component[] comps = parent.component; + + Dimension d = parent.getSize (); + Insets ins = parent.getInsets (); + + ComponentOrientation orient = parent.getComponentOrientation (); + boolean left_to_right = orient.isLeftToRight (); + + int y = ins.top + vgap; + int i = 0; + while (i < num) + { + // Find the components which go in the current row. + int new_w = ins.left + hgap + ins.right; + int new_h = 0; + int j; + boolean found_one = false; + for (j = i; j < num; ++j) + { + // Skip invisible items. + if (! comps[j].visible) + continue; + + Dimension c = comps[j].getPreferredSize (); + + int next_w = new_w + hgap + c.width; + if (next_w <= d.width || ! found_one) + { + new_w = next_w; + new_h = Math.max (new_h, c.height); + found_one = true; + } + else + { + // Must start a new row, and we already found an item + break; + } + } + + // Set the location of each component for this row. + int x; + + int myalign = align; + if (align == LEADING) + myalign = left_to_right ? LEFT : RIGHT; + else if (align == TRAILING) + myalign = left_to_right ? RIGHT : LEFT; + + if (myalign == RIGHT) + x = ins.left + (d.width - new_w) + hgap; + else if (myalign == CENTER) + x = ins.left + (d.width - new_w) / 2 + hgap; + else // LEFT and all other values of align. + x = ins.left + hgap; + + for (int k = i; k < j; ++k) + { + if (comps[k].visible) + { + Dimension c = comps[k].getPreferredSize (); + comps[k].setBounds (x, y + (new_h - c.height) / 2, + c.width, c.height); + x += c.width + hgap; + } + } + + // Advance to next row. + i = j; + y += new_h + vgap; + } + } + } + + /** + * Returns the minimum layout size for the specified container using + * this layout. + * @param cont The parent container + * @return The minimum layout size. + */ + public Dimension minimumLayoutSize (Container cont) + { + return getSize (cont, true); + } + + /** + * Returns the preferred layout size for the specified container using + * this layout. + * @param cont The parent container + * @return The preferred layout size. + */ + public Dimension preferredLayoutSize (Container cont) + { + return getSize (cont, false); + } + + /** Remove the indicated component from this layout manager. + * This particular implementation does nothing. + * @param comp The component to remove + */ + public void removeLayoutComponent (Component comp) + { + // Nothing. + } + + /** + * Sets the justification value for this object to the specified value. + * + * @param align The new justification value for this object, which must + * be one of the constants in this class. + */ + public void setAlignment (int align) + { + // The JDK accepts invalid values and treats them as + // LEFT during layout, so do we. The invalid value is even stored, + // getAlignment() returns the same invalid value. + this.align = align; + } + + /** + * Sets the horizontal gap between lines of components to the specified value. + * No Exception is thrown if hgap < 0. + * + * @param hgap The new horizontal gap between components. + */ + public void setHgap (int hgap) + { + this.hgap = hgap; + } + + /** + * Sets the vertical gap between lines of components to the specified value. + * No Exception is thrown if vgap < 0. + * + * @param vgap The new vertical gap. + */ + public void setVgap (int vgap) + { + this.vgap = vgap; + } + + /** Return String description of this object. + * @return A string representation of this object. + */ + public String toString () + { + return ("[" + getClass ().getName () + ",hgap=" + hgap + ",vgap=" + vgap + + ",align=" + align + "]"); + } + + // This method is used to compute the various sizes. + private Dimension getSize (Container parent, boolean is_min) + { + synchronized (parent.getTreeLock ()) + { + int w, h, num = parent.getComponentCount (); + // This is more efficient than calling getComponents(). + Component[] comps = parent.component; + + w = 0; + h = 0; + for (int i = 0; i < num; ++i) + { + if (! comps[i].visible) + continue; + + // FIXME: can we just directly read the fields in Component? + // Or will that not work with subclassing? + Dimension d; + + if (is_min) + d = comps[i].getMinimumSize (); + else + d = comps[i].getPreferredSize (); + + w += d.width; + h = Math.max (d.height, h); + } + + Insets ins = parent.getInsets (); + + if (num == 0) + w += 2 * hgap + ins.left + ins.right; + else + w += (num + 1) * hgap + ins.left + ins.right; + h += 2 * vgap + ins.top + ins.bottom; + + return new Dimension (w, h); + } + } + + /** + * @serial The justification alignment of the lines of components, which + * will be one of the constants defined in this class. + */ + private int align; + + /** + * @serial The horizontal gap between components. + */ + private int hgap; + + /** + * @serial The vertical gap between lines of components. + */ + private int vgap; +} diff --git a/libjava/classpath/java/awt/FocusTraversalPolicy.java b/libjava/classpath/java/awt/FocusTraversalPolicy.java new file mode 100644 index 000000000..d9374eae8 --- /dev/null +++ b/libjava/classpath/java/awt/FocusTraversalPolicy.java @@ -0,0 +1,103 @@ +/* FocusTraversalPolicy.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +/** + * @since 1.4 + */ +public abstract class FocusTraversalPolicy +{ + /** + * Creates a <code>FocusTraversalPolicy</code> object. + */ + public FocusTraversalPolicy() + { + // Do nothing in here. + } + + /** + * Returns the Component that should receive the focus after a Component. + * + * @exception IllegalArgumentException If root or current is null, + * or if root is not a focus cycle root of current. + */ + public abstract Component getComponentAfter(Container root, + Component current); + + /** + * Returns the Component that should receive the focus before a Component. + * + * @exception IllegalArgumentException If root or current is null, + * or if root is not a focus cycle root of current. + */ + public abstract Component getComponentBefore(Container root, + Component current); + + /** + * Returns the first Component in the traversal cycle. + * + * @exception IllegalArgumentException If root is null. + */ + public abstract Component getFirstComponent(Container root); + + /** + * Returns the last Component in the traversal cycle. + * + * @exception IllegalArgumentException If root is null. + */ + public abstract Component getLastComponent(Container root); + + /** + * Returns the default Component to focus. + * + * @exception IllegalArgumentException If root is null. + */ + public abstract Component getDefaultComponent(Container root); + + /** + * Returns the Component that should receive the focus when a Window is made + * visible for the first time. + * + * @exception IllegalArgumentException If window is null. + */ + public Component getInitialComponent(Window window) + { + return getDefaultComponent(window); + } +} // class FocusTraversalPolicy diff --git a/libjava/classpath/java/awt/Font.java b/libjava/classpath/java/awt/Font.java new file mode 100644 index 000000000..89ff1f52a --- /dev/null +++ b/libjava/classpath/java/awt/Font.java @@ -0,0 +1,1451 @@ +/* Font.java -- Font object + Copyright (C) 1999, 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import gnu.java.awt.ClasspathToolkit; +import gnu.java.awt.peer.ClasspathFontPeer; + +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.LineMetrics; +import java.awt.font.TextAttribute; +import java.awt.font.TextLayout; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.peer.FontPeer; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.Serializable; +import java.text.AttributedCharacterIterator; +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.StringTokenizer; + +/** + * This class represents a windowing system font. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * @author Graydon Hoare (graydon@redhat.com) + */ +public class Font implements Serializable +{ + + /** + * Constant indicating a "plain" font. + */ + public static final int PLAIN = 0; + + /** + * Constant indicating a "bold" font. + */ + public static final int BOLD = 1; + + /** + * Constant indicating an "italic" font. + */ + public static final int ITALIC = 2; + + /** + * Constant indicating the baseline mode characteristic of Roman. + */ + public static final int ROMAN_BASELINE = 0; + + /** + * Constant indicating the baseline mode characteristic of Chinese. + */ + public static final int CENTER_BASELINE = 1; + + /** + * Constant indicating the baseline mode characteristic of Devanigri. + */ + public static final int HANGING_BASELINE = 2; + + + /** + * Indicates to <code>createFont</code> that the supplied font data + * is in TrueType format. + * + * <p><em>Specification Note:</em> The Sun JavaDoc for J2SE 1.4 does + * not indicate whether this value also subsumes OpenType. OpenType + * is essentially the same format as TrueType, but allows to define + * glyph shapes in the same way as PostScript, using cubic bezier + * curves. + * + * @since 1.3 + */ + public static final int TRUETYPE_FONT = 0; + + /** + * Indicates to <code>createFont</code> that the supplied font data + * is in Type1 format. + * + * @since 1.5 + */ + public static final int TYPE1_FONT = 1; + + /** + * A flag for <code>layoutGlyphVector</code>, indicating that the + * orientation of a text run is from left to right. + * + * @since 1.4 + */ + public static final int LAYOUT_LEFT_TO_RIGHT = 0; + + + /** + * A flag for <code>layoutGlyphVector</code>, indicating that the + * orientation of a text run is from right to left. + * + * @since 1.4 + */ + public static final int LAYOUT_RIGHT_TO_LEFT = 1; + + + /** + * A flag for <code>layoutGlyphVector</code>, indicating that the + * text does not contain valid characters before the + * <code>start</code> position. If this flag is set, + * <code>layoutGlyphVector</code> does not examine the text before + * <code>start</code>, even if this would be necessary to select the + * correct glyphs (e.g., for Arabic text). + * + * @since 1.4 + */ + public static final int LAYOUT_NO_START_CONTEXT = 2; + + + /** + * A flag for <code>layoutGlyphVector</code>, indicating that the + * text does not contain valid characters after the + * <code>limit</code> position. If this flag is set, + * <code>layoutGlyphVector</code> does not examine the text after + * <code>limit</code>, even if this would be necessary to select the + * correct glyphs (e.g., for Arabic text). + * + * @since 1.4 + */ + public static final int LAYOUT_NO_LIMIT_CONTEXT = 4; + + /** + * @since 1.6 + */ + public static final String DIALOG = "Dialog"; + + /** + * @since 1.6 + */ + public static final String DIALOG_INPUT = "DialogInput"; + + /** + * @since 1.6 + */ + public static final String MONOSPACED = "Monospaced"; + + /** + * @since 1.6 + */ + public static final String SANS_SERIF = "SansSerif"; + + /** + * @since 1.6 + */ + public static final String SERIF = "Serif"; + + /** + * The logical name of this font. + * + * @since 1.0 + */ + protected String name; + + /** + * The size of this font in points, rounded. + * + * @since 1.0 + */ + protected int size; + + /** + * The size of this font in points. + * + * @since 1.0 + */ + protected float pointSize; + + /** + * The style of this font -- PLAIN, BOLD, ITALIC or BOLD+ITALIC. + * + * @since 1.0 + */ + protected int style; + +//Serialization constant + private static final long serialVersionUID = -4206021311591459213L; + + + // The ClasspathToolkit-provided peer which implements this font + private transient ClasspathFontPeer peer; + + /** + * The cached hashcode. A value of 0 (default initialized) means that the + * hashcode is not computed yet. + */ + private transient int hashCode; + + /** + * Creates a <code>Font</code> object from the specified string, which + * is in one of the following formats: + * <p> + * <ul> + * <li>fontname-style-pointsize + * <li>fontname-style + * <li>fontname-pointsize + * <li>fontname + * </ul> + * <p> + * The style should be one of BOLD, ITALIC, or BOLDITALIC. The default + * style if none is specified is PLAIN. The default size if none + * is specified is 12. + * + * @param fontspec a string specifying the required font (<code>null</code> + * permitted, interpreted as 'Dialog-PLAIN-12'). + * + * @return A font. + */ + public static Font decode(String fontspec) + { + if (fontspec == null) + fontspec = "Dialog-PLAIN-12"; + String name = null; + int style = PLAIN; + int size = 12; + + StringTokenizer st = new StringTokenizer(fontspec, "- "); + while (st.hasMoreTokens()) + { + String token = st.nextToken(); + if (name == null) + { + name = token; + continue; + } + + if (token.toUpperCase().equals("BOLD")) + { + style = BOLD; + continue; + } + if (token.toUpperCase().equals("ITALIC")) + { + style = ITALIC; + continue; + } + if (token.toUpperCase().equals("BOLDITALIC")) + { + style = BOLD | ITALIC; + continue; + } + + int tokenval = 0; + try + { + tokenval = Integer.parseInt(token); + } + catch (NumberFormatException e) + { + // Ignored. + } + + if (tokenval != 0) + size = tokenval; + } + + HashMap attrs = new HashMap(); + ClasspathFontPeer.copyStyleToAttrs(style, attrs); + ClasspathFontPeer.copySizeToAttrs(size, attrs); + + return getFontFromToolkit(name, attrs); + } + + /* These methods delegate to the toolkit. */ + + static ClasspathToolkit tk() + { + return (ClasspathToolkit) Toolkit.getDefaultToolkit(); + } + + /* Every factory method in Font should eventually call this. */ + static Font getFontFromToolkit(String name, Map attribs) + { + return tk().getFont(name, attribs); + } + + /* Every Font constructor should eventually call this. */ + static ClasspathFontPeer getPeerFromToolkit(String name, Map attrs) + { + return tk().getClasspathFontPeer(name, attrs); + } + + + /** + * Returns a <code>Font</code> object from the passed property name. + * + * @param propname The name of the system property. + * @param defval Value to use if the property is not found. + * + * @return The requested font, or <code>default</code> if the property + * not exist or is malformed. + */ + public static Font getFont(String propname, Font defval) + { + String propval = System.getProperty(propname); + if (propval != null) + return decode(propval); + return defval; + } + + /** + * Returns a <code>Font</code> object from the passed property name. + * + * @param propname The name of the system property. + * + * @return The requested font, or <code>null</code> if the property + * not exist or is malformed. + */ + public static Font getFont(String propname) + { + return getFont(propname, (Font) null); + } + + protected Font(Font font) + { + this(font.getName(), font.getAttributes()); + } + + /** + * Initializes a new instance of <code>Font</code> with the specified + * attributes. + * + * @param name The name of the font. + * @param style The font style. + * @param size The font point size. + */ + public Font(String name, int style, int size) + { + HashMap attrs = new HashMap(); + ClasspathFontPeer.copyStyleToAttrs(style, attrs); + ClasspathFontPeer.copySizeToAttrs(size, attrs); + this.peer = getPeerFromToolkit(name, attrs); + this.size = size; + this.pointSize = (float) size; + if (name != null) + this.name = name; + else + this.name = peer.getName(this); + } + + public Font(Map<? extends AttributedCharacterIterator.Attribute, ?> attrs) + { + this(null, attrs); + } + + /* This extra constructor is here to permit ClasspathToolkit and to + build a font with a "logical name" as well as attrs. + ClasspathToolkit.getFont(String,Map) uses reflection to call this + package-private constructor. */ + Font(String name, Map attrs) + { + // If attrs is null, setting it to an empty HashMap will give this + // Font default attributes. + if (attrs == null) + attrs = new HashMap(); + peer = getPeerFromToolkit(name, attrs); + size = (int) peer.getSize(this); + pointSize = peer.getSize(this); + if (name != null) + this.name = name; + else + this.name = peer.getName(this); + } + + /** + * Returns the logical name of the font. A logical name is the name the + * font was constructed with. It may be the name of a logical font (one + * of 6 required names in all java environments) or it may be a face + * name. + * + * @return The logical name of the font. + * + * @see #getFamily() + * @see #getFontName() + */ + public String getName () + { + return peer.getName(this); + } + + /** + * Returns the size of the font, in typographics points (1/72 of an inch), + * rounded to an integer. + * + * @return The font size + */ + public int getSize() + { + return size; + } + + /** + * Returns the size of the font, in typographics points (1/72 of an inch). + * + * @return The font size + */ + public float getSize2D() + { + return pointSize; + } + + /** + * Tests whether or not this is a plain font. This will be true if + * and only if neither the bold nor the italics style is set. + * + * @return <code>true</code> if this is a plain font, <code>false</code> + * otherwise. + */ + public boolean isPlain() + { + return peer.isPlain(this); + } + + /** + * Tests whether or not this font is bold. + * + * @return <code>true</code> if this font is bold, <code>false</code> + * otherwise. + */ + public boolean isBold() + { + return peer.isBold(this); + } + + /** + * Tests whether or not this font is italic. + * + * @return <code>true</code> if this font is italic, <code>false</code> + * otherwise. + */ + public boolean isItalic() + { + return peer.isItalic(this); + } + + /** + * Returns the family name of this font. A family name describes a design + * or "brand name" (such as Helvetica or Palatino). It is less specific + * than a font face name (such as Helvetica Bold). + * + * @return A string containing the font family name. + * + * @since 1.2 + * + * @see #getName() + * @see #getFontName() + * @see GraphicsEnvironment#getAvailableFontFamilyNames() + */ + public String getFamily() + { + return peer.getFamily(this); + } + + /** + * Returns integer code representing the sum of style flags of this font, a + * combination of either {@link #PLAIN}, {@link #BOLD}, or {@link #ITALIC}. + * + * @return code representing the style of this font. + * + * @see #isPlain() + * @see #isBold() + * @see #isItalic() + */ + public int getStyle() + { + return peer.getStyle(this); + } + + /** + * Checks if specified character maps to a glyph in this font. + * + * @param c The character to check. + * + * @return Whether the character has a corresponding glyph in this font. + * + * @since 1.2 + */ + public boolean canDisplay(char c) + { + return canDisplay((int) c); + } + + public boolean canDisplay(int codePoint) + { + return peer.canDisplay(this, codePoint); + } + + /** + * Checks how much of a given string can be mapped to glyphs in + * this font. + * + * @param s The string to check. + * + * @return The index of the first character in <code>s</code> which cannot + * be converted to a glyph by this font, or <code>-1</code> if all + * characters can be mapped to glyphs. + * + * @since 1.2 + */ + public int canDisplayUpTo(String s) + { + return peer.canDisplayUpTo(this, new StringCharacterIterator(s), + 0, s.length() - 1); + } + + /** + * Checks how much of a given sequence of text can be mapped to glyphs in + * this font. + * + * @param text Array containing the text to check. + * @param start Position of first character to check in <code>text</code>. + * @param limit Position of last character to check in <code>text</code>. + * + * @return The index of the first character in the indicated range which + * cannot be converted to a glyph by this font, or <code>-1</code> if all + * characters can be mapped to glyphs. + * + * @since 1.2 + * + * @throws IndexOutOfBoundsException if the range [start, limit] is + * invalid in <code>text</code>. + */ + public int canDisplayUpTo (char[] text, int start, int limit) + { + return peer.canDisplayUpTo(this, + new StringCharacterIterator(new String (text)), + start, limit); + } + + /** + * Checks how much of a given sequence of text can be mapped to glyphs in + * this font. + * + * @param i Iterator over the text to check. + * @param start Position of first character to check in <code>i</code>. + * @param limit Position of last character to check in <code>i</code>. + * + * @return The index of the first character in the indicated range which + * cannot be converted to a glyph by this font, or <code>-1</code> if all + * characters can be mapped to glyphs. + * + * @since 1.2 + * + * @throws IndexOutOfBoundsException if the range [start, limit] is + * invalid in <code>i</code>. + */ + public int canDisplayUpTo(CharacterIterator i, int start, int limit) + { + return peer.canDisplayUpTo(this, i, start, limit); + } + + /** + * Creates a new font with point size 1 and {@link #PLAIN} style, + * reading font data from the provided input stream. The resulting font + * can have further fonts derived from it using its + * <code>deriveFont</code> method. + * + * @param fontFormat Integer code indicating the format the font data is + * in.Currently this can only be {@link #TRUETYPE_FONT}. + * @param is {@link InputStream} from which font data will be read. This + * stream is not closed after font data is extracted. + * + * @return A new {@link Font} of the format indicated. + * + * @throws IllegalArgumentException if <code>fontType</code> is not + * recognized. + * @throws FontFormatException if data in InputStream is not of format + * indicated. + * @throws IOException if insufficient data is present on InputStream. + * + * @since 1.3 + */ + public static Font createFont (int fontFormat, InputStream is) + throws FontFormatException, IOException + { + return tk().createFont(fontFormat, is); + } + + /** + * Creates a new font from a File object. + * + * @see #layoutGlyphVector(FontRenderContext, char[], int, int, int) + * + * @param fontFormat - Integer code indicating the format the font data is + * in.Currently this can only be {@link #TRUETYPE_FONT}. + * @param file - a {@link File} from which font data will be read. + * + * @return A new {@link Font} of the format indicated. + * + * @throws IllegalArgumentException if <code>fontType</code> is not + * recognized. + * @throws NullPointerException if <code>file</code> is <code>null</code>. + * @throws FontFormatException if data in the file is invalid or cannot be read.. + * @throws SecurityException if the caller has no read permission for the file. + * @throws IOException if the file cannot be read + * + * @since 1.5 + */ + public static Font createFont (int fontFormat, File file) + throws FontFormatException, IOException + { + if( file == null ) + throw new NullPointerException("Null file argument"); + return tk().createFont(fontFormat, new FileInputStream( file )); + } + + /** + * Maps characters to glyphs in a one-to-one relationship, returning a new + * {@link GlyphVector} with a mapped glyph for each input character. This + * sort of mapping is often sufficient for some scripts such as Roman, but + * is inappropriate for scripts with special shaping or contextual layout + * requirements such as Arabic, Indic, Hebrew or Thai. + * + * @param ctx The rendering context used for precise glyph placement. + * @param str The string to convert to Glyphs. + * + * @return A new {@link GlyphVector} containing glyphs mapped from str, + * through the font's cmap table. + * + * @see #layoutGlyphVector(FontRenderContext, char[], int, int, int) + */ + public GlyphVector createGlyphVector(FontRenderContext ctx, String str) + { + return peer.createGlyphVector(this, ctx, new StringCharacterIterator(str)); + } + + /** + * Maps characters to glyphs in a one-to-one relationship, returning a new + * {@link GlyphVector} with a mapped glyph for each input character. This + * sort of mapping is often sufficient for some scripts such as Roman, but + * is inappropriate for scripts with special shaping or contextual layout + * requirements such as Arabic, Indic, Hebrew or Thai. + * + * @param ctx The rendering context used for precise glyph placement. + * @param i Iterator over the text to convert to glyphs. + * + * @return A new {@link GlyphVector} containing glyphs mapped from str, + * through the font's cmap table. + * + * @see #layoutGlyphVector(FontRenderContext, char[], int, int, int) + */ + public GlyphVector createGlyphVector(FontRenderContext ctx, + CharacterIterator i) + { + return peer.createGlyphVector(this, ctx, i); + } + + /** + * Maps characters to glyphs in a one-to-one relationship, returning a new + * {@link GlyphVector} with a mapped glyph for each input character. This + * sort of mapping is often sufficient for some scripts such as Roman, but + * is inappropriate for scripts with special shaping or contextual layout + * requirements such as Arabic, Indic, Hebrew or Thai. + * + * @param ctx The rendering context used for precise glyph placement. + * @param chars Array of characters to convert to glyphs. + * + * @return A new {@link GlyphVector} containing glyphs mapped from str, + * through the font's cmap table. + * + * @see #layoutGlyphVector(FontRenderContext, char[], int, int, int) + */ + public GlyphVector createGlyphVector(FontRenderContext ctx, char[] chars) + { + return peer.createGlyphVector(this, ctx, + new StringCharacterIterator(new String(chars))); + } + + /** + * Extracts a sequence of glyphs from a font, returning a new {@link + * GlyphVector} with a mapped glyph for each input glyph code. + * + * @param ctx The rendering context used for precise glyph placement. + * @param glyphCodes Array of characters to convert to glyphs. + * + * @return A new {@link GlyphVector} containing glyphs mapped from str, + * through the font's cmap table. + * + * @see #layoutGlyphVector(FontRenderContext, char[], int, int, int) + * + * @specnote This method is documented to perform character-to-glyph + * conversions, in the Sun documentation, but its second parameter name is + * "glyphCodes" and it is not clear to me why it would exist if its + * purpose was to transport character codes inside integers. I assume it + * is mis-documented in the Sun documentation. + */ + public GlyphVector createGlyphVector(FontRenderContext ctx, int[] glyphCodes) + { + return peer.createGlyphVector(this, ctx, glyphCodes); + } + + /** + * Produces a new {@link Font} based on the current font, adjusted to a + * new size and style. + * + * @param style The style of the newly created font. + * @param size The size of the newly created font. + * + * @return A clone of the current font, with the specified size and style. + * + * @since 1.2 + */ + public Font deriveFont(int style, float size) + { + return peer.deriveFont(this, style, size); + } + + /** + * Produces a new {@link Font} based on the current font, adjusted to a + * new size. + * + * @param size The size of the newly created font. + * + * @return A clone of the current font, with the specified size. + * + * @since 1.2 + */ + public Font deriveFont(float size) + { + return peer.deriveFont(this, size); + } + + /** + * Produces a new {@link Font} based on the current font, adjusted to a + * new style. + * + * @param style The style of the newly created font. + * + * @return A clone of the current font, with the specified style. + * + * @since 1.2 + */ + public Font deriveFont(int style) + { + return peer.deriveFont(this, style); + } + + /** + * Produces a new {@link Font} based on the current font, adjusted to a + * new style and subjected to a new affine transformation. + * + * @param style The style of the newly created font. + * @param a The transformation to apply. + * + * @return A clone of the current font, with the specified style and + * transform. + * + * @throws IllegalArgumentException If transformation is + * <code>null</code>. + * + * @since 1.2 + */ + public Font deriveFont(int style, AffineTransform a) + { + if (a == null) + throw new IllegalArgumentException("Affine transformation is null"); + + return peer.deriveFont(this, style, a); + } + + /** + * Produces a new {@link Font} based on the current font, subjected + * to a new affine transformation. + * + * @param a The transformation to apply. + * + * @return A clone of the current font, with the specified transform. + * + * @throws IllegalArgumentException If transformation is + * <code>null</code>. + * + * @since 1.2 + */ + public Font deriveFont(AffineTransform a) + { + if (a == null) + throw new IllegalArgumentException("Affine transformation is null"); + + return peer.deriveFont(this, a); + } + + /** + * Produces a new {@link Font} based on the current font, adjusted to a + * new set of attributes. + * + * @param attributes Attributes of the newly created font. + * + * @return A clone of the current font, with the specified attributes. + * + * @since 1.2 + */ + public Font deriveFont(Map<? extends AttributedCharacterIterator.Attribute, ?> attributes) + { + return peer.deriveFont(this, attributes); + } + + /** + * Returns a map of chracter attributes which this font currently has set. + * + * @return A map of chracter attributes which this font currently has set. + * + * @see #getAvailableAttributes() + * @see java.text.AttributedCharacterIterator.Attribute + * @see java.awt.font.TextAttribute + */ + public Map<TextAttribute, ?> getAttributes() + { + return peer.getAttributes(this); + } + + /** + * Returns an array of chracter attribute keys which this font understands. + * + * @return An array of chracter attribute keys which this font understands. + * + * @see #getAttributes() + * @see java.text.AttributedCharacterIterator.Attribute + * @see java.awt.font.TextAttribute + */ + public AttributedCharacterIterator.Attribute[] getAvailableAttributes() + { + return peer.getAvailableAttributes(this); + } + + /** + * Returns a baseline code (one of {@link #ROMAN_BASELINE}, {@link + * #CENTER_BASELINE} or {@link #HANGING_BASELINE}) indicating which baseline + * this font will measure baseline offsets for, when presenting glyph + * metrics for a given character. + * + * Baseline offsets describe the position of a glyph relative to an + * invisible line drawn under, through the center of, or over a line of + * rendered text, respectively. Different scripts use different baseline + * modes, so clients should not assume all baseline offsets in a glyph + * vector are from a common baseline. + * + * @param c The character code to select a baseline mode for. + * + * @return The baseline mode which would be used in a glyph associated + * with the provided character. + * + * @since 1.2 + * + * @see LineMetrics#getBaselineOffsets() + */ + public byte getBaselineFor(char c) + { + return peer.getBaselineFor(this, c); + } + + /** + * Returns the family name of this font. A family name describes a + * typographic style (such as Helvetica or Palatino). It is more specific + * than a logical font name (such as Sans Serif) but less specific than a + * font face name (such as Helvetica Bold). + * + * @param lc The locale in which to describe the name of the font family. + * + * @return A string containing the font family name, localized for the + * provided locale. + * + * @since 1.2 + * + * @see #getName() + * @see #getFontName() + * @see GraphicsEnvironment#getAvailableFontFamilyNames() + * @see Locale + */ + public String getFamily(Locale lc) + { + return peer.getFamily(this, lc); + } + + /** + * Returns a font appropriate for the given attribute set. + * + * @param attributes The attributes required for the new font. + * + * @return A new Font with the given attributes. + * + * @since 1.2 + * + * @see java.awt.font.TextAttribute + */ + public static Font getFont(Map<? extends AttributedCharacterIterator.Attribute, ?> attributes) + { + return getFontFromToolkit(null, attributes); + } + + /** + * Returns the font face name of the font. A font face name describes a + * specific variant of a font family (such as Helvetica Bold). It is more + * specific than both a font family name (such as Helvetica) and a logical + * font name (such as Sans Serif). + * + * @return The font face name of the font. + * + * @since 1.2 + * + * @see #getName() + * @see #getFamily() + */ + public String getFontName() + { + return peer.getFontName(this); + } + + /** + * Returns the font face name of the font. A font face name describes a + * specific variant of a font family (such as Helvetica Bold). It is more + * specific than both a font family name (such as Helvetica). + * + * @param lc The locale in which to describe the name of the font face. + * + * @return A string containing the font face name, localized for the + * provided locale. + * + * @since 1.2 + * + * @see #getName() + * @see #getFamily() + */ + public String getFontName(Locale lc) + { + return peer.getFontName(this, lc); + } + + /** + * Returns the italic angle of this font, a measurement of its slant when + * style is {@link #ITALIC}. The precise meaning is the inverse slope of a + * caret line which "best measures" the font's italic posture. + * + * @return The italic angle. + * + * @see java.awt.font.TextAttribute#POSTURE + */ + public float getItalicAngle() + { + return peer.getItalicAngle(this); + } + + /** + * Returns a {@link LineMetrics} object constructed with the specified + * text and {@link FontRenderContext}. + * + * @param text The string to calculate metrics from. + * @param begin Index of first character in <code>text</code> to measure. + * @param limit Index of last character in <code>text</code> to measure. + * @param rc Context for calculating precise glyph placement and hints. + * + * @return A new {@link LineMetrics} object. + * + * @throws IndexOutOfBoundsException if the range [begin, limit] is + * invalid in <code>text</code>. + */ + public LineMetrics getLineMetrics(String text, int begin, + int limit, FontRenderContext rc) + { + return peer.getLineMetrics(this, new StringCharacterIterator(text), + begin, limit, rc); + } + + /** + * Returns a {@link LineMetrics} object constructed with the specified + * text and {@link FontRenderContext}. + * + * @param chars The string to calculate metrics from. + * @param begin Index of first character in <code>text</code> to measure. + * @param limit Index of last character in <code>text</code> to measure. + * @param rc Context for calculating precise glyph placement and hints. + * + * @return A new {@link LineMetrics} object. + * + * @throws IndexOutOfBoundsException if the range [begin, limit] is + * invalid in <code>chars</code>. + */ + public LineMetrics getLineMetrics(char[] chars, int begin, + int limit, FontRenderContext rc) + { + return peer.getLineMetrics(this, + new StringCharacterIterator(new String(chars)), + begin, limit, rc); + } + + /** + * Returns a {@link LineMetrics} object constructed with the specified + * text and {@link FontRenderContext}. + * + * @param ci The string to calculate metrics from. + * @param begin Index of first character in <code>text</code> to measure. + * @param limit Index of last character in <code>text</code> to measure. + * @param rc Context for calculating precise glyph placement and hints. + * + * @return A new {@link LineMetrics} object. + * + * @throws IndexOutOfBoundsException if the range [begin, limit] is + * invalid in <code>ci</code>. + */ + public LineMetrics getLineMetrics(CharacterIterator ci, int begin, + int limit, FontRenderContext rc) + { + return peer.getLineMetrics(this, ci, begin, limit, rc); + } + + /** + * Returns the maximal bounding box of all the bounding boxes in this + * font, when the font's bounding boxes are evaluated in a given {@link + * FontRenderContext} + * + * @param rc Context in which to evaluate bounding boxes. + * + * @return The maximal bounding box. + */ + public Rectangle2D getMaxCharBounds(FontRenderContext rc) + { + return peer.getMaxCharBounds(this, rc); + } + + /** + * Returns the glyph code this font uses to represent missing glyphs. This + * code will be present in glyph vectors when the font was unable to + * locate a glyph to represent a particular character code. + * + * @return The missing glyph code. + * + * @since 1.2 + */ + public int getMissingGlyphCode() + { + return peer.getMissingGlyphCode(this); + } + + /** + * Returns the overall number of glyphs in this font. This number is one + * more than the greatest glyph code used in any glyph vectors this font + * produces. In other words, glyph codes are taken from the range + * <code>[ 0, getNumGlyphs() - 1 ]</code>. + * + * @return The number of glyphs in this font. + * + * @since 1.2 + */ + public int getNumGlyphs() + { + return peer.getNumGlyphs(this); + } + + /** + * Returns the PostScript Name of this font. + * + * @return The PostScript Name of this font. + * + * @since 1.2 + * + * @see #getName() + * @see #getFamily() + * @see #getFontName() + */ + public String getPSName() + { + return peer.getPostScriptName(this); + } + + /** + * Returns the logical bounds of the specified string when rendered with this + * font in the specified {@link FontRenderContext}. This box will include the + * glyph origin, ascent, advance, height, and leading, but may not include all + * diacritics or accents. To get the complete visual bounding box of all the + * glyphs in a run of text, use the {@link TextLayout#getBounds} method of + * {@link TextLayout}. + * + * @param str The string to measure. + * @param frc The context in which to make the precise glyph measurements. + * + * @return A bounding box covering the logical bounds of the specified text. + * + * @see #createGlyphVector(FontRenderContext, String) + */ + public Rectangle2D getStringBounds(String str, FontRenderContext frc) + { + char[] chars = str.toCharArray(); + return getStringBounds(chars, 0, chars.length, frc); + } + + /** + * Returns the logical bounds of the specified string when rendered with this + * font in the specified {@link FontRenderContext}. This box will include the + * glyph origin, ascent, advance, height, and leading, but may not include all + * diacritics or accents. To get the complete visual bounding box of all the + * glyphs in a run of text, use the {@link TextLayout#getBounds} method of + * {@link TextLayout}. + * + * @param str The string to measure. + * @param begin Index of the first character in <code>str</code> to measure. + * @param limit Index of the last character in <code>str</code> to measure. + * @param frc The context in which to make the precise glyph measurements. + * + * @return A bounding box covering the logical bounds of the specified text. + * + * @throws IndexOutOfBoundsException if the range [begin, limit] is + * invalid in <code>str</code>. + * + * @since 1.2 + * + * @see #createGlyphVector(FontRenderContext, String) + */ + public Rectangle2D getStringBounds(String str, int begin, + int limit, FontRenderContext frc) + { + String sub = str.substring(begin, limit); + return getStringBounds(sub, frc); + } + + /** + * Returns the logical bounds of the specified string when rendered with this + * font in the specified {@link FontRenderContext}. This box will include the + * glyph origin, ascent, advance, height, and leading, but may not include all + * diacritics or accents. To get the complete visual bounding box of all the + * glyphs in a run of text, use the {@link TextLayout#getBounds} method of + * {@link TextLayout}. + * + * @param ci The text to measure. + * @param begin Index of the first character in <code>ci</code> to measure. + * @param limit Index of the last character in <code>ci</code> to measure. + * @param frc The context in which to make the precise glyph measurements. + * + * @return A bounding box covering the logical bounds of the specified text. + * + * @throws IndexOutOfBoundsException if the range [begin, limit] is + * invalid in <code>ci</code>. + * + * @since 1.2 + * + * @see #createGlyphVector(FontRenderContext, CharacterIterator) + */ + public Rectangle2D getStringBounds(CharacterIterator ci, int begin, + int limit, FontRenderContext frc) + { + int start = ci.getBeginIndex(); + int end = ci.getEndIndex(); + char[] chars = new char[limit - start]; + ci.setIndex(start); + for (int index = 0; index < chars.length; index++) + { + chars[index] = ci.current(); + ci.next(); + } + return getStringBounds(chars, 0, chars.length, frc); + } + + /** + * Returns the logical bounds of the specified string when rendered with this + * font in the specified {@link FontRenderContext}. This box will include the + * glyph origin, ascent, advance, height, and leading, but may not include all + * diacritics or accents. To get the complete visual bounding box of all the + * glyphs in a run of text, use the {@link TextLayout#getBounds} method of + * {@link TextLayout}. + * + * @param chars The text to measure. + * @param begin Index of the first character in <code>ci</code> to measure. + * @param limit Index of the last character in <code>ci</code> to measure. + * @param frc The context in which to make the precise glyph measurements. + * + * @return A bounding box covering the logical bounds of the specified text. + * + * @throws IndexOutOfBoundsException if the range [begin, limit] is + * invalid in <code>chars</code>. + * + * @since 1.2 + * + * @see #createGlyphVector(FontRenderContext, char[]) + */ + public Rectangle2D getStringBounds(char[] chars, int begin, + int limit, FontRenderContext frc) + { + String str = new String(chars, begin, limit - begin); + TextLayout layout = new TextLayout(str, this, frc); + return new Rectangle2D.Float(0, -layout.getAscent(), layout.getAdvance(), + layout.getDescent() + layout.getLeading()); + } + + /** + * Returns a copy of the affine transformation this font is currently + * subject to, if any. + * + * @return The current transformation. + */ + public AffineTransform getTransform() + { + return peer.getTransform(this); + } + + /** + * Indicates whether this font's line metrics are uniform. A font may be + * composed of several "subfonts", each covering a different code range, + * and each with their own line metrics. A font with no subfonts, or + * subfonts with identical line metrics, is said to have "uniform" line + * metrics. + * + * @return Whether this font has uniform line metrics. + * + * @see LineMetrics + * @see #getLineMetrics(String, FontRenderContext) + */ + public boolean hasUniformLineMetrics() + { + return peer.hasUniformLineMetrics(this); + } + + /** + * Indicates whether this font is subject to a non-identity affine + * transformation. + * + * @return <code>true</code> iff the font has a non-identity affine + * transformation applied to it. + */ + public boolean isTransformed() + { + return peer.isTransformed(this); + } + + /** + * Produces a glyph vector representing a full layout fo the specified + * text in this font. Full layouts may include complex shaping and + * reordering operations, for scripts such as Arabic or Hindi. + * + * Bidirectional (bidi) layout is not performed in this method; text + * should have its bidi direction specified with one of the flags {@link + * #LAYOUT_LEFT_TO_RIGHT} or {@link #LAYOUT_RIGHT_TO_LEFT}. + * + * Some types of layout (notably Arabic glyph shaping) may examine context + * characters beyond the bounds of the indicated range, in order to select + * an appropriate shape. The flags {@link #LAYOUT_NO_START_CONTEXT} and + * {@link #LAYOUT_NO_LIMIT_CONTEXT} can be provided to prevent these extra + * context areas from being examined, for instance if they contain invalid + * characters. + * + * @param frc Context in which to perform the layout. + * @param chars Text to perform layout on. + * @param start Index of first character to perform layout on. + * @param limit Index of last character to perform layout on. + * @param flags Combination of flags controlling layout. + * + * @return A new {@link GlyphVector} representing the specified text. + * + * @throws IndexOutOfBoundsException if the range [begin, limit] is + * invalid in <code>chars</code>. + */ + public GlyphVector layoutGlyphVector(FontRenderContext frc, + char[] chars, int start, + int limit, int flags) + { + return peer.layoutGlyphVector(this, frc, chars, start, limit, flags); + } + + + /** + * Returns a native peer object for this font. + * + * @return A native peer object for this font. + * + * @deprecated + */ + public FontPeer getPeer() + { + return peer; + } + + + /** + * Returns a hash value for this font. + * + * @return A hash for this font. + */ + public int hashCode() + { + // We cache the hashcode. This makes sense, because the font wouldn't + // change the relevant properties. + if (hashCode == 0) + { + hashCode = getName().hashCode() ^ getTransform().hashCode() ^ getSize() + ^ getStyle(); + // In the rare case when the above yields 0, we set this to some other + // value to avoid recomputing over and over again. This is still + // conform to the specification of hashCode(). + if (hashCode == 0) + { + hashCode = -1; + } + } + return hashCode; + } + + + /** + * Tests whether or not the specified object is equal to this font. This + * will be true if and only if: + * <P> + * <ul> + * <li>The object is not <code>null</code>. + * <li>The object is an instance of <code>Font</code>. + * <li>The object has the same names, style, size, and transform as this object. + * </ul> + * + * @return <code>true</code> if the specified object is equal to this + * object, <code>false</code> otherwise. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + + if (! (obj instanceof Font)) + return false; + + Font f = (Font) obj; + + return (f.getName().equals(this.getName()) + && f.getFamily().equals(this.getFamily()) + && f.getFontName().equals(this.getFontName()) + && f.getTransform().equals(this.getTransform ()) + && f.getSize() == this.getSize() + && f.getStyle() == this.getStyle()); + } + + /** + * Returns a string representation of this font. + * + * @return A string representation of this font. + */ + public String toString() + { + String styleString = ""; + + switch (getStyle()) + { + case 0: + styleString = "plain"; + break; + case 1: + styleString = "bold"; + break; + case 2: + styleString = "italic"; + break; + default: + styleString = "unknown"; + } + + return getClass().getName() + + "[family=" + getFamily () + + ",name=" + getFontName () + + ",style=" + styleString + + ",size=" + getSize () + "]"; + } + + + /** + * Determines the line metrics for a run of text. + * + * @param str the text run to be measured. + * + * @param frc the font rendering parameters that are used for the + * measurement. The exact placement and size of text slightly + * depends on device-specific characteristics, for instance + * the device resolution or anti-aliasing. For this reason, + * the returned measurement will only be accurate if the + * passed <code>FontRenderContext</code> correctly reflects + * the relevant parameters. Hence, <code>frc</code> should be + * obtained from the same <code>Graphics2D</code> that will + * be used for drawing, and any rendering hints should be set + * to the desired values before obtaining <code>frc</code>. + * + * @see java.awt.Graphics2D#getFontRenderContext() + */ + public LineMetrics getLineMetrics(String str, FontRenderContext frc) + { + return getLineMetrics(str, 0, str.length() - 1, frc); + } + + public boolean hasLayoutAttributes() + { + // TODO: Implement properly. + return false; + } + + /** + * Reads the normal fields from the stream and then constructs the + * peer from the style and size through getPeerFromToolkit(). + */ + private void readObject(ObjectInputStream ois) + throws IOException, ClassNotFoundException + { + ois.defaultReadObject(); + + HashMap attrs = new HashMap(); + ClasspathFontPeer.copyStyleToAttrs(style, attrs); + ClasspathFontPeer.copySizeToAttrs(size, attrs); + peer = getPeerFromToolkit(name, attrs); + + } +} diff --git a/libjava/classpath/java/awt/FontFormatException.java b/libjava/classpath/java/awt/FontFormatException.java new file mode 100644 index 000000000..6ec8757fb --- /dev/null +++ b/libjava/classpath/java/awt/FontFormatException.java @@ -0,0 +1,65 @@ +/* FontFormatException.java -- the specified font is bad + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +/** + * Thrown when a specified font is bad. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see Font + * @since 1.3 + * @status updated to 1.4 + */ +public class FontFormatException extends Exception +{ + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = -4481290147811361272L; + + /** + * Create a new instance with the specified detailed error message. + * + * @param message the detailed error message + */ + public FontFormatException(String message) + { + super(message); + } +} // class FontFormatException diff --git a/libjava/classpath/java/awt/FontMetrics.java b/libjava/classpath/java/awt/FontMetrics.java new file mode 100644 index 000000000..e483d28fc --- /dev/null +++ b/libjava/classpath/java/awt/FontMetrics.java @@ -0,0 +1,448 @@ +/* FontMetrics.java -- Information about about a fonts display characteristics + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.font.FontRenderContext; +import java.awt.font.LineMetrics; +import java.awt.geom.Rectangle2D; +import java.text.CharacterIterator; + +// FIXME: I leave many methods basically unimplemented. This +// should be reviewed. + +/** + * This class returns information about the display characteristics of + * a font. It is abstract, and concrete subclasses should implement at + * least the following methods: + * + * <ul> + * <li>getAscent()</li> + * <li>getDescent()</li> + * <li>getLeading()</li> + * <li>getMaxAdvance()</li> + * <li>charWidth(char)</li> + * <li>charsWidth(char[], int, int)</li> + * </ul> + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public abstract class FontMetrics implements java.io.Serializable +{ + // Serialization constant. + private static final long serialVersionUID = 1681126225205050147L; + + /** + * This is the font for which metrics will be returned. + */ + protected Font font; + + /** + * Initializes a new instance of <code>FontMetrics</code> for the + * specified font. + * + * @param font The font to return metric information for. + */ + protected FontMetrics(Font font) + { + this.font = font; + } + + /** + * Returns the font that this object is creating metric information fo. + * + * @return The font for this object. + */ + public Font getFont() + { + return font; + } + + /** + * Returns the leading, or spacing between lines, for this font. + * + * @return The font leading. + */ + public int getLeading() + { + return 0; + } + + /** + * Returns the ascent of the font, which is the distance from the base + * to the top of the majority of characters in the set. Some characters + * can exceed this value however. + * + * @return The font ascent. + */ + public int getAscent() + { + return 1; + } + + /** + * Returns the descent of the font, which is the distance from the base + * to the bottom of the majority of characters in the set. Some characters + * can exceed this value however. + * + * @return The font descent. + */ + public int getDescent() + { + return 1; + } + + /** + * Returns the height of a line in this font. This will be the sum + * of the leading, the ascent, and the descent. + * + * @return The height of the font. + */ + public int getHeight() + { + return getAscent() + getDescent() + getLeading(); + } + + /** + * Returns the maximum ascent value. This is the maximum distance any + * character in the font rised above the baseline. + * + * @return The maximum ascent for this font. + */ + public int getMaxAscent() + { + return getAscent(); + } + + /** + * Returns the maximum descent value. This is the maximum distance any + * character in the font extends below the baseline. + * + * @return The maximum descent for this font. + */ + public int getMaxDescent() + { + return getMaxDecent(); + } + + /** + * Returns the maximum descent value. This is the maximum distance any + * character in the font extends below the baseline. + * + * @return The maximum descent for this font. + * + * @deprecated This method is deprecated in favor of + * <code>getMaxDescent()</code>. + */ + public int getMaxDecent() + { + return getDescent(); + } + + /** + * Returns the width of the widest character in the font. + * + * @return The width of the widest character in the font. + */ + public int getMaxAdvance() + { + return -1; + } + + /** + * Returns the width of the specified character. + * + * @param ch The character to return the width of. + * + * @return The width of the specified character. + */ + public int charWidth(int ch) + { + char[] chars = Character.toChars(ch); + return charsWidth(chars, 0, chars.length); + } + + /** + * Returns the width of the specified character. + * + * @param ch The character to return the width of. + * + * @return The width of the specified character. + */ + public int charWidth(char ch) + { + return 1; + } + + /** + * Returns the total width of the specified string + * + * @param str The string to return the width of. + * + * @return The width of the string. + */ + public int stringWidth(String str) + { + char[] buf = new char[str.length()]; + str.getChars(0, str.length(), buf, 0); + + return charsWidth(buf, 0, buf.length); + } + + /** + * Returns the total width of the specified character array. + * + * @param buf The character array containing the data. + * @param offset The offset into the array to start calculating from. + * @param len The total number of bytes to process. + * + * @return The width of the requested characters. + */ + public int charsWidth(char[] buf, int offset, int len) + { + int total_width = 0; + int endOffset = offset + len; + for (int i = offset; i < endOffset; i++) + total_width += charWidth(buf[i]); + return total_width; + } + + /** + * Returns the total width of the specified byte array. + * + * @param buf The byte array containing the data. + * @param offset The offset into the array to start calculating from. + * @param len The total number of bytes to process. + * + * @return The width of the requested characters. + */ + public int bytesWidth(byte[] buf, int offset, int len) + { + int total_width = 0; + for (int i = offset; i < len; i++) + total_width = charWidth((char) buf[i]); + + return total_width; + } + + /** + * Returns the widths of the first 256 characters in the font. + * + * @return The widths of the first 256 characters in the font. + */ + public int[] getWidths() + { + int[] result = new int[256]; + for (char i = 0; i < 256; i++) + result[i] = charWidth(i); + return result; + } + + /** + * Returns a string representation of this object. + * + * @return A string representation of this object. + */ + public String toString() + { + return (this.getClass() + "[font=" + font + ",ascent=" + getAscent() + + ",descent=" + getDescent() + ",height=" + getHeight() + "]"); + } + + // Generic FontRenderContext used when getLineMetrics is called with a + // plain Graphics object. + private static final FontRenderContext gRC = new FontRenderContext(null, + false, + false); + + /** + * Returns a {@link LineMetrics} object constructed with the + * specified text and the {@link FontRenderContext} of the Graphics + * object when it is an instance of Graphics2D or a generic + * FontRenderContext with a null transform, not anti-aliased and not + * using fractional metrics. + * + * @param text The string to calculate metrics from. + * @param g The Graphics object that will be used. + * + * @return A new {@link LineMetrics} object. + */ + public LineMetrics getLineMetrics(String text, Graphics g) + { + return getLineMetrics(text, 0, text.length(), g); + } + + /** + * Returns a {@link LineMetrics} object constructed with the + * specified text and the {@link FontRenderContext} of the Graphics + * object when it is an instance of Graphics2D or a generic + * FontRenderContext with a null transform, not anti-aliased and not + * using fractional metrics. + * + * @param text The string to calculate metrics from. + * @param begin Index of first character in <code>text</code> to measure. + * @param limit Index of last character in <code>text</code> to measure. + * @param g The Graphics object that will be used. + * + * @return A new {@link LineMetrics} object. + * + * @throws IndexOutOfBoundsException if the range [begin, limit] is + * invalid in <code>text</code>. + */ + public LineMetrics getLineMetrics(String text, int begin, int limit, + Graphics g) + { + FontRenderContext rc; + if (g instanceof Graphics2D) + rc = ((Graphics2D) g).getFontRenderContext(); + else + rc = gRC; + return font.getLineMetrics(text, begin, limit, rc); + } + + /** + * Returns a {@link LineMetrics} object constructed with the + * specified text and the {@link FontRenderContext} of the Graphics + * object when it is an instance of Graphics2D or a generic + * FontRenderContext with a null transform, not anti-aliased and not + * using fractional metrics. + * + * @param chars The string to calculate metrics from. + * @param begin Index of first character in <code>text</code> to measure. + * @param limit Index of last character in <code>text</code> to measure. + * @param g The Graphics object that will be used. + * + * @return A new {@link LineMetrics} object. + * + * @throws IndexOutOfBoundsException if the range [begin, limit] is + * invalid in <code>text</code>. + */ + public LineMetrics getLineMetrics(char[] chars, int begin, int limit, + Graphics g) + { + FontRenderContext rc; + if (g instanceof Graphics2D) + rc = ((Graphics2D) g).getFontRenderContext(); + else + rc = gRC; + return font.getLineMetrics(chars, begin, limit, rc); + } + + /** + * Returns the bounds of the largest character in a Graphics context. + * @param context the Graphics context object. + * @return a <code>Rectangle2D</code> representing the bounds + */ + public Rectangle2D getMaxCharBounds(Graphics context) + { + if( context instanceof Graphics2D ) + return font.getMaxCharBounds(((Graphics2D)context).getFontRenderContext()); + return font.getMaxCharBounds( gRC ); + } + + /** + * Returns a {@link LineMetrics} object constructed with the + * specified text and the {@link FontRenderContext} of the Graphics + * object when it is an instance of Graphics2D or a generic + * FontRenderContext with a null transform, not anti-aliased and not + * using fractional metrics. + * + * @param ci An iterator over the string to calculate metrics from. + * @param begin Index of first character in <code>text</code> to measure. + * @param limit Index of last character in <code>text</code> to measure. + * @param g The Graphics object that will be used. + * + * @return A new {@link LineMetrics} object. + * + * @throws IndexOutOfBoundsException if the range [begin, limit] is + * invalid in <code>text</code>. + */ + public LineMetrics getLineMetrics(CharacterIterator ci, int begin, + int limit, Graphics g) + { + FontRenderContext rc; + if (g instanceof Graphics2D) + rc = ((Graphics2D) g).getFontRenderContext(); + else + rc = gRC; + return font.getLineMetrics(ci, begin, limit, rc); + } + + public Rectangle2D getStringBounds(String str, Graphics context) + { + return font.getStringBounds(str, getFontRenderContext(context)); + } + + public Rectangle2D getStringBounds(String str, int beginIndex, int limit, + Graphics context) + { + return font.getStringBounds(str, beginIndex, limit, + getFontRenderContext(context)); + } + + public Rectangle2D getStringBounds(char[] chars, int beginIndex, int limit, + Graphics context) + { + return font.getStringBounds(chars, beginIndex, limit, + getFontRenderContext(context)); + } + + public Rectangle2D getStringBounds(CharacterIterator ci, int beginIndex, + int limit, Graphics context) + { + return font.getStringBounds(ci, beginIndex, limit, + getFontRenderContext(context)); + } + + private FontRenderContext getFontRenderContext(Graphics context) + { + if (context instanceof Graphics2D) + return ((Graphics2D) context).getFontRenderContext(); + + return gRC; + } + + /** + * Returns if the font has uniform line metrics. + * @see Font#hasUniformLineMetrics() + */ + public boolean hasUniformLineMetrics() + { + return font.hasUniformLineMetrics(); + } +} diff --git a/libjava/classpath/java/awt/Frame.java b/libjava/classpath/java/awt/Frame.java new file mode 100644 index 000000000..83bdb0947 --- /dev/null +++ b/libjava/classpath/java/awt/Frame.java @@ -0,0 +1,704 @@ +/* Frame.java -- AWT toplevel window + Copyright (C) 1999, 2000, 2002, 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.peer.FramePeer; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Vector; + +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; + +/** + * This class is a top-level window with a title bar and window + * decorations. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class Frame extends Window implements MenuContainer +{ + + /** + * Constant for the default cursor. + * + * @deprecated Replaced by <code>Cursor.DEFAULT_CURSOR</code> instead. + */ + public static final int DEFAULT_CURSOR = Cursor.DEFAULT_CURSOR; + + /** + * Constant for a cross-hair cursor. + * + * @deprecated Use <code>Cursor.CROSSHAIR_CURSOR</code> instead. + */ + public static final int CROSSHAIR_CURSOR = Cursor.CROSSHAIR_CURSOR; + + /** + * Constant for a cursor over a text field. + * + * @deprecated Use <code>Cursor.TEXT_CURSOR</code> instead. + */ + public static final int TEXT_CURSOR = Cursor.TEXT_CURSOR; + + /** + * Constant for a cursor to display while waiting for an action to complete. + * + * @deprecated Use <code>Cursor.WAIT_CURSOR</code>. + */ + public static final int WAIT_CURSOR = Cursor.WAIT_CURSOR; + + /** + * Cursor used over SW corner of window decorations. + * + * @deprecated Use <code>Cursor.SW_RESIZE_CURSOR</code> instead. + */ + public static final int SW_RESIZE_CURSOR = Cursor.SW_RESIZE_CURSOR; + + /** + * Cursor used over SE corner of window decorations. + * @deprecated Use <code>Cursor.SE_RESIZE_CURSOR</code> instead. + */ + public static final int SE_RESIZE_CURSOR = Cursor.SE_RESIZE_CURSOR; + + /** + * Cursor used over NW corner of window decorations. + * + * @deprecated Use <code>Cursor.NW_RESIZE_CURSOR</code> instead. + */ + public static final int NW_RESIZE_CURSOR = Cursor.NW_RESIZE_CURSOR; + + /** + * Cursor used over NE corner of window decorations. + * + * @deprecated Use <code>Cursor.NE_RESIZE_CURSOR</code> instead. + */ + public static final int NE_RESIZE_CURSOR = Cursor.NE_RESIZE_CURSOR; + + /** + * Cursor used over N edge of window decorations. + * + * @deprecated Use <code>Cursor.N_RESIZE_CURSOR</code> instead. + */ + public static final int N_RESIZE_CURSOR = Cursor.N_RESIZE_CURSOR; + + /** + * Cursor used over S edge of window decorations. + * + * @deprecated Use <code>Cursor.S_RESIZE_CURSOR</code> instead. + */ + public static final int S_RESIZE_CURSOR = Cursor.S_RESIZE_CURSOR; + + /** + * Cursor used over E edge of window decorations. + * + * @deprecated Use <code>Cursor.E_RESIZE_CURSOR</code> instead. + */ + public static final int E_RESIZE_CURSOR = Cursor.E_RESIZE_CURSOR; + + /** + * Cursor used over W edge of window decorations. + * + * @deprecated Use <code>Cursor.W_RESIZE_CURSOR</code> instead. + */ + public static final int W_RESIZE_CURSOR = Cursor.W_RESIZE_CURSOR; + + /** + * Constant for a hand cursor. + * + * @deprecated Use <code>Cursor.HAND_CURSOR</code> instead. + */ + public static final int HAND_CURSOR = Cursor.HAND_CURSOR; + + /** + * Constant for a cursor used during window move operations. + * + * @deprecated Use <code>Cursor.MOVE_CURSOR</code> instead. + */ + public static final int MOVE_CURSOR = Cursor.MOVE_CURSOR; + + public static final int ICONIFIED = 1; + public static final int MAXIMIZED_BOTH = 6; + public static final int MAXIMIZED_HORIZ = 2; + public static final int MAXIMIZED_VERT = 4; + public static final int NORMAL = 0; + +//Serialization version constant + private static final long serialVersionUID = 2673458971256075116L; + + /** + * @serial The version of the class data being serialized + * FIXME: what is this value? + */ + private int frameSerializedDataVersion; + + /** + * @serial Image used as the icon when this frame is minimized. + */ + private Image icon; + + /** + * @serial Constant used by the JDK Motif peer set. Not used in + * this implementation. + */ + private boolean mbManagement; + + /** + * @serial The menu bar for this frame. + */ + private MenuBar menuBar; + + /** + * @serial A list of other top-level windows owned by this window. + */ + Vector ownedWindows = new Vector(); + + /** + * @serial Indicates whether or not this frame is resizable. + */ + private boolean resizable = true; + + /** + * @serial The state of this frame. + * // FIXME: What are the values here? + * This is package-private to avoid an accessor method. + */ + int state; + + /** + * @serial The title of the frame. + */ + private String title = ""; + + /** + * Maximized bounds for this frame. + */ + private Rectangle maximizedBounds; + + /** + * This field indicates whether the frame is undecorated or not. + */ + private boolean undecorated = false; + + /* + * The number used to generate the name returned by getName. + */ + private static transient long next_frame_number; + + /** + * Initializes a new instance of <code>Frame</code> that is not visible + * and has no title. + */ + public Frame() + { + this(""); + noteFrame(this); + } + + /** + * Initializes a new instance of <code>Frame</code> that is not visible + * and has the specified title. + * + * @param title the title of this frame + */ + public Frame(String title) + { + super(); + this.title = title; + // Top-level frames are initially invisible. + visible = false; + noteFrame(this); + } + + public Frame(GraphicsConfiguration gc) + { + super(gc); + visible = false; + noteFrame(this); + } + + public Frame(String title, GraphicsConfiguration gc) + { + super(gc); + setTitle(title); + visible = false; + noteFrame(this); + } + + /** + * Returns this frame's title string. + * + * @return this frame's title string + */ + public String getTitle() + { + return title; + } + + /** + * Sets this frame's title to the specified value. + * + * @param title the new frame title + */ + public synchronized void setTitle(String title) + { + this.title = title; + if (peer != null) + ((FramePeer) peer).setTitle(title); + } + + /** + * Returns this frame's icon. + * + * @return this frame's icon, or <code>null</code> if this frame does not + * have an icon + */ + public Image getIconImage() + { + return icon; + } + + /** + * Sets this frame's icon to the specified value. + * + * @icon the new icon for this frame + */ + public synchronized void setIconImage(Image icon) + { + this.icon = icon; + if (peer != null) + ((FramePeer) peer).setIconImage(icon); + } + + /** + * Returns this frame's menu bar. + * + * @return this frame's menu bar, or <code>null</code> if this frame + * does not have a menu bar + */ + public MenuBar getMenuBar() + { + return menuBar; + } + + /** + * Sets this frame's menu bar. Removes any existing menu bar. If the + * given menu bar is part of another frame it will be removed from + * that frame. + * + * @param menuBar the new menu bar for this frame + */ + public synchronized void setMenuBar(MenuBar menuBar) + { + if (this.menuBar != null) + remove(this.menuBar); + + this.menuBar = menuBar; + if (menuBar != null) + { + MenuContainer parent = menuBar.getParent(); + if (parent != null) + parent.remove(menuBar); + menuBar.setParent(this); + + // Create local copy for thread safety. + FramePeer p = (FramePeer) peer; + if (p != null) + { + if (menuBar != null) + menuBar.addNotify(); + if (valid) + invalidate(); + p.setMenuBar(menuBar); + } + } + } + + /** + * Tests whether or not this frame is resizable. This will be + * <code>true</code> by default. + * + * @return <code>true</code> if this frame is resizable, <code>false</code> + * otherwise + */ + public boolean isResizable() + { + return resizable; + } + + /** + * Sets the resizability of this frame to the specified value. + * + * @param resizable <code>true</code> to make the frame resizable, + * <code>false</code> to make it non-resizable + */ + public synchronized void setResizable(boolean resizable) + { + this.resizable = resizable; + if (peer != null) + ((FramePeer) peer).setResizable(resizable); + } + + /** + * Returns the cursor type of the cursor for this window. This will + * be one of the constants in this class. + * + * @return the cursor type for this frame + * + * @deprecated Use <code>Component.getCursor()</code> instead. + */ + public int getCursorType() + { + return getCursor().getType(); + } + + /** + * Sets the cursor for this window to the specified type. The specified + * type should be one of the constants in this class. + * + * @param type the cursor type + * + * @deprecated Use <code>Component.setCursor(Cursor)</code> instead. + */ + public void setCursor(int type) + { + setCursor(new Cursor(type)); + } + + /** + * Removes the specified menu component from this frame. If it is + * the current MenuBar it is removed from the frame. If it is a + * Popup it is removed from this component. If it is any other menu + * component it is ignored. + * + * @param menu the menu component to remove + */ + public void remove(MenuComponent menu) + { + if (menu == menuBar) + { + if (menuBar != null) + { + if (peer != null) + { + ((FramePeer) peer).setMenuBar(null); + menuBar.removeNotify(); + } + menuBar.setParent(null); + } + menuBar = null; + } + else + super.remove(menu); + } + + public void addNotify() + { + if (menuBar != null) + menuBar.addNotify(); + if (peer == null) + peer = getToolkit ().createFrame (this); + + super.addNotify(); + } + + public void removeNotify() + { + if (menuBar != null) + menuBar.removeNotify(); + super.removeNotify(); + } + + /** + * Returns a debugging string describing this window. + * + * @return a debugging string describing this window + */ + protected String paramString() + { + String title = getTitle(); + + String resizable = ""; + if (isResizable ()) + resizable = ",resizable"; + + String state = ""; + switch (getState ()) + { + case NORMAL: + state = ",normal"; + break; + case ICONIFIED: + state = ",iconified"; + break; + case MAXIMIZED_BOTH: + state = ",maximized-both"; + break; + case MAXIMIZED_HORIZ: + state = ",maximized-horiz"; + break; + case MAXIMIZED_VERT: + state = ",maximized-vert"; + break; + } + + return super.paramString () + ",title=" + title + resizable + state; + } + + /** + * The list of active frames. GC'ed frames get removed in noteFrame(). + */ + private static ArrayList<WeakReference<Frame>> weakFrames = + new ArrayList<WeakReference<Frame>>(); + + /** + * The death queue for all frames. + */ + private static ReferenceQueue weakFramesQueue = + new ReferenceQueue<Frame>(); + + private static void noteFrame(Frame f) + { + synchronized (weakFrames) + { + // Remove GCed frames from the list. + Reference ref = weakFramesQueue.poll(); + while (ref != null) + { + weakFrames.remove(ref); + ref = weakFramesQueue.poll(); + } + // Add new frame. + weakFrames.add(new WeakReference<Frame>(f)); + } + } + + /** + * Returns <code>true</code> when there are any displayable frames, + * <code>false</code> otherwise. + * + * @return <code>true</code> when there are any displayable frames, + * <code>false</code> otherwise + */ + static boolean hasDisplayableFrames() + { + synchronized (weakFrames) + { + for (WeakReference<Frame> r : Frame.weakFrames) + { + Frame f = (Frame) r.get(); + if (f != null && f.isDisplayable()) + return true; + } + } + return false; + } + + public static Frame[] getFrames() + { + synchronized (weakFrames) + { + ArrayList<Frame> existingFrames = new ArrayList<Frame>(); + for (WeakReference<Frame> ref : weakFrames) + { + Frame f = ref.get(); + if (f != null) + { + existingFrames.add(f); + } + } + Frame[] frames = new Frame[existingFrames.size()]; + frames = existingFrames.toArray(frames); + return frames; + } + } + + public void setState(int state) + { + int current_state = getExtendedState (); + + if (state == NORMAL + && (current_state & ICONIFIED) != 0) + setExtendedState(current_state | ICONIFIED); + + if (state == ICONIFIED + && (current_state & ~ICONIFIED) == 0) + setExtendedState(current_state & ~ICONIFIED); + } + + public int getState() + { + return (getExtendedState() & ICONIFIED) != 0 ? ICONIFIED : NORMAL; + } + + /** + * @since 1.4 + */ + public void setExtendedState(int state) + { + if (getToolkit().isFrameStateSupported(state)) + { + this.state = state; + FramePeer p = (FramePeer) peer; + if (p != null) + p.setState(state); + } + } + + /** + * @since 1.4 + */ + public int getExtendedState() + { + FramePeer p = (FramePeer) peer; + if (p != null) + state = p.getState(); + return state; + } + + /** + * @since 1.4 + */ + public void setMaximizedBounds(Rectangle maximizedBounds) + { + this.maximizedBounds = maximizedBounds; + } + + /** + * Returns the maximized bounds of this frame. + * + * @return the maximized rectangle, may be null + * + * @since 1.4 + */ + public Rectangle getMaximizedBounds() + { + return maximizedBounds; + } + + /** + * Returns whether this frame is undecorated or not. + * + * @since 1.4 + */ + public boolean isUndecorated() + { + return undecorated; + } + + /** + * Disables or enables decorations for this frame. This method can only be + * called while the frame is not displayable. + * + * @throws IllegalComponentStateException if this frame is displayable + * + * @since 1.4 + */ + public void setUndecorated(boolean undecorated) + { + if (isDisplayable()) + throw new IllegalComponentStateException(); + + this.undecorated = undecorated; + } + + /** + * Generate a unique name for this frame. + * + * @return a unique name for this frame + */ + String generateName() + { + return "frame" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_frame_number++; + } + + /** + * Accessibility support for <code>Frame</code>. + */ + protected class AccessibleAWTFrame extends AccessibleAWTWindow + { + private static final long serialVersionUID = -6172960752956030250L; + + /** + * Gets the role of this object. + * @return AccessibleRole.FRAME + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.FRAME; + } + + /** + * Gets the state set of this object. + * @return The current state of this frame. + */ + public AccessibleStateSet getAccessibleStateSet() + { + AccessibleStateSet states = super.getAccessibleStateSet(); + if (isResizable()) + states.add(AccessibleState.RESIZABLE); + if ((state & ICONIFIED) != 0) + states.add(AccessibleState.ICONIFIED); + return states; + } + } + + /** + * Gets the AccessibleContext associated with this <code>Frame</code>. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + // Create the context if this is the first request. + if (accessibleContext == null) + accessibleContext = new AccessibleAWTFrame(); + return accessibleContext; + } +} diff --git a/libjava/classpath/java/awt/GradientPaint.java b/libjava/classpath/java/awt/GradientPaint.java new file mode 100644 index 000000000..0bb840755 --- /dev/null +++ b/libjava/classpath/java/awt/GradientPaint.java @@ -0,0 +1,229 @@ +/* GradientPaint.java -- + Copyright (C) 2002, 2005, Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; +import gnu.java.awt.GradientPaintContext; + +/** + * A paint object that can be used to color a region by blending two colors. + * Instances of this class are immutable. + */ +public class GradientPaint implements Paint +{ + private final float x1; + private final float y1; + private final Color c1; + private final float x2; + private final float y2; + private final Color c2; + private final boolean cyclic; + + /** + * Creates a new acyclic <code>GradientPaint</code>. + * + * @param x1 the x-coordinate of the anchor point for color 1. + * @param y1 the y-coordinate of the anchor point for color 1. + * @param c1 color 1 (<code>null</code> not permitted). + * @param x2 the x-coordinate of the anchor point for color 2. + * @param y2 the y-coordinate of the anchor point for color 2. + * @param c2 the second color (<code>null</code> not permitted). + */ + public GradientPaint(float x1, float y1, Color c1, + float x2, float y2, Color c2) + { + this(x1, y1, c1, x2, y2, c2, false); + } + + /** + * Creates a new acyclic <code>GradientPaint</code>. + * + * @param p1 anchor point 1 (<code>null</code> not permitted). + * @param c1 color 1 (<code>null</code> not permitted). + * @param p2 anchor point 2 (<code>null</code> not permitted). + * @param c2 color 2 (<code>null</code> not permitted). + */ + public GradientPaint(Point2D p1, Color c1, Point2D p2, Color c2) + { + this((float) p1.getX(), (float) p1.getY(), c1, + (float) p2.getX(), (float) p2.getY(), c2, false); + } + + /** + * Creates a new cyclic or acyclic <code>GradientPaint</code>. + * + * @param x1 the x-coordinate of the anchor point for color 1. + * @param y1 the y-coordinate of the anchor point for color 1. + * @param c1 color 1 (<code>null</code> not permitted). + * @param x2 the x-coordinate of the anchor point for color 2. + * @param y2 the y-coordinate of the anchor point for color 2. + * @param c2 the second color (<code>null</code> not permitted). + * @param cyclic a flag that controls whether the gradient is cyclic or + * acyclic. + */ + public GradientPaint(float x1, float y1, Color c1, + float x2, float y2, Color c2, boolean cyclic) + { + if (c1 == null || c2 == null) + throw new NullPointerException(); + this.x1 = x1; + this.y1 = y1; + this.c1 = c1; + this.x2 = x2; + this.y2 = y2; + this.c2 = c2; + this.cyclic = cyclic; + } + + /** + * Creates a new cyclic or acyclic <code>GradientPaint</code>. + * + * @param p1 anchor point 1 (<code>null</code> not permitted). + * @param c1 color 1 (<code>null</code> not permitted). + * @param p2 anchor point 2 (<code>null</code> not permitted). + * @param c2 color 2 (<code>null</code> not permitted). + * @param cyclic a flag that controls whether the gradient is cyclic or + * acyclic. + */ + public GradientPaint(Point2D p1, Color c1, Point2D p2, Color c2, + boolean cyclic) + { + this((float) p1.getX(), (float) p1.getY(), c1, + (float) p2.getX(), (float) p2.getY(), c2, cyclic); + } + + /** + * Returns a point with the same coordinates as the anchor point for color 1. + * Note that if you modify this point, the <code>GradientPaint</code> remains + * unchanged. + * + * @return A point with the same coordinates as the anchor point for color 1. + */ + public Point2D getPoint1() + { + return new Point2D.Float(x1, y1); + } + + /** + * Returns the first color. + * + * @return The color (never <code>null</code>). + */ + public Color getColor1() + { + return c1; + } + + /** + * Returns a point with the same coordinates as the anchor point for color 2. + * Note that if you modify this point, the <code>GradientPaint</code> remains + * unchanged. + * + * @return A point with the same coordinates as the anchor point for color 2. + */ + public Point2D getPoint2() + { + return new Point2D.Float(x2, y2); + } + + /** + * Returns the second color. + * + * @return The color (never <code>null</code>). + */ + public Color getColor2() + { + return c2; + } + + /** + * Returns <code>true</code> if this <code>GradientPaint</code> instance is + * cyclic, and <code>false</code> otherwise. + * + * @return A boolean. + */ + public boolean isCyclic() + { + return cyclic; + } + + /** + * Returns the {@link PaintContext} used to generate the color pattern. + * + * @param cm the color model, used as a hint (ignored in this + * implementation). + * @param deviceBounds the device space bounding box of the painted area. + * @param userBounds the user space bounding box of the painted area. + * @param xform the transformation from user space to device space. + * @param hints any hints for choosing between rendering alternatives. + * + * @return The context for performing the paint + */ + public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, + Rectangle2D userBounds, + AffineTransform xform, + RenderingHints hints) + { + Point2D xp1 = xform.transform(getPoint1(), null); + Point2D xp2 = xform.transform(getPoint2(), null); + return new GradientPaintContext((float) xp1.getX(), (float) xp1.getY(), c1, + (float) xp2.getX(), (float) xp2.getY(), c2, cyclic); + } + + /** + * Returns the transparency code for this <code>GradientPaint</code> instance. + * This is derived from the two {@link Color} objects used in creating this + * object: if both colors are opaque, this method returns + * {@link Transparency#OPAQUE}, otherwise it returns + * {@link Transparency#TRANSLUCENT}. + * + * @return {@link Transparency#OPAQUE} or {@link Transparency#TRANSLUCENT}. + */ + public int getTransparency() + { + if (c1.getAlpha() == 255 && c2.getAlpha() == 255) + return Transparency.OPAQUE; + else + return Transparency.TRANSLUCENT; + } + +} // class GradientPaint diff --git a/libjava/classpath/java/awt/Graphics.java b/libjava/classpath/java/awt/Graphics.java new file mode 100644 index 000000000..dfc772207 --- /dev/null +++ b/libjava/classpath/java/awt/Graphics.java @@ -0,0 +1,639 @@ +/* Graphics.java -- Abstract Java drawing class + Copyright (C) 1999, 2000, 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.image.ImageObserver; +import java.text.AttributedCharacterIterator; + +/** + * This is the abstract superclass of classes for drawing to graphics + * devices such as the screen or printers. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public abstract class Graphics +{ + + /** + * Default constructor for subclasses. + */ + protected + Graphics() + { + } + + /** + * Returns a copy of this <code>Graphics</code> object. + * + * @return A copy of this object. + */ + public abstract Graphics create(); + + /** + * Returns a copy of this <code>Graphics</code> object. The origin point + * will be translated to the point (x, y) and the cliping rectangle set + * to the intersection of the clipping rectangle in this object and the + * rectangle specified by the parameters to this method. + * + * @param x The new X coordinate of the clipping region rect. + * @param y The new Y coordinate of the clipping region rect. + * @param width The width of the clipping region intersect rectangle. + * @param height The height of the clipping region intersect rectangle. + * + * @return A copy of this object, modified as specified. + */ + public Graphics create(int x, int y, int width, int height) + { + Graphics g = create(); + + g.translate(x, y); + // FIXME: I'm not sure if this will work. Are the old clip rect bounds + // translated above? + g.clipRect(0, 0, width, height); + + return(g); + } + + /** + * Translates this context so that its new origin point is the point + * (x, y). + * + * @param x The new X coordinate of the origin. + * @param y The new Y coordinate of the origin. + */ + public abstract void translate(int x, int y); + + /** + * Returns the current color for this object. + * + * @return The color for this object. + */ + public abstract Color getColor(); + + /** + * Sets the current color for this object. + * + * @param color The new color. + */ + public abstract void setColor(Color color); + + /** + * Sets this context into "paint" mode, where the target pixels are + * completely overwritten when drawn on. + */ + public abstract void setPaintMode(); + + /** + * Sets this context info "XOR" mode, where the targe pixles are + * XOR-ed when drawn on. + * + * @param color The color to XOR against. + */ + public abstract void setXORMode(Color color); + + /** + * Returns the current font for this graphics context. + * + * @return The current font. + */ + public abstract Font getFont(); + + /** + * Sets the font for this graphics context to the specified value. + * + * @param font The new font. + */ + public abstract void setFont(Font font); + + /** + * Returns the font metrics for the current font. + * + * @return The font metrics for the current font. + */ + public FontMetrics getFontMetrics() + { + return getFontMetrics(getFont()); + } + + /** + * Returns the font metrics for the specified font. + * + * @param font The font to return metrics for. + * + * @return The requested font metrics. + */ + public abstract FontMetrics getFontMetrics(Font font); + + /** + * Returns the bounding rectangle of the clipping region for this + * graphics context. + * + * @return The bounding rectangle for the clipping region. + */ + public abstract Rectangle getClipBounds(); + + /** + * Returns the bounding rectangle of the clipping region for this + * graphics context. + * + * @return The bounding rectangle for the clipping region. + * + * @deprecated This method is deprecated in favor of + * <code>getClipBounds()</code>. + */ + public Rectangle getClipRect() + { + return getClipBounds(); + } + + /** + * Sets the clipping region to the intersection of the current clipping + * region and the rectangle determined by the specified parameters. + * + * @param x The X coordinate of the upper left corner of the intersect rect. + * @param y The Y coordinate of the upper left corner of the intersect rect. + * @param width The width of the intersect rect. + * @param height The height of the intersect rect. + */ + public abstract void clipRect(int x, int y, int width, int height); + + /** + * Sets the clipping region to the rectangle determined by the specified + * parameters. + * + * @param x The X coordinate of the upper left corner of the rect. + * @param y The Y coordinate of the upper left corner of the rect. + * @param width The width of the rect. + * @param height The height of the rect. + */ + public abstract void setClip(int x, int y, int width, int height); + + /** + * Returns the current clipping region as a <code>Shape</code> object. + * + * @return The clipping region as a <code>Shape</code>. + */ + public abstract Shape getClip(); + + /** + * Sets the clipping region to the specified <code>Shape</code>. + * + * @param clip The new clipping region. + */ + public abstract void setClip(Shape clip); + + /** + * Copies the specified rectangle to the specified offset location. + * + * @param x The X coordinate of the upper left corner of the copy rect. + * @param y The Y coordinate of the upper left corner of the copy rect. + * @param width The width of the copy rect. + * @param height The height of the copy rect. + * @param dx The offset from the X value to start drawing. + * @param dy The offset from the Y value to start drawing. + */ + public abstract void copyArea(int x, int y, int width, int height, int dx, + int dy); + + /** + * Draws a line between the two specified points. + * + * @param x1 The X coordinate of the first point. + * @param y1 The Y coordinate of the first point. + * @param x2 The X coordinate of the second point. + * @param y2 The Y coordinate of the second point. + */ + public abstract void drawLine(int x1, int y1, int x2, int y2); + + /** + * Fills the area bounded by the specified rectangle. + * + * @param x The X coordinate of the upper left corner of the fill rect. + * @param y The Y coordinate of the upper left corner of the fill rect. + * @param width The width of the fill rect. + * @param height The height of the fill rect. + */ + public abstract void fillRect(int x, int y, int width, int height); + + /** + * Draws the outline of the specified rectangle. + * + * @param x The X coordinate of the upper left corner of the draw rect. + * @param y The Y coordinate of the upper left corner of the draw rect. + * @param width The width of the draw rect. + * @param height The height of the draw rect. + */ + public void drawRect(int x, int y, int width, int height) + { + int x1 = x; + int y1 = y; + int x2 = x + width; + int y2 = y + height; + drawLine(x1, y1, x2, y1); + drawLine(x2, y1, x2, y2); + drawLine(x2, y2, x1, y2); + drawLine(x1, y2, x1, y1); + } + + /** + * Clears the specified rectangle. + * + * @param x The X coordinate of the upper left corner of the clear rect. + * @param y The Y coordinate of the upper left corner of the clear rect. + * @param width The width of the clear rect. + * @param height The height of the clear rect. + */ + public abstract void clearRect(int x, int y, int width, int height); + + /** + * Draws the outline of the specified rectangle with rounded cornders. + * + * @param x The X coordinate of the upper left corner of the draw rect. + * @param y The Y coordinate of the upper left corner of the draw rect. + * @param width The width of the draw rect. + * @param height The height of the draw rect. + * @param arcWidth The width of the corner arcs. + * @param arcHeight The height of the corner arcs. + */ + public abstract void drawRoundRect(int x, int y, int width, int height, + int arcWidth, int arcHeight); + + /** + * Fills the specified rectangle with rounded cornders. + * + * @param x The X coordinate of the upper left corner of the fill rect. + * @param y The Y coordinate of the upper left corner of the fill rect. + * @param width The width of the fill rect. + * @param height The height of the fill rect. + * @param arcWidth The width of the corner arcs. + * @param arcHeight The height of the corner arcs. + */ + public abstract void fillRoundRect(int x, int y, int width, int height, + int arcWidth, int arcHeight); + + public void draw3DRect(int x, int y, int width, int height, boolean raised) + { + Color color = getColor(); + Color tl = color.brighter(); + Color br = color.darker(); + + if (!raised) + { + Color tmp = tl; + tl = br; + br = tmp; + } + + int x1 = x; + int y1 = y; + int x2 = x + width; + int y2 = y + height; + + setColor(tl); + drawLine(x1, y1, x2, y1); + drawLine(x1, y2, x1, y1); + setColor(br); + drawLine(x2, y1, x2, y2); + drawLine(x2, y2, x1, y2); + setColor(color); + } + + /** + * Fills the specified rectangle with a 3D effect + * + * @param x The X coordinate of the upper left corner of the fill rect. + * @param y The Y coordinate of the upper left corner of the fill rect. + * @param width The width of the fill rect. + * @param height The height of the fill rect. + * @param raised <code>true</code> if the rectangle appears raised, + * <code>false</code> if it should appear etched. + */ + public void fill3DRect(int x, int y, int width, int height, boolean raised) + { + fillRect(x, y, width, height); + draw3DRect(x, y, width-1, height-1, raised); + } + + /** + * Draws an oval that just fits within the specified rectangle. + * + * @param x The X coordinate of the upper left corner of the rect. + * @param y The Y coordinate of the upper left corner of the rect. + * @param width The width of the rect. + * @param height The height of the rect. + */ + public abstract void drawOval(int x, int y, int width, int height); + + /** + * Fills an oval that just fits within the specified rectangle. + * + * @param x The X coordinate of the upper left corner of the rect. + * @param y The Y coordinate of the upper left corner of the rect. + * @param width The width of the rect. + * @param height The height of the rect. + */ + public abstract void fillOval(int x, int y, int width, int height); + + /** + * Draws an arc using the specified bounding rectangle and the specified + * angle parameter. The arc is centered at the center of the rectangle. + * The arc starts at the arcAngle position and extend for arcAngle + * degrees. The degree origin is at the 3 o'clock position. + * + * @param x The X coordinate of the upper left corner of the rect. + * @param y The Y coordinate of the upper left corner of the rect. + * @param width The width of the rect. + * @param height The height of the rect. + * @param arcStart The beginning angle of the arc. + * @param arcAngle The extent of the arc. + */ + public abstract void drawArc(int x, int y, int width, int height, + int arcStart, int arcAngle); + + /** + * Fills the arc define by the specified bounding rectangle and the specified + * angle parameter. The arc is centered at the center of the rectangle. + * The arc starts at the arcAngle position and extend for arcAngle + * degrees. The degree origin is at the 3 o'clock position. + * + * @param x The X coordinate of the upper left corner of the rect. + * @param y The Y coordinate of the upper left corner of the rect. + * @param width The width of the rect. + * @param height The height of the rect. + * @param arcStart The beginning angle of the arc. + * @param arcAngle The extent of the arc. + */ + public abstract void fillArc(int x, int y, int width, int height, + int arcStart, int arcAngle); + + /** + * Draws a series of interconnected lines determined by the arrays + * of corresponding x and y coordinates. + * + * @param xPoints The X coordinate array. + * @param yPoints The Y coordinate array. + * @param npoints The number of points to draw. + */ + public abstract void drawPolyline(int xPoints[], int yPoints[], int npoints); + + /** + * Draws a series of interconnected lines determined by the arrays + * of corresponding x and y coordinates. The figure is closed if necessary + * by connecting the first and last points. + * + * @param xPoints The X coordinate array. + * @param yPoints The Y coordinate array. + * @param npoints The number of points to draw. + */ + public abstract void drawPolygon(int xPoints[], int yPoints[], int npoints); + + /** + * Draws the specified polygon. + * + * @param polygon The polygon to draw. + */ + public void drawPolygon(Polygon polygon) + { + drawPolygon(polygon.xpoints, polygon.ypoints, polygon.npoints); + } + + /** + * Fills the polygon determined by the arrays + * of corresponding x and y coordinates. + * + * @param xPoints The X coordinate array. + * @param yPoints The Y coordinate array. + * @param npoints The number of points to draw. + */ + public abstract void fillPolygon(int xPoints[], int yPoints[], int npoints); + + /** + * Fills the specified polygon + * + * @param polygon The polygon to fill. + */ + public void fillPolygon(Polygon polygon) + { + fillPolygon(polygon.xpoints, polygon.ypoints, polygon.npoints); + } + + /** + * Draws the specified string starting at the specified point. + * + * @param string The string to draw. + * @param x The X coordinate of the point to draw at. + * @param y The Y coordinate of the point to draw at. + */ + public abstract void drawString(String string, int x, int y); + + public abstract void drawString (AttributedCharacterIterator ci, int x, + int y); + + /** + * Draws the specified characters starting at the specified point. + * + * @param data The array of characters to draw. + * @param offset The offset into the array to start drawing characters from. + * @param length The number of characters to draw. + * @param x The X coordinate of the point to draw at. + * @param y The Y coordinate of the point to draw at. + */ + public void drawChars(char data[], int offset, int length, int x, int y) + { + drawString(new String(data, offset, length), x, y); + } + + public void drawBytes(byte[] data, int offset, int length, int x, int y) + { + String str = new String(data, offset, length); + drawString(str, x, y); + } + + /** + * Draws all of the image that is available and returns. If the image + * is not completely loaded, <code>false</code> is returned and + * the specified iamge observer is notified as more data becomes + * available. + * + * @param image The image to draw. + * @param x The X coordinate of the point to draw at. + * @param y The Y coordinate of the point to draw at. + * @param observer The image observer to notify as data becomes available. + * + * @return <code>true</code> if all the image data is available, + * <code>false</code> otherwise. + */ + public abstract boolean drawImage(Image image, int x, int y, + ImageObserver observer); + + /** + * Draws all of the image that is available and returns. The image + * is scaled to fit in the specified rectangle. If the image + * is not completely loaded, <code>false</code> is returned and + * the specified iamge observer is notified as more data becomes + * available. + * + * @param image The image to draw. + * @param x The X coordinate of the point to draw at. + * @param y The Y coordinate of the point to draw at. + * @param width The width of the rectangle to draw in. + * @param height The height of the rectangle to draw in. + * @param observer The image observer to notify as data becomes available. + * + * @return <code>true</code> if all the image data is available, + * <code>false</code> otherwise. + */ + public abstract boolean drawImage(Image image, int x, int y, int width, + int height, ImageObserver observer); + + /** + * Draws all of the image that is available and returns. If the image + * is not completely loaded, <code>false</code> is returned and + * the specified iamge observer is notified as more data becomes + * available. + * + * @param image The image to draw. + * @param x The X coordinate of the point to draw at. + * @param y The Y coordinate of the point to draw at. + * @param bgcolor The background color to use for the image. + * @param observer The image observer to notify as data becomes available. + * + * @return <code>true</code> if all the image data is available, + * <code>false</code> otherwise. + */ + public abstract boolean drawImage(Image image, int x, int y, Color bgcolor, + ImageObserver observer); + + /** + * Draws all of the image that is available and returns. The image + * is scaled to fit in the specified rectangle. If the image + * is not completely loaded, <code>false</code> is returned and + * the specified iamge observer is notified as more data becomes + * available. + * + * @param image The image to draw. + * @param x The X coordinate of the point to draw at. + * @param y The Y coordinate of the point to draw at. + * @param width The width of the rectangle to draw in. + * @param height The height of the rectangle to draw in. + * @param bgcolor The background color to use for the image. + * @param observer The image observer to notify as data becomes available. + * + * @return <code>true</code> if all the image data is available, + * <code>false</code> otherwise. + */ + public abstract boolean drawImage(Image image, int x, int y, int width, + int height, Color bgcolor, + ImageObserver observer); + + /** + * FIXME: Write Javadocs for this when you understand it. + */ + public abstract boolean drawImage(Image image, int dx1, int dy1, int dx2, + int dy2, int sx1, int sy1, int sx2, + int sy2, ImageObserver observer); + + /** + * FIXME: Write Javadocs for this when you understand it. + */ + public abstract boolean drawImage(Image image, int dx1, int dy1, int dx2, + int dy2, int sx1, int sy1, int sx2, + int sy2, Color bgcolor, + ImageObserver observer); + + /** + * Free any resources held by this graphics context immediately instead + * of waiting for the object to be garbage collected and finalized. + */ + public abstract void dispose(); + + /** + * Frees the resources held by this graphics context when it is + * garbage collected. + */ + public void finalize() + { + dispose(); + } + + /** + * Returns a string representation of this object. + * + * @return A string representation of this object. + */ + public String toString() + { + return getClass ().getName () + "[font=" + getFont () + ",color=" + + getColor () + "]"; + } + + /** + * Returns <code>true</code> if the specified rectangle intersects with the + * current clip, <code>false</code> otherwise. + * + * @param x the X coordinate of the upper left corner of the test rectangle + * @param y the Y coordinate of the upper left corner of the test rectangle + * @param width the width of the upper left corner of the test rectangle + * @param height the height of the upper left corner of the test rectangle + * @return <code>true</code> if the specified rectangle intersects with the + * current clip, <code>false</code> otherwise + */ + public boolean hitClip(int x, int y, int width, int height) + { + Shape clip = getClip(); + if (clip == null) + return true; + return getClip().intersects(x, y, width, height); + } + + public Rectangle getClipBounds(Rectangle r) + { + Rectangle clipBounds = getClipBounds(); + + if (r == null) + return clipBounds; + + r.x = clipBounds.x; + r.y = clipBounds.y; + r.width = clipBounds.width; + r.height = clipBounds.height; + return r; + } +} diff --git a/libjava/classpath/java/awt/Graphics2D.java b/libjava/classpath/java/awt/Graphics2D.java new file mode 100644 index 000000000..7c9622aef --- /dev/null +++ b/libjava/classpath/java/awt/Graphics2D.java @@ -0,0 +1,358 @@ +/* Copyright (C) 2000, 2002, 2004, 2006, Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ImageObserver; +import java.awt.image.RenderedImage; +import java.awt.image.renderable.RenderableImage; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.text.AttributedCharacterIterator; +import java.util.Map; + +/** + * An abstract class defining a device independent two-dimensional vector + * graphics API. Concrete subclasses implement this API for output of + * vector graphics to: + * <p> + * <ul> + * <li>a {@link javax.swing.JComponent} - in the + * {@link javax.swing.JComponent#paint(Graphics)} method, the incoming + * {@link Graphics} should always be an instance of + * <code>Graphics2D</code>;</li> + * <li>a {@link BufferedImage} - see + * {@link BufferedImage#createGraphics()};</li> + * <li>a {@link java.awt.print.PrinterJob} - in the + * {@link Printable#print(Graphics, PageFormat, int)} method, the incoming + * {@link Graphics} should always be an instance of + * <code>Graphics2D</code>.</li> + * </ul> + * <p> + * Third party libraries provide support for output to other formats via this + * API, including encapsulated postscript (EPS), portable document format (PDF), + * and scalable vector graphics (SVG). + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public abstract class Graphics2D extends Graphics +{ + + protected Graphics2D() + { + } + + public void draw3DRect(int x, int y, int width, int height, + boolean raised) + { + super.draw3DRect(x, y, width, height, raised); + } + + public void fill3DRect(int x, int y, int width, int height, + boolean raised) + { + super.fill3DRect(x, y, width, height, raised); + } + + /** + * Draws an outline around a shape using the current stroke and paint. + * + * @param shape the shape (<code>null</code> not permitted). + * + * @see #getStroke() + * @see #getPaint() + */ + public abstract void draw(Shape shape); + + public abstract boolean drawImage(Image image, AffineTransform xform, + ImageObserver obs); + + public abstract void drawImage(BufferedImage image, + BufferedImageOp op, + int x, + int y); + + public abstract void drawRenderedImage(RenderedImage image, + AffineTransform xform); + + public abstract void drawRenderableImage(RenderableImage image, + AffineTransform xform); + + /** + * Draws a string at the specified location, using the current font. + * + * @param text the string to draw. + * @param x the x-coordinate. + * @param y the y-coordinate. + * + * @see Graphics#setFont(Font) + */ + public abstract void drawString(String text, int x, int y); + + /** + * Draws a string at the specified location, using the current font. + * + * @param text the string to draw. + * @param x the x-coordinate. + * @param y the y-coordinate. + * + * @see Graphics#setFont(Font) + */ + public abstract void drawString(String text, float x, float y); + + /** + * Draws an attributed string at the specified location. + * + * @param iterator the source of the attributed text. + * @param x the x-coordinate. + * @param y the y-coordinate. + */ + public abstract void drawString(AttributedCharacterIterator iterator, + int x, int y); + + /** + * Draws an attributed string at the specified location. + * + * @param iterator the source of the attributed text. + * @param x the x-coordinate. + * @param y the y-coordinate. + */ + public abstract void drawString(AttributedCharacterIterator iterator, + float x, float y); + + /** + * Fills the interior of the specified <code>shape</code> using the current + * paint. + * + * @param shape the shape to fill (<code>null</code> not permitted). + * + * @see #draw(Shape) + * @see #getPaint() + */ + public abstract void fill(Shape shape); + + public abstract boolean hit(Rectangle rect, Shape text, + boolean onStroke); + + public abstract GraphicsConfiguration getDeviceConfiguration(); + + /** + * Sets the current compositing rule. + * + * @param comp the composite. + * + * @see #getComposite() + */ + public abstract void setComposite(Composite comp); + + /** + * Sets the paint to be used for subsequent drawing operations. + * + * @param paint the paint (<code>null</code> not permitted). + * + * @see #getPaint() + */ + public abstract void setPaint(Paint paint); + + /** + * Sets the stroke to be used for subsequent drawing operations. + * + * @param stroke the stroke (<code>null</code> not permitted). + * + * @see #getStroke() + */ + public abstract void setStroke(Stroke stroke); + + /** + * Adds or updates a hint in the current rendering hints table. + * + * @param hintKey the hint key. + * @param hintValue the hint value. + */ + public abstract void setRenderingHint(RenderingHints.Key hintKey, + Object hintValue); + + /** + * Returns the current value of a rendering hint. + * + * @param hintKey the key for the hint. + * + * @return The value for the specified hint. + */ + public abstract Object getRenderingHint(RenderingHints.Key hintKey); + + /** + * Replaces the current rendering hints with the supplied hints. + * + * @param hints the hints. + * + * @see #addRenderingHints(Map) + */ + public abstract void setRenderingHints(Map<?,?> hints); + + /** + * Adds/updates the rendering hint. + * + * @param hints the hints to add or update. + */ + public abstract void addRenderingHints(Map<?,?> hints); + + /** + * Returns the current rendering hints. + * + * @return The current rendering hints. + */ + public abstract RenderingHints getRenderingHints(); + + public abstract void translate(int x, int y); + + public abstract void translate(double tx, double ty); + + public abstract void rotate(double theta); + + public abstract void rotate(double theta, double x, double y); + + public abstract void scale(double scaleX, double scaleY); + + public abstract void shear(double shearX, double shearY); + + /** + * Sets the current transform to a concatenation of <code>transform</code> + * and the existing transform. + * + * @param transform the transform. + */ + public abstract void transform(AffineTransform transform); + + /** + * Sets the current transform. If the caller specifies a <code>null</code> + * transform, this method should set the current transform to the + * identity transform. + * + * @param transform the transform (<code>null</code> permitted). + * + * @see #getTransform() + */ + public abstract void setTransform(AffineTransform transform); + + /** + * Returns the current transform. + * + * @return The current transform. + * + * @see #setTransform(AffineTransform) + */ + public abstract AffineTransform getTransform(); + + /** + * Returns the current paint. + * + * @return The current paint. + * + * @see #setPaint(Paint) + */ + public abstract Paint getPaint(); + + /** + * Returns the current compositing rule. + * + * @return The current compositing rule. + * + * @see #setComposite(Composite) + */ + public abstract Composite getComposite(); + + /** + * Sets the background color (used by the + * {@link Graphics#clearRect(int, int, int, int)} method). + * + * @param color the color. + * + * @see #getBackground() + */ + public abstract void setBackground(Color color); + + /** + * Returns the color used by the + * {@link Graphics#clearRect(int, int, int, int)} method. + * + * @return The background color. + * + * @see #setBackground(Color) + */ + public abstract Color getBackground(); + + /** + * Returns the current stroke. + * + * @return The current stroke. + * + * @see #setStroke(Stroke) + */ + public abstract Stroke getStroke(); + + /** + * Sets the clip region to the intersection of the current clipping region + * and <code>s</code>. + * + * @param s the shape to intersect with the current clipping region. + * + * @see Graphics#setClip(Shape) + */ + public abstract void clip(Shape s); + + /** + * Returns the font render context. + * + * @return The font render context. + */ + public abstract FontRenderContext getFontRenderContext(); + + /** + * Draws a glyph vector at the specified location. + * + * @param g the glyph vector. + * @param x the x-coordinate. + * @param y the y-coordinate. + */ + public abstract void drawGlyphVector(GlyphVector g, float x, float y); +} diff --git a/libjava/classpath/java/awt/GraphicsConfigTemplate.java b/libjava/classpath/java/awt/GraphicsConfigTemplate.java new file mode 100644 index 000000000..e46888378 --- /dev/null +++ b/libjava/classpath/java/awt/GraphicsConfigTemplate.java @@ -0,0 +1,106 @@ +/* GraphicsConfigTemplate.java -- a template for selecting configurations + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.io.Serializable; + +/** + * This allows filtering an array of GraphicsConfigurations for the best + * one based on various requirements. The resulting configuration has had + * all non-default attributes set as required to meet or exceed the request. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see GraphicsConfiguration + * @see GraphicsDevice + * @since 1.2 + * @status updated to 1.4 + */ +public abstract class GraphicsConfigTemplate implements Serializable +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -8061369279557787079L; + + /** States that a feature is required to select a configuration. */ + public static final int REQUIRED = 1; + + /** + * States that a feature is preferred, but not required, to select a + * configuration. In the case of multiple valid configurations, the tie + * breaks in favor of the one with the feature. + */ + public static final int PREFERRED = 2; + + /** + * States that a feature is not necessary in the configuration. In the case + * of multiple valid configurations, the tie breaks in favor of the one + * without the feature, to reduce overhead. + */ + public static final int UNNECESSARY = 3; + + /** + * The default constructor. + */ + public GraphicsConfigTemplate() + { + } + + /** + * Returns the "best" match among the array of possible configurations, given + * the criteria of this template. + * + * @param array the array to choose from + * @return the best match + * @throws NullPointerException if array is null + */ + public abstract GraphicsConfiguration getBestConfiguration + (GraphicsConfiguration[] array); + + /** + * Returns true if the given configuration supports all the features required + * by this template. + * + * @param config the configuration to test + * @return true if it is a match + * @throws NullPointerException if config is null + */ + public abstract boolean isGraphicsConfigSupported + (GraphicsConfiguration config); +} // class GraphicsConfigTemplate diff --git a/libjava/classpath/java/awt/GraphicsConfiguration.java b/libjava/classpath/java/awt/GraphicsConfiguration.java new file mode 100644 index 000000000..bbd9820c9 --- /dev/null +++ b/libjava/classpath/java/awt/GraphicsConfiguration.java @@ -0,0 +1,275 @@ +/* GraphicsConfiguration.java -- describes characteristics of graphics + Copyright (C) 2000, 2001, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.VolatileImage; + +/** + * This class describes the configuration of various graphics devices, such + * as a monitor or printer. Different configurations may exist for the same + * device, according to the different native modes supported. + * + * <p>Virtual devices are supported (for example, in a multiple screen + * environment, a virtual device covers all screens simultaneously); the + * configuration will have a non-zero relative coordinate system in such + * a case. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see Window + * @see Frame + * @see GraphicsEnvironment + * @see GraphicsDevice + * @since 1.0 + * @status updated to 1.4 + */ +public abstract class GraphicsConfiguration +{ + + /** The cached image capabilities. */ + private ImageCapabilities imageCapabilities; + + /** The cached buffer capabilities. */ + private BufferCapabilities bufferCapabilities; + + /** + * The default constructor. + * + * @see GraphicsDevice#getConfigurations() + * @see GraphicsDevice#getDefaultConfiguration() + * @see GraphicsDevice#getBestConfiguration(GraphicsConfigTemplate) + * @see Graphics2D#getDeviceConfiguration() + */ + protected GraphicsConfiguration () + { + } + + /** + * Gets the associated device that this configuration describes. + * + * @return the device + */ + public abstract GraphicsDevice getDevice(); + + /** + * Returns a buffered image optimized to this device, so that blitting can + * be supported in the buffered image. + * + * @param w the width of the buffer + * @param h the height of the buffer + * @return the buffered image, or null if none is supported + */ + public abstract BufferedImage createCompatibleImage(int w, int h); + + /** + * Returns a buffered volatile image optimized to this device, so that + * blitting can be supported in the buffered image. Because the buffer is + * volatile, it can be optimized by native graphics accelerators. + * + * @param w the width of the buffer + * @param h the height of the buffer + * @return the buffered image, or null if none is supported + * @see Component#createVolatileImage(int, int) + * @since 1.4 + */ + public abstract VolatileImage createCompatibleVolatileImage(int w, int h); + + /** + * Returns a buffered volatile image optimized to this device, and with the + * given capabilities, so that blitting can be supported in the buffered + * image. Because the buffer is volatile, it can be optimized by native + * graphics accelerators. + * + * @param w the width of the buffer + * @param h the height of the buffer + * @param caps the desired capabilities of the image buffer + * @return the buffered image, or null if none is supported + * @throws AWTException if the capabilities cannot be met + * @since 1.4 + */ + public VolatileImage createCompatibleVolatileImage(int w, int h, + ImageCapabilities caps) + throws AWTException + { + // Must be overridden by implementations to check caps. + return createCompatibleVolatileImage(w, h); + } + + /** + * Returns a buffered volatile image optimized to this device, and + * with the given transparency. Because the buffer is volatile, it + * can be optimized by native graphics accelerators. + * + * @param width the width of the buffer + * @param height the height of the buffer + * @param transparency the transparency value for the buffer + * @return the buffered image, or null if none is supported + * @since 1.5 + */ + public abstract VolatileImage createCompatibleVolatileImage(int width, + int height, + int transparency); + + /** + * Creates a volatile image with the specified capabilities and transparency. + * If the backend cannot meet the requested capabilities and transparency, + * an AWTException is thrown. + * + * @param width the width of the image + * @param height the height of the image + * @param caps the requested capabilities + * @param transparency the required transparency + * + * @return a volatile image with the specified capabilites and transparency + * + * @throws AWTException if the required capabilities and transparency cannot + * be met + * + * @since 1.5 + */ + public VolatileImage createCompatibleVolatileImage(int width, int height, + ImageCapabilities caps, + int transparency) + throws AWTException + { + // Must be overridden by implementations to check caps. + return createCompatibleVolatileImage(width, height, transparency); + } + + /** + * Returns a buffered image optimized to this device, and with the specified + * transparency, so that blitting can be supported in the buffered image. + * + * @param w the width of the buffer + * @param h the height of the buffer + * @param transparency the transparency of the buffer + * @return the buffered image, or null if none is supported + * @see Transparency#OPAQUE + * @see Transparency#BITMASK + * @see Transparency#TRANSLUCENT + */ + public abstract BufferedImage createCompatibleImage(int w, int h, + int transparency); + + /** + * Gets the color model of the corresponding device. + * + * @return the color model + */ + public abstract ColorModel getColorModel(); + + /** + * Gets a color model for the corresponding device which supports the desired + * transparency level. + * + * @param transparency the transparency of the model + * @return the color model, with transparency + * @see Transparency#OPAQUE + * @see Transparency#BITMASK + * @see Transparency#TRANSLUCENT + */ + public abstract ColorModel getColorModel(int transparency); + + /** + * Returns a transform that maps user coordinates to device coordinates. The + * preferred mapping is about 72 user units to 1 inch (2.54 cm) of physical + * space. This is often the identity transform. The device coordinates have + * the origin at the upper left, with increasing x to the right, and + * increasing y to the bottom. + * + * @return the transformation from user space to device space + * @see #getNormalizingTransform() + */ + public abstract AffineTransform getDefaultTransform(); + + /** + * Returns a transform that maps user coordinates to device coordinates. The + * exact mapping is 72 user units to 1 inch (2.54 cm) of physical space. + * This is often the identity transform. The device coordinates have the + * origin at the upper left, with increasing x to the right, and increasing + * y to the bottom. Note that this is more accurate (and thus, sometimes more + * costly) than the default transform. + * + * @return the normalized transformation from user space to device space + * @see #getDefaultTransform() + */ + public abstract AffineTransform getNormalizingTransform(); + + /** + * Returns the bounds of the configuration, in device coordinates. If this + * is a virtual device (for example, encompassing several screens), the + * bounds may have a non-zero origin. + * + * @return the device bounds + * @since 1.3 + */ + public abstract Rectangle getBounds(); + + /** + * Returns the buffering capabilities of this configuration. + * + * @return the buffer capabilities + * @since 1.4 + */ + public BufferCapabilities getBufferCapabilities() + { + if (imageCapabilities == null) + getImageCapabilities(); + + if (bufferCapabilities == null) + bufferCapabilities = new BufferCapabilities(imageCapabilities, + imageCapabilities, null); + return bufferCapabilities; + } + + /** + * Returns the imaging capabilities of this configuration. + * + * @return the image capabilities + * @since 1.4 + */ + public ImageCapabilities getImageCapabilities() + { + if (imageCapabilities == null) + imageCapabilities = new ImageCapabilities(false); + return imageCapabilities; + } +} // class GraphicsConfiguration diff --git a/libjava/classpath/java/awt/GraphicsDevice.java b/libjava/classpath/java/awt/GraphicsDevice.java new file mode 100644 index 000000000..c99c14b1b --- /dev/null +++ b/libjava/classpath/java/awt/GraphicsDevice.java @@ -0,0 +1,292 @@ +/* GraphicsDevice.java -- information about a graphics device + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.image.VolatileImage; + +/** + * This describes a graphics device available to the given environment. This + * includes screen and printer devices, and the different configurations for + * each device. Also, this allows you to create virtual devices which operate + * over a multi-screen environment. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see GraphicsEnvironment + * @see GraphicsConfiguration + * @since 1.3 + * @status updated to 1.4 + */ +public abstract class GraphicsDevice +{ + /** Device is a raster screen. */ + public static final int TYPE_RASTER_SCREEN = 0; + + /** Device is a printer. */ + public static final int TYPE_PRINTER = 1; + + /** Device is an image buffer not visible to the user. */ + public static final int TYPE_IMAGE_BUFFER = 2; + + /** The current full-screen window, or null if there is none. */ + private Window full_screen; + + /** + * The bounds of the fullscreen window before it has been switched to full + * screen. + */ + private Rectangle fullScreenOldBounds; + + /** The current display mode, or null if unknown. */ + private DisplayMode mode; + + /** + * The default constructor. + * + * @see GraphicsEnvironment#getScreenDevices() + * @see GraphicsEnvironment#getDefaultScreenDevice() + * @see GraphicsConfiguration#getDevice() + */ + protected GraphicsDevice() + { + } + + /** + * Returns the type of the device. + * + * @return the device type + * @see #TYPE_RASTER_SCREEN + * @see #TYPE_PRINTER + * @see #TYPE_IMAGE_BUFFER + */ + public abstract int getType(); + + /** + * Returns an identification string for the device. This can be + * vendor-specific, and may be useful for debugging. + * + * @return the identification + */ + public abstract String getIDstring(); + + /** + * Return all configurations valid for this device. + * + * @return an array of configurations + */ + public abstract GraphicsConfiguration[] getConfigurations(); + + /** + * Return the default configuration for this device. + * + * @return the default configuration + */ + public abstract GraphicsConfiguration getDefaultConfiguration(); + + /** + * Return the best configuration, according to the criteria in the given + * template. + * + * @param template the template to adjust by + * @return the best configuration + * @throws NullPointerException if template is null + */ + public GraphicsConfiguration getBestConfiguration + (GraphicsConfigTemplate template) + { + return template.getBestConfiguration(getConfigurations()); + } + + /** + * Returns true if the device supports full-screen exclusive mode. The + * default implementation returns true; subclass it if this is not the case. + * + * @return true if full screen support is available + * @since 1.4 + */ + public boolean isFullScreenSupported() + { + return true; + } + + /** + * Toggle the given window between full screen and normal mode. The previous + * full-screen window, if different, is restored; if the given window is + * null, no window will be full screen. If + * <code>isFullScreenSupported()</code> returns true, full screen mode is + * considered to be exclusive, which implies:<ul> + * <li>Windows cannot overlap the full-screen window. All other application + * windows will always appear beneath the full-screen window in the + * Z-order.</li> + * <li>Input method windows are disabled. It is advisable to call + * <code>Component.enableInputMethods(false)</code> to make a component + * a non-client of the input method framework.</li> + * </ul><br> + * If <code>isFullScreenSupported()</code> returns false, full-screen + * exclusive mode is simulated by resizing the window to the size of the + * screen and positioning it at (0,0). This is also what this method does. + * If a device supports real fullscreen mode then it should override this + * method as well as #isFullScreenSupported and #getFullScreenWindow. + * + * @param w the window to toggle + * @see #isFullScreenSupported() + * @see #getFullScreenWindow() + * @see #setDisplayMode(DisplayMode) + * @see Component#enableInputMethods(boolean) + * @since 1.4 + */ + public synchronized void setFullScreenWindow(Window w) + { + // Restore the previous window to normal mode and release the reference. + if (full_screen != null) + { + full_screen.setBounds(fullScreenOldBounds); + } + + full_screen = null; + + // If w != null, make it full-screen. + if (w != null) + { + fullScreenOldBounds = w.getBounds(); + full_screen = w; + DisplayMode dMode = getDisplayMode(); + full_screen.setBounds(0, 0, dMode.getWidth(), dMode.getHeight()); + full_screen.requestFocus(); + full_screen.setLocationRelativeTo(null); + } + } + + /** + * Returns the current full-screen window of the device, or null if no + * window is full-screen. + * + * @return the full-screen window + * @see #setFullScreenWindow(Window) + * @since 1.4 + */ + public Window getFullScreenWindow() + { + return full_screen; + } + + /** + * Returns whether this device supports low-level display changes. This may + * depend on whether full-screen exclusive mode is available. + * + * XXX The default implementation returns false for now. + * + * @return true if display changes are supported + * @see #setDisplayMode(DisplayMode) + * @since 1.4 + */ + public boolean isDisplayChangeSupported() + { + return false; + } + + /** + * Sets the display mode. This may be dependent on the availability of + * full-screen exclusive mode. + * + * @param mode the new mode + * @throws IllegalArgumentException if the new mode is not in getDisplayModes + * @throws UnsupportedOperationException if ! isDisplayChangeSupported() + * @see #getDisplayMode() + * @see #getDisplayModes() + * @see #isDisplayChangeSupported() + * @since 1.4 + */ + public void setDisplayMode(DisplayMode mode) + { + DisplayMode[] array = getDisplayModes(); + if (! isDisplayChangeSupported()) + throw new UnsupportedOperationException(); + int i = array == null ? 0 : array.length; + while (--i >= 0) + if (array[i].equals(mode)) + break; + if (i < 0) + throw new IllegalArgumentException(); + this.mode = mode; + } + + /** + * Returns the current display mode of this device, or null if unknown. + * + * @return the current display mode + * @see #setDisplayMode(DisplayMode) + * @see #getDisplayModes() + * @since 1.4 + */ + public DisplayMode getDisplayMode() + { + return mode; + } + + /** + * Return an array of all available display modes. This implementation + * returns a 0-length array, so subclasses must override this. + * + * @return the array of available modes + * @since 1.4 + */ + public DisplayMode[] getDisplayModes() + { + return new DisplayMode[0]; + } + + /** + * Return the number of bytes available in accelerated memory on this + * device. The device may support creation or caching on a first-come, + * first-served basis, depending on the operating system and driver. + * Memory may be a finite resource, and because of multi-threading, you + * are not guaranteed that the result of this method ensures your image + * will successfully be put in accelerated memory. A negative result means + * the memory is unlimited. The default implementation assumes no special + * memory is available, and returns 0. + * + * @return the size of accelerated memory available + * @see VolatileImage#flush() + * @see ImageCapabilities#isAccelerated() + */ + public int getAvailableAcceleratedMemory() + { + return 0; + } +} // class GraphicsDevice diff --git a/libjava/classpath/java/awt/GraphicsEnvironment.java b/libjava/classpath/java/awt/GraphicsEnvironment.java new file mode 100644 index 000000000..a82e7a357 --- /dev/null +++ b/libjava/classpath/java/awt/GraphicsEnvironment.java @@ -0,0 +1,244 @@ +/* GraphicsEnvironment.java -- information about the graphics environment + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import gnu.java.awt.ClasspathToolkit; +import gnu.classpath.SystemProperties; +import java.awt.image.BufferedImage; +import java.util.Locale; + +/** + * This descibes the collection of GraphicsDevice and Font objects available + * on a given platform. The resources might be local or remote, and specify + * the valid configurations for displaying graphics. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see GraphicsDevice + * @see GraphicsConfiguration + * @since 1.4 + * @status updated to 1.4 + */ +public abstract class GraphicsEnvironment +{ + private static GraphicsEnvironment localGraphicsEnvironment; + + /** + * The environment must be obtained from a factory or query method, hence + * this constructor is protected. + */ + protected GraphicsEnvironment() + { + } + + /** + * Returns the local graphics environment. If the java.awt.graphicsenv + * system property is set, it instantiates the specified class, + * otherwise it assume that the awt toolkit is a ClasspathToolkit + * and delegates to it to create the instance. + * + * @return the local environment + */ + public static GraphicsEnvironment getLocalGraphicsEnvironment() + { + if (localGraphicsEnvironment != null) + return localGraphicsEnvironment; + + String graphicsenv = SystemProperties.getProperty("java.awt.graphicsenv", + null); + if (graphicsenv != null) + { + try + { + // We intentionally use the bootstrap class loader. + localGraphicsEnvironment = (GraphicsEnvironment) + Class.forName(graphicsenv).newInstance(); + return localGraphicsEnvironment; + } + catch (Exception x) + { + throw (InternalError) + new InternalError("Unable to instantiate java.awt.graphicsenv") + .initCause(x); + } + } + else + { + ClasspathToolkit tk; + tk = ((ClasspathToolkit) Toolkit.getDefaultToolkit()); + localGraphicsEnvironment = tk.getLocalGraphicsEnvironment(); + return localGraphicsEnvironment; + } + } + + /** + * Check if the local environment is headless, meaning that it does not + * support a display, keyboard, or mouse. Many methods in the Abstract + * Windows Toolkit (java.awt) throw a {@link HeadlessException} if this + * returns true. + * + * This method returns true if the java.awt.headless property is set + * to "true". + * + * @return true if the environment is headless, meaning that graphics are + * unsupported + * @since 1.4 + */ + public static boolean isHeadless() + { + String headless = SystemProperties.getProperty("java.awt.headless", null); + return "true".equalsIgnoreCase(headless); + } + + /** + * Check if the given environment is headless, meaning that it does not + * support a display, keyboard, or mouse. Many methods in the Abstract + * Windows Toolkit (java.awt) throw a {@link HeadlessException} if this + * returns true. This default implementation returns isHeadless(), so + * subclasses need only override it if they differ. + * + * @return true if the environment is headless, meaning that graphics are + * unsupported + * @since 1.4 + */ + public boolean isHeadlessInstance() + { + return isHeadless(); + } + + /** + * Get an array of all the GraphicsDevice objects. + * + * @return the available graphics devices, may be 0 length + * @throws HeadlessException if the environment is headless + */ + public abstract GraphicsDevice[] getScreenDevices(); + + /** + * Get the default screen GraphicsDevice object. + * + * @return the default screen device + * @throws HeadlessException if the environment is headless + */ + public abstract GraphicsDevice getDefaultScreenDevice(); + + /** + * Return a Graphics2D object which will render into the specified image. + * + * @param image the image to render into + * @return the object that renders into the image + */ + public abstract Graphics2D createGraphics(BufferedImage image); + + /** + * Returns an array of the one-point size fonts available in this + * environment. From there, the user can select the font and derive the + * correct one of proper size and attributes, using <code>deriveFont</code>. + * Only one master version of each font appears in this array; if a font + * can be derived from another, it must be created in that way. + * + * @return the array of available fonts + * @see #getAvailableFontFamilyNames() + * @see Font#deriveFont(int, float) + * @since 1.2 + */ + public abstract Font[] getAllFonts(); + + /** + * Returns an array of the font family names available in this environment. + * This allows flexibility in choosing the style of font, while still letting + * the Font class decide its best match. + * + * @return the array of available font families + * @see #getAllFonts() + * @see Font#getFamily() + * @since 1.2 + */ + public abstract String[] getAvailableFontFamilyNames(); + + /** + * Returns an array of the font family names available in this environment, + * localized to the current Locale if l is non-null. This allows + * flexibility in choosing the style of font, while still letting the Font + * class decide its best match. + * + * @param l the locale to use + * @return the array of available font families, localized + * @see #getAllFonts() + * @see Font#getFamily() + * @since 1.2 + */ + public abstract String[] getAvailableFontFamilyNames(Locale l); + + /** + * Returns the point where a window should be centered. You should probably + * also check that the window fits within the screen bounds. The default + * simply returns the center of the maximum window bounds; subclasses should + * override this if native objects (like scrollbars) make that off-centered. + * + * @return the centering point + * @throws HeadlessException if the environment is headless + * @see #getMaximumWindowBounds() + * @since 1.4 + */ + public Point getCenterPoint() + { + Rectangle r = getMaximumWindowBounds(); + return new Point(r.x + r.width / 2, r.y + r.height / 2); + } + + /** + * Returns the maximum bounds for a centered window object. The default + * implementation simply returns the bounds of the default configuration + * of the default screen; subclasses should override this to if native + * objects (like scrollbars) reduce what is truly available. Also, + * subclasses should override this if the window should be centered across + * a multi-screen display. + * + * @return the maximum window bounds + * @throws HeadlessException if the environment is headless + * @see #getCenterPoint() + * @see GraphicsConfiguration#getBounds() + * @see Toolkit#getScreenInsets(GraphicsConfiguration) + * @since 1.4 + */ + public Rectangle getMaximumWindowBounds() + { + return getDefaultScreenDevice().getDefaultConfiguration().getBounds(); + } +} // class GraphicsEnvironment diff --git a/libjava/classpath/java/awt/GridBagConstraints.java b/libjava/classpath/java/awt/GridBagConstraints.java new file mode 100644 index 000000000..823130058 --- /dev/null +++ b/libjava/classpath/java/awt/GridBagConstraints.java @@ -0,0 +1,246 @@ +/* GridBagConstraints.java -- Constraints for GridBag layout manager + Copyright (C) 2000, 2001, 2002, 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.io.Serializable; + +/** + * This specifies the constraints for a component managed by the + * GridBagLayout layout manager. + */ +public class GridBagConstraints implements Cloneable, Serializable +{ + static final long serialVersionUID = -1000070633030801713L; + + // Fill values. + /** + * Don't fill. + */ + public static final int NONE = 0; + + /** + * Fill in both directions. + */ + public static final int BOTH = 1; + + /** + * Fill horizontally. + */ + public static final int HORIZONTAL = 2; + + /** + * Fill vertically. + */ + public static final int VERTICAL = 3; + + // Anchor values. + /** + * Position in the center. + */ + public static final int CENTER = 10; + + /** + * Position to the north. + */ + public static final int NORTH = 11; + + /** + * Position to the northeast. + */ + public static final int NORTHEAST = 12; + + /** + * Position to the east. + */ + public static final int EAST = 13; + + /** + * Position to the southeast. + */ + public static final int SOUTHEAST = 14; + + /** + * Position to the south. + */ + public static final int SOUTH = 15; + + /** + * Position to the southwest. + */ + public static final int SOUTHWEST = 16; + + /** + * Position to the west. + */ + public static final int WEST = 17; + + /** + * Position to the northwest. + */ + public static final int NORTHWEST = 18; + + // gridx and gridy values. + /** + * Occupy all remaining cells except last cell. + */ + public static final int RELATIVE = -1; + + /** + * Occupy all remaining cells. + */ + public static final int REMAINDER = 0; + + /** + * Position to where a page starts. Equals NORTH for horizontal orientations. + */ + public static final int PAGE_START = 19; + + /** + * Position to where a page ends. Equals SOUTH for horizontal orientations. + */ + public static final int PAGE_END = 20; + + /** + * Position to where a text line would start. Equals to WEST for + * left-to-right orientations. + */ + public static final int LINE_START = 21; + + /** + * Position to where a text line would end. Equals to EAST for + * left-to-right orientations. + */ + public static final int LINE_END = 22; + + /** + * Position to where the first text line would start. Equals to NORTHWEST for + * horizontal left-to-right orientations. + */ + public static final int FIRST_LINE_START = 23; + + /** + * Position to where the first text line would end. Equals to NORTHEAST for + * horizontal left-to-right orientations. + */ + public static final int FIRST_LINE_END = 24; + + /** + * Position to where the last text line would start. Equals to SOUTHWEST for + * horizontal left-to-right orientations. + */ + public static final int LAST_LINE_START = 25; + + /** + * Position to where the last text line would end. Equals to SOUTHEAST for + * horizontal left-to-right orientations. + */ + public static final int LAST_LINE_END = 26; + + public int anchor; + public int fill; + public int gridheight; + public int gridwidth; + public int gridx; + public int gridy; + public Insets insets; + public int ipadx; + public int ipady; + public double weightx; + public double weighty; + + /** + * Create a copy of this object. + */ + public Object clone () + { + try + { + GridBagConstraints g = (GridBagConstraints) super.clone (); + g.insets = (Insets) insets.clone (); + return g; + } + catch (CloneNotSupportedException _) + { + // Can't happen. + return null; + } + } + + /** + * Create a new GridBagConstraints object with the default + * parameters. + */ + public GridBagConstraints () + { + this.anchor = CENTER; + this.fill = NONE; + this.gridx = RELATIVE; + this.gridy = RELATIVE; + this.gridwidth = 1; + this.gridheight = 1; + this.ipadx = 0; + this.ipady = 0; + this.insets = new Insets (0, 0, 0, 0); + this.weightx = 0; + this.weighty = 0; + } + + /** + * Create a new GridBagConstraints object with the indicated + * parameters. + */ + public GridBagConstraints (int gridx, int gridy, + int gridwidth, int gridheight, + double weightx, double weighty, + int anchor, int fill, + Insets insets, int ipadx, int ipady) + { + this.anchor = anchor; + this.fill = fill; + this.gridx = gridx; + this.gridy = gridy; + this.gridwidth = gridwidth; + this.gridheight = gridheight; + this.ipadx = ipadx; + this.ipady = ipady; + this.insets = insets; + this.weightx = weightx; + this.weighty = weighty; + } +} diff --git a/libjava/classpath/java/awt/GridBagLayout.java b/libjava/classpath/java/awt/GridBagLayout.java new file mode 100644 index 000000000..224d53ff2 --- /dev/null +++ b/libjava/classpath/java/awt/GridBagLayout.java @@ -0,0 +1,1114 @@ +/* GridBagLayout - Layout manager for components according to GridBagConstraints + Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Hashtable; + +/** + * @author Michael Koch (konqueror@gmx.de) + * @author Jeroen Frijters (jeroen@frijters.net) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +public class GridBagLayout + implements Serializable, LayoutManager2 +{ + private static final long serialVersionUID = 8838754796412211005L; + + protected static final int MINSIZE = 1; + protected static final int PREFERREDSIZE = 2; + protected static final int MAXGRIDSIZE = 512; + + // comptable remembers the original contraints given to us. + // internalcomptable is used to keep track of modified constraint values + // that we calculate, particularly when we are given RELATIVE and + // REMAINDER constraints. + // Constraints kept in comptable are never modified, and constraints + // kept in internalcomptable can be modified internally only. + protected Hashtable<Component,GridBagConstraints> comptable; + private Hashtable<Component,GridBagConstraints> internalcomptable; + protected GridBagLayoutInfo layoutInfo; + protected GridBagConstraints defaultConstraints; + + public double[] columnWeights; + public int[] columnWidths; + public double[] rowWeights; + public int[] rowHeights; + + public GridBagLayout () + { + this.comptable = new Hashtable<Component,GridBagConstraints>(); + this.internalcomptable = new Hashtable<Component,GridBagConstraints>(); + this.defaultConstraints= new GridBagConstraints(); + } + + /** + * Helper method to calc the sum of a range of elements in an int array. + */ + private int sumIntArray (int[] array, int upto) + { + int result = 0; + + for (int i = 0; i < upto; i++) + result += array [i]; + + return result; + } + + /** + * Helper method to calc the sum of all elements in an int array. + */ + private int sumIntArray (int[] array) + { + return sumIntArray(array, array.length); + } + + /** + * Helper method to calc the sum of all elements in an double array. + */ + private double sumDoubleArray (double[] array) + { + double result = 0; + + for (int i = 0; i < array.length; i++) + result += array [i]; + + return result; + } + + public void addLayoutComponent (String name, Component component) + { + // do nothing here. + } + + public void removeLayoutComponent (Component component) + { + // do nothing here + } + + public void addLayoutComponent (Component component, Object constraints) + { + if (constraints == null) + return; + + if (!(constraints instanceof GridBagConstraints)) + throw new IllegalArgumentException("constraints " + + constraints + + " are not an instance of GridBagConstraints"); + + setConstraints (component, (GridBagConstraints) constraints); + } + + public Dimension preferredLayoutSize (Container parent) + { + if (parent == null) + return new Dimension (0, 0); + + GridBagLayoutInfo li = getLayoutInfo (parent, PREFERREDSIZE); + return getMinSize (parent, li); + } + + public Dimension minimumLayoutSize (Container parent) + { + if (parent == null) + return new Dimension (0, 0); + + GridBagLayoutInfo li = getLayoutInfo (parent, MINSIZE); + return getMinSize (parent, li); + } + + public Dimension maximumLayoutSize (Container target) + { + return new Dimension (Integer.MAX_VALUE, Integer.MAX_VALUE); + } + + public void layoutContainer (Container parent) + { + arrangeGrid (parent); + } + + public float getLayoutAlignmentX (Container target) + { + return Component.CENTER_ALIGNMENT; + } + + public float getLayoutAlignmentY (Container target) + { + return Component.CENTER_ALIGNMENT; + } + + public void invalidateLayout (Container target) + { + this.layoutInfo = null; + } + + public void setConstraints (Component component, + GridBagConstraints constraints) + { + GridBagConstraints clone = (GridBagConstraints) constraints.clone(); + + if (clone.gridx < 0) + clone.gridx = GridBagConstraints.RELATIVE; + + if (clone.gridy < 0) + clone.gridy = GridBagConstraints.RELATIVE; + + if (clone.gridwidth == 0) + clone.gridwidth = GridBagConstraints.REMAINDER; + else if (clone.gridwidth < 0) + clone.gridwidth = 1; + + if (clone.gridheight == 0) + clone.gridheight = GridBagConstraints.REMAINDER; + else if (clone.gridheight < 0) + clone.gridheight = 1; + + comptable.put (component, clone); + } + + public GridBagConstraints getConstraints (Component component) + { + return (GridBagConstraints) (lookupConstraints (component).clone()); + } + + protected GridBagConstraints lookupConstraints (Component component) + { + GridBagConstraints result = comptable.get (component); + + if (result == null) + { + setConstraints (component, defaultConstraints); + result = comptable.get (component); + } + + return result; + } + + private GridBagConstraints lookupInternalConstraints (Component component) + { + GridBagConstraints result = internalcomptable.get (component); + + if (result == null) + { + result = (GridBagConstraints) lookupConstraints(component).clone(); + internalcomptable.put (component, result); + } + + return result; + } + + /** + * @since 1.1 + */ + public Point getLayoutOrigin () + { + if (layoutInfo == null) + return new Point (0, 0); + + return new Point (layoutInfo.pos_x, layoutInfo.pos_y); + } + + /** + * @since 1.1 + */ + public int[][] getLayoutDimensions () + { + int[][] result = new int [2][]; + if (layoutInfo == null) + { + result[0] = new int[0]; + result[1] = new int[0]; + + return result; + } + + result [0] = new int [layoutInfo.cols]; + System.arraycopy (layoutInfo.colWidths, 0, result [0], 0, layoutInfo.cols); + result [1] = new int [layoutInfo.rows]; + System.arraycopy (layoutInfo.rowHeights, 0, result [1], 0, layoutInfo.rows); + return result; + } + + public double[][] getLayoutWeights () + { + double[][] result = new double [2][]; + if (layoutInfo == null) + { + result[0] = new double[0]; + result[1] = new double[0]; + + return result; + } + + result [0] = new double [layoutInfo.cols]; + System.arraycopy (layoutInfo.colWeights, 0, result [0], 0, layoutInfo.cols); + result [1] = new double [layoutInfo.rows]; + System.arraycopy (layoutInfo.rowWeights, 0, result [1], 0, layoutInfo.rows); + return result; + } + + /** + * @since 1.1 + */ + public Point location (int x, int y) + { + if (layoutInfo == null) + return new Point (0, 0); + + int col; + int row; + int pixel_x = layoutInfo.pos_x; + int pixel_y = layoutInfo.pos_y; + + for (col = 0; col < layoutInfo.cols; col++) + { + int w = layoutInfo.colWidths [col]; + if (x < pixel_x + w) + break; + + pixel_x += w; + } + + for (row = 0; row < layoutInfo.rows; row++) + { + int h = layoutInfo.rowHeights [row]; + if (y < pixel_y + h) + break; + + pixel_y += h; + } + + return new Point (col, row); + } + + /** + * Return a string representation of this GridBagLayout. + * + * @return a string representation + */ + public String toString() + { + return getClass().getName(); + } + + /** + * Move and resize a rectangle according to a set of grid bag + * constraints. The x, y, width and height fields of the + * rectangle argument are adjusted to the new values. + * + * @param constraints position and size constraints + * @param r rectangle to be moved and resized + */ + protected void AdjustForGravity (GridBagConstraints constraints, + Rectangle r) + { + Insets insets = constraints.insets; + if (insets != null) + { + r.x += insets.left; + r.y += insets.top; + r.width -= insets.left + insets.right; + r.height -= insets.top + insets.bottom; + } + } + + /** + * Obsolete. + */ + protected void ArrangeGrid (Container parent) + { + Component[] components = parent.getComponents(); + + if (components.length == 0) + return; + + GridBagLayoutInfo info = getLayoutInfo (parent, PREFERREDSIZE); + if (info.cols == 0 && info.rows == 0) + return; + + // DEBUG + //dumpLayoutInfo (info); + + // Calling setBounds on these components causes this layout to + // be invalidated, clearing the layout information cache, + // layoutInfo. So we wait until after this for loop to set + // layoutInfo. + Component lastComp = null; + + Rectangle cell = new Rectangle(); + + for (int i = 0; i < components.length; i++) + { + Component component = components[i]; + + // If component is not visible we dont have to care about it. + if (! component.isVisible()) + continue; + + Dimension dim = component.getPreferredSize(); + GridBagConstraints constraints = lookupInternalConstraints(component); + + if (lastComp != null + && constraints.gridheight == GridBagConstraints.REMAINDER) + cell.y += cell.height; + else + cell.y = sumIntArray(info.rowHeights, constraints.gridy); + + if (lastComp != null + && constraints.gridwidth == GridBagConstraints.REMAINDER) + cell.x += cell.width; + else + cell.x = sumIntArray(info.colWidths, constraints.gridx); + + cell.width = sumIntArray(info.colWidths, constraints.gridx + + constraints.gridwidth) - cell.x; + cell.height = sumIntArray(info.rowHeights, constraints.gridy + + constraints.gridheight) - cell.y; + + // Adjust for insets. + AdjustForGravity( constraints, cell ); + + // Note: Documentation says that padding is added on both sides, but + // visual inspection shows that the Sun implementation only adds it + // once, so we do the same. + dim.width += constraints.ipadx; + dim.height += constraints.ipady; + + switch (constraints.fill) + { + case GridBagConstraints.HORIZONTAL: + dim.width = cell.width; + break; + case GridBagConstraints.VERTICAL: + dim.height = cell.height; + break; + case GridBagConstraints.BOTH: + dim.width = cell.width; + dim.height = cell.height; + break; + } + + int x = 0; + int y = 0; + + switch (constraints.anchor) + { + case GridBagConstraints.NORTH: + x = cell.x + (cell.width - dim.width) / 2; + y = cell.y; + break; + case GridBagConstraints.SOUTH: + x = cell.x + (cell.width - dim.width) / 2; + y = cell.y + cell.height - dim.height; + break; + case GridBagConstraints.WEST: + x = cell.x; + y = cell.y + (cell.height - dim.height) / 2; + break; + case GridBagConstraints.EAST: + x = cell.x + cell.width - dim.width; + y = cell.y + (cell.height - dim.height) / 2; + break; + case GridBagConstraints.NORTHEAST: + x = cell.x + cell.width - dim.width; + y = cell.y; + break; + case GridBagConstraints.NORTHWEST: + x = cell.x; + y = cell.y; + break; + case GridBagConstraints.SOUTHEAST: + x = cell.x + cell.width - dim.width; + y = cell.y + cell.height - dim.height; + break; + case GridBagConstraints.SOUTHWEST: + x = cell.x; + y = cell.y + cell.height - dim.height; + break; + default: + x = cell.x + (cell.width - dim.width) / 2; + y = cell.y + (cell.height - dim.height) / 2; + break; + } + component.setBounds(info.pos_x + x, info.pos_y + y, dim.width, + dim.height); + lastComp = component; + } + + // DEBUG + //dumpLayoutInfo(info); + + // Cache layout information. + layoutInfo = getLayoutInfo(parent, PREFERREDSIZE); + } + + /** + * Obsolete. + */ + protected GridBagLayoutInfo GetLayoutInfo (Container parent, int sizeflag) + { + if (sizeflag != MINSIZE && sizeflag != PREFERREDSIZE) + throw new IllegalArgumentException(); + + Dimension parentDim = parent.getSize (); + Insets parentInsets = parent.getInsets (); + parentDim.width -= parentInsets.left + parentInsets.right; + parentDim.height -= parentInsets.top + parentInsets.bottom; + + int current_y = 0; + int max_x = 0; + int max_y = 0; + + // Guaranteed to contain the last component added to the given row + // or column, whose gridwidth/height is not REMAINDER. + HashMap<Integer,Component> lastInRow = new HashMap<Integer,Component>(); + HashMap<Integer,Component> lastInCol = new HashMap<Integer,Component>(); + + Component[] components = parent.getComponents(); + + // Components sorted by gridwidths/heights, + // smallest to largest, with REMAINDER and RELATIVE at the end. + // These are useful when determining sizes and weights. + ArrayList<Component> sortedByWidth = + new ArrayList<Component>(components.length); + ArrayList<Component> sortedByHeight = + new ArrayList<Component>(components.length); + + // STEP 1: first we figure out how many rows/columns + for (int i = 0; i < components.length; i++) + { + Component component = components [i]; + // If component is not visible we dont have to care about it. + if (!component.isVisible()) + continue; + + // When looking up the constraint for the first time, check the + // original unmodified constraint. After the first time, always + // refer to the internal modified constraint. + GridBagConstraints originalConstraints = lookupConstraints (component); + GridBagConstraints constraints = (GridBagConstraints) originalConstraints.clone(); + internalcomptable.put(component, constraints); + + // Cases: + // + // 1. gridy == RELATIVE, gridx == RELATIVE + // + // use y as the row number; check for the next + // available slot at row y + // + // 2. only gridx == RELATIVE + // + // check for the next available slot at row gridy + // + // 3. only gridy == RELATIVE + // + // check for the next available slot at column gridx + // + // 4. neither gridx or gridy == RELATIVE + // + // nothing to check; just add it + + // cases 1 and 2 + if(constraints.gridx == GridBagConstraints.RELATIVE) + { + if (constraints.gridy == GridBagConstraints.RELATIVE) + constraints.gridy = current_y; + + int x; + + // Check the component that occupies the right-most spot in this + // row. We want to add this component after it. + // If this row is empty, add to the 0 position. + if (!lastInRow.containsKey(new Integer(constraints.gridy))) + x = 0; + else + { + Component lastComponent = lastInRow.get(new Integer(constraints.gridy)); + GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); + x = lastConstraints.gridx + Math.max(1, lastConstraints.gridwidth); + } + + // Determine if this component will fit in the slot vertically. + // If not, bump it over to where it does fit. + for (int y = constraints.gridy + 1; y < constraints.gridy + Math.max(1, constraints.gridheight); y++) + { + if (lastInRow.containsKey(new Integer(y))) + { + Component lastComponent = lastInRow.get(new Integer(y)); + GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); + x = Math.max (x, + lastConstraints.gridx + Math.max(1, lastConstraints.gridwidth)); + } + } + + constraints.gridx = x; + } + // case 3 + else if(constraints.gridy == GridBagConstraints.RELATIVE) + { + int y; + // Check the component that occupies the bottom-most spot in + // this column. We want to add this component below it. + // If this column is empty, add to the 0 position. + if (!lastInCol.containsKey(new Integer(constraints.gridx))) + { + y = current_y; + } + else + { + Component lastComponent = lastInCol.get(new Integer(constraints.gridx)); + GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); + y = lastConstraints.gridy + Math.max(1, lastConstraints.gridheight); + } + + // Determine if this component will fit in the slot horizontally. + // If not, bump it down to where it does fit. + for (int x = constraints.gridx + 1; x < constraints.gridx + Math.max(1, constraints.gridwidth); x++) + { + if (lastInCol.containsKey(new Integer(x))) + { + Component lastComponent = lastInCol.get(new Integer(x)); + GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); + y = Math.max (y, + lastConstraints.gridy + Math.max(1, lastConstraints.gridheight)); + } + } + + constraints.gridy = y; + } + // case 4: do nothing + + max_x = Math.max(max_x, + constraints.gridx + Math.max(1, constraints.gridwidth)); + max_y = Math.max(max_y, + constraints.gridy + Math.max(1, constraints.gridheight)); + + sortBySpan(component, constraints.gridwidth, sortedByWidth, true); + sortBySpan(component, constraints.gridheight, sortedByHeight, false); + + // Update our reference points for RELATIVE gridx and gridy. + if(constraints.gridwidth == GridBagConstraints.REMAINDER) + { + current_y = constraints.gridy + Math.max(1, constraints.gridheight); + } + else if (constraints.gridwidth != GridBagConstraints.REMAINDER) + { + for (int y = constraints.gridy; y < constraints.gridy + Math.max(1, constraints.gridheight); y++) + { + if(lastInRow.containsKey(new Integer(y))) + { + Component lastComponent = lastInRow.get(new Integer(y)); + GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); + if (constraints.gridx > lastConstraints.gridx) + { + lastInRow.put(new Integer(y), component); + } + } + else + { + lastInRow.put(new Integer(y), component); + } + } + + for (int x = constraints.gridx; x < constraints.gridx + Math.max(1, constraints.gridwidth); x++) + { + if(lastInCol.containsKey(new Integer(x))) + { + Component lastComponent = lastInCol.get(new Integer(x)); + GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); + if (constraints.gridy > lastConstraints.gridy) + { + lastInCol.put(new Integer(x), component); + } + } + else + { + lastInCol.put(new Integer(x), component); + } + } + } + } // end of STEP 1 + + GridBagLayoutInfo info = new GridBagLayoutInfo(max_x, max_y); + + // Check if column widths and row heights are overridden. + + for (int x = 0; x < max_x; x++) + { + if(columnWidths != null && columnWidths.length > x) + info.colWidths[x] = columnWidths[x]; + if(columnWeights != null && columnWeights.length > x) + info.colWeights[x] = columnWeights[x]; + } + + for (int y = 0; y < max_y; y++) + { + if(rowHeights != null && rowHeights.length > y) + info.rowHeights[y] = rowHeights[y]; + if(rowWeights != null && rowWeights.length > y) + info.rowWeights[y] = rowWeights[y]; + } + + // STEP 2: Fix up any cells with width/height as REMAINDER/RELATIVE. + for (int i = 0; i < components.length; i++) + { + Component component = components [i]; + + // If component is not visible we dont have to care about it. + if (!component.isVisible()) + continue; + + GridBagConstraints constraints = lookupInternalConstraints (component); + + if(constraints.gridwidth == GridBagConstraints.REMAINDER || constraints.gridwidth == GridBagConstraints.RELATIVE) + { + if(constraints.gridwidth == GridBagConstraints.REMAINDER) + { + for (int y = constraints.gridy; y < constraints.gridy + Math.max(1, constraints.gridheight); y++) + { + if (lastInRow.containsKey(new Integer(y))) + { + Component lastComponent = lastInRow.get(new Integer(y)); + GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); + + if (lastConstraints.gridwidth == GridBagConstraints.RELATIVE) + { + constraints.gridx = max_x - 1; + break; + } + else + { + constraints.gridx = Math.max (constraints.gridx, + lastConstraints.gridx + Math.max (1, lastConstraints.gridwidth)); + } + } + } + constraints.gridwidth = max_x - constraints.gridx; + } + else if (constraints.gridwidth == GridBagConstraints.RELATIVE) + { + constraints.gridwidth = max_x - constraints.gridx - 1; + } + + // Re-sort + sortedByWidth.remove(sortedByWidth.indexOf(component)); + sortBySpan(component, constraints.gridwidth, sortedByWidth, true); + } + + if(constraints.gridheight == GridBagConstraints.REMAINDER || constraints.gridheight == GridBagConstraints.RELATIVE) + { + if(constraints.gridheight == GridBagConstraints.REMAINDER) + { + for (int x = constraints.gridx; x < constraints.gridx + Math.max(1, constraints.gridwidth); x++) + { + if (lastInCol.containsKey(new Integer(x))) + { + Component lastComponent = lastInRow.get(new Integer(x)); + if (lastComponent != null) + { + GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); + + if (lastConstraints.gridheight == GridBagConstraints.RELATIVE) + { + constraints.gridy = max_y - 1; + break; + } + else + { + constraints.gridy = Math.max (constraints.gridy, + lastConstraints.gridy + Math.max (1, lastConstraints.gridheight)); + } + } + } + } + constraints.gridheight = max_y - constraints.gridy; + } + else if (constraints.gridheight == GridBagConstraints.RELATIVE) + { + constraints.gridheight = max_y - constraints.gridy - 1; + } + + // Re-sort + sortedByHeight.remove(sortedByHeight.indexOf(component)); + sortBySpan(component, constraints.gridheight, sortedByHeight, false); + } + } // end of STEP 2 + + // STEP 3: Determine sizes and weights for columns. + for (int i = 0; i < sortedByWidth.size(); i++) + { + Component component = sortedByWidth.get(i); + + // If component is not visible we dont have to care about it. + if (!component.isVisible()) + continue; + + GridBagConstraints constraints = lookupInternalConstraints (component); + + int width = (sizeflag == PREFERREDSIZE) ? + component.getPreferredSize().width : + component.getMinimumSize().width; + + if(constraints.insets != null) + width += constraints.insets.left + constraints.insets.right; + + width += constraints.ipadx; + + distributeSizeAndWeight(width, + constraints.weightx, + constraints.gridx, + constraints.gridwidth, + info.colWidths, + info.colWeights); + } // end of STEP 3 + + // STEP 4: Determine sizes and weights for rows. + for (int i = 0; i < sortedByHeight.size(); i++) + { + Component component = sortedByHeight.get(i); + + // If component is not visible we dont have to care about it. + if (!component.isVisible()) + continue; + + GridBagConstraints constraints = lookupInternalConstraints (component); + + int height = (sizeflag == PREFERREDSIZE) ? + component.getPreferredSize().height : + component.getMinimumSize().height; + + if(constraints.insets != null) + height += constraints.insets.top + constraints.insets.bottom; + + height += constraints.ipady; + + distributeSizeAndWeight(height, + constraints.weighty, + constraints.gridy, + constraints.gridheight, + info.rowHeights, + info.rowWeights); + } // end of STEP 4 + + // Adjust cell sizes iff parent size not zero. + if (parentDim.width > 0 && parentDim.height > 0) + { + calcCellSizes (info.colWidths, info.colWeights, parentDim.width); + calcCellSizes (info.rowHeights, info.rowWeights, parentDim.height); + } + + int totalWidth = sumIntArray(info.colWidths); + int totalHeight = sumIntArray(info.rowHeights); + + // Make sure pos_x and pos_y are never negative. + if (totalWidth >= parentDim.width) + info.pos_x = parentInsets.left; + else + info.pos_x = parentInsets.left + (parentDim.width - totalWidth) / 2; + + if (totalHeight >= parentDim.height) + info.pos_y = parentInsets.top; + else + info.pos_y = parentInsets.top + (parentDim.height - totalHeight) / 2; + + // DEBUG + //dumpLayoutInfo (info); + + return info; + } + + /** + * Obsolete. + */ + protected Dimension GetMinSize (Container parent, GridBagLayoutInfo info) + { + if (parent == null || info == null) + return new Dimension (0, 0); + + Insets insets = parent.getInsets(); + int width = sumIntArray (info.colWidths) + insets.left + insets.right; + int height = sumIntArray (info.rowHeights) + insets.top + insets.bottom; + return new Dimension (width, height); + } + + /** + * @since 1.4 + */ + protected Dimension getMinSize (Container parent, GridBagLayoutInfo info) + { + return GetMinSize (parent, info); + } + + /** + * Helper method used by GetLayoutInfo to keep components sorted, either + * by gridwidth or gridheight. + * + * @param component Component to add to the sorted list. + * @param span Either the component's gridwidth or gridheight. + * @param list <code>ArrayList</code> of components, sorted by + * their span. + * @param sortByWidth Flag indicating sorting index. If true, sort by + * width. Otherwise, sort by height. + * FIXME: Use a better sorting algorithm. + */ + private void sortBySpan (Component component, int span, + ArrayList<Component> list, boolean sortByWidth) + { + if (span == GridBagConstraints.REMAINDER + || span == GridBagConstraints.RELATIVE) + { + // Put all RELATIVE and REMAINDER components at the end. + list.add(component); + } + else + { + int i = 0; + if (list.size() > 0) + { + GridBagConstraints gbc = lookupInternalConstraints(list.get(i)); + int otherspan = sortByWidth ? + gbc.gridwidth : + gbc.gridheight; + while (otherspan != GridBagConstraints.REMAINDER + && otherspan != GridBagConstraints.RELATIVE + && span >= otherspan) + { + i++; + if (i < list.size()) + { + gbc = lookupInternalConstraints(list.get(i)); + otherspan = sortByWidth ? + gbc.gridwidth : + gbc.gridheight; + } + else + break; + } + } + list.add(i, component); + } + } + + /** + * Helper method used by GetLayoutInfo to distribute a component's size + * and weight. + * + * @param size Preferred size of component, with inset and padding + * already added. + * @param weight Weight of component. + * @param start Starting position of component. Either + * constraints.gridx or gridy. + * @param span Span of component. either contraints.gridwidth or + * gridheight. + * @param sizes Sizes of rows or columns. + * @param weights Weights of rows or columns. + */ + private void distributeSizeAndWeight (int size, double weight, + int start, int span, + int[] sizes, double[] weights) + { + if (span == 1) + { + sizes[start] = Math.max(sizes[start], size); + weights[start] = Math.max(weights[start], weight); + } + else + { + int numOccupied = span; + int lastOccupied = -1; + + for(int i = start; i < start + span; i++) + { + if (sizes[i] == 0.0) + numOccupied--; + else + { + size -= sizes[i]; + lastOccupied = i; + } + } + + // A component needs to occupy at least one row. + if(numOccupied == 0) + sizes[start + span - 1] = size; + else if (size > 0) + sizes[lastOccupied] += size; + + calcCellWeights(weight, weights, start, span); + } + } + + /** + * Helper method used by GetLayoutInfo to calculate weight distribution. + * @param weight Weight of component. + * @param weights Weights of rows/columns. + * @param start Starting position of component in grid (gridx/gridy). + * @param span Span of component (gridwidth/gridheight). + */ + private void calcCellWeights (double weight, double[] weights, int start, int span) + { + double totalWeight = 0.0; + for(int k = start; k < start + span; k++) + totalWeight += weights[k]; + + if(weight > totalWeight) + { + if (totalWeight == 0.0) + { + weights[start + span - 1] += weight; + } + else + { + double diff = weight - totalWeight ; + double remaining = diff; + + for(int k = start; k < start + span; k++) + { + double extraWeight = diff * weights[k] / totalWeight; + weights[k] += extraWeight; + remaining -= extraWeight; + } + + if (remaining > 0.0 && weights[start + span - 1] != 0.0) + { + weights[start + span - 1] += remaining; + } + } + } + } + + /** + * Helper method used by GetLayoutInfo to distribute extra space + * based on weight distribution. + * + * @param sizes Sizes of rows/columns. + * @param weights Weights of rows/columns. + * @param range Dimension of container. + */ + private void calcCellSizes (int[] sizes, double[] weights, int range) + { + int totalSize = sumIntArray (sizes); + double totalWeight = sumDoubleArray (weights); + + int diff = range - totalSize; + + if (diff == 0) + return; + + for (int i = 0; i < sizes.length; i++) + { + int newsize = (int) (sizes[i] + (((double) diff) * weights [i] / totalWeight )); + + if (newsize > 0) + sizes[i] = newsize; + } + } + + private void dumpLayoutInfo (GridBagLayoutInfo info) + { + System.out.println ("GridBagLayoutInfo:"); + System.out.println ("cols: " + info.cols + ", rows: " + info.rows); + System.out.print ("colWidths: "); + dumpArray(info.colWidths); + System.out.print ("rowHeights: "); + dumpArray(info.rowHeights); + System.out.print ("colWeights: "); + dumpArray(info.colWeights); + System.out.print ("rowWeights: "); + dumpArray(info.rowWeights); + } + + private void dumpArray(int[] array) + { + String sep = ""; + for(int i = 0; i < array.length; i++) + { + System.out.print(sep); + System.out.print(array[i]); + sep = ", "; + } + System.out.println(); + } + + private void dumpArray(double[] array) + { + String sep = ""; + for(int i = 0; i < array.length; i++) + { + System.out.print(sep); + System.out.print(array[i]); + sep = ", "; + } + System.out.println(); + } + + /** + * @since 1.4 + */ + protected void arrangeGrid (Container parent) + { + ArrangeGrid (parent); + } + + /** + * @since 1.4 + */ + protected GridBagLayoutInfo getLayoutInfo (Container parent, int sizeflag) + { + return GetLayoutInfo (parent, sizeflag); + } + + /** + * Move and resize a rectangle according to a set of grid bag + * constraints. The x, y, width and height fields of the + * rectangle argument are adjusted to the new values. + * + * @param constraints position and size constraints + * @param r rectangle to be moved and resized + * + * @since 1.4 + */ + protected void adjustForGravity (GridBagConstraints constraints, + Rectangle r) + { + AdjustForGravity (constraints, r); + } +} diff --git a/libjava/classpath/java/awt/GridBagLayoutInfo.java b/libjava/classpath/java/awt/GridBagLayoutInfo.java new file mode 100644 index 000000000..43ba09d72 --- /dev/null +++ b/libjava/classpath/java/awt/GridBagLayoutInfo.java @@ -0,0 +1,70 @@ +/* GridBagLayoutInfo - + Copyright (C) 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.io.Serializable; + +/** + * @author Michael Koch (konqueror@gmx.de) + */ +class GridBagLayoutInfo implements Serializable +{ + private static final long serialVersionUID = -4899416460737170217L; + + int pos_x; + int pos_y; + int cols; + int rows; + int colWidths[]; + int rowHeights[]; + double colWeights[]; + double rowWeights[]; + + GridBagLayoutInfo (int cols, int rows) + { + this.pos_x = 0; + this.pos_y = 0; + this.cols = cols; + this.rows = rows; + this.colWidths = new int [cols]; + this.rowHeights = new int [rows]; + this.colWeights = new double [cols]; + this.rowWeights = new double [rows]; + } +} diff --git a/libjava/classpath/java/awt/GridLayout.java b/libjava/classpath/java/awt/GridLayout.java new file mode 100644 index 000000000..a8b0189de --- /dev/null +++ b/libjava/classpath/java/awt/GridLayout.java @@ -0,0 +1,354 @@ +/* GridLayout.java -- Grid-based layout engine + Copyright (C) 1999, 2000, 2002, 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.io.Serializable; + +/** This class implements a grid-based layout scheme. Components are + * all given the same size and are laid out from left to right and top + * to bottom. A GridLayout is configured with a number of rows and a + * number of columns. If both are specified, then the number of + * columns is ignored and is derived from the number of rows and the + * total number of components. If either is zero then that dimension + * is computed based on the actual size of the container. An + * exception is thrown if an attempt is made to set both the number of + * rows and the number of columns to 0. This class also supports + * horizontal and vertical gaps; these are used as spacing between + * cells. + * + * @author Tom Tromey (tromey@redhat.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class GridLayout implements LayoutManager, Serializable +{ + static final long serialVersionUID = -7411804673224730901L; + + /** Add a new component to the layout. This particular implementation + * does nothing. + * @param name The name of the component to add. + * @param comp The component to add. + */ + public void addLayoutComponent (String name, Component comp) + { + // Nothing. + } + + /** Return the number of columns in this layout. */ + public int getColumns () + { + return cols; + } + + /** Return the horizontal gap. */ + public int getHgap () + { + return hgap; + } + + /** Return the number of rows in this layout. */ + public int getRows () + { + return rows; + } + + /** Return the vertical gap. */ + public int getVgap () + { + return vgap; + } + + /** Create a new <code>GridLayout</code> with one row and any number + * of columns. Both gaps are set to 0. + */ + public GridLayout () + { + this (1, 0, 0, 0); + } + + /** Create a new <code>GridLayout</code> with the specified number + * of rows and columns. Both gaps are set to 0. Note that the row + * and column settings cannot both be zero. If both the row and + * column values are non-zero, the rows value takes precedence. + * @param rows Number of rows + * @param cols Number of columns + * @exception IllegalArgumentException If rows and columns are both + * 0, or if either are negative + */ + public GridLayout (int rows, int cols) + { + this (rows, cols, 0, 0); + } + + /** Create a new GridLayout with the specified number of rows and + * columns and the specified gaps. + * Note that the row and column settings cannot both be + * zero. If both the row and column values are non-zero, the rows value + * takes precedence. + * @param rows Number of rows + * @param cols Number of columns + * @param hgap The horizontal gap + * @param vgap The vertical gap + * @exception IllegalArgumentException If rows and columns are both + * 0, if either are negative, or if either gap is negative + */ + public GridLayout (int rows, int cols, int hgap, int vgap) + { + if (rows < 0) + throw new IllegalArgumentException ("number of rows cannot be negative"); + if (cols < 0) + throw new IllegalArgumentException ("number of columns cannot be negative"); + if (rows == 0 && cols == 0) + throw new IllegalArgumentException ("both rows and columns cannot be 0"); + if (hgap < 0) + throw new IllegalArgumentException ("horizontal gap must be nonnegative"); + if (vgap < 0) + throw new IllegalArgumentException ("vertical gap must be nonnegative"); + this.rows = rows; + this.cols = cols; + this.hgap = hgap; + this.vgap = vgap; + } + + /** Lay out the container's components based on current settings. + * The free space in the container is divided evenly into the specified + * number of rows and columns in this object. + * @param parent The container to lay out + */ + public void layoutContainer (Container parent) + { + synchronized (parent.getTreeLock ()) + { + int num = parent.ncomponents; + + // There's no point, and handling this would mean adding special + // cases. + if (num == 0) + return; + + // This is more efficient than calling getComponents(). + Component[] comps = parent.component; + + int real_rows = rows; + int real_cols = cols; + if (real_rows == 0) + real_rows = (num + real_cols - 1) / real_cols; + else + real_cols = (num + real_rows - 1) / real_rows; + + // We might have less than a single row. In this case we expand + // to fill. + if (num < real_cols) + real_cols = num; + + Dimension d = parent.getSize (); + Insets ins = parent.getInsets (); + + // Compute width and height of each cell in the grid. + int tw = d.width - ins.left - ins.right; + tw = (tw - (real_cols - 1) * hgap) / real_cols; + int th = d.height - ins.top - ins.bottom; + th = (th - (real_rows - 1) * vgap) / real_rows; + + // If the cells are too small, still try to do something. + if (tw < 0) + tw = 1; + if (th < 0) + th = 1; + + int x = ins.left; + int y = ins.top; + int i = 0; + int recount = 0; + + while (i < num) + { + comps[i].setBounds (x, y, tw, th); + + ++i; + ++recount; + if (recount == real_cols) + { + recount = 0; + y += vgap + th; + x = ins.left; + } + else + x += hgap + tw; + } + } + } + + /** Get the minimum layout size of the container. + * @param cont The parent container + */ + public Dimension minimumLayoutSize (Container cont) + { + return getSize (cont, true); + } + + /** Get the preferred layout size of the container. + * @param cont The parent container + */ + public Dimension preferredLayoutSize (Container cont) + { + return getSize (cont, false); + } + + /** Remove the indicated component from this layout manager. + * This particular implementation does nothing. + * @param comp The component to remove + */ + public void removeLayoutComponent (Component comp) + { + // Nothing. + } + + /** Set the number of columns. + * @param newCols + * @exception IllegalArgumentException If the number of columns is + * negative, or if the number of columns is zero and the number + * of rows is already 0. + */ + public void setColumns (int newCols) + { + if (newCols < 0) + throw new IllegalArgumentException ("number of columns cannot be negative"); + if (newCols == 0 && rows == 0) + throw new IllegalArgumentException ("number of rows is already 0"); + this.cols = newCols; + } + + /** Set the horizontal gap. An Exception is not thrown if hgap < 0. + * @param hgap The horizontal gap + */ + public void setHgap (int hgap) + { + this.hgap = hgap; + } + + /** Set the number of rows + * @param newRows + * @exception IllegalArgumentException If the number of rows is + * negative, or if the number of rows is zero and the number + * of columns is already 0. + */ + public void setRows (int newRows) + { + if (newRows < 0) + throw new IllegalArgumentException ("number of rows cannot be negative"); + if (newRows == 0 && cols == 0) + throw new IllegalArgumentException ("number of columns is already 0"); + this.rows = newRows; + } + + /** Set the vertical gap. An Exception is not thrown if vgap < 0. + * @param vgap The vertical gap + */ + public void setVgap (int vgap) + { + this.vgap = vgap; + } + + /** Return String description of this object. */ + public String toString () + { + return (getClass ().getName () + "[" + + "hgap=" + hgap + ",vgap=" + vgap + + ",rows=" + rows + ",cols=" + cols + + "]"); + } + + // This method is used to compute the various sizes. + private Dimension getSize (Container parent, boolean is_min) + { + synchronized (parent.getTreeLock ()) + { + int w = 0, h = 0, num = parent.ncomponents; + // This is more efficient than calling getComponents(). + Component[] comps = parent.component; + + for (int i = 0; i < num; ++i) + { + Dimension d; + + if (is_min) + d = comps[i].getMinimumSize (); + else + d = comps[i].getPreferredSize (); + + w = Math.max (d.width, w); + h = Math.max (d.height, h); + } + + int real_rows = rows; + int real_cols = cols; + if (real_rows == 0) + real_rows = (num + real_cols - 1) / real_cols; + else + real_cols = (num + real_rows - 1) / real_rows; + + Insets ins = parent.getInsets (); + // We subtract out an extra gap here because the gaps are only + // between cells. + w = ins.left + ins.right + real_cols * (w + hgap) - hgap; + h = ins.top + ins.bottom + real_rows * (h + vgap) - vgap; + return new Dimension (w, h); + } + } + + /** + * @serial The number of columns in the grid. + */ + private int cols; + + /** + * @serial The number of rows in the grid. + */ + private int rows; + + /** + * @serial The horizontal gap between columns + */ + private int hgap; + + /** + * @serial The vertical gap between rows + */ + private int vgap; +} diff --git a/libjava/classpath/java/awt/HeadlessException.java b/libjava/classpath/java/awt/HeadlessException.java new file mode 100644 index 000000000..b180b1d86 --- /dev/null +++ b/libjava/classpath/java/awt/HeadlessException.java @@ -0,0 +1,72 @@ +/* HeadlessException.java -- operation not possible in headless environment + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +/** + * This exception is thrown when code dependent on a keyboard, mouse, or + * display is executed in a headless environment. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.4 + * @status updated to 1.4 + */ +public class HeadlessException extends UnsupportedOperationException +{ + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = 167183644944358563L; + + /** + * Create a new instance with no detailed error message. + */ + public HeadlessException() + { + } + + /** + * Create a new instance with the specified detailed error message. + * + * @param message the detailed error message + */ + public HeadlessException(String message) + { + super(message); + } +} // class HeadlessException diff --git a/libjava/classpath/java/awt/IllegalComponentStateException.java b/libjava/classpath/java/awt/IllegalComponentStateException.java new file mode 100644 index 000000000..4a47f1da9 --- /dev/null +++ b/libjava/classpath/java/awt/IllegalComponentStateException.java @@ -0,0 +1,71 @@ +/* IllegalComponentStateException.java -- bad component state + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +/** + * This exception is thrown when the requested operation failed because + * a component was not in the proper state. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @status updated to 1.4 + */ +public class IllegalComponentStateException extends IllegalStateException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -1889339587208144238L; + + /** + * Create a new instance with no detailed error message. + */ + public IllegalComponentStateException() + { + } + + /** + * Create a new instance with the specified detailed error message. + * + * @param message the detailed error message + */ + public IllegalComponentStateException(String message) + { + super(message); + } +} // class IllegalComponentStateException diff --git a/libjava/classpath/java/awt/Image.java b/libjava/classpath/java/awt/Image.java new file mode 100644 index 000000000..7b2cee7ae --- /dev/null +++ b/libjava/classpath/java/awt/Image.java @@ -0,0 +1,242 @@ +/* Image.java -- superclass for images + Copyright (C) 1999, 2002, 2004, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.image.AreaAveragingScaleFilter; +import java.awt.image.FilteredImageSource; +import java.awt.image.ImageFilter; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.ReplicateScaleFilter; + +/** + * This is the abstract superclass of all image objects in Java. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.0 + * @status updated to 1.5 + */ +public abstract class Image +{ + /** + * This variable is returned whenever a property that is not defined + * is requested. + */ + // For debug purposes, this might as well be a unique string. + public static final Object UndefinedProperty + = new String("undefined property"); + + /** + * Constant indicating that the default scaling algorithm should be used. + * + * @since 1.1 + */ + public static final int SCALE_DEFAULT = 1; + + /** + * Constant indicating that a fast scaling algorithm should be used. + * + * @since 1.1 + */ + public static final int SCALE_FAST = 2; + + /** + * Constant indicating that a smooth scaling algorithm should be used. + * + * @since 1.1 + */ + public static final int SCALE_SMOOTH = 4; + + /** + * Constant indicating that the <code>ReplicateScaleFilter</code> class + * algorithm should be used for scaling. + * + * @see ReplicateScaleFilter + * @since 1.1 + */ + public static final int SCALE_REPLICATE = 8; + + /** + * Constant indicating that the area averaging scaling algorithm should be + * used. + * + * @see java.awt.image.AreaAveragingScaleFilter + * @since 1.1 + */ + public static final int SCALE_AREA_AVERAGING = 16; + + /** + * The acceleration priority of the image + * @since 1.5 + */ + protected float accelerationPriority; + + /** + * A default constructor for subclasses. + */ + public Image() + { + } + + /** + * Returns the width of the image, or -1 if it is unknown. If the + * image width is unknown, the observer object will be notified when + * the value is known. + * + * @param observer the image observer for this object + * @return the width in pixels + * @see #getHeight(ImageObserver) + */ + public abstract int getWidth(ImageObserver observer); + + /** + * Returns the height of the image, or -1 if it is unknown. If the + * image height is unknown, the observer object will be notified when + * the value is known. + * + * @param observer the image observer for this object + * @return the height in pixels + * @see #getWidth(ImageObserver) + */ + public abstract int getHeight(ImageObserver observer); + + /** + * Returns the image producer object for this object. The producer is the + * object which generates pixels for this image. + * + * @return the image producer for this object + */ + public abstract ImageProducer getSource(); + + /** + * Returns a graphics context object for drawing an off-screen object. + * This method is only valid for off-screen objects. + * + * @return a graphics context object for an off-screen object + */ + public abstract Graphics getGraphics(); + + /** + * This method requests a named property for an object. The value of the + * property is returned. The value <code>UndefinedProperty</code> is + * returned if there is no property with the specified name. The value + * <code>null</code> is returned if the properties for the object are + * not yet known. In this case, the specified image observer is notified + * when the properties are known. + * + * @param name the requested property name + * @param observer the image observer for this object + * @return the named property, if available + * @see #UndefinedProperty + */ + public abstract Object getProperty(String name, ImageObserver observer); + + /** + * Scales the image to the requested dimension. A new Image with asynchronous + * loading will be produced according to the hints of the algorithm + * requested. If either the width or height is non-positive, it is adjusted + * to preserve the original aspect ratio. + * If an illegal value of <code>flags</code> is passed, + * the default algorithm is used. + * + * @param width the width of the scaled image + * @param height the height of the scaled image + * @param flags a value indicating the algorithm to use + * @return the scaled <code>Image</code> object + * @see #SCALE_DEFAULT + * @see #SCALE_FAST + * @see #SCALE_SMOOTH + * @see #SCALE_REPLICATE + * @see #SCALE_AREA_AVERAGING + * @since 1.1 + */ + public Image getScaledInstance(int width, int height, int flags) + { + ImageFilter filter; + switch (flags) + { + case SCALE_AREA_AVERAGING: + case SCALE_SMOOTH: + filter = new AreaAveragingScaleFilter(width, height); + break; + case SCALE_DEFAULT: + case SCALE_FAST: + case SCALE_REPLICATE: + default: + filter = new ReplicateScaleFilter(width, height); + } + + ImageProducer producer = new FilteredImageSource(getSource(), filter); + return Toolkit.getDefaultToolkit().createImage(producer); + } + + /** + * Flushes (that is, destroys) any resources used for this image. This + * includes the actual image data. + */ + public abstract void flush(); + + /** + * Sets the acceleration priority of the image. + * This is a value from 0 (lowest) to 1 (highest), which may + * be used as a hint for image acceleration. + * E.g. higher priority images may be stored in video memory. + * @param priority - the priority + * @throws IllegalArgumentException if priority is not >= 0 and <= 1. + * + * @since 1.5 + */ + public void setAccelerationPriority(float priority) + { + if( priority < 0f || priority > 1f) + throw new IllegalArgumentException("Invalid priority value."); + accelerationPriority = priority; + } + + /** + * Returns the acceleration priority of the image. + * + * @see #setAccelerationPriority(float) + * @since 1.5 + */ + public float getAccelerationPriority() + { + return accelerationPriority; + } +} // class Image diff --git a/libjava/classpath/java/awt/ImageCapabilities.java b/libjava/classpath/java/awt/ImageCapabilities.java new file mode 100644 index 000000000..2fe71d1e2 --- /dev/null +++ b/libjava/classpath/java/awt/ImageCapabilities.java @@ -0,0 +1,107 @@ +/* ImageCapabilities.java -- the capabilities of an image buffer + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +/** + * This class represents the capabilities of an image buffer. An + * image buffer may be backed by accelerated graphics resources. + * Those resources may or may not be volatile. This class is used to + * describe these image buffer characteristics. + */ +public class ImageCapabilities implements Cloneable +{ + /** + * Whether or not this the image buffer uses accelerated graphics + * resources. + */ + private final boolean accelerated; + + /** + * Create a new image capability descriptor. + * + * @param accelerated true if the image buffer uses accelerated + * graphics resources + */ + public ImageCapabilities(boolean accelerated) + { + this.accelerated = accelerated; + } + + /** + * Returns whether or not the image buffer uses accelerated graphics + * resources. + * + * @return true if the image buffer uses accelerated graphics + * resources; false otherwise + */ + public boolean isAccelerated() + { + return accelerated; + } + + /** + * Returns whether or not the image buffer's resources are volatile, + * meaning that they can be reclaimed by the graphics system at any + * time. + * + * @return true if the image buffer's resources are volatile; false + * otherwise + */ + public boolean isTrueVolatile() + { + return true; + } + + /** + * Clone this image capability descriptor. + * + * @return a clone of this image capability descriptor + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); + } + } +} diff --git a/libjava/classpath/java/awt/Insets.java b/libjava/classpath/java/awt/Insets.java new file mode 100644 index 000000000..1747cae6a --- /dev/null +++ b/libjava/classpath/java/awt/Insets.java @@ -0,0 +1,177 @@ +/* Insets.java -- information about a container border + Copyright (C) 1999, 2000, 2002, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.io.Serializable; + +/** + * This class represents the "margin" or space around a container. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @status + */ +public class Insets implements Cloneable, Serializable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -2272572637695466749L; + + /** + * The gap from the top. + * + * @serial the top inset + */ + public int top; + + /** + * The gap from the left. + * + * @serial the left inset + */ + public int left; + + /** + * The gap from the bottom. + * + * @serial the bottom inset + */ + public int bottom; + + /** + * The gap from the right. + * + * @serial the right inset + */ + public int right; + + /** + * Initializes a new instance of <code>Inset</code> with the specified + * inset values. + * + * @param top the top inset + * @param left the left inset + * @param bottom the bottom inset + * @param right the right inset + */ + public Insets(int top, int left, int bottom, int right) + { + this.top = top; + this.left = left; + this.bottom = bottom; + this.right = right; + } + + /** + * Set the contents of this Insets object to the specified values. + * + * @param top the top inset + * @param left the left inset + * @param bottom the bottom inset + * @param right the right inset + * + * @since 1.5 + */ + public void set(int top, int left, int bottom, int right) + { + this.top = top; + this.left = left; + this.bottom = bottom; + this.right = right; + } + + /** + * Tests whether this object is equal to the specified object. The other + * object must be an instance of Insets with identical field values. + * + * @param obj the object to test against + * @return true if the specified object is equal to this one + * + * @since 1.1 + */ + public boolean equals(Object obj) + { + if (! (obj instanceof Insets)) + return false; + Insets i = (Insets) obj; + return top == i.top && bottom == i.bottom + && left == i.left && right == i.right; + } + + /** + * Returns a hashcode for this instance. The formula is unspecified, but + * appears to be <code>XXX what is it? </code>. + * + * @return the hashcode + */ + public int hashCode() + { + // This can't be right... + return top + bottom + left + right; + } + + /** + * Returns a string representation of this object, which will be non-null. + * + * @return a string representation of this object + */ + public String toString() + { + return getClass().getName() + "[top=" + top + ",left=" + left + + ",bottom=" + bottom + ",right=" + right + ']'; + } + + /** + * Returns a copy of this object. + * + * @return a copy of this object + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } +} // class Insets diff --git a/libjava/classpath/java/awt/ItemSelectable.java b/libjava/classpath/java/awt/ItemSelectable.java new file mode 100644 index 000000000..f155f723e --- /dev/null +++ b/libjava/classpath/java/awt/ItemSelectable.java @@ -0,0 +1,75 @@ +/* ItemSelectable.java -- items that can be selected + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.ItemListener; + +/** + * This interface is for objects that can have one or more items selected. + * For example, radio buttons. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.0 + * @status updated to 1.4 + */ +public interface ItemSelectable +{ + /** + * Returns the list of objects that are selected in this component. + * + * @return the list of selected objects, or null + */ + Object[] getSelectedObjects(); + + /** + * Adds an item listener to this object. It will receive selection events + * for this object by the user (but not programatically). If listener is + * null, it is ignored. + * + * @param listener the item listener to add + */ + void addItemListener(ItemListener listener); + + /** + * Removes an item listener from this object. + * + * @param listener the item listener to remove + */ + void removeItemListener(ItemListener listener); +} // interface ItemSelectable diff --git a/libjava/classpath/java/awt/JobAttributes.java b/libjava/classpath/java/awt/JobAttributes.java new file mode 100644 index 000000000..e84901d33 --- /dev/null +++ b/libjava/classpath/java/awt/JobAttributes.java @@ -0,0 +1,502 @@ +/* JobAttributes.java -- + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import gnu.java.lang.CPStringBuilder; + +/** + * Needs documentation... + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + * @status updated to 1.4, lacks documentation + */ +public final class JobAttributes implements Cloneable +{ + public static final class DefaultSelectionType extends AttributeValue + { + private static final String[] NAMES = { "all", "range", "selection" }; + public static final DefaultSelectionType ALL + = new DefaultSelectionType(0); + public static final DefaultSelectionType RANGE + = new DefaultSelectionType(1); + public static final DefaultSelectionType SELECTION + = new DefaultSelectionType(2); + private DefaultSelectionType(int value) + { + super(value, NAMES); + } + } // class DefaultSelectionType + + public static final class DestinationType extends AttributeValue + { + private static final String[] NAMES = { "file", "printer" }; + public static final DestinationType FILE = new DestinationType(0); + public static final DestinationType PRINTER = new DestinationType(1); + private DestinationType(int value) + { + super(value, NAMES); + } + } // class DestinationType + + public static final class DialogType extends AttributeValue + { + private static final String[] NAMES = { "common", "native", "none" }; + public static final DialogType COMMON = new DialogType(0); + public static final DialogType NATIVE = new DialogType(1); + public static final DialogType NONE = new DialogType(2); + private DialogType(int value) + { + super(value, NAMES); + } + } // class DialogType + + public static final class MultipleDocumentHandlingType + extends AttributeValue + { + private static final String[] NAMES = { + "separate-documents-collated-copies", + "separate-documents-uncollated-copies" + }; + public static final MultipleDocumentHandlingType + SEPARATE_DOCUMENTS_COLLATED_COPIES + = new MultipleDocumentHandlingType(0); + public static final MultipleDocumentHandlingType + SEPARATE_DOCUMENTS_UNCOLLATED_COPIES + = new MultipleDocumentHandlingType(1); + private MultipleDocumentHandlingType(int value) + { + super(value, NAMES); + } + } // class MultipleDocumentHandlingType + + public static final class SidesType extends AttributeValue + { + private static final String[] NAMES + = { "one-sided", "two-sided-long-edge", "two-sided-short-edge" }; + public static final SidesType ONE_SIDED = new SidesType(0); + public static final SidesType TWO_SIDED_LONG_EDGE = new SidesType(1); + public static final SidesType TWO_SIDED_SHORT_EDGE = new SidesType(2); + private SidesType(int value) + { + super(value, NAMES); + } + } // class SidesType + + private int copies; + private DefaultSelectionType selection; + private DestinationType destination; + private DialogType dialog; + private String filename; + private int maxPage; + private int minPage; + private MultipleDocumentHandlingType multiple; + private int[][] pageRanges; // null for default value + private int fromPage; // 0 for default value + private int toPage; // 0 for default value + private String printer; + private SidesType sides; + + public JobAttributes() + { + copies = 1; + selection = DefaultSelectionType.ALL; + destination = DestinationType.PRINTER; + dialog = DialogType.NATIVE; + maxPage = Integer.MAX_VALUE; + minPage = 1; + multiple + = MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_UNCOLLATED_COPIES; + sides = SidesType.ONE_SIDED; + } + + public JobAttributes(JobAttributes attr) + { + set(attr); + } + + public JobAttributes(int copies, DefaultSelectionType selection, + DestinationType destination, DialogType dialog, + String filename, int max, int min, + MultipleDocumentHandlingType multiple, + int[][] pageRanges, String printer, SidesType sides) + { + if (copies <= 0 || selection == null || destination == null + || dialog == null || max < min || min <= 0 || multiple == null + || sides == null) + throw new IllegalArgumentException(); + this.copies = copies; + this.selection = selection; + this.destination = destination; + this.dialog = dialog; + this.filename = filename; + maxPage = max; + minPage = min; + this.multiple = multiple; + setPageRanges(pageRanges); + this.printer = printer; + this.sides = sides; + } + + public Object clone() + { + return new JobAttributes(this); + } + + public void set(JobAttributes attr) + { + copies = attr.copies; + selection = attr.selection; + destination = attr.destination; + dialog = attr.dialog; + filename = attr.filename; + maxPage = attr.maxPage; + minPage = attr.minPage; + multiple = attr.multiple; + pageRanges = (int[][]) attr.pageRanges.clone(); + printer = attr.printer; + sides = attr.sides; + fromPage = attr.fromPage; + toPage = attr.toPage; + } + + public int getCopies() + { + return copies; + } + + public void setCopies(int copies) + { + if (copies <= 0) + throw new IllegalArgumentException(); + this.copies = copies; + } + + public void setCopiesToDefault() + { + copies = 1; + } + + public DefaultSelectionType getDefaultSelection() + { + return selection; + } + + public void setDefaultSelection(DefaultSelectionType selection) + { + if (selection == null) + throw new IllegalArgumentException(); + this.selection = selection; + } + + public DestinationType getDestination() + { + return destination; + } + + public void setDestination(DestinationType destination) + { + if (destination == null) + throw new IllegalArgumentException(); + this.destination = destination; + } + + public DialogType getDialog() + { + return dialog; + } + + public void setDialog(DialogType dialog) + { + if (dialog == null) + throw new IllegalArgumentException(); + this.dialog = dialog; + } + + public String getFileName() + { + return filename; + } + + public void setFileName(String filename) + { + this.filename = filename; + } + + public int getFromPage() + { + return fromPage != 0 ? fromPage + : pageRanges != null ? pageRanges[0][0] + : toPage != 0 ? toPage : minPage; + } + + public void setFromPage(int fromPage) + { + if (fromPage < minPage || (fromPage > toPage && toPage != 0) + || fromPage > maxPage) + throw new IllegalArgumentException(); + if (pageRanges == null) + this.fromPage = fromPage; + } + + public int getMaxPage() + { + return maxPage; + } + + public void setMaxPage(int maxPage) + { + if (maxPage < minPage) + throw new IllegalArgumentException(); + this.maxPage = maxPage; + if (maxPage < fromPage) + fromPage = maxPage; + if (maxPage < toPage) + toPage = maxPage; + if (pageRanges != null) + { + int i = pageRanges.length - 1; + while (i >= 0 && maxPage < pageRanges[i][1]) + i--; + if (maxPage >= pageRanges[++i][0]) + pageRanges[i++][1] = maxPage; + if (i == 0) + pageRanges = null; + else if (i < pageRanges.length) + { + int[][] tmp = new int[i][]; + System.arraycopy(pageRanges, 0, tmp, 0, i); + pageRanges = tmp; + } + } + } + + public int getMinPage() + { + return minPage; + } + + public void setMinPage(int minPage) + { + if (minPage <= 0 || minPage > maxPage) + throw new IllegalArgumentException(); + this.minPage = minPage; + if (minPage > toPage) + toPage = minPage; + if (minPage > fromPage) + fromPage = minPage; + if (pageRanges != null) + { + int size = pageRanges.length; + int i = 0; + while (i < size && minPage > pageRanges[i][0]) + i++; + if (minPage <= pageRanges[i - 1][1]) + pageRanges[--i][0] = minPage; + if (i == size) + pageRanges = null; + else if (i > 0) + { + int[][] tmp = new int[size - i][]; + System.arraycopy(pageRanges, i, tmp, 0, size - i); + pageRanges = tmp; + } + } + } + + public MultipleDocumentHandlingType getMultipleDocumentHandling() + { + return multiple; + } + + public void setMultipleDocumentHandling + (MultipleDocumentHandlingType multiple) + { + if (multiple == null) + throw new IllegalArgumentException(); + this.multiple = multiple; + } + + public void setMultipleDocumentHandlingToDefault() + { + multiple + = MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_UNCOLLATED_COPIES; + } + + public int[][] getPageRanges() + { + if (pageRanges == null) + return new int[][] { { getFromPage(), getToPage() } }; + // Perform a deep clone, so user code cannot affect original arrays. + int i = pageRanges.length; + int[][] result = new int[i][]; + while (--i >= 0) + result[i] = (int[]) pageRanges[i].clone(); + return result; + } + + public void setPageRanges(int[][] pageRanges) + { + int size = pageRanges == null ? 0 : pageRanges.length; + if (size == 0) + throw new IllegalArgumentException(); + while (--size >= 0) + { + int[] range = pageRanges[size]; + if (range == null || range.length != 2 + || range[0] < minPage || range[1] < range[0] || range[1] > maxPage + || (size != 0 && range[0] <= pageRanges[size - 1][1])) + throw new IllegalArgumentException(); + } + size = pageRanges.length; + if (fromPage > 0 && pageRanges[0][0] > fromPage) + fromPage = pageRanges[0][0]; + if (toPage > 0 && pageRanges[size - 1][1] < toPage) + toPage = pageRanges[size - 1][1]; + this.pageRanges = new int[size][]; + while (--size >= 0) + this.pageRanges[size] = (int[]) pageRanges[size].clone(); + } + + public String getPrinter() + { + return printer; + } + + public void setPrinter(String printer) + { + this.printer = printer; + } + + public SidesType getSides() + { + return sides; + } + + public void setSides(SidesType sides) + { + if (sides == null) + throw new IllegalArgumentException(); + this.sides = sides; + } + + public void setSidesToDefault() + { + sides = SidesType.ONE_SIDED; + } + + public int getToPage() + { + return toPage != 0 ? toPage + : pageRanges != null ? pageRanges[pageRanges.length - 1][1] + : fromPage != 0 ? fromPage : maxPage; + } + + public void setToPage(int toPage) + { + if (toPage < minPage || (fromPage > toPage && fromPage != 0) + || toPage > maxPage) + throw new IllegalArgumentException(); + if (pageRanges == null) + this.toPage = toPage; + } + + public boolean equals(Object o) + { + if (this == o) + return true; + if (! (o instanceof JobAttributes)) + return false; + JobAttributes ja = (JobAttributes) o; + if (copies != ja.copies || selection != ja.selection + || destination != ja.destination || dialog != ja.dialog + || ! filename.equals(ja.filename) || maxPage != ja.maxPage + || minPage != ja.minPage || multiple != ja.multiple + || fromPage != ja.fromPage || toPage != ja.toPage + || ! printer.equals(ja.printer) || sides != ja.sides + || (pageRanges == null) != (ja.pageRanges == null)) + return false; + if (pageRanges != ja.pageRanges) + for (int i = pageRanges.length; --i >= 0; ) + if (pageRanges[i][0] != ja.pageRanges[i][0] + || pageRanges[i][1] != ja.pageRanges[i][1]) + return false; + return true; + } + + public int hashCode() + { + int hash = (selection.value << 6) ^ (destination.value << 5) + ^ (dialog.value << 3) ^ (multiple.value << 2) ^ sides.value + ^ (filename == null ? 0 : filename.hashCode()) + ^ (printer == null ? 0 : printer.hashCode()); + // The effect of the above fields on the hashcode match the JDK. However, + // I am unable to reverse engineer the effect of the fields listed below, + // so I am using my own implementation. Note that this still satisfies + // the general contract of hashcode, it just doesn't match the JDK. + hash ^= (copies << 27) ^ (maxPage << 22) ^ (minPage << 17); + if (pageRanges == null) + hash ^= (getFromPage() << 13) ^ (getToPage() << 8); + else + for (int i = pageRanges.length; --i >= 0; ) + hash ^= (pageRanges[i][0] << 13) ^ (pageRanges[i][1] << 8); + return hash; + } + + public String toString() + { + CPStringBuilder s = new CPStringBuilder("copies=").append(copies) + .append(",defaultSelection=").append(selection).append(",destination=") + .append(destination).append(",dialog=").append(dialog) + .append(",fileName=").append(filename).append(",fromPage=") + .append(getFromPage()).append(",maxPage=").append(maxPage) + .append(",minPage=").append(minPage) + .append(",multiple-document-handling=").append(multiple) + .append(",page-ranges=["); + if (pageRanges == null) + s.append(minPage).append(':').append(minPage).append(']'); + else + for (int i = 0; i < pageRanges.length; i++) + s.append(pageRanges[i][0]).append(':').append(pageRanges[i][1]) + .append(','); + s.setLength(s.length() - 1); + return s.append("],printer=").append(printer).append(",sides=") + .append(sides).append(",toPage=").append(getToPage()).toString(); + } +} // class JobAttributes diff --git a/libjava/classpath/java/awt/KeyEventDispatcher.java b/libjava/classpath/java/awt/KeyEventDispatcher.java new file mode 100644 index 000000000..30997278e --- /dev/null +++ b/libjava/classpath/java/awt/KeyEventDispatcher.java @@ -0,0 +1,82 @@ +/* KeyEventDispatcher.java -- dispatches key events + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.KeyEvent; + +/** + * An instance of this interface coordinates with a KeyboardFocusManager to + * target and dispatch all key events. This allows retargeting, consuming, + * changing, or otherwise manipulating the key event before sending it on to + * a target. + * + * <p>By default, the KeyboardFocusManager is the sink for all key events not + * dispatched by other dispatchers. Therefore, it is unnecessary for the user + * to register the focus manager as a dispatcher. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see KeyboardFocusManager#addKeyEventDispatcher(KeyEventDispatcher) + * @see KeyboardFocusManager#removeKeyEventDispatcher(KeyEventDispatcher) + * @since 1.4 + * @status updated to 1.4 + */ +public interface KeyEventDispatcher +{ + /** + * Called by the KeyboardFocusManager to request that a key event be + * dispatched. The dispatcher is free to retarget the event, consume it, + * dispatch it, or make other changes. This is usually done to allow + * delivery of key events to objects other than the window in focus, such + * as for navigating non-focusable components. If this dispatcher chooses + * to dispatch the event itself, it should call <code>redispatchEvent</code> + * to avoid infinite recursion. + * + * <p>If the return value is false, the KeyEvent is passed to the next + * dispatcher in the chain, ending with the KeyboardFocusManager. If the + * return value is true, the event has been consumed (although it might + * have been ignored), and no further action will be taken on the event. Be + * sure to check whether the event was consumed before dispatching it + * further. + * + * @param e the key event + * @return true if the event has been consumed + * @see KeyboardFocusManager#redispatchEvent(Component, AWTEvent) + */ + boolean dispatchKeyEvent(KeyEvent e); +} // interface KeyEventDispatcher diff --git a/libjava/classpath/java/awt/KeyEventPostProcessor.java b/libjava/classpath/java/awt/KeyEventPostProcessor.java new file mode 100644 index 000000000..0b39dc250 --- /dev/null +++ b/libjava/classpath/java/awt/KeyEventPostProcessor.java @@ -0,0 +1,81 @@ +/* KeyEventPostProcessor.java -- performs actions after a key event dispatch + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.KeyEvent; + +/** + * An instance of this interface coordinates with a KeyboardFocusManager to + * target and dispatch all key events that are otherwise unconsumed. This + * allows events which take place when nothing has focus to still operate, + * such as menu keyboard shortcuts. + * + * <p>By default, the KeyboardFocusManager is the sink for all key events not + * post-processed elsewhere. Therefore, it is unnecessary for the user + * to register the focus manager as a dispatcher. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see KeyboardFocusManager#addKeyEventPostProcessor(KeyEventPostProcessor) + * @see KeyboardFocusManager#removeKeyEventPostProcessor(KeyEventPostProcessor) + * @since 1.4 + * @status updated to 1.4 + */ +public interface KeyEventPostProcessor +{ + /** + * Called by the KeyboardFocusManager to request that a key event be + * post-processed. Typically, the event has already been dispatched and + * handled, unless no object has focus. Thus, this allows global event + * handling for things like menu shortcuts. If this post-processor chooses + * to dispatch the event, it should call <code>redispatchEvent</code> + * to avoid infinite recursion. + * + * <p>If the return value is false, the KeyEvent is passed to the next + * dispatcher in the chain, ending with the KeyboardFocusManager. If the + * return value is true, the event has been consumed (although it might + * have been ignored), and no further action will be taken on the event. Be + * sure to check whether the event was consumed before dispatching it + * further. + * + * @param e the key event + * @return true if the event has been consumed + * @see KeyboardFocusManager#redispatchEvent(Component, AWTEvent) + */ + boolean postProcessKeyEvent(KeyEvent e); +} // interface KeyEventPostProcessor diff --git a/libjava/classpath/java/awt/KeyboardFocusManager.java b/libjava/classpath/java/awt/KeyboardFocusManager.java new file mode 100644 index 000000000..691351175 --- /dev/null +++ b/libjava/classpath/java/awt/KeyboardFocusManager.java @@ -0,0 +1,1479 @@ +/* KeyboardFocusManager.java -- manage component focusing via the keyboard + Copyright (C) 2002, 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.applet.Applet; +import java.awt.FocusTraversalPolicy; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.awt.event.WindowEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.beans.PropertyVetoException; +import java.beans.VetoableChangeListener; +import java.beans.VetoableChangeSupport; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * The <code>KeyboardFocusManager</code> handles the focusing of + * windows for receiving keyboard events. The manager handles + * the dispatch of all <code>FocusEvent</code>s and + * <code>KeyEvent</code>s, along with <code>WindowEvent</code>s + * relating to the focused window. Users can use the manager + * to ascertain the current focus owner and fire events. + * <br /> + * <br /> + * The focus owner is the <code>Component</code> that receives + * key events. The focus owner is either the currently focused + * window or a component within this window. + * <br /> + * <br /> + * The underlying native windowing system may denote the active + * window or its children with special decorations (e.g. a highlighted + * title bar). The active window is always either a <code>Frame</code> + * or <code>Dialog</code>, and is either the currently focused + * window or its owner. + * <br /> + * <br /> + * Applets may be partitioned into different applet contexts, according + * to their code base. In this case, each context has its own + * <code>KeyboardFocusManager</code>, as opposed to the global + * manager maintained by applets which share the same context. + * Each context is insulated from the others, and they don't interact. + * The resulting behaviour, as with context division, depends on the browser + * supporting the applets. Regardless, there can only ever be + * one focused window, one active window and one focus owner + * per <code>ClassLoader</code>. + * <br /> + * <br /> + * To support this separation of focus managers, the manager instances + * and the internal state information is grouped by the + * <code>ThreadGroup</code> to which it pertains. With respect to + * applets, each code base has its own <code>ThreadGroup</code>, so the + * isolation of each context is enforced within the manager. + * <br /> + * <br /> + * By default, the manager defines TAB and Ctrl+TAB as the + * forward focus traversal keys and Shift+TAB and Ctrl+Shift+TAB + * as the backward focus traversal keys. No up or down cycle + * traversal keys are defined by default. Traversal takes effect + * on the firing of a relevant <code>KEY_PRESSED</code> event. + * However, all other key events related to the use of the + * defined focus traversal key sequence are consumed and not + * dispatched. + * <br /> + * <br /> + * These default traversal keys come into effect on all windows + * for which no alternative set of keys is defined. This also + * applies recursively to any child components of such a window, + * which define no traversal keys of their own. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @author Thomas Fitzsimmons (fitzsim@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.4 + */ +public abstract class KeyboardFocusManager + implements KeyEventDispatcher, KeyEventPostProcessor +{ + /** Identifies {@link AWTKeyStroke}s that move the focus forward in + the focus cycle. */ + public static final int FORWARD_TRAVERSAL_KEYS = 0; + + /** Identifies {@link AWTKeyStroke}s that move the focus backward in + the focus cycle. */ + public static final int BACKWARD_TRAVERSAL_KEYS = 1; + + /** Identifies {@link AWTKeyStroke}s that move the focus up to the + parent focus cycle root. */ + public static final int UP_CYCLE_TRAVERSAL_KEYS = 2; + + /** Identifies {@link AWTKeyStroke}s that move the focus down to the + child focus cycle root. */ + public static final int DOWN_CYCLE_TRAVERSAL_KEYS = 3; + + /** The set of {@link AWTKeyStroke}s that cause focus to be moved to + the next focusable Component in the focus cycle. */ + private static final Set DEFAULT_FORWARD_KEYS; + + /** The set of {@link AWTKeyStroke}s that cause focus to be moved to + the previous focusable Component in the focus cycle. */ + private static final Set DEFAULT_BACKWARD_KEYS; + + /** Populate the DEFAULT_FORWARD_KEYS and DEFAULT_BACKWARD_KEYS + {@link java.util.Set}s. */ + static + { + Set s = new HashSet(); + s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, 0)); + s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, + KeyEvent.CTRL_DOWN_MASK)); + DEFAULT_FORWARD_KEYS = Collections.unmodifiableSet(s); + s = new HashSet(); + s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, + KeyEvent.SHIFT_DOWN_MASK)); + s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, + KeyEvent.SHIFT_DOWN_MASK + | KeyEvent.CTRL_DOWN_MASK)); + DEFAULT_BACKWARD_KEYS = Collections.unmodifiableSet(s); + } + + /** The global object {@link java.util.Map}s. */ + + /** For security reasons, {@link java.applet.Applet}s in different + codebases must be insulated from one another. Since {@link + KeyboardFocusManager}s have the ability to return {@link + Component}s from a given {@link java.applet.Applet}, each + codebase must have an independent {@link KeyboardFocusManager}. + Since each codebase has its own {@link ThreadGroup} in which its + {@link Applet}s run, it makes sense to partition {@link + KeyboardFocusManager}s according to {@link + java.lang.ThreadGroup}. Thus, currentKeyboardFocusManagers is a + {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}. */ + private static Map currentKeyboardFocusManagers = new HashMap (); + + /** {@link java.applet.Applet}s in one codebase must not be allowed + to access {@link Component}s in {@link java.applet.Applet}s in + other codebases. To enforce this restriction, we key the + following {@link java.util.Map}s on {@link java.lang.ThreadGroup}s (which + are per-codebase). For example, if {@link + java.lang.ThreadGroup} A calls {@link #setGlobalFocusOwner}, + passing {@link Component} C, currentFocusOwners[A] is assigned + C, and all other currentFocusOwners values are nullified. Then + if {@link java.lang.ThreadGroup} A subsequently calls {@link + #getGlobalFocusOwner}, it will return currentFocusOwners[A], + that is, {@link Component} C. If another {@link + java.lang.ThreadGroup} K calls {@link #getGlobalFocusOwner}, it + will return currentFocusOwners[K], that is, null. + + Since this is a static field, we ensure that there is only one + focused {@link Component} per class loader. */ + private static Map currentFocusOwners = new HashMap (); + + /** A {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}s + that stores the {@link Component} that owns the permanent + keyboard focus. @see currentFocusOwners */ + private static Map currentPermanentFocusOwners = new HashMap (); + + /** A {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}s + that stores the focused {@link Window}. @see + currentFocusOwners */ + private static Map currentFocusedWindows = new HashMap (); + + /** A {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}s + that stores the active {@link Window}. @see + currentFocusOwners */ + private static Map currentActiveWindows = new HashMap (); + + /** A {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}s + that stores the focus cycle root {@link Container}. @see + currentFocusOwners */ + private static Map currentFocusCycleRoots = new HashMap (); + + /** The default {@link FocusTraversalPolicy} that focus-managing + {@link Container}s will use to define their initial focus + traversal policy. */ + private FocusTraversalPolicy defaultPolicy; + + /** An array that stores the {@link #FORWARD_TRAVERSAL_KEYS}, {@link + #BACKWARD_TRAVERSAL_KEYS}, {@link #UP_CYCLE_TRAVERSAL_KEYS} and + {@link #DOWN_CYCLE_TRAVERSAL_KEYS} {@link AWTKeyStroke}s {@link + java.util.Set}s. */ + private Set[] defaultFocusKeys = new Set[] + { + DEFAULT_FORWARD_KEYS, DEFAULT_BACKWARD_KEYS, + Collections.EMPTY_SET, Collections.EMPTY_SET + }; + + /** + * A utility class to support the handling of events relating to property changes. + */ + private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport (this); + + /** + * A utility class to support the handling of events relating to vetoable changes. + */ + private final VetoableChangeSupport vetoableChangeSupport = new VetoableChangeSupport (this); + + /** A list of {@link KeyEventDispatcher}s that process {@link + KeyEvent}s before they are processed the default keyboard focus + manager. */ + private final ArrayList keyEventDispatchers = new ArrayList(); + + /** A list of {@link KeyEventPostProcessor}s that process unconsumed + {@link KeyEvent}s. */ + private final ArrayList keyEventPostProcessors = new ArrayList(); + + /** + * Construct a KeyboardFocusManager. + */ + public KeyboardFocusManager () + { + } + + /** + * Retrieve the keyboard focus manager associated with the {@link + * java.lang.ThreadGroup} to which the calling thread belongs. + * + * @return the keyboard focus manager associated with the current + * thread group + */ + public static KeyboardFocusManager getCurrentKeyboardFocusManager () + { + ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); + + if (currentKeyboardFocusManagers.get (currentGroup) == null) + setCurrentKeyboardFocusManager (null); + + return (KeyboardFocusManager) currentKeyboardFocusManagers.get (currentGroup); + } + + /** + * Set the keyboard focus manager associated with the {@link + * java.lang.ThreadGroup} to which the calling thread belongs. + * + * @param m the keyboard focus manager for the current thread group + */ + public static void setCurrentKeyboardFocusManager (KeyboardFocusManager m) + { + SecurityManager sm = System.getSecurityManager (); + if (sm != null) + sm.checkPermission (new AWTPermission ("replaceKeyboardFocusManager")); + + ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); + KeyboardFocusManager manager; + + if (m == null) + manager = new DefaultKeyboardFocusManager(); + else + manager = m; + + currentKeyboardFocusManagers.put (currentGroup, manager); + } + + /** + * Retrieve the {@link Component} that has the keyboard focus, or + * null if the focus owner was not set by a thread in the current + * {@link java.lang.ThreadGroup}. + * + * @return the keyboard focus owner or null + */ + public Component getFocusOwner () + { + return (Component) getObject (currentFocusOwners); + } + + /** + * Retrieve the {@link Component} that has the keyboard focus, + * regardless of whether or not it was set by a thread in the + * current {@link java.lang.ThreadGroup}. If there is no temporary + * focus owner in effect then this method will return the same value + * as {@link #getGlobalPermanentFocusOwner}. + * + * @return the keyboard focus owner + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + */ + protected Component getGlobalFocusOwner () + { + return (Component) getGlobalObject(currentFocusOwners, true); + } + + /** + * Set the {@link Component} that will be returned by {@link + * #getFocusOwner} (when it is called from the current {@link + * java.lang.ThreadGroup}) and {@link #getGlobalFocusOwner}. This + * method does not actually transfer the keyboard focus. + * + * @param owner the Component to return from getFocusOwner and + * getGlobalFocusOwner + * + * @see Component#requestFocus() + * @see Component#requestFocusInWindow() + */ + protected void setGlobalFocusOwner (Component owner) + { + if (owner == null || owner.focusable) + setGlobalObject (currentFocusOwners, owner, "focusOwner"); + } + + /** + * Clear the global focus owner and deliver a FOCUS_LOST event to + * the previously-focused {@link Component}. Until another {@link + * Component} becomes the keyboard focus owner, key events will be + * discarded by top-level windows. + */ + public void clearGlobalFocusOwner () + { + synchronized (currentFocusOwners) + { + Component focusOwner = getGlobalFocusOwner (); + Component permanentFocusOwner = getGlobalPermanentFocusOwner (); + + setGlobalFocusOwner (null); + setGlobalPermanentFocusOwner (null); + + // Inform the old focus owner that it has lost permanent + // focus. + if (focusOwner != null) + { + // We can't cache the event queue, because of + // bootstrapping issues. We need to set the default + // KeyboardFocusManager in EventQueue before the event + // queue is started. + EventQueue q = Toolkit.getDefaultToolkit ().getSystemEventQueue (); + if (focusOwner != permanentFocusOwner) + q.postEvent (new FocusEvent (focusOwner, FocusEvent.FOCUS_LOST, true)); + else + q.postEvent (new FocusEvent (focusOwner, FocusEvent.FOCUS_LOST, false)); + } + + if (focusOwner != permanentFocusOwner) + { + EventQueue q = Toolkit.getDefaultToolkit ().getSystemEventQueue (); + q.postEvent (new FocusEvent (permanentFocusOwner, FocusEvent.FOCUS_LOST, false)); + } + } + } + + /** + * Retrieve the {@link Component} that has the permanent keyboard + * focus, or null if the focus owner was not set by a thread in the + * current {@link java.lang.ThreadGroup}. + * + * @return the keyboard focus owner or null + */ + public Component getPermanentFocusOwner () + { + return (Component) getObject (currentPermanentFocusOwners); + } + + /** + * Retrieve the {@link Component} that has the permanent keyboard + * focus, regardless of whether or not it was set by a thread in the + * current {@link java.lang.ThreadGroup}. + * + * @return the keyboard focus owner + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + */ + protected Component getGlobalPermanentFocusOwner () + { + return (Component) getGlobalObject (currentPermanentFocusOwners, true); + } + + /** + * Set the {@link Component} that will be returned by {@link + * #getPermanentFocusOwner} (when it is called from the current + * {@link java.lang.ThreadGroup}) and {@link + * #getGlobalPermanentFocusOwner}. This method does not actually + * transfer the keyboard focus. + * + * @param focusOwner the Component to return from + * getPermanentFocusOwner and getGlobalPermanentFocusOwner + * + * @see Component#requestFocus() + * @see Component#requestFocusInWindow() + */ + protected void setGlobalPermanentFocusOwner (Component focusOwner) + { + if (focusOwner == null || focusOwner.focusable) + setGlobalObject (currentPermanentFocusOwners, focusOwner, + "permanentFocusOwner"); + } + + /** + * Retrieve the {@link Window} that is or contains the keyboard + * focus owner, or null if the focused window was not set by a + * thread in the current {@link java.lang.ThreadGroup}. + * + * @return the focused window or null + */ + public Window getFocusedWindow () + { + return (Window) getObject (currentFocusedWindows); + } + + /** + * Retrieve the {@link Window} that is or contains the focus owner, + * regardless of whether or not the {@link Window} was set focused + * by a thread in the current {@link java.lang.ThreadGroup}. + * + * @return the focused window + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + */ + protected Window getGlobalFocusedWindow () + { + return (Window) getGlobalObject (currentFocusedWindows, true); + } + + /** + * Set the {@link Window} that will be returned by {@link + * #getFocusedWindow} (when it is called from the current {@link + * java.lang.ThreadGroup}) and {@link #getGlobalFocusedWindow}. + * This method does not actually cause <code>window</code> to become + * the focused {@link Window}. + * + * @param window the Window to return from getFocusedWindow and + * getGlobalFocusedWindow + */ + protected void setGlobalFocusedWindow (Window window) + { + if (window == null || window.focusable) + setGlobalObject (currentFocusedWindows, window, "focusedWindow"); + } + + /** + * Retrieve the active {@link Window}, or null if the active window + * was not set by a thread in the current {@link + * java.lang.ThreadGroup}. + * + * @return the active window or null + */ + public Window getActiveWindow() + { + return (Window) getObject (currentActiveWindows); + } + + /** + * Retrieve the active {@link Window}, regardless of whether or not + * the {@link Window} was made active by a thread in the current + * {@link java.lang.ThreadGroup}. + * + * @return the active window + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + */ + protected Window getGlobalActiveWindow() + { + return (Window) getGlobalObject (currentActiveWindows, true); + } + + /** + * Set the {@link Window} that will be returned by {@link + * #getActiveWindow} (when it is called from the current {@link + * java.lang.ThreadGroup}) and {@link #getGlobalActiveWindow}. This + * method does not actually cause <code>window</code> to be made + * active. + * + * @param window the Window to return from getActiveWindow and + * getGlobalActiveWindow + */ + protected void setGlobalActiveWindow(Window window) + { + setGlobalObject (currentActiveWindows, window, "activeWindow"); + } + + /** + * Retrieve the default {@link FocusTraversalPolicy}. + * Focus-managing {@link Container}s use the returned object to + * define their initial focus traversal policy. + * + * @return a non-null default FocusTraversalPolicy object + */ + public FocusTraversalPolicy getDefaultFocusTraversalPolicy () + { + if (defaultPolicy == null) + defaultPolicy = new DefaultFocusTraversalPolicy (); + return defaultPolicy; + } + + /** + * Set the {@link FocusTraversalPolicy} returned by {@link + * #getDefaultFocusTraversalPolicy}. Focus-managing {@link + * Container}s created after this call will use policy as their + * initial focus traversal policy. Existing {@link Container}s' + * focus traversal policies will not be affected by calls to this + * method. + * + * @param policy the FocusTraversalPolicy that will be returned by + * subsequent calls to getDefaultFocusTraversalPolicy + * @throws IllegalArgumentException if policy is null + */ + public void setDefaultFocusTraversalPolicy (FocusTraversalPolicy policy) + { + if (policy == null) + throw new IllegalArgumentException (); + firePropertyChange ("defaultFocusTraversalPolicy", defaultPolicy, policy); + defaultPolicy = policy; + } + + /** + * Set the default {@link java.util.Set} of focus traversal keys for + * one of the focus traversal directions. + * + * @param id focus traversal direction identifier + * @param keystrokes set of AWTKeyStrokes + * + * @see #FORWARD_TRAVERSAL_KEYS + * @see #BACKWARD_TRAVERSAL_KEYS + * @see #UP_CYCLE_TRAVERSAL_KEYS + * @see #DOWN_CYCLE_TRAVERSAL_KEYS + */ + public void setDefaultFocusTraversalKeys (int id, + Set<? extends AWTKeyStroke> + keystrokes) + { + if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && + id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) + throw new IllegalArgumentException (); + + if (keystrokes == null) + throw new IllegalArgumentException (); + + Set sa; + Set sb; + Set sc; + String type; + switch (id) + { + case FORWARD_TRAVERSAL_KEYS: + sa = defaultFocusKeys[BACKWARD_TRAVERSAL_KEYS]; + sb = defaultFocusKeys[UP_CYCLE_TRAVERSAL_KEYS]; + sc = defaultFocusKeys[DOWN_CYCLE_TRAVERSAL_KEYS]; + type = "forwardDefaultFocusTraversalKeys"; + break; + case BACKWARD_TRAVERSAL_KEYS: + sa = defaultFocusKeys[FORWARD_TRAVERSAL_KEYS]; + sb = defaultFocusKeys[UP_CYCLE_TRAVERSAL_KEYS]; + sc = defaultFocusKeys[DOWN_CYCLE_TRAVERSAL_KEYS]; + type = "backwardDefaultFocusTraversalKeys"; + break; + case UP_CYCLE_TRAVERSAL_KEYS: + sa = defaultFocusKeys[FORWARD_TRAVERSAL_KEYS]; + sb = defaultFocusKeys[BACKWARD_TRAVERSAL_KEYS]; + sc = defaultFocusKeys[DOWN_CYCLE_TRAVERSAL_KEYS]; + type = "upCycleDefaultFocusTraversalKeys"; + break; + case DOWN_CYCLE_TRAVERSAL_KEYS: + sa = defaultFocusKeys[FORWARD_TRAVERSAL_KEYS]; + sb = defaultFocusKeys[BACKWARD_TRAVERSAL_KEYS]; + sc = defaultFocusKeys[UP_CYCLE_TRAVERSAL_KEYS]; + type = "downCycleDefaultFocusTraversalKeys"; + break; + default: + throw new IllegalArgumentException (); + } + int i = keystrokes.size (); + Iterator iter = keystrokes.iterator (); + while (--i >= 0) + { + Object o = iter.next (); + if (!(o instanceof AWTKeyStroke) + || sa.contains (o) || sb.contains (o) || sc.contains (o) + || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED) + throw new IllegalArgumentException (); + } + keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes)); + firePropertyChange (type, defaultFocusKeys[id], keystrokes); + defaultFocusKeys[id] = keystrokes; + } + + /** + * Retrieve the default {@link java.util.Set} of focus traversal + * keys for one of the focus traversal directions. + * + * @param id focus traversal direction identifier + * + * @return the default set of AWTKeyStrokes + * + * @see #FORWARD_TRAVERSAL_KEYS + * @see #BACKWARD_TRAVERSAL_KEYS + * @see #UP_CYCLE_TRAVERSAL_KEYS + * @see #DOWN_CYCLE_TRAVERSAL_KEYS + */ + public Set<AWTKeyStroke> getDefaultFocusTraversalKeys (int id) + { + if (id < FORWARD_TRAVERSAL_KEYS || id > DOWN_CYCLE_TRAVERSAL_KEYS) + throw new IllegalArgumentException (); + return defaultFocusKeys[id]; + } + + /** + * Retrieve the current focus cycle root, or null if the focus owner + * was not set by a thread in the current {@link + * java.lang.ThreadGroup}. + * + * @return the current focus cycle root or null + */ + public Container getCurrentFocusCycleRoot () + { + return (Container) getObject (currentFocusCycleRoots); + } + + /** + * Retrieve the current focus cycle root, regardless of whether or + * not it was made set by a thread in the current {@link + * java.lang.ThreadGroup}. + * + * @return the current focus cycle root + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + */ + protected Container getGlobalCurrentFocusCycleRoot () + { + return (Container) getGlobalObject (currentFocusCycleRoots, true); + } + + /** + * Set the {@link Container} that will be returned by {@link + * #getCurrentFocusCycleRoot} (when it is called from the current + * {@link java.lang.ThreadGroup}) and {@link + * #getGlobalCurrentFocusCycleRoot}. This method does not actually + * make <code>cycleRoot</code> the current focus cycle root. + * + * @param cycleRoot the focus cycle root to return from + * getCurrentFocusCycleRoot and getGlobalCurrentFocusCycleRoot + */ + public void setGlobalCurrentFocusCycleRoot (Container cycleRoot) + { + setGlobalObject (currentFocusCycleRoots, cycleRoot, "currentFocusCycleRoot"); + } + + /** + * Registers the supplied property change listener for receiving + * events caused by the following property changes: + * + * <ul> + * <li>the current focus owner ("focusOwner")</li> + * <li>the permanent focus owner ("permanentFocusOwner")</li> + * <li>the focused window ("focusedWindow")</li> + * <li>the active window ("activeWindow")</li> + * <li>the default focus traversal policy ("defaultFocusTraversalPolicy")</li> + * <li>the default set of forward traversal keys ("forwardDefaultFocusTraversalKeys")</li> + * <li>the default set of backward traversal keys ("backwardDefaultFocusTraversalKeys")</li> + * <li>the default set of up cycle traversal keys ("upCycleDefaultFocusTraversalKeys")</li> + * <li>the default set of down cycle traversal keys ("downCycleDefaultFocusTraversalKeys")</li> + * <li>the current focus cycle root ("currentFocusCycleRoot")</li> + * </ul> + * + * If the supplied listener is null, nothing occurs. + * + * @param l the new listener to register. + * @see KeyboardFocusManager#addPropertyChangeListener(String, java.beans.PropertyChangeListener) + */ + public void addPropertyChangeListener(PropertyChangeListener l) + { + if (l != null) + propertyChangeSupport.addPropertyChangeListener(l); + } + + /** + * Removes the supplied property change listener from the list + * of registered listeners. If the supplied listener is null, + * nothing occurs. + * + * @param l the listener to remove. + */ + public void removePropertyChangeListener(PropertyChangeListener l) + { + if (l != null) + propertyChangeSupport.removePropertyChangeListener(l); + } + + /** + * Returns the currently registered property change listeners + * in array form. The returned array is empty if no listeners are + * currently registered. + * + * @return an array of registered property change listeners. + */ + public PropertyChangeListener[] getPropertyChangeListeners() + { + return propertyChangeSupport.getPropertyChangeListeners(); + } + + /** + * Registers a property change listener for receiving events relating + * to a change to a specified property. The supplied property name can be + * either user-defined or one from the following list of properties + * relevant to this class: + * + * <ul> + * <li>the current focus owner ("focusOwner")</li> + * <li>the permanent focus owner ("permanentFocusOwner")</li> + * <li>the focused window ("focusedWindow")</li> + * <li>the active window ("activeWindow")</li> + * <li>the default focus traversal policy ("defaultFocusTraversalPolicy")</li> + * <li>the default set of forward traversal keys ("forwardDefaultFocusTraversalKeys")</li> + * <li>the default set of backward traversal keys ("backwardDefaultFocusTraversalKeys")</li> + * <li>the default set of up cycle traversal keys ("upCycleDefaultFocusTraversalKeys")</li> + * <li>the default set of down cycle traversal keys ("downCycleDefaultFocusTraversalKeys")</li> + * <li>the current focus cycle root ("currentFocusCycleRoot")</li> + * </ul> + * + * Nothing occurs if a null listener is supplied. null is regarded as a valid property name. + * + * @param name the name of the property to handle change events for. + * @param l the listener to register for changes to the specified property. + * @see KeyboardFocusManager#addPropertyChangeListener(java.beans.PropertyChangeListener) + */ + public void addPropertyChangeListener(String name, PropertyChangeListener l) + { + if (l != null) + propertyChangeSupport.addPropertyChangeListener(name, l); + } + + /** + * Removes the supplied property change listener registered for the + * specified property from the list of registered listeners. If the + * supplied listener is null, nothing occurs. + * + * @param name the name of the property the listener is + * monitoring changes to. + * @param l the listener to remove. + */ + public void removePropertyChangeListener(String name, + PropertyChangeListener l) + { + if (l != null) + propertyChangeSupport.removePropertyChangeListener(name, l); + } + + /** + * Returns the currently registered property change listeners + * in array form, which listen for changes to the supplied property. + * The returned array is empty, if no listeners are currently registered + * for events pertaining to the supplied property. + * + * @param name The property the returned listeners monitor for changes. + * @return an array of registered property change listeners which + * listen for changes to the supplied property. + */ + public PropertyChangeListener[] getPropertyChangeListeners(String name) + { + return propertyChangeSupport.getPropertyChangeListeners(name); + } + + /** + * Fires a property change event as a response to a change to + * to the specified property. The event is only fired if a + * change has actually occurred (i.e. o and n are different). + * + * @param name The name of the property to which a change occurred. + * @param o The old value of the property. + * @param n The new value of the property. + */ + protected void firePropertyChange(String name, Object o, Object n) + { + propertyChangeSupport.firePropertyChange(name, o, n); + } + + /** + * Registers a vetoable property change listener for receiving events + * relating to the following properties: + * + * <ul> + * <li>the current focus owner ("focusOwner")</li> + * <li>the permanent focus owner ("permanentFocusOwner")</li> + * <li>the focused window ("focusedWindow")</li> + * <li>the active window ("activeWindow")</li> + * </ul> + * + * Nothing occurs if a null listener is supplied. + * + * @param l the listener to register. + * @see KeyboardFocusManager#addVetoableChangeListener(String, java.beans.VetoableChangeListener) + */ + public void addVetoableChangeListener(VetoableChangeListener l) + { + if (l != null) + vetoableChangeSupport.addVetoableChangeListener(l); + } + + /** + * Removes the supplied vetoable property change listener from + * the list of registered listeners. If the supplied listener + * is null, nothing occurs. + * + * @param l the listener to remove. + */ + public void removeVetoableChangeListener(VetoableChangeListener l) + { + if (l != null) + vetoableChangeSupport.removeVetoableChangeListener(l); + } + + /** + * Returns the currently registered vetoable property change listeners + * in array form. The returned array is empty if no listeners are + * currently registered. + * + * @return an array of registered vetoable property change listeners. + * @since 1.4 + */ + public VetoableChangeListener[] getVetoableChangeListeners() + { + return vetoableChangeSupport.getVetoableChangeListeners(); + } + + /** + * Registers a vetoable property change listener for receiving events relating + * to a vetoable change to a specified property. The supplied property name can be + * either user-defined or one from the following list of properties + * relevant to this class: + * + * <ul> + * <li>the current focus owner ("focusOwner")</li> + * <li>the permanent focus owner ("permanentFocusOwner")</li> + * <li>the focused window ("focusedWindow")</li> + * <li>the active window ("activeWindow")</li> + * </ul> + * + * Nothing occurs if a null listener is supplied. null is regarded as a valid property name. + * + * @param name the name of the property to handle change events for. + * @param l the listener to register for changes to the specified property. + * @see KeyboardFocusManager#addVetoableChangeListener(java.beans.VetoableChangeListener) + */ + public void addVetoableChangeListener(String name, VetoableChangeListener l) + { + if (l != null) + vetoableChangeSupport.addVetoableChangeListener(name, l); + } + + /** + * Removes the supplied vetoable property change listener registered + * for the specified property from the list of registered listeners. + * If the supplied listener is null, nothing occurs. + * + * @param name the name of the vetoable property the listener is + * monitoring changes to. + * @param l the listener to remove. + */ + public void removeVetoableChangeListener(String name, + VetoableChangeListener l) + { + if (l != null) + vetoableChangeSupport.removeVetoableChangeListener(name, l); + } + + /** + * Returns the currently registered vetoable property change listeners + * in array form, which listen for changes to the supplied property. + * The returned array is empty, if no listeners are currently registered + * for events pertaining to the supplied property. + * + * @param name The property the returned listeners monitor for changes. + * @return an array of registered property change listeners which + * listen for changes to the supplied property. + * @since 1.4 + */ + public VetoableChangeListener[] getVetoableChangeListeners(String name) + { + return vetoableChangeSupport.getVetoableChangeListeners(name); + } + + /** + * Fires a property change event as a response to a vetoable change to + * to the specified property. The event is only fired if a + * change has actually occurred (i.e. o and n are different). + * In the event that the property change is vetoed, the following + * occurs: + * + * <ol> + * <li> + * This method throws a <code>PropertyVetoException</code> to + * the proposed change. + * </li> + * <li> + * A new event is fired to reverse the previous change. + * </li> + * <li> + * This method again throws a <code>PropertyVetoException</code> + * in response to the reversion. + * </li> + * </ol> + * + * @param name The name of the property to which a change occurred. + * @param o The old value of the property. + * @param n The new value of the property. + * @throws PropertyVetoException if one of the listeners vetos + * the change by throwing this exception. + */ + protected void fireVetoableChange(String name, Object o, Object n) + throws PropertyVetoException + { + vetoableChangeSupport.fireVetoableChange(name, o, n); + } + + /** + * Adds a key event dispatcher to the list of registered dispatchers. + * When a key event is fired, each dispatcher's <code>dispatchKeyEvent</code> + * method is called in the order that they were added, prior to the manager + * dispatching the event itself. Notifications halt when one of the + * dispatchers returns true. + * <br /> + * <br /> + * The same dispatcher can exist multiple times within the list + * of registered dispatchers, and there is no limit on the length + * of this list. A null dispatcher is simply ignored. + * + * @param dispatcher The dispatcher to register. + */ + public void addKeyEventDispatcher(KeyEventDispatcher dispatcher) + { + if (dispatcher != null) + keyEventDispatchers.add(dispatcher); + } + + /** + * Removes the specified key event dispatcher from the list of + * registered dispatchers. The manager always dispatches events, + * regardless of its existence within the list. The manager + * can be added and removed from the list, as with any other + * dispatcher, but this does not affect its ability to dispatch + * key events. Non-existent and null dispatchers are simply ignored + * by this method. + * + * @param dispatcher The dispatcher to remove. + */ + public void removeKeyEventDispatcher(KeyEventDispatcher dispatcher) + { + keyEventDispatchers.remove(dispatcher); + } + + /** + * Returns the currently registered key event dispatchers in <code>List</code> + * form. At present, this only includes dispatchers explicitly registered + * via the <code>addKeyEventDispatcher()</code> method, but this behaviour + * is subject to change and should not be depended on. The manager itself + * may be a member of the list, but only if explicitly registered. If no + * dispatchers have been registered, the list will be empty. + * + * @return A list of explicitly registered key event dispatchers. + * @see KeyboardFocusManager#addKeyEventDispatcher(java.awt.KeyEventDispatcher) + */ + protected List<KeyEventDispatcher> getKeyEventDispatchers () + { + return (List<KeyEventDispatcher>) keyEventDispatchers.clone (); + } + + /** + * Adds a key event post processor to the list of registered post processors. + * Post processors work in the same way as key event dispatchers, except + * that they are invoked after the manager has dispatched the key event, + * and not prior to this. Each post processor's <code>postProcessKeyEvent</code> + * method is called to see if any post processing needs to be performed. THe + * processors are called in the order in which they were added to the list, + * and notifications continue until one returns true. As with key event + * dispatchers, the manager is implicitly called following this process, + * regardless of whether or not it is present within the list. + * <br /> + * <br /> + * The same post processor can exist multiple times within the list + * of registered post processors, and there is no limit on the length + * of this list. A null post processor is simply ignored. + * + * @param postProcessor the post processor to register. + * @see KeyboardFocusManager#addKeyEventDispatcher(java.awt.KeyEventDispatcher) + */ + public void addKeyEventPostProcessor (KeyEventPostProcessor postProcessor) + { + if (postProcessor != null) + keyEventPostProcessors.add (postProcessor); + } + + /** + * Removes the specified key event post processor from the list of + * registered post processors. The manager always post processes events, + * regardless of its existence within the list. The manager + * can be added and removed from the list, as with any other + * post processor, but this does not affect its ability to post process + * key events. Non-existent and null post processors are simply ignored + * by this method. + * + * @param postProcessor the post processor to remove. + */ + public void removeKeyEventPostProcessor (KeyEventPostProcessor postProcessor) + { + keyEventPostProcessors.remove (postProcessor); + } + + /** + * Returns the currently registered key event post processors in <code>List</code> + * form. At present, this only includes post processors explicitly registered + * via the <code>addKeyEventPostProcessor()</code> method, but this behaviour + * is subject to change and should not be depended on. The manager itself + * may be a member of the list, but only if explicitly registered. If no + * post processors have been registered, the list will be empty. + * + * @return A list of explicitly registered key event post processors. + * @see KeyboardFocusManager#addKeyEventPostProcessor(java.awt.KeyEventPostProcessor) + */ + protected List<KeyEventPostProcessor> getKeyEventPostProcessors () + { + return (List<KeyEventPostProcessor>) keyEventPostProcessors.clone (); + } + + /** + * The AWT event dispatcher uses this method to request that the manager + * handle a particular event. If the manager fails or refuses to + * dispatch the supplied event (this method returns false), the + * AWT event dispatcher will try to dispatch the event itself. + * <br /> + * <br /> + * The manager is expected to handle all <code>FocusEvent</code>s + * and <code>KeyEvent</code>s, and <code>WindowEvent</code>s + * relating to the focus. Dispatch is done with regard to the + * the focus owner and the currently focused and active windows. + * In handling the event, the source of the event may be overridden. + * <br /> + * <br /> + * The actual dispatching is performed by calling + * <code>redispatchEvent()</code>. This avoids the infinite recursion + * of dispatch requests which may occur if this method is called on + * the target component. + * + * @param e the event to dispatch. + * @return true if the event was dispatched. + * @see KeyboardFocusManager#redispatchEvent(java.awt.Component, java.awt.AWTEvent) + * @see KeyEvent + * @see FocusEvent + * @see WindowEvent + */ + public abstract boolean dispatchEvent (AWTEvent e); + + /** + * Handles redispatching of an event so that recursion of + * dispatch requests does not occur. Event dispatch methods + * within this manager (<code>dispatchEvent()</code>) and + * the key event dispatchers should use this method to handle + * dispatching rather than the dispatch method of the target + * component. + * <br /> + * <br /> + * <strong> + * This method is not intended for general consumption, and is + * only for the use of the aforementioned classes. + * </strong> + * + * @param target the target component to which the event is + * dispatched. + * @param e the event to dispatch. + */ + public final void redispatchEvent (Component target, AWTEvent e) + { + e.isFocusManagerEvent = true; + target.dispatchEvent (e); + e.isFocusManagerEvent = false; + } + + /** + * Attempts to dispatch key events for which no key event dispatcher + * has so far succeeded. This method is usually called by + * <code>dispatchEvent()</code> following the sending of the key + * event to any registered key event dispatchers. If the key + * event reaches this stage, none of the dispatchers returned + * true. This is, of course, always the case if there are no + * registered dispatchers. + * <br /> + * <br /> + * If this method also fails to handle the key event, then + * false is returned to the caller. In the case of + * <code>dispatchEvent()</code>, the calling method may try + * to handle the event itself or simply forward on the + * false result to its caller. When the event is dispatched + * by this method, a true result is propogated through the + * calling methods. + * + * @param e the key event to dispatch. + * @return true if the event was dispatched successfully. + */ + public abstract boolean dispatchKeyEvent (KeyEvent e); + + /** + * Handles the post processing of key events. By default, + * this method will map unhandled key events to appropriate + * <code>MenuShortcut</code>s. The event is consumed + * in the process and the shortcut is activated. This + * method is usually called by <code>dispatchKeyEvent</code>. + * + * @param e the key event to post process. + * @return true by default, as the event was handled. + */ + public abstract boolean postProcessKeyEvent (KeyEvent e); + + /** + * Handles focus traversal operations for key events which + * represent focus traversal keys in relation to the supplied + * component. The supplied component is assumed to have the + * focus, whether it does so or not, and the operation is + * carried out as appropriate, with this in mind. + * + * @param focused the component on which to perform focus traversal, + * on the assumption that this component has the focus. + * @param e the possible focus traversal key event. + */ + public abstract void processKeyEvent (Component focused, KeyEvent e); + + /** + * Delays all key events following the specified timestamp until the + * supplied component has focus. The AWT calls this method when it is + * determined that a focus change may occur within the native windowing + * system. Any key events which occur following the time specified by + * after are delayed until a <code>FOCUS_GAINED</code> event is received + * for the untilFocused component. The manager is responsible for ensuring + * this takes place. + * + * @param after the timestamp beyond which all key events are delayed until + * the supplied component gains focus. + * @param untilFocused the component to wait on gaining focus. + */ + protected abstract void enqueueKeyEvents (long after, Component untilFocused); + + /** + * Removes the key event block specified by the supplied timestamp and component. + * All delayed key events are released for normal dispatching following its + * removal and subsequent key events that would have been blocked are now + * immediately dispatched. If the specified timestamp is below 0, then + * the request with the oldest timestamp is removed. + * + * @param after the timestamp of the key event block to be removed, or a + * value smaller than 0 if the oldest is to be removed. + * @param untilFocused the component of the key event block to be removed. + */ + protected abstract void dequeueKeyEvents (long after, Component untilFocused); + + /** + * Discards all key event blocks relating to focus requirements for + * the supplied component, regardless of timestamp. + * + * @param comp the component of the key event block(s) to be removed. + */ + protected abstract void discardKeyEvents (Component comp); + + /** + * Moves the current focus to the next component following + * comp, based on the current focus traversal policy. By + * default, only visible, displayable, accepted components + * can receive focus. <code>Canvas</code>es, <code>Panel</code>s, + * <code>Label</code>s, <code>ScrollPane</code>s, <code>Scrollbar</code>s, + * <code>Window</code>s and lightweight components are judged + * to be unacceptable by default. See the + * <code>DefaultFocusTraversalPolicy</code> for more details. + * + * @param comp the component prior to the one which will + * become the focus, following execution of this method. + * @see DefaultFocusTraversalPolicy + */ + public abstract void focusNextComponent(Component comp); + + /** + * Moves the current focus to the previous component, prior to + * comp, based on the current focus traversal policy. By + * default, only visible, displayable, accepted components + * can receive focus. <code>Canvas</code>es, <code>Panel</code>s, + * <code>Label</code>s, <code>ScrollPane</code>s, <code>Scrollbar</code>s, + * <code>Window</code>s and lightweight components are judged + * to be unacceptable by default. See the + * <code>DefaultFocusTraversalPolicy</code> for more details. + * + * @param comp the component following the one which will + * become the focus, following execution of this method. + * @see DefaultFocusTraversalPolicy + */ + public abstract void focusPreviousComponent(Component comp); + + /** + * Moves the current focus upwards by one focus cycle. + * Both the current focus owner and current focus cycle root + * become the focus cycle root of the supplied component. + * However, in the case of a <code>Window</code>, the default + * focus component becomes the focus owner and the focus cycle + * root is not changed. + * + * @param comp the component used as part of the focus traversal. + */ + public abstract void upFocusCycle(Component comp); + + /** + * Moves the current focus downwards by one focus cycle. + * If the supplied container is a focus cycle root, then this + * becomes the current focus cycle root and the focus goes + * to the default component of the specified container. + * Nothing happens for non-focus cycle root containers. + * + * @param cont the container used as part of the focus traversal. + */ + public abstract void downFocusCycle(Container cont); + + /** + * Moves the current focus to the next component, based on the + * current focus traversal policy. By default, only visible, + * displayable, accepted component can receive focus. + * <code>Canvas</code>es, <code>Panel</code>s, + * <code>Label</code>s, <code>ScrollPane</code>s, <code>Scrollbar</code>s, + * <code>Window</code>s and lightweight components are judged + * to be unacceptable by default. See the + * <code>DefaultFocusTraversalPolicy</code> for more details. + * + * @see DefaultFocusTraversalPolicy + */ + public final void focusNextComponent() + { + focusNextComponent (null); + } + + /** + * Moves the current focus to the previous component, based on the + * current focus traversal policy. By default, only visible, + * displayable, accepted component can receive focus. + * <code>Canvas</code>es, <code>Panel</code>s, + * <code>Label</code>s, <code>ScrollPane</code>s, <code>Scrollbar</code>s, + * <code>Window</code>s and lightweight components are judged + * to be unacceptable by default. See the + * <code>DefaultFocusTraversalPolicy</code> for more details. + * + * @see DefaultFocusTraversalPolicy + */ + public final void focusPreviousComponent() + { + focusPreviousComponent (null); + } + + /** + * Moves the current focus upwards by one focus cycle, + * so that the new focus owner is the focus cycle root + * of the current owner. The current focus cycle root then + * becomes the focus cycle root of the new focus owner. + * However, in the case of the focus cycle root of the + * current focus owner being a <code>Window</code>, the default + * component of this window becomes the focus owner and the + * focus cycle root is not changed. + */ + public final void upFocusCycle() + { + upFocusCycle (null); + } + + /** + * Moves the current focus downwards by one focus cycle, + * iff the current focus cycle root is a <code>Container</code>. + * Usually, the new focus owner is set to the default component + * of the container and the current focus cycle root is set + * to the current focus owner. Nothing occurs if the current + * focus cycle root is not a container. + */ + public final void downFocusCycle() + { + Component focusOwner = getGlobalFocusOwner (); + if (focusOwner instanceof Container + && ((Container) focusOwner).isFocusCycleRoot ()) + downFocusCycle ((Container) focusOwner); + } + + /** + * Retrieve an object from one of the global object {@link + * java.util.Map}s, if the object was set by the a thread in the + * current {@link java.lang.ThreadGroup}. Otherwise, return null. + * + * @param globalMap one of the global object Maps + * + * @return a global object set by the current ThreadGroup, or null + * + * @see #getFocusOwner() + * @see #getPermanentFocusOwner() + * @see #getFocusedWindow() + * @see #getActiveWindow() + * @see #getCurrentFocusCycleRoot() + */ + private Object getObject (Map globalMap) + { + ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); + return globalMap.get (currentGroup); + } + + /** + * Retrieve an object from one of the global object {@link + * java.util.Map}s, regardless of whether or not the object was set + * by a thread in the current {@link java.lang.ThreadGroup}. + * + * @param globalMap one of the global object Maps + * + * @return a global object set by the current ThreadGroup, or null + * + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + * + * @see #getGlobalFocusOwner() + * @see #getGlobalPermanentFocusOwner() + * @see #getGlobalFocusedWindow() + * @see #getGlobalActiveWindow() + * @see #getGlobalCurrentFocusCycleRoot() + */ + private Object getGlobalObject (Map globalMap, boolean checkThread) + { + if (checkThread) + { + ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); + KeyboardFocusManager managerForCallingThread = + (KeyboardFocusManager) currentKeyboardFocusManagers.get(currentGroup); + + if (this != managerForCallingThread) + throw new SecurityException ("Attempted to retrieve an object from a " + + "keyboard focus manager that isn't " + + "associated with the current thread group."); + } + synchronized (globalMap) + { + Collection globalObjects = globalMap.values (); + Iterator i = globalObjects.iterator (); + Component globalObject; + + while (i.hasNext ()) + { + globalObject = (Component) i.next (); + if (globalObject != null) + return globalObject; + } + } + + // No Object was found. + return null; + } + + /** + * Set an object in one of the global object {@link java.util.Map}s, + * that will be returned by subsequent calls to getGlobalObject on + * the same {@link java.util.Map}. + * + * @param globalMap one of the global object Maps + * @param newObject the object to set + * @param property the property that will change + * + * @see #setGlobalFocusOwner(Component) + * @see #setGlobalPermanentFocusOwner(Component) + * @see #setGlobalFocusedWindow(Window) + * @see #setGlobalActiveWindow(Window) + * @see #setGlobalCurrentFocusCycleRoot(Container) + */ + private void setGlobalObject (Map globalMap, + Object newObject, + String property) + { + synchronized (globalMap) + { + // Save old object. + Object oldObject = getGlobalObject(globalMap, false); + + // Nullify old object. + Collection threadGroups = globalMap.keySet (); + Iterator i = threadGroups.iterator (); + while (i.hasNext ()) + { + ThreadGroup oldThreadGroup = (ThreadGroup) i.next (); + if (globalMap.get (oldThreadGroup) != null) + { + globalMap.put (oldThreadGroup, null); + // There should only be one object set at a time, so + // we can short circuit. + break; + } + } + + ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); + firePropertyChange (property, oldObject, newObject); + try + { + fireVetoableChange (property, oldObject, newObject); + // Set new object. + globalMap.put (currentGroup, newObject); + } + catch (PropertyVetoException e) + { + } + } + } + + + /** + * Maps focus requests from heavyweight to lightweight components. + */ + private static HashMap focusRequests = new HashMap(); + + /** + * Retargets focus events that come from the peer (which only know about + * heavyweight components) to go to the correct lightweight component + * if appropriate. + * + * @param ev the event to check + * + * @return the retargetted event + */ + static AWTEvent retargetFocusEvent(AWTEvent ev) + { + if (ev instanceof FocusEvent) + { + FocusEvent fe = (FocusEvent) ev; + Component target = fe.getComponent(); + if (focusRequests.containsKey(target)) + { + Component lightweight = (Component) focusRequests.get(target); + ev = new FocusEvent(lightweight, fe.id, fe.isTemporary()); + focusRequests.remove(target); + } + } + return ev; + } + + /** + * Adds a lightweight focus request for a heavyweight component. + * + * @param heavyweight the heavyweight from which we will receive a focus + * event soon + * @param lightweight the lightweight that ultimately receives the request + */ + static void addLightweightFocusRequest(Component heavyweight, + Component lightweight) + { + focusRequests.put(heavyweight, lightweight); + } +} diff --git a/libjava/classpath/java/awt/Label.java b/libjava/classpath/java/awt/Label.java new file mode 100644 index 000000000..1522dac36 --- /dev/null +++ b/libjava/classpath/java/awt/Label.java @@ -0,0 +1,294 @@ +/* Label.java -- Java label widget + Copyright (C) 1999, 2000, 2002, 2004, 2005, 2006, Free Software + Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.peer.LabelPeer; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; + +/** + * This component is used for displaying simple text strings that cannot + * be edited by the user. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +public class Label extends Component implements Accessible +{ + + /** + * Alignment constant aligning the text to the left of its window. + */ + public static final int LEFT = 0; + + /** + * Alignment constant aligning the text in the center of its window. + */ + public static final int CENTER = 1; + + /** + * Alignment constant aligning the text to the right of its window. + */ + public static final int RIGHT = 2; + + // Serialization version constant: + private static final long serialVersionUID = 3094126758329070636L; + + /** + * @serial Indicates the alignment of the text within this label's window. + * This is one of the constants in this class. The default value is + * <code>LEFT</code>. + */ + private int alignment; + + /** + * @serial The text displayed in the label + */ + private String text; + + /** + * Initializes a new instance of <code>Label</code> with no text. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public Label() + { + this("", LEFT); + } + + /** + * Initializes a new instance of <code>Label</code> with the specified + * text that is aligned to the left. + * + * @param text The text of the label. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public Label(String text) + { + this(text, LEFT); + } + + /** + * Initializes a new instance of <code>Label</code> with the specified + * text and alignment. + * + * @param text The text of the label. + * @param alignment The desired alignment for the text in this label, + * which must be one of <code>LEFT</code>, <code>CENTER</code>, or + * <code>RIGHT</code>. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public Label(String text, int alignment) + { + setAlignment(alignment); + setText(text); + + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException(); + } + + /** + * Returns the constant indicating the alignment of the text in this + * label. The value returned will be one of the alignment constants + * from this class. + * + * @return The alignment of the text in the label. + */ + public int getAlignment() + { + return(alignment); + } + + /** + * Sets the text alignment of this label to the specified value. + * + * @param alignment The desired alignment for the text in this label, + * which must be one of <code>LEFT</code>, <code>CENTER</code>, or + * <code>RIGHT</code>. + */ + public synchronized void setAlignment(int alignment) + { + if (alignment != CENTER && alignment != LEFT && alignment != RIGHT) + throw new IllegalArgumentException("invalid alignment: " + alignment); + this.alignment = alignment; + if (peer != null) + { + LabelPeer lp = (LabelPeer) peer; + lp.setAlignment(alignment); + } + } + + /** + * Returns the text displayed in this label. + * + * @return The text for this label. + */ + public String getText() + { + return text; + } + + /** + * Sets the text in this label to the specified value. + * + * @param text The new text for this label. + */ + public synchronized void setText(String text) + { + if ((this.text == null && text != null) + || (this.text != null && ! this.text.equals(text))) + { + this.text = text; + + if (peer != null) + { + LabelPeer lp = (LabelPeer) peer; + lp.setText(text); + } + invalidate(); + } + } + + /** + * Notifies this label that it has been added to a container, causing + * the peer to be created. This method is called internally by the AWT + * system. + */ + public void addNotify() + { + if (peer == null) + peer = getToolkit().createLabel(this); + super.addNotify(); + } + + /** + * Returns a parameter string useful for debugging. + * + * @return A debugging string. + */ + protected String paramString() + { + return ("text=" + getText() + ",alignment=" + + getAlignment() + "," + super.paramString()); + } + + /** + * This class provides accessibility support for the label. + */ + protected class AccessibleAWTLabel + extends AccessibleAWTComponent + { + /** + * For compatability with Sun's JDK 1.4.2 rev. 5 + */ + private static final long serialVersionUID = -3568967560160480438L; + + /** + * Constructor for the accessible label. + */ + public AccessibleAWTLabel() + { + } + + /** + * Returns the accessible name for the label. This is + * the text used in the label. + * + * @return a <code>String</code> containing the accessible + * name for this label. + */ + public String getAccessibleName() + { + return getText(); + } + + /** + * Returns the accessible role for the label. + * + * @return an instance of <code>AccessibleRole</code>, describing + * the role of the label. + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.LABEL; + } + + } + + /** + * Gets the AccessibleContext associated with this <code>Label</code>. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTLabel(); + return accessibleContext; + } + + /** + * Generate a unique name for this button. + * + * @return A unique name for this button. + */ + String generateName() + { + return "label" + getUniqueLong(); + } + + /** + * The number used to generate the name returned by getName. + */ + private static transient long nextLabelNumber; + + private static synchronized long getUniqueLong() + { + return nextLabelNumber++; + } + +} diff --git a/libjava/classpath/java/awt/LayoutManager.java b/libjava/classpath/java/awt/LayoutManager.java new file mode 100644 index 000000000..62ff8087e --- /dev/null +++ b/libjava/classpath/java/awt/LayoutManager.java @@ -0,0 +1,92 @@ +/* LayoutManager.java -- lay out elements in a Container + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +/** + * This interface is for laying out containers in a particular sequence. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see Container + * @since 1.0 + * @status updated to 1.4 + */ +public interface LayoutManager +{ + /** + * Adds the specified component to the layout group. + * + * @param name the name of the component to add + * @param component the component to add + */ + void addLayoutComponent(String name, Component component); + + /** + * Removes the specified component from the layout group. + * + * @param component the component to remove + */ + void removeLayoutComponent(Component component); + + /** + * Calculates the preferred size for this container, taking into account + * the components it contains. + * + * @param parent the parent container to lay out + * @return the preferred dimensions of this container + * @see #minimumLayoutSize(Container) + */ + Dimension preferredLayoutSize(Container parent); + + /** + * Calculates the minimum size for this container, taking into account + * the components it contains. + * + * @param parent the parent container to lay out + * @return the minimum dimensions of this container + * @see #preferredLayoutSize(Container) + */ + Dimension minimumLayoutSize(Container parent); + + /** + * Lays out the components in the given container. + * + * @param parent the container to lay out + */ + void layoutContainer(Container parent); +} // interface LayoutManager diff --git a/libjava/classpath/java/awt/LayoutManager2.java b/libjava/classpath/java/awt/LayoutManager2.java new file mode 100644 index 000000000..45fc5430f --- /dev/null +++ b/libjava/classpath/java/awt/LayoutManager2.java @@ -0,0 +1,100 @@ +/* LayoutManager2.java -- enhanced layout manager + Copyright (C) 1999, 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +/** + * Layout manager for laying out containers based on contraints. The + * constraints control how the layout will proceed. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see LayoutManager + * @see Container + * @since 1.0 + * @status updated to 1.4 + */ +public interface LayoutManager2 extends LayoutManager +{ + /** + * Adds the specified component to the layout, with the specified + * constraints object. + * + * @param component the component to add + * @param constraints the constraints to satisfy + */ + void addLayoutComponent(Component component, Object constraints); + + /** + * Determines the maximum size of the specified target container. + * + * @param target the container to lay out + * @return the maximum size of the container + * @see Component#getMaximumSize() + */ + Dimension maximumLayoutSize(Container target); + + /** + * Returns the preferred X axis alignment for the specified target + * container. This value will range from 0 to 1 where 0 is alignment + * closest to the origin, 0.5 is centered, and 1 is aligned furthest + * from the origin. + * + * @param target the target container + * @return the x-axis alignment preference + */ + float getLayoutAlignmentX(Container target); + + /** + * Returns the preferred Y axis alignment for the specified target + * container. This value will range from 0 to 1 where 0 is alignment + * closest to the origin, 0.5 is centered, and 1 is aligned furthest + * from the origin. + * + * @param target the target container + * @return the y-axis alignment preference + */ + float getLayoutAlignmentY(Container target); + + /** + * Forces the layout manager to purge any cached information about the + * layout of the target container. This will force it to be recalculated. + * + * @param target the target container + */ + void invalidateLayout(Container target); +} // interface LayoutManager2 diff --git a/libjava/classpath/java/awt/LightweightDispatcher.java b/libjava/classpath/java/awt/LightweightDispatcher.java new file mode 100644 index 000000000..11b83d8bf --- /dev/null +++ b/libjava/classpath/java/awt/LightweightDispatcher.java @@ -0,0 +1,362 @@ +/* LightweightDispatcher.java -- Dispatches mouse events to lightweights + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseWheelEvent; +import java.awt.peer.LightweightPeer; +import java.util.WeakHashMap; + +/** + * Redispatches mouse events to lightweight components. The native peers know + * nothing about the lightweight components and thus mouse events are always + * targetted at Windows or heavyweight components. This class listenes directly + * on the eventqueue and dispatches mouse events to lightweight components. + * + * @author Roman Kennke (kennke@aicas.com) + */ +final class LightweightDispatcher +{ + + /** + * Maps thread groups to lightweight dispatcher instances. We need to + * have one instance per thread group so that 2 or more applets or otherwise + * separated applications (like in OSGI) do not interfer with each other. + */ + private static WeakHashMap instances = new WeakHashMap(); + + /** + * The last mouse event target. If the target changes, additional + * MOUSE_ENTERED and MOUSE_EXITED events must be dispatched. + */ + private Component lastTarget; + + /** + * The current mouseEventTarget. + */ + private Component mouseEventTarget; + + /** + * Returns an instance of LightweightDispatcher for the current thread's + * thread group. + * + * @return an instance of LightweightDispatcher for the current thread's + * thread group + */ + static LightweightDispatcher getInstance() + { + Thread t = Thread.currentThread(); + ThreadGroup tg = t.getThreadGroup(); + LightweightDispatcher instance = (LightweightDispatcher) instances.get(tg); + if (instance == null) + { + instance = new LightweightDispatcher(); + instances.put(tg, instance); + } + return instance; + } + + /** + * Creates a new LightweightDispatcher. This is private to prevent access + * from outside. Use {@link #getInstance()} instead. + */ + private LightweightDispatcher() + { + // Nothing to do here. + } + + /** + * Receives notification if a mouse event passes along the eventqueue. + * + * @param event the event + */ + public boolean dispatchEvent(final AWTEvent event) + { + if (event instanceof MouseEvent) + { + MouseEvent mouseEvent = (MouseEvent) event; + return handleMouseEvent(mouseEvent); + } + return false; + } + + /** + * Handles all mouse events that are targetted at toplevel containers + * (Window instances) and dispatches them to the correct lightweight child. + * + * @param ev the mouse event + * @return whether or not we found a lightweight that handled the event. + */ + private boolean handleMouseEvent(final MouseEvent ev) + { + Container container = (Container) ev.getSource(); + Component target = findTarget(container, ev.getX(), ev.getY()); + trackEnterExit(target, ev); + int id = ev.getID(); + + // Dont update the mouseEventTarget when dragging. Also, MOUSE_CLICKED + // must be dispatched to the original target of MOUSE_PRESSED, so don't + // update in this case either. + if (! isDragging(ev) && id != MouseEvent.MOUSE_CLICKED) + mouseEventTarget = (target != container) ? target : null; + + if (mouseEventTarget != null) + { + switch (id) + { + case MouseEvent.MOUSE_ENTERED: + case MouseEvent.MOUSE_EXITED: + // This is already handled in trackEnterExit(). + break; + case MouseEvent.MOUSE_PRESSED: + case MouseEvent.MOUSE_RELEASED: + case MouseEvent.MOUSE_MOVED: + redispatch(ev, mouseEventTarget, id); + break; + case MouseEvent.MOUSE_CLICKED: + // MOUSE_CLICKED must be dispatched to the original target of + // MOUSE_PRESSED. + if (target == mouseEventTarget) + redispatch(ev, mouseEventTarget, id); + break; + case MouseEvent.MOUSE_DRAGGED: + if (isDragging(ev)) + redispatch(ev, mouseEventTarget, id); + break; + case MouseEvent.MOUSE_WHEEL: + redispatch(ev, mouseEventTarget, id); + } + ev.consume(); + } + + return ev.isConsumed(); + } + + /** + * Finds the actual target for a mouseevent, starting at <code>c</code>. + * This searches through the children of the container and finds the first + * one which is showing, at the location from the mouse event and has + * a MouseListener or MouseMotionListener attached. If no such child component + * is found, null is returned. + * + * @param c the container to search through + * @param loc the mouse event point + * + * @return the actual receiver of the mouse event, or null, if no such + * component has been found + */ + private Component findTarget(final Container c, final int x, final int y) + { + Component target = null; + + // First we check the children of the container. + + // Note: It is important that we use the package private Container + // fields ncomponents and component here. There are applications + // that override getComponentCount() + // and getComponent() to hide internal components, which makes + // the LightweightDispatcher not work correctly in these cases. + // As a positive sideeffect this is slightly more efficient. + int nChildren = c.ncomponents; + for (int i = 0; i < nChildren && target == null; i++) + { + Component child = c.component[i]; + int childX = x - child.x; + int childY = y - child.y; + if (child != null && child.visible + && child.peer instanceof LightweightPeer + && child.contains(childX, childY)) + { + // Check if there's a deeper possible target. + if (child instanceof Container) + { + Component deeper = findTarget((Container) child, + childX, childY); + if (deeper != null) + target = deeper; + } + // Check if the child itself is interested in mouse events. + else if (isMouseListening(child)) + target = child; + } + } + + // Check the container itself, if we didn't find a target yet. + if (target == null && c.contains(x, y) && isMouseListening(c)) + target = c; + + return target; + } + + /** + * Checks if the specified component would be interested in a mouse event. + * + * @param c the component to check + * + * @return <code>true</code> if the component has mouse listeners installed, + * <code>false</code> otherwise + */ + private boolean isMouseListening(final Component c) + { + // Note: It is important to NOT check if the component is listening + // for a specific event (for instance, mouse motion events). The event + // gets dispatched to the component if the component is listening + // for ANY mouse event, even when the component is not listening for the + // specific type of event. There are applications that depend on this + // (sadly). + return c.mouseListener != null + || c.mouseMotionListener != null + || c.mouseWheelListener != null + || (c.eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0 + || (c.eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0 + || (c.eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0; + } + + /** + * Tracks MOUSE_ENTERED and MOUSE_EXIT as well as MOUSE_MOVED and + * MOUSE_DRAGGED and creates synthetic MOUSE_ENTERED and MOUSE_EXITED for + * lightweight component.s + * + * @param target the current mouse event target + * @param ev the mouse event + */ + private void trackEnterExit(final Component target, final MouseEvent ev) + { + int id = ev.getID(); + if (target != lastTarget) + { + if (lastTarget != null) + redispatch(ev, lastTarget, MouseEvent.MOUSE_EXITED); + if (id == MouseEvent.MOUSE_EXITED) + ev.consume(); + if (target != null) + redispatch(ev, target, MouseEvent.MOUSE_ENTERED); + if (id == MouseEvent.MOUSE_ENTERED) + ev.consume(); + lastTarget = target; + } + + } + + /** + * Redispatches the specified mouse event to the specified target with the + * specified id. + * + * @param ev the mouse event + * @param target the new target + * @param id the new id + */ + private void redispatch(MouseEvent ev, Component target, int id) + { + Component source = ev.getComponent(); + assert target != null; + if (target.isShowing()) + { + // Translate coordinates. + int x = ev.getX(); + int y = ev.getY(); + for (Component c = target; c != null && c != source; c = c.getParent()) + { + x -= c.x; + y -= c.y; + } + + // Retarget event. + MouseEvent retargeted; + if (id == MouseEvent.MOUSE_WHEEL) + { + MouseWheelEvent mwe = (MouseWheelEvent) ev; + retargeted = new MouseWheelEvent(target, id, ev.getWhen(), + ev.getModifiers() + | ev.getModifiersEx(), x, y, + ev.getClickCount(), + ev.isPopupTrigger(), + mwe.getScrollType(), + mwe.getScrollAmount(), + mwe.getWheelRotation()); + } + else + { + retargeted = new MouseEvent(target, id, ev.getWhen(), + ev.getModifiers() | ev.getModifiersEx(), + x, y, ev.getClickCount(), + ev.isPopupTrigger(), ev.getButton()); + } + + if (target == source) + ((Container) target).dispatchNoLightweight(retargeted); + else + target.dispatchEvent(retargeted); + } + } + + /** + * Determines if we are in the middle of a drag operation, that is, if + * any of the buttons is held down. + * + * @param ev the mouse event to check + * + * @return <code>true</code> if we are in the middle of a drag operation, + * <code>false</code> otherwise + */ + private boolean isDragging(MouseEvent ev) + { + int mods = ev.getModifiersEx(); + int id = ev.getID(); + if (id == MouseEvent.MOUSE_PRESSED || id == MouseEvent.MOUSE_RELEASED) + { + switch (ev.getButton()) + { + case MouseEvent.BUTTON1: + mods ^= InputEvent.BUTTON1_DOWN_MASK; + break; + case MouseEvent.BUTTON2: + mods ^= InputEvent.BUTTON2_DOWN_MASK; + break; + case MouseEvent.BUTTON3: + mods ^= InputEvent.BUTTON3_DOWN_MASK; + break; + } + } + return (mods & (InputEvent.BUTTON1_DOWN_MASK + | InputEvent.BUTTON2_DOWN_MASK + | InputEvent.BUTTON3_DOWN_MASK)) != 0; + } +} diff --git a/libjava/classpath/java/awt/List.java b/libjava/classpath/java/awt/List.java new file mode 100644 index 000000000..dc1199bbc --- /dev/null +++ b/libjava/classpath/java/awt/List.java @@ -0,0 +1,1222 @@ +/* List.java -- A listbox widget + Copyright (C) 1999, 2002, 2004, 2006, Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.peer.ListPeer; +import java.util.EventListener; +import java.util.Vector; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleSelection; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; + +/** + * Class that implements a listbox widget + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class List extends Component + implements ItemSelectable, Accessible +{ + + /** + * The number used to generate the name returned by getName. + */ + private static transient long next_list_number; + + // Serialization constant + private static final long serialVersionUID = -3304312411574666869L; + + // FIXME: Need read/writeObject + + /** + * @serial The items in the list. + */ + private Vector items = new Vector(); + + /** + * @serial Indicates whether or not multiple items can be selected + * simultaneously. + */ + private boolean multipleMode; + + /** + * @serial The number of rows in the list. This is set on creation + * only and cannot be modified. + */ + private int rows; + + /** + * @serial An array of the item indices that are selected. + */ + private int[] selected; + + /** + * @serial An index value used by <code>makeVisible()</code> and + * <code>getVisibleIndex</code>. + */ + private int visibleIndex = -1; + + // The list of ItemListeners for this object. + private ItemListener item_listeners; + + // The list of ActionListeners for this object. + private ActionListener action_listeners; + + /** + * Initializes a new instance of <code>List</code> with no visible lines + * and multi-select disabled. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + * @since 1.1 + */ + public List() + { + this(4, false); + } + + /** + * Initializes a new instance of <code>List</code> with the specified + * number of visible lines and multi-select disabled. + * + * @param rows The number of visible rows in the list. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public List(int rows) + { + this(rows, false); + } + + /** + * Initializes a new instance of <code>List</code> with the specified + * number of lines and the specified multi-select setting. + * + * @param rows The number of visible rows in the list. + * @param multipleMode <code>true</code> if multiple lines can be selected + * simultaneously, <code>false</code> otherwise. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public List(int rows, boolean multipleMode) + { + if (rows == 0) + this.rows = 4; + else + this.rows = rows; + + this.multipleMode = multipleMode; + selected = new int[0]; + + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException(); + + } + + /** + * Returns the number of items in this list. + * + * @return The number of items in this list. + * + * @since 1.1 + */ + public int getItemCount() + { + return countItems(); + } + + /** + * Returns the number of items in this list. + * + * @return The number of items in this list. + * + * @deprecated This method is deprecated in favor of + * <code>getItemCount()</code> + */ + public int countItems() + { + return items.size(); + } + + /** + * Returns the complete list of items. + * + * @return The complete list of items in the list. + * + * @since 1.1 + */ + public synchronized String[] getItems() + { + String[] l_items = new String[getItemCount()]; + + items.copyInto(l_items); + return(l_items); + } + + /** + * Returns the item at the specified index. + * + * @param index The index of the item to retrieve. + * + * @exception IndexOutOfBoundsException If the index value is not valid. + */ + public String getItem(int index) + { + return((String) items.elementAt(index)); + } + + /** + * Returns the number of visible rows in the list. + * + * @return The number of visible rows in the list. + */ + public int getRows() + { + return(rows); + } + + /** + * Tests whether or not multi-select mode is enabled. + * + * @return <code>true</code> if multi-select mode is enabled, + * <code>false</code> otherwise. + * + * @since 1.1 + */ + public boolean isMultipleMode() + { + return allowsMultipleSelections (); + } + + /** + * Tests whether or not multi-select mode is enabled. + * + * @return <code>true</code> if multi-select mode is enabled, + * <code>false</code> otherwise. + * + * @deprecated This method is deprecated in favor of + * <code>isMultipleMode()</code>. + */ + public boolean allowsMultipleSelections() + { + return multipleMode; + } + + /** + * This method enables or disables multiple selection mode for this + * list. + * + * @param multipleMode <code>true</code> to enable multiple mode, + * <code>false</code> otherwise. + * + * @since 1.1 + */ + public void setMultipleMode(boolean multipleMode) + { + setMultipleSelections (multipleMode); + } + + /** + * This method enables or disables multiple selection mode for this + * list. + * + * @param multipleMode <code>true</code> to enable multiple mode, + * <code>false</code> otherwise. + * + * @deprecated + */ + public void setMultipleSelections(boolean multipleMode) + { + this.multipleMode = multipleMode; + + ListPeer peer = (ListPeer) getPeer(); + if (peer != null) + peer.setMultipleMode(multipleMode); + + } + + /** + * Returns the minimum size of this component. + * + * @return The minimum size of this component. + * + * @since 1.1 + */ + public Dimension getMinimumSize() + { + return getMinimumSize(getRows()); + } + + /** + * Returns the minimum size of this component. + * + * @return The minimum size of this component. + * + * @deprecated This method is deprecated in favor of + * <code>getMinimumSize</code>. + */ + public Dimension minimumSize() + { + return minimumSize(getRows()); + } + + /** + * Returns the minimum size of this component assuming it had the specified + * number of rows. + * + * @param rows The number of rows to size for. + * + * @return The minimum size of this component. + * + * @since 1.1 + */ + public Dimension getMinimumSize(int rows) + { + return minimumSize(rows); + } + + /** + * Returns the minimum size of this component assuming it had the specified + * number of rows. + * + * @param rows The number of rows to size for. + * + * @return The minimum size of this component. + * + * @deprecated This method is deprecated in favor of + * <code>getMinimumSize(int)</code>> + */ + public Dimension minimumSize(int rows) + { + ListPeer peer = (ListPeer) getPeer(); + if (peer != null) + return peer.minimumSize(rows); + else + return new Dimension(0, 0); + } + + /** + * Returns the preferred size of this component. + * + * @return The preferred size of this component. + * + * @since 1.1 + */ + public Dimension getPreferredSize() + { + return getPreferredSize(getRows()); + } + + /** + * Returns the preferred size of this component. + * + * @return The preferred size of this component. + * + * @deprecated This method is deprecated in favor of + * <code>getPreferredSize</code>. + */ + public Dimension preferredSize() + { + return preferredSize(getRows()); + } + + /** + * Returns the preferred size of this component assuming it had the specified + * number of rows. + * + * @param rows The number of rows to size for. + * + * @return The preferred size of this component. + * + * @since 1.1 + */ + public Dimension getPreferredSize(int rows) + { + return preferredSize(rows); + } + + /** + * Returns the preferred size of this component assuming it had the specified + * number of rows. + * + * @param rows The number of rows to size for. + * + * @return The preferred size of this component. + * + * @deprecated This method is deprecated in favor of + * <code>getPreferredSize(int)</code>> + */ + public Dimension preferredSize(int rows) + { + ListPeer peer = (ListPeer)getPeer(); + if (peer != null) + return peer.preferredSize(rows); + else + return getSize(); + } + + /** + * This method adds the specified item to the end of the list. + * + * @param item The item to add to the list. + * + * @since 1.1 + */ + public void add(String item) + { + add (item, -1); + } + + /** + * This method adds the specified item to the end of the list. + * + * @param item The item to add to the list. + * + * @deprecated Use add() instead. + */ + public void addItem(String item) + { + addItem(item, -1); + } + + /** + * Adds the specified item to the specified location in the list. + * If the desired index is -1 or greater than the number of rows + * in the list, then the item is added to the end. + * + * @param item The item to add to the list. + * @param index The location in the list to add the item, or -1 to add + * to the end. + * + * @since 1.1 + */ + public void add(String item, int index) + { + addItem(item, index); + } + + /** + * Adds the specified item to the specified location in the list. + * If the desired index is -1 or greater than the number of rows + * in the list, then the item is added to the end. + * + * @param item The item to add to the list. + * @param index The location in the list to add the item, or -1 to add + * to the end. + * + * @deprecated Use add() instead. + */ + public void addItem(String item, int index) + { + if (item == null) + item = ""; + + if (index < -1) + index = -1; + + if ((index == -1) || (index >= items.size ())) + items.addElement (item); + else + items.insertElementAt(item, index); + + ListPeer peer = (ListPeer) getPeer(); + if (peer != null) + peer.add (item, index); + } + + /** + * Deletes the item at the specified index. + * + * @param index The index of the item to delete. + * + * @exception IllegalArgumentException If the index is not valid + * + * @deprecated + */ + public void delItem(int index) throws IllegalArgumentException + { + boolean selected = false; + if (isSelected(index)) + { + selected = true; + deselect(index); + } + + items.removeElementAt (index); + + if (selected) + select(index); + + ListPeer peer = (ListPeer) getPeer(); + if (peer != null) + peer.delItems (index, index); + } + + /** + * Deletes the item at the specified index. + * + * @param index The index of the item to delete. + * + * @exception IllegalArgumentException If the index is not valid + * + * @since 1.1 + */ + public void remove(int index) throws IllegalArgumentException + { + delItem(index); + } + + /** + * Deletes all items in the specified index range. + * + * @param start The beginning index of the range to delete. + * @param end The ending index of the range to delete. + * + * @exception IllegalArgumentException If the indexes are not valid + * + * @deprecated This method is deprecated for some unknown reason. + */ + public synchronized void delItems(int start, int end) + throws IllegalArgumentException + { + // We must run the loop in reverse direction. + for (int i = end; i >= start; --i) + items.removeElementAt (i); + if (peer != null) + { + ListPeer l = (ListPeer) peer; + l.delItems (start, end); + } + } + + /** + * Deletes the first occurrence of the specified item from the list. + * + * @param item The item to delete. + * + * @exception IllegalArgumentException If the specified item does not exist. + * + * @since 1.1 + */ + public synchronized void remove(String item) throws IllegalArgumentException + { + int index = items.indexOf(item); + if (index == -1) + throw new IllegalArgumentException("List element to delete not found"); + + remove(index); + } + + /** + * Deletes all of the items from the list. + * + * @since 1.1 + */ + public synchronized void removeAll() + { + clear(); + } + + /** + * Deletes all of the items from the list. + * + * @deprecated This method is deprecated in favor of <code>removeAll()</code>. + */ + public void clear() + { + items.clear(); + + ListPeer peer = (ListPeer) getPeer(); + if (peer != null) + peer.removeAll(); + + selected = new int[0]; + } + + /** + * Replaces the item at the specified index with the specified item. + * + * @param item The new item value. + * @param index The index of the item to replace. + * + * @exception ArrayIndexOutOfBoundsException If the index is not valid. + */ + public synchronized void replaceItem(String item, int index) + throws ArrayIndexOutOfBoundsException + { + if ((index < 0) || (index >= items.size())) + throw new ArrayIndexOutOfBoundsException("Bad list index: " + index); + + items.insertElementAt(item, index + 1); + items.removeElementAt (index); + + if (peer != null) + { + ListPeer l = (ListPeer) peer; + + /* We add first and then remove so that the selected + item remains the same */ + l.add (item, index + 1); + l.delItems (index, index); + } + } + + /** + * Returns the index of the currently selected item. -1 will be returned + * if there are no selected rows or if there are multiple selected rows. + * + * @return The index of the selected row. + */ + public synchronized int getSelectedIndex() + { + if (peer != null) + { + ListPeer l = (ListPeer) peer; + selected = l.getSelectedIndexes (); + } + + if (selected == null || selected.length != 1) + return -1; + + return selected[0]; + } + + /** + * Returns an array containing the indexes of the rows that are + * currently selected. + * + * @return A list of indexes of selected rows. + */ + public synchronized int[] getSelectedIndexes() + { + if (peer != null) + { + ListPeer l = (ListPeer) peer; + selected = l.getSelectedIndexes(); + } + + return selected; + } + + /** + * Returns the item that is currently selected, or <code>null</code> if there + * is no item selected. FIXME: What happens if multiple items selected? + * + * @return The selected item, or <code>null</code> if there is no + * selected item. + */ + public synchronized String getSelectedItem() + { + int index = getSelectedIndex(); + if (index == -1) + return(null); + + return((String) items.elementAt(index)); + } + + /** + * Returns the list of items that are currently selected in this list. + * + * @return The list of currently selected items. + */ + public synchronized String[] getSelectedItems() + { + int[] indexes = getSelectedIndexes(); + if (indexes == null) + return(new String[0]); + + String[] retvals = new String[indexes.length]; + if (retvals.length > 0) + for (int i = 0 ; i < retvals.length; i++) + retvals[i] = (String)items.elementAt(indexes[i]); + + return(retvals); + } + + /** + * Returns the list of items that are currently selected in this list as + * an array of type <code>Object[]</code> instead of <code>String[]</code>. + * + * @return The list of currently selected items. + */ + public synchronized Object[] getSelectedObjects() + { + int[] indexes = getSelectedIndexes(); + if (indexes == null) + return(new Object[0]); + + Object[] retvals = new Object[indexes.length]; + if (retvals.length > 0) + for (int i = 0 ; i < retvals.length; i++) + retvals[i] = items.elementAt(indexes[i]); + + return(retvals); + } + + /** + * Tests whether or not the specified index is selected. + * + * @param index The index to test. + * + * @return <code>true</code> if the index is selected, <code>false</code> + * otherwise. + * + * @since 1.1 + */ + public boolean isIndexSelected(int index) + { + return isSelected(index); + } + + /** + * Tests whether or not the specified index is selected. + * + * @param index The index to test. + * + * @return <code>true</code> if the index is selected, <code>false</code> + * otherwise. + * + * @deprecated This method is deprecated in favor of + * <code>isIndexSelected(int)</code>. + */ + public boolean isSelected(int index) + { + int[] indexes = getSelectedIndexes(); + + for (int i = 0; i < indexes.length; i++) + if (indexes[i] == index) + return true; + + return false; + } + + /** + * This method ensures that the item at the specified index is visible. + * + * @param index The index of the item to be made visible. + */ + public synchronized void makeVisible(int index) + throws IllegalArgumentException + { + visibleIndex = index; + if (peer != null) + { + ListPeer l = (ListPeer) peer; + l.makeVisible (index); + } + } + + /** + * Returns the index of the last item that was made visible via the + * <code>makeVisible()</code> method. + * + * @return The index of the last item made visible via the + * <code>makeVisible()</code> method. + */ + public int getVisibleIndex() + { + return visibleIndex; + } + + /** + * Makes the item at the specified index selected. + * + * @param index The index of the item to select. + */ + public synchronized void select(int index) + { + ListPeer lp = (ListPeer) getPeer(); + if (lp != null) + lp.select(index); + + if (selected != null) + { + boolean found = false; + for (int i = 0; i < selected.length; i++) + { + if (selected[i] == index) + found = true; + } + if (! found) + { + if (! isMultipleMode()) + { + selected = new int[] { index }; + return; + } + int[] temp = new int[selected.length + 1]; + System.arraycopy(selected, 0, temp, 0, selected.length); + temp[selected.length] = index; + selected = temp; + } + } + else + { + selected = new int[1]; + selected[0] = index; + } + } + + /** + * Makes the item at the specified index not selected. + * + * @param index The index of the item to unselect. + */ + public synchronized void deselect(int index) + { + if (isSelected(index)) + { + ListPeer lp = (ListPeer)getPeer(); + if (lp != null) + lp.deselect(index); + + int[] temp = new int[selected.length - 1]; + for (int i = 0; i < temp.length; i++) + { + if (selected[i] != index) + temp[i] = selected[i]; + else + { + System.arraycopy(selected, i + 1, temp, i, + selected.length - i - 1); + break; + } + } + selected = temp; + } + } + + /** + * Notifies this object to create its native peer. + */ + public void addNotify() + { + if (peer == null) + peer = getToolkit ().createList(this); + super.addNotify (); + } + + /** + * Notifies this object to destroy its native peer. + */ + public void removeNotify() + { + super.removeNotify(); + } + + /** + * Adds the specified <code>ActionListener</code> to the list of + * registered listeners for this object. + * + * @param listener The listener to add. + * + * @since 1.1 + */ + public synchronized void addActionListener(ActionListener listener) + { + action_listeners = AWTEventMulticaster.add(action_listeners, listener); + } + + /** + * Removes the specified <code>ActionListener</code> from the list of + * registers listeners for this object. + * + * @param listener The listener to remove. + * + * @since 1.1 + */ + public synchronized void removeActionListener(ActionListener listener) + { + action_listeners = AWTEventMulticaster.remove(action_listeners, listener); + } + + /** + * Adds the specified <code>ItemListener</code> to the list of + * registered listeners for this object. + * + * @param listener The listener to add. + * + * @since 1.1 + */ + public synchronized void addItemListener(ItemListener listener) + { + item_listeners = AWTEventMulticaster.add(item_listeners, listener); + } + + /** + * Removes the specified <code>ItemListener</code> from the list of + * registers listeners for this object. + * + * @param listener The listener to remove. + * + * @since 1.1 + */ + public synchronized void removeItemListener(ItemListener listener) + { + item_listeners = AWTEventMulticaster.remove(item_listeners, listener); + } + + /** + * Processes the specified event for this object. If the event is an + * instance of <code>ActionEvent</code> then the + * <code>processActionEvent()</code> method is called. Similarly, if the + * even is an instance of <code>ItemEvent</code> then the + * <code>processItemEvent()</code> method is called. Otherwise the + * superclass method is called to process this event. + * + * @param event The event to process. + * + * @since 1.1 + */ + protected void processEvent(AWTEvent event) + { + if (event instanceof ActionEvent) + processActionEvent((ActionEvent)event); + else if (event instanceof ItemEvent) + processItemEvent((ItemEvent)event); + else + super.processEvent(event); + } + + /** + * This method processes the specified event by dispatching it to any + * registered listeners. Note that this method will only get called if + * action events are enabled. This will happen automatically if any + * listeners are added, or it can be done "manually" by calling + * the <code>enableEvents()</code> method. + * + * @param event The event to process. + * + * @since 1.1 + */ + protected void processActionEvent(ActionEvent event) + { + if (action_listeners != null) + action_listeners.actionPerformed(event); + } + + /** + * This method processes the specified event by dispatching it to any + * registered listeners. Note that this method will only get called if + * item events are enabled. This will happen automatically if any + * listeners are added, or it can be done "manually" by calling + * the <code>enableEvents()</code> method. + * + * @param event The event to process. + * + * @since 1.1 + */ + protected void processItemEvent(ItemEvent event) + { + if (item_listeners != null) + item_listeners.itemStateChanged(event); + } + + void dispatchEventImpl(AWTEvent e) + { + if (e.id <= ItemEvent.ITEM_LAST + && e.id >= ItemEvent.ITEM_FIRST + && (item_listeners != null + || (eventMask & AWTEvent.ITEM_EVENT_MASK) != 0)) + processEvent(e); + else if (e.id <= ActionEvent.ACTION_LAST + && e.id >= ActionEvent.ACTION_FIRST + && (action_listeners != null + || (eventMask & AWTEvent.ACTION_EVENT_MASK) != 0)) + processEvent(e); + else + super.dispatchEventImpl(e); + } + + /** + * Returns a debugging string for this object. + * + * @return A debugging string for this object. + */ + protected String paramString() + { + return "multiple=" + multipleMode + ",rows=" + rows + super.paramString(); + } + + /** + * Returns an array of all the objects currently registered as FooListeners + * upon this <code>List</code>. FooListeners are registered using the + * addFooListener method. + * + * @exception ClassCastException If listenerType doesn't specify a class or + * interface that implements java.util.EventListener. + * + * @since 1.3 + */ + public <T extends EventListener> T[] getListeners (Class<T> listenerType) + { + if (listenerType == ActionListener.class) + return AWTEventMulticaster.getListeners (action_listeners, listenerType); + + if (listenerType == ItemListener.class) + return AWTEventMulticaster.getListeners (item_listeners, listenerType); + + return super.getListeners (listenerType); + } + + /** + * Returns all action listeners registered to this object. + * + * @since 1.4 + */ + public ActionListener[] getActionListeners () + { + return (ActionListener[]) getListeners (ActionListener.class); + } + + /** + * Returns all action listeners registered to this object. + * + * @since 1.4 + */ + public ItemListener[] getItemListeners () + { + return (ItemListener[]) getListeners (ItemListener.class); + } + + // Accessibility internal class + protected class AccessibleAWTList extends AccessibleAWTComponent + implements AccessibleSelection, ItemListener, ActionListener + { + private static final long serialVersionUID = 7924617370136012829L; + + protected class AccessibleAWTListChild extends AccessibleAWTComponent + implements Accessible + { + private static final long serialVersionUID = 4412022926028300317L; + + // Field names are fixed by serialization spec. + private List parent; + private int indexInParent; + + public AccessibleAWTListChild(List parent, int indexInParent) + { + this.parent = parent; + this.indexInParent = indexInParent; + if (parent == null) + this.indexInParent = -1; + } + + /* (non-Javadoc) + * @see javax.accessibility.Accessible#getAccessibleContext() + */ + public AccessibleContext getAccessibleContext() + { + return this; + } + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.LIST_ITEM; + } + + public AccessibleStateSet getAccessibleStateSet() + { + AccessibleStateSet states = super.getAccessibleStateSet(); + if (parent.isIndexSelected(indexInParent)) + states.add(AccessibleState.SELECTED); + return states; + } + + public int getAccessibleIndexInParent() + { + return indexInParent; + } + + } + + public AccessibleAWTList() + { + addItemListener(this); + addActionListener(this); + } + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.LIST; + } + + public AccessibleStateSet getAccessibleStateSet() + { + AccessibleStateSet states = super.getAccessibleStateSet(); + states.add(AccessibleState.SELECTABLE); + if (isMultipleMode()) + states.add(AccessibleState.MULTISELECTABLE); + return states; + } + + public int getAccessibleChildrenCount() + { + return getItemCount(); + } + + public Accessible getAccessibleChild(int i) + { + if (i >= getItemCount()) + return null; + return new AccessibleAWTListChild(List.this, i); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleSelection#getAccessibleSelectionCount() + */ + public int getAccessibleSelectionCount() + { + return getSelectedIndexes().length; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleSelection#getAccessibleSelection() + */ + public AccessibleSelection getAccessibleSelection() + { + return this; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleSelection#getAccessibleSelection(int) + */ + public Accessible getAccessibleSelection(int i) + { + int[] items = getSelectedIndexes(); + if (i >= items.length) + return null; + return new AccessibleAWTListChild(List.this, items[i]); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleSelection#isAccessibleChildSelected(int) + */ + public boolean isAccessibleChildSelected(int i) + { + return isIndexSelected(i); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleSelection#addAccessibleSelection(int) + */ + public void addAccessibleSelection(int i) + { + select(i); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleSelection#removeAccessibleSelection(int) + */ + public void removeAccessibleSelection(int i) + { + deselect(i); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleSelection#clearAccessibleSelection() + */ + public void clearAccessibleSelection() + { + for (int i = 0; i < getItemCount(); i++) + deselect(i); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleSelection#selectAllAccessibleSelection() + */ + public void selectAllAccessibleSelection() + { + if (isMultipleMode()) + for (int i = 0; i < getItemCount(); i++) + select(i); + } + + /* (non-Javadoc) + * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent) + */ + public void itemStateChanged(ItemEvent event) + { + } + + /* (non-Javadoc) + * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) + */ + public void actionPerformed(ActionEvent event) + { + } + + } + + /** + * Gets the AccessibleContext associated with this <code>List</code>. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTList(); + return accessibleContext; + } + + /** + * Generate a unique name for this <code>List</code>. + * + * @return A unique name for this <code>List</code>. + */ + String generateName() + { + return "list" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_list_number++; + } +} // class List diff --git a/libjava/classpath/java/awt/MediaTracker.java b/libjava/classpath/java/awt/MediaTracker.java new file mode 100644 index 000000000..e69d23e8b --- /dev/null +++ b/libjava/classpath/java/awt/MediaTracker.java @@ -0,0 +1,698 @@ +/* MediaTracker.java -- Class used for keeping track of images + Copyright (C) 1999, 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.image.ImageObserver; +import java.util.ArrayList; + +/** + * This class is used for keeping track of the status of various media + * objects. + * + * Media objects are tracked by assigning them an ID. It is possible + * to assign the same ID to mutliple objects, effectivly grouping them + * together. In this case the status flags ({@link #statusID}) and error flag + * (@link #isErrorID} and {@link #getErrorsID}) are ORed together. This + * means that you cannot say exactly which media object has which status, + * at most you can say that there <em>are</em> certain media objects with + * some certain status. + * + * At the moment only images are supported by this class. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Bryce McKinlay + */ +public class MediaTracker implements java.io.Serializable +{ + /** Indicates that the media is still loading. */ + public static final int LOADING = 1 << 0; + + /** Indicates that the loading operation has been aborted. */ + public static final int ABORTED = 1 << 1; + + /** Indicates that an error has occured during loading of the media. */ + public static final int ERRORED = 1 << 2; + + /** Indicates that the media has been successfully and completely loaded. */ + public static final int COMPLETE = 1 << 3; + + /** The component on which the media is eventually been drawn. */ + Component target; + + /** The head of the linked list of tracked media objects. */ + MediaEntry head; + + /** Our serialVersionUID for serialization. */ + static final long serialVersionUID = -483174189758638095L; + + /** + * This represents a media object that is tracked by a MediaTracker. + * It also implements a simple linked list. + */ + // FIXME: The serialized form documentation says MediaEntry is a + // serializable field, but the serialized form of MediaEntry itself + // doesn't appear to be documented. + class MediaEntry implements ImageObserver + { + /** The ID of the media object. */ + int id; + + /** The media object. (only images are supported ATM). */ + Image image; + + /** The link to the next entry in the list. */ + MediaEntry next; + + /** The tracking status. */ + int status; + + /** The width of the image. */ + int width; + + /** The height of the image. */ + int height; + + /** + * Receives notification from an {@link java.awt.image.ImageProducer} + * that more data of the image is available. + * + * @param img the image that is updated + * @param flags flags from the ImageProducer that indicate the status + * of the loading process + * @param x the X coordinate of the upper left corner of the image + * @param y the Y coordinate of the upper left corner of the image + * @param width the width of the image + * @param height the height of the image + * + * @return <code>true</code> if more data is needed, <code>false</code> + * otherwise + * + * @see java.awt.image.ImageObserver + */ + public boolean imageUpdate(Image img, int flags, int x, int y, + int width, int height) + { + if ((flags & ABORT) != 0) + status = ABORTED; + else if ((flags & ERROR) != 0) + status = ERRORED; + else if ((flags & ALLBITS) != 0) + status = COMPLETE; + else + status = 0; + + synchronized (MediaTracker.this) + { + MediaTracker.this.notifyAll(); + } + + // If status is not COMPLETE then we need more updates. + return ((status & (COMPLETE | ERRORED | ABORTED)) == 0); + } + } + + /** + * Constructs a new MediaTracker for the component <code>c</code>. The + * component should be the component that uses the media (i.e. draws it). + * + * @param c the Component that wants to use the media + */ + public MediaTracker(Component c) + { + target = c; + } + + /** + * Adds an image to the tracker with the specified <code>ID</code>. + * + * @param image the image to be added + * @param id the ID of the tracker list to which the image is added + */ + public void addImage(Image image, int id) + { + MediaEntry e = new MediaEntry(); + e.id = id; + e.image = image; + synchronized(this) + { + e.next = head; + head = e; + } + } + + /** + * Adds an image to the tracker with the specified <code>ID</code>. + * The image is expected to be rendered with the specified width and + * height. + * + * @param image the image to be added + * @param id the ID of the tracker list to which the image is added + * @param width the width of the image + * @param height the height of the image + */ + public void addImage(Image image, int id, int width, int height) + { + MediaEntry e = new MediaEntry(); + e.id = id; + e.image = image; + e.width = width; + e.height = height; + synchronized(this) + { + e.next = head; + head = e; + } + } + + /** + * Checks if all media objects have finished loading, i.e. are + * {@link #COMPLETE}, {@link #ABORTED} or {@link #ERRORED}. + * + * If the media objects are not already loading, a call to this + * method does <em>not</em> start loading. This is equivalent to + * a call to <code>checkAll(false)</code>. + * + * @return if all media objects have finished loading either by beeing + * complete, have been aborted or errored. + */ + public boolean checkAll() + { + return checkAll(false); + } + + /** + * Checks if all media objects have finished loading, i.e. are + * {@link #COMPLETE}, {@link #ABORTED} or {@link #ERRORED}. + * + * If the media objects are not already loading, and <code>load</code> + * is <code>true</code> then a call to this + * method starts loading the media objects. + * + * @param load if <code>true</code> this method starts loading objects + * that are not already loading + * + * @return if all media objects have finished loading either by beeing + * complete, have been aborted or errored. + */ + public boolean checkAll(boolean load) + { + MediaEntry e = head; + boolean result = true; + + while (e != null) + { + if ((e.status & (COMPLETE | ERRORED | ABORTED)) == 0) + { + if (load && ((e.status & LOADING) == 0)) + { + if (target.prepareImage(e.image, e)) + e.status = COMPLETE; + else + { + e.status = LOADING; + int flags = target.checkImage(e.image, e); + if ((flags & ImageObserver.ABORT) != 0) + e.status = ABORTED; + else if ((flags & ImageObserver.ERROR) != 0) + e.status = ERRORED; + else if ((flags & ImageObserver.ALLBITS) != 0) + e.status = COMPLETE; + } + boolean complete = (e.status + & (COMPLETE | ABORTED | ERRORED)) != 0; + if (!complete) + result = false; + } + else + result = false; + } + e = e.next; + } + return result; + } + + /** + * Checks if any of the registered media objects has encountered an error + * during loading. + * + * @return <code>true</code> if at least one media object has encountered + * an error during loading, <code>false</code> otherwise + * + */ + public boolean isErrorAny() + { + MediaEntry e = head; + while (e != null) + { + if ((e.status & ERRORED) != 0) + return true; + e = e.next; + } + return false; + } + + /** + * Returns all media objects that have encountered errors during loading. + * + * @return an array of all media objects that have encountered errors + * or <code>null</code> if there were no errors at all + */ + public Object[] getErrorsAny() + { + MediaEntry e = head; + ArrayList result = null; + while (e != null) + { + if ((e.status & ERRORED) != 0) + { + if (result == null) + result = new ArrayList(); + result.add(e.image); + } + e = e.next; + } + if (result == null) + return null; + else + return result.toArray(); + } + + /** + * Waits for all media objects to finish loading, either by completing + * successfully or by aborting or encountering an error. + * + * @throws InterruptedException if another thread interrupted the + * current thread while waiting + */ + public void waitForAll() throws InterruptedException + { + synchronized (this) + { + while (checkAll(true) == false) + wait(); + } + } + + /** + * Waits for all media objects to finish loading, either by completing + * successfully or by aborting or encountering an error. + * + * This method waits at most <code>ms</code> milliseconds. If the + * media objects have not completed loading within this timeframe, this + * method returns <code>false</code>, otherwise <code>true</code>. + * + * @param ms timeframe in milliseconds to wait for the media objects to + * finish + * + * @return <code>true</code> if all media objects have successfully loaded + * within the timeframe, <code>false</code> otherwise + * + * @throws InterruptedException if another thread interrupted the + * current thread while waiting + */ + public boolean waitForAll(long ms) throws InterruptedException + { + long start = System.currentTimeMillis(); + boolean result = checkAll(true); + synchronized (this) + { + while (result == false) + { + wait(ms); + result = checkAll(true); + if ((System.currentTimeMillis() - start) > ms) + break; + } + } + + return result; + } + + /** + * Returns the status flags of all registered media objects ORed together. + * If <code>load</code> is <code>true</code> then media objects that + * are not already loading will be started to load. + * + * @param load if set to <code>true</code> then media objects that are + * not already loading are started + * + * @return the status flags of all tracked media objects ORed together + */ + public int statusAll(boolean load) + { + int result = 0; + MediaEntry e = head; + while (e != null) + { + if (load && e.status == 0) + { + if (target.prepareImage(e.image, e)) + e.status = COMPLETE; + else + { + e.status = LOADING; + int flags = target.checkImage(e.image, e); + if ((flags & ImageObserver.ABORT) != 0) + e.status = ABORTED; + else if ((flags & ImageObserver.ERROR) != 0) + e.status = ERRORED; + else if ((flags & ImageObserver.ALLBITS) != 0) + e.status = COMPLETE; + } + } + result |= e.status; + e = e.next; + } + return result; + } + + /** + * Checks if the media objects with <code>ID</code> have completed loading. + * + * @param id the ID of the media objects to check + * + * @return <code>true</code> if all media objects with <code>ID</code> + * have successfully finished + */ + public boolean checkID(int id) + { + return checkID(id, false); + } + + /** + * Checks if the media objects with <code>ID</code> have completed loading. + * If <code>load</code> is <code>true</code> then media objects that + * are not already loading will be started to load. + * + * @param id the ID of the media objects to check + * @param load if set to <code>true</code> then media objects that are + * not already loading are started + * + * @return <code>true</code> if all media objects with <code>ID</code> + * have successfully finished + */ + public boolean checkID(int id, boolean load) + { + MediaEntry e = head; + boolean result = true; + + while (e != null) + { + if (e.id == id && ((e.status & (COMPLETE | ABORTED | ERRORED)) == 0)) + { + if (load && ((e.status & LOADING) == 0)) + { + e.status = LOADING; + if (target.prepareImage(e.image, e)) + e.status = COMPLETE; + else + { + int flags = target.checkImage(e.image, e); + if ((flags & ImageObserver.ABORT) != 0) + e.status = ABORTED; + else if ((flags & ImageObserver.ERROR) != 0) + e.status = ERRORED; + else if ((flags & ImageObserver.ALLBITS) != 0) + e.status = COMPLETE; + } + boolean complete = (e.status + & (COMPLETE | ABORTED | ERRORED)) != 0; + if (!complete) + result = false; + } + else + result = false; + } + e = e.next; + } + return result; + } + + /** + * Returns <code>true</code> if any of the media objects with <code>ID</code> + * have encountered errors during loading, false otherwise. + * + * @param id the ID of the media objects to check + * + * @return <code>true</code> if any of the media objects with <code>ID</code> + * have encountered errors during loading, false otherwise + */ + public boolean isErrorID(int id) + { + MediaEntry e = head; + while (e != null) + { + if (e.id == id && ((e.status & ERRORED) != 0)) + return true; + e = e.next; + } + return false; + } + + /** + * Returns all media objects with the specified ID that have encountered + * an error. + * + * @param id the ID of the media objects to check + * + * @return an array of all media objects with the specified ID that + * have encountered an error + */ + public Object[] getErrorsID(int id) + { + MediaEntry e = head; + ArrayList result = null; + while (e != null) + { + if (e.id == id && ((e.status & ERRORED) != 0)) + { + if (result == null) + result = new ArrayList(); + result.add(e.image); + } + e = e.next; + } + if (result == null) + return null; + else + return result.toArray(); + } + + /** + * Waits for all media objects with the specified ID to finish loading, + * either by completing successfully or by aborting or encountering an error. + * + * @param id the ID of the media objects to wait for + * + * @throws InterruptedException if another thread interrupted the + * current thread while waiting + */ + public void waitForID(int id) throws InterruptedException + { + MediaEntry e = head; + synchronized (this) + { + while (checkID (id, true) == false) + wait(); + } + } + + /** + * Waits for all media objects with the specified ID to finish loading, + * either by completing successfully or by aborting or encountering an error. + * + * This method waits at most <code>ms</code> milliseconds. If the + * media objects have not completed loading within this timeframe, this + * method returns <code>false</code>, otherwise <code>true</code>. + * + * @param id the ID of the media objects to wait for + * @param ms timeframe in milliseconds to wait for the media objects to + * finish + * + * @return <code>true</code> if all media objects have successfully loaded + * within the timeframe, <code>false</code> otherwise + * + * @throws InterruptedException if another thread interrupted the + * current thread while waiting + */ + public boolean waitForID(int id, long ms) throws InterruptedException + { + MediaEntry e = head; + long start = System.currentTimeMillis(); + boolean result = checkID(id, true); + + synchronized (this) + { + while (result == false) + { + wait(ms); + result = checkID(id, true); + if ((System.currentTimeMillis() - start) > ms) + break; + } + } + + return result; + } + + /** + * Returns the status flags of the media objects with the specified ID + * ORed together. + * + * If <code>load</code> is <code>true</code> then media objects that + * are not already loading will be started to load. + * + * @param load if set to <code>true</code> then media objects that are + * not already loading are started + * + * @return the status flags of all tracked media objects ORed together + */ + public int statusID(int id, boolean load) + { + int result = 0; + MediaEntry e = head; + while (e != null) + { + if (e.id == id) + { + if (load && e.status == 0) + { + if (target.prepareImage(e.image, e)) + e.status = COMPLETE; + else + { + e.status = LOADING; + int flags = target.checkImage(e.image, e); + if ((flags & ImageObserver.ABORT) != 0) + e.status = ABORTED; + else if ((flags & ImageObserver.ERROR) != 0) + e.status = ERRORED; + else if ((flags & ImageObserver.ALLBITS) != 0) + e.status = COMPLETE; + } + } + result |= e.status; + } + e = e.next; + } + return result; + } + + /** + * Removes an image from this MediaTracker. + * + * @param image the image to be removed + */ + public void removeImage(Image image) + { + synchronized (this) + { + MediaEntry e = head; + MediaEntry prev = null; + while (e != null) + { + if (e.image == image) + { + if (prev == null) + head = e.next; + else + prev.next = e.next; + } + else + prev = e; + e = e.next; + } + } + } + + /** + * Removes an image with the specified ID from this MediaTracker. + * + * @param image the image to be removed + */ + public void removeImage(Image image, int id) + { + synchronized (this) + { + MediaEntry e = head; + MediaEntry prev = null; + while (e != null) + { + if (e.id == id && e.image == image) + { + if (prev == null) + head = e.next; + else + prev.next = e.next; + } + else + prev = e; + e = e.next; + } + } + } + + /** + * Removes an image with the specified ID and scale from this MediaTracker. + * + * @param image the image to be removed + */ + public void removeImage(Image image, int id, int width, int height) + { + synchronized (this) + { + MediaEntry e = head; + MediaEntry prev = null; + while (e != null) + { + if (e.id == id && e.image == image + && e.width == width && e.height == height) + { + if (prev == null) + head = e.next; + else + prev.next = e.next; + } + else + prev = e; + e = e.next; + } + } + } +} diff --git a/libjava/classpath/java/awt/Menu.java b/libjava/classpath/java/awt/Menu.java new file mode 100644 index 000000000..c640b5e85 --- /dev/null +++ b/libjava/classpath/java/awt/Menu.java @@ -0,0 +1,444 @@ +/* Menu.java -- A Java AWT Menu + Copyright (C) 1999, 2002, 2004, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.peer.MenuPeer; +import java.io.Serializable; +import java.util.Enumeration; +import java.util.Vector; + +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; + +/** + * This class represents a pull down or tear off menu in Java's AWT. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class Menu extends MenuItem implements MenuContainer, Serializable +{ + + /** + * The number used to generate the name returned by getName. + */ + private static transient long next_menu_number; + + // Serialization Constant + private static final long serialVersionUID = -8809584163345499784L; + + /** + * @serial The actual items in the menu + */ + private Vector items = new Vector(); + + /** + * @serial Flag indicating whether or not this menu is a tear off + */ + private boolean tearOff; + + /** + * @serial Indicates whether or not this is a help menu. + */ + private boolean isHelpMenu; + + /* + * @serial Unused in this implementation, but present in Sun's + * serialization spec. Value obtained via reflection. + */ + private int menuSerializedDataVersion = 1; + + static final transient String separatorLabel = "-"; + + /** + * Initializes a new instance of <code>Menu</code> with no label and that + * is not a tearoff; + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public Menu() + { + } + + /** + * Initializes a new instance of <code>Menu</code> that is not a tearoff and + * that has the specified label. + * + * @param label The menu label. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public Menu(String label) + { + this(label, false); + } + + /** + * Initializes a new instance of <code>Menu</code> with the specified + * label and tearoff status. + * + * @param label The label for this menu + * @param isTearOff <code>true</code> if this menu is a tear off menu, + * <code>false</code> otherwise. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public Menu(String label, boolean isTearOff) + { + super(label); + + tearOff = isTearOff; + + if (label.equals("Help")) + isHelpMenu = true; + + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException(); + } + + /** + * Tests whether or not this menu is a tearoff. + * + * @return <code>true</code> if this menu is a tearoff, <code>false</code> + * otherwise. + */ + public boolean isTearOff() + { + return(tearOff); + } + + /** + * Returns the number of items in this menu. + * + * @return The number of items in this menu. + */ + public int getItemCount() + { + return countItems(); + } + + /** + * Returns the number of items in this menu. + * + * @return The number of items in this menu. + * + * @deprecated As of JDK 1.1, replaced by getItemCount(). + */ + public int countItems() + { + return items.size(); + } + + /** + * Returns the item at the specified index. + * + * @param index the item index. + * + * @return The item at the specified index. + * + * @exception ArrayIndexOutOfBoundsException If the index value is not valid. + */ + public MenuItem getItem(int index) + { + return((MenuItem) items.elementAt(index)); + } + + /** + * Adds the specified item to this menu. If it was previously part of + * another menu, it is first removed from that menu. + * + * @param item The new item to add. + * + * @return The item that was added. + */ + public MenuItem add(MenuItem item) + { + MenuContainer parent = item.getParent(); + if (parent != null) + parent.remove(item); + + items.addElement(item); + item.setParent(this); + + if (peer != null) + { + item.addNotify(); + MenuPeer mp = (MenuPeer) peer; + mp.addItem(item); + } + + return item; + } + + /** + * Add an item with the specified label to this menu. + * + * @param label The label of the menu item to add. + */ + public void add(String label) + { + add(new MenuItem(label)); + } + + /** + * Inserts the specified menu item into this menu at the specified index. If + * the index is greater than or equal to the number of items already in the + * menu, the new item is added as the last item in the menu. + * + * @param item The menu item to add (<code>null</code> not permitted). + * @param index The index of the menu item (>= 0). + * + * @throws IllegalArgumentException if the index is less than zero. + * @throws NullPointerException if <code>item</code> is <code>null</code>. + */ + public void insert(MenuItem item, int index) + { + if (index < 0) + throw new IllegalArgumentException("Index is less than zero"); + + int count = getItemCount(); + + if (index >= count) + add(item); + else + { + MenuContainer parent = item.getParent(); + if (parent != null) + parent.remove(item); + + items.insertElementAt(item, index); + item.setParent(this); + + MenuPeer peer = (MenuPeer) getPeer(); + if (peer == null) + return; + + for (int i = count - 1; i >= index; i--) + peer.delItem(i); + + item.addNotify(); + peer.addItem(item); + + // bear in mind that count is the number of items *before* the new + // item was added + for (int i = index + 1; i <= count; i++) + peer.addItem((MenuItem) items.elementAt(i)); + } + + } + + /** + * Inserts an item with the specified label into this menu at the specified + * index. If the index is greater than or equal to the number of items + * already in the menu, the new item is added as the last item in the menu. + * + * @param label The label of the item to add. + * @param index The index of the menu item (>= 0). + * + * @throws IllegalArgumentException If the index is less than zero. + */ + public void insert(String label, int index) + { + insert(new MenuItem(label), index); + } + + /** + * Adds a separator bar at the current menu location. + */ + public void addSeparator() + { + add(new MenuItem(separatorLabel)); + } + + /** + * Inserts a separator bar at the specified index value. + * + * @param index The index at which to insert a separator bar. + * + * @exception IllegalArgumentException If the index is less than zero. + * @exception ArrayIndexOutOfBoundsException If the index is otherwise invalid. + */ + public void insertSeparator(int index) + { + insert(new MenuItem(separatorLabel), index); + } + + /** + * Deletes the item at the specified index from this menu. + * + * @param index The index of the item to remove. + * + * @exception ArrayIndexOutOfBoundsException If the index is otherwise invalid. + */ + public synchronized void remove(int index) + { + MenuItem item = (MenuItem) items.remove(index); + + MenuPeer mp = (MenuPeer) getPeer(); + if (mp != null) + { + mp.delItem(index); + item.removeNotify(); + } + item.setParent(null); + } + + /** + * Removes the specifed item from the menu. If the specified component + * does not exist, this method does nothing. + * + * @param item The component to remove. + */ + public void remove(MenuComponent item) + { + int index = items.indexOf(item); + if (index == -1) + return; + + remove(index); + } + + /** + * Removes all the elements from this menu. + */ + public synchronized void removeAll() + { + int count = getItemCount(); + for(int i = 0; i < count; i++) + { + // We must always remove item 0. + remove(0); + } + } + + /** + * Creates the native peer for this object. + */ + public void addNotify() + { + MenuPeer peer = (MenuPeer) getPeer(); + if (peer == null) + { + peer = getToolkit().createMenu(this); + setPeer(peer); + } + + Enumeration e = items.elements(); + while (e.hasMoreElements()) + { + MenuItem mi = (MenuItem)e.nextElement(); + mi.addNotify(); + peer.addItem(mi); + } + + super.addNotify(); + } + + /** + * Destroys the native peer for this object. + */ + public void removeNotify() + { + Enumeration e = items.elements(); + while (e.hasMoreElements()) + { + MenuItem mi = (MenuItem) e.nextElement(); + mi.removeNotify(); + } + super.removeNotify(); + } + + /** + * Returns a debugging string for this menu. + * + * @return A debugging string for this menu. + */ + public String paramString() + { + return (",tearOff=" + tearOff + ",isHelpMenu=" + isHelpMenu + + super.paramString()); + } + + /** + * Basic Accessibility class for Menu. Details get provided in derived + * classes. + */ + protected class AccessibleAWTMenu extends AccessibleAWTMenuItem + { + private static final long serialVersionUID = 5228160894980069094L; + + protected AccessibleAWTMenu() + { + } + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.MENU; + } + } + + /** + * Gets the AccessibleContext associated with this <code>Menu</code>. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTMenu(); + return accessibleContext; + } + + /** + * Generate a unique name for this <code>Menu</code>. + * + * @return A unique name for this <code>Menu</code>. + */ + String generateName() + { + return "menu" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_menu_number++; + } + +} // class Menu diff --git a/libjava/classpath/java/awt/MenuBar.java b/libjava/classpath/java/awt/MenuBar.java new file mode 100644 index 000000000..3fc5622ac --- /dev/null +++ b/libjava/classpath/java/awt/MenuBar.java @@ -0,0 +1,390 @@ +/* MenuBar.java -- An AWT menu bar class + Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.peer.MenuBarPeer; + +import java.io.Serializable; +import java.util.Enumeration; +import java.util.Vector; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; + +/** + * This class implements a menu bar in the AWT system. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +public class MenuBar extends MenuComponent + implements MenuContainer, Serializable, Accessible +{ + + // Serialization Constant + private static final long serialVersionUID = -4930327919388951260L; + + /** + * The number used to generate the name returned by getName. + */ + private static transient long next_menubar_number; + + /** + * @serial The menu used for providing help information + */ + private Menu helpMenu; + + /** + * @serial The menus contained in this menu bar. + */ + private Vector menus = new Vector(); + + /** + * Initializes a new instance of <code>MenuBar</code>. + * + * @throws HeadlessException if GraphicsEnvironment.isHeadless() is true + */ + public MenuBar() + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException(); + } + + /** + * Returns the help menu for this menu bar. This may be <code>null</code>. + * + * @return the help menu for this menu bar + */ + public Menu getHelpMenu() + { + return helpMenu; + } + + /** + * Sets the help menu for this menu bar. + * + * @param menu the new help menu for this menu bar + */ + public synchronized void setHelpMenu(Menu menu) + { + MenuBarPeer myPeer = (MenuBarPeer) getPeer (); + + if (helpMenu != null) + { + if (myPeer != null) + helpMenu.removeNotify(); + helpMenu.setParent(null); + } + helpMenu = menu; + + MenuContainer parent = menu.getParent(); + if (parent != null) + parent.remove(menu); + menu.setParent(this); + + if (myPeer != null) + { + menu.addNotify(); + myPeer.addHelpMenu(menu); + } + } + + /** + * Add a menu to this MenuBar. If the menu has already has a + * parent, it is first removed from its old parent before being + * added. + * + * @param menu the menu to add + * + * @return the menu that was added + */ + public synchronized Menu add(Menu menu) + { + MenuBarPeer myPeer = (MenuBarPeer) getPeer (); + + MenuContainer parent = menu.getParent(); + if (parent != null) + parent.remove(menu); + + menus.addElement(menu); + menu.setParent(this); + + if (myPeer != null) + { + menu.addNotify(); + myPeer.addMenu(menu); + } + return menu; + } + + /** + * Removes the menu at the specified index. + * + * @param index the index of the menu to remove from the menu bar + */ + public synchronized void remove(int index) + { + Menu m = (Menu) menus.remove(index); + MenuBarPeer mp = (MenuBarPeer) getPeer(); + + if (mp != null) + m.removeNotify(); + + m.setParent(null); + + if (mp != null) + mp.delMenu(index); + } + + /** + * Removes the specified menu from the menu bar. + * + * @param menu the menu to remove from the menu bar + */ + public void remove(MenuComponent menu) + { + int index = menus.indexOf(menu); + if (index == -1) + return; + + remove(index); + } + + /** + * Returns the number of elements in this menu bar. + * + * @return the number of elements in the menu bar + */ + public int getMenuCount() + { + return countMenus(); + } + + /** + * Returns the number of elements in this menu bar. + * + * @return the number of elements in the menu bar + * + * @deprecated This method is deprecated in favor of + * <code>getMenuCount()</code>. + */ + public int countMenus() + { + return menus.size() + (getHelpMenu() == null ? 0 : 1); + } + + /** + * Returns the menu at the specified index. + * + * @param index the index of the menu + * + * @return the requested menu + * + * @throws ArrayIndexOutOfBoundsException if the index is not valid + */ + public Menu getMenu(int index) + { + return (Menu) menus.elementAt(index); + } + + /** + * Creates this object's native peer. + */ + public void addNotify() + { + MenuBarPeer peer = (MenuBarPeer) getPeer(); + if (peer == null) + { + peer = getToolkit().createMenuBar(this); + setPeer(peer); + } + + Enumeration e = menus.elements(); + while (e.hasMoreElements()) + { + Menu mi = (Menu)e.nextElement(); + mi.addNotify(); + peer.addMenu(mi); + } + + if (helpMenu != null) + { + helpMenu.addNotify(); + peer.addHelpMenu(helpMenu); + } + } + + /** + * Destroys this object's native peer. + */ + public void removeNotify() + { + Enumeration e = menus.elements(); + while (e.hasMoreElements()) + { + Menu mi = (Menu) e.nextElement(); + mi.removeNotify(); + } + super.removeNotify(); + } + + /** + * Returns a list of all shortcuts for the menus in this menu bar. + * + * @return a list of all shortcuts for the menus in this menu bar + */ + public synchronized Enumeration<MenuShortcut> shortcuts() + { + Vector shortcuts = new Vector(); + Enumeration e = menus.elements(); + + while (e.hasMoreElements()) + { + Menu menu = (Menu)e.nextElement(); + if (menu.getShortcut() != null) + shortcuts.addElement(menu.getShortcut()); + } + + return shortcuts.elements(); + } + + /** + * Returns the menu item for the specified shortcut, or <code>null</code> + * if no such item exists. + * + * @param shortcut the shortcut to return the menu item for + * + * @return the menu item for the specified shortcut + */ + public MenuItem getShortcutMenuItem(MenuShortcut shortcut) + { + Enumeration e = menus.elements(); + + while (e.hasMoreElements()) + { + Menu menu = (Menu) e.nextElement(); + MenuShortcut s = menu.getShortcut(); + if ((s != null) && s.equals(shortcut)) + return menu; + } + + return null; + } + + /** + * Deletes the specified menu shortcut. + * + * @param shortcut the shortcut to delete + */ + public void deleteShortcut(MenuShortcut shortcut) + { + MenuItem it; + // This is a slow implementation, but it probably doesn't matter. + while ((it = getShortcutMenuItem (shortcut)) != null) + it.deleteShortcut(); + } + + /** + * Gets the AccessibleContext associated with this <code>MenuBar</code>. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + // Create the context if this is the first request. + if (accessibleContext == null) + accessibleContext = new AccessibleAWTMenuBar(); + return accessibleContext; + } + + /** + * Generate a unique name for this <code>MenuBar</code>. + * + * @return A unique name for this <code>MenuBar</code>. + */ + String generateName() + { + return "menubar" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_menubar_number++; + } + + /** + * This class provides accessibility support for AWT menu bars. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ + protected class AccessibleAWTMenuBar + extends AccessibleAWTMenuComponent + { + + /** + * Compatible with JDK 1.4.2 revision 5 + */ + private static final long serialVersionUID = -8577604491830083815L; + + /** + * This is the default constructor, which simply calls the default + * constructor of the superclass. + */ + protected AccessibleAWTMenuBar() + { + super(); + } + + /** + * Returns the accessible role relating to the menu bar. + * + * @return <code>AccessibleRole.MENU_BAR</code> + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.MENU_BAR; + } + + } + +} diff --git a/libjava/classpath/java/awt/MenuComponent.java b/libjava/classpath/java/awt/MenuComponent.java new file mode 100644 index 000000000..fb0f14eb0 --- /dev/null +++ b/libjava/classpath/java/awt/MenuComponent.java @@ -0,0 +1,1302 @@ +/* MenuComponent.java -- Superclass of all AWT menu components + Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.peer.MenuComponentPeer; +import java.io.Serializable; +import java.util.Locale; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleComponent; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleSelection; +import javax.accessibility.AccessibleStateSet; + +/** + * This is the superclass of all menu AWT widgets. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +public abstract class MenuComponent implements Serializable +{ + +//Serialization Constant + private static final long serialVersionUID = -4536902356223894379L; + + /** + * The font for this component. + * + * @see #getFont() + * @see #setFont(java.awt.Font) + * @serial the component's font. + */ + private Font font; + + /** + * The name of the component. + * + * @see #getName() + * @see #setName(String) + * @serial the component's name. + */ + private String name; + + /** + * The parent of this component. + * + * @see #getParent() + * @see #setParent(java.awt.MenuContainer) + * @serial ignored. + */ + transient MenuContainer parent; + + /** + * The native peer for this component. + * + * @see #getPeer() + * @see #setPeer(java.awt.peer.MenuComponentPeer) + * @serial ignored. + */ + transient MenuComponentPeer peer; + + /** + * The synchronization locking object for this component. + * + * @serial ignored. + */ + private transient Object tree_lock = this; + + /** + * The toolkit for this object. + * + * @see #getToolkit() + * @serial ignored. + */ + private static transient Toolkit toolkit = Toolkit.getDefaultToolkit(); + + /** + * The accessible context for this component. + * + * @see #getAccessibleContext() + * @serial the accessibility information for this component. + */ + AccessibleContext accessibleContext; + + /** + * Was the name of the component set? This value defaults + * to false and becomes true after a call to <code>setName()</code>. + * Please note that this does not guarantee that name will then + * be non-null, as this may be the value passed to <code>setName()</code>. + * + * @see #setName(String) + * @serial true if the name value has been explicitly set by calling + * <code>setName()</code>. + */ + private boolean nameExplicitlySet; + + /** + * Does this component handle new events? Events will be handled + * by this component if this is true. Otherwise, they will be forwarded + * up the component hierarchy. This implementation does not use this + * variable; it is merely provided for serialization compatability. + * + * @see #dispatchEvent(AWTEvent) + * @serial true if events are to be processed locally. Unused. + */ + private boolean newEventsOnly; + + /** + * The focus listener chain handler which deals with focus events for + * the accessible context of this component. + * + * @see AccessibleAWTMenuComponent#addFocusListener(java.awt.event.FocusListener) + * @serial ignored. + * This is package-private to avoid an accessor method. + */ + transient FocusListener focusListener; + + /** + * Default constructor for subclasses. + * + * @throws HeadlessException ff GraphicsEnvironment.isHeadless() is true + */ + public MenuComponent() + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException(); + } + +/** + * Returns the font in use for this component. + * + * @return the font for this component + */ + public Font getFont() + { + if (font != null) + return font; + + if (parent != null) + return parent.getFont(); + + return null; + } + + /** + * Sets the font for this component to the specified font. + * + * @param font the new font for this component + */ + public void setFont(Font font) + { + this.font = font; + } + + /** + * Returns the name of this component. + * + * @return the name of this component + */ + public String getName() + { + if (name == null && ! nameExplicitlySet) + name = generateName(); + return name; + } + + /** + * Subclasses should override this to return unique component names like + * "menuitem0". + * + * @return the generated name for this menu component + */ + String generateName() + { + // MenuComponent is abstract. + return null; + } + + /** + * Sets the name of this component to the specified name. + * + * @param name the new name of this component + */ + public void setName(String name) + { + this.name = name; + nameExplicitlySet = true; + } + + /** + * Returns the parent of this component. + * + * @return the parent of this component + */ + public MenuContainer getParent() + { + return parent; + } + + /** + * Sets the parent of this component. + * + * @param parent the parent to set + */ + final void setParent(MenuContainer parent) + { + this.parent = parent; + } + + /** + * Returns the native windowing system peer for this component. + * + * @return the peer for this component + * + * @deprecated + */ + public MenuComponentPeer getPeer() + { + return peer; + } + + /** + * Sets the peer for this component. + * + * @param peer the peer to set + */ + final void setPeer(MenuComponentPeer peer) + { + this.peer = peer; + } + + /** + * Destroys this component's native peer + */ + public void removeNotify() + { + if (peer != null) + peer.dispose(); + peer = null; + } + + /** + * Returns the toolkit in use for this component. + * + * @return the toolkit for this component + */ + final Toolkit getToolkit() + { + return toolkit; + } + + /** + * Returns the object used for synchronization locks on this component + * when performing tree and layout functions. + * + * @return the synchronization lock for this component + */ + protected final Object getTreeLock() + { + return tree_lock; + } + + /** + * Sets the sync lock object for this component. + * + * @param treeLock the sync lock to set + */ + final void setTreeLock(Object treeLock) + { + this.tree_lock = treeLock; + } + + /** + * AWT 1.0 event dispatcher. + * + * @return true if the event was dispatched, false otherwise + * + * @deprecated Deprecated in favor of <code>dispatchEvent()</code>. + */ + public boolean + postEvent(Event event) + { + boolean retVal = false; + MenuContainer parent = getParent(); + if (parent != null) + retVal = parent.postEvent(event); + + return retVal; + } + + /** + * Sends this event to this component or a subcomponent for processing. + * + * @param event The event to dispatch + */ + public final void dispatchEvent(AWTEvent event) + { + // Convert AWT 1.1 event to AWT 1.0 event. + Event oldStyleEvent = Component.translateEvent(event); + if (oldStyleEvent != null) + { + postEvent(oldStyleEvent); + } + + // See comment in Component.dispatchEvent(). + dispatchEventImpl(event); + } + + /** + * Implementation of dispatchEvent. Allows trusted package classes + * to dispatch additional events first. This implementation first + * translates <code>event</code> to an AWT 1.0 event and sends the + * result to {@link #postEvent}. The event is then + * passed on to {@link #processEvent} for local processing. + * + * @param event the event to dispatch + */ + void dispatchEventImpl(AWTEvent event) + { + // Do local processing. + processEvent(event); + } + + /** + * Processes the specified event. In this class, this method simply + * calls one of the more specific event handlers. + * + * @param event the event to process + */ + protected void processEvent(AWTEvent event) + { + // Pass a focus event to the focus listener for + // the accessibility context. + if (event instanceof FocusEvent) + { + if (focusListener != null) + { + switch (event.id) + { + case FocusEvent.FOCUS_GAINED: + focusListener.focusGained((FocusEvent) event); + break; + case FocusEvent.FOCUS_LOST: + focusListener.focusLost((FocusEvent) event); + break; + } + } + } + } + + /** + * Returns a string representation of this component. + * + * @return a string representation of this component + */ + public String toString() + { + return getClass().getName() + "[" + paramString() + "]"; + } + + /** + * Returns a debugging string for this component + */ + protected String paramString() + { + return "name=" + getName(); + } + + /** + * Gets the AccessibleContext associated with this <code>MenuComponent</code>. + * As an abstract class, we return null. Concrete subclasses should return + * their implementation of the accessibility context. + * + * @return null + */ + public AccessibleContext getAccessibleContext() + { + return null; + } + + /** + * This class provides a base for the accessibility support of menu + * components. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ + protected abstract class AccessibleAWTMenuComponent + extends AccessibleContext + implements Serializable, AccessibleComponent, AccessibleSelection + { + + /** + * Compatible with JDK 1.4.2 revision 5 + */ + private static final long serialVersionUID = -4269533416223798698L; + + /** + * This is the default constructor. It should be called by + * concrete subclasses to ensure necessary groundwork is completed. + */ + protected AccessibleAWTMenuComponent() + { + // Nothing to do here. + } + + /** + * Replaces or supplements the component's selection with the + * <code>Accessible</code> child at the supplied index. If + * the component supports multiple selection, the child is + * added to the current selection. Otherwise, the current + * selection becomes the specified child. If the child is + * already selected, nothing happens. + * <br /> + * <br /> + * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + * + * @param index the index of the specified child within a + * zero-based list of the component's children + */ + public void addAccessibleSelection(int index) + { + // Subclasses with children should implement this. + } + + /** + * Registers the specified focus listener to receive + * focus events from this component. + * + * @param listener the new focus listener + */ + public void addFocusListener(FocusListener listener) + { + // Chain the new focus listener to the existing chain + // of focus listeners. Each new focus listener is + // coupled via multicasting to the existing chain. + focusListener = AWTEventMulticaster.add(focusListener, listener); + } + + /** + * Clears the component's current selection. Following + * the calling of this method, no children of the component + * will be selected. + * <br /> + * <br /> + * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + */ + public void clearAccessibleSelection() + { + // Nothing to do here. + } + + /** + * Returns true if the specified point lies within the + * component. The supplied co-ordinates are assumed to + * be relative to the co-ordinate system of the component + * itself. Thus, the point (0,0) is the upper left corner + * of this component. + * <br /> + * <br /> + * Please note that this method depends on a correctly implemented + * version of the <code>getBounds()</code> method. Subclasses + * must provide the bounding rectangle via <code>getBounds()</code> + * in order for this method to work. + * + * @param point the point to check against this component + * @return true if the point is within this component + * @see #getBounds() + */ + public boolean contains(Point point) + { + // We can simply return the result of a + // test for containment in the bounding rectangle. + return getBounds().contains(point); + } + + /** + * Returns the <code>Accessible</code> child of this component present + * at the specified point. The supplied co-ordinates are + * assumed to be relative to the co-ordinate system of this + * component (the parent of any returned accessible). Thus, + * the point (0,0) is the upper left corner of this menu + * component. + * <br /> + * <br /> + * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + * + * @param point the point at which the returned accessible + * is located + * @return null + */ + public Accessible getAccessibleAt(Point point) + { + return null; + } + + /** + * Returns the <code>Accessible</code> child at the supplied + * index within the list of children of this component. + * <br /> + * <br /> + * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + * + * @param index the index of the <code>Accessible</code> child + * to retrieve + * + * @return null + */ + public Accessible getAccessibleChild(int index) + { + return null; + } + + /** + * Returns the number of children of this component which + * implement the <code>Accessible</code> interface. If + * all children of this component are accessible, then + * the returned value will be the same as the number of + * children. + * <br /> + * <br /> + * + * @return 0 + */ + public int getAccessibleChildrenCount() + { + return 0; + } + + /** + * Retrieves the <code>AccessibleComponent</code> associated + * with this accessible context and its component. As the + * context itself implements <code>AccessibleComponent</code>, + * this is the return value. + * + * @return the context itself + */ + public AccessibleComponent getAccessibleComponent() + { + return this; + } + + /** + * Returns the accessible name for this menu component. This + * is the name given to the component, which may be null if + * not set using <code>setName()</code>. + * <br /> + * <br /> + * The name is not the most appropriate description of this + * object. Subclasses should preferably provide a more + * accurate description. For example, a File menu could + * have the description `Lists commands related to the + * file system'. + * + * @return a description of the component. Currently, + * this is just the contents of the name property + * + * @see MenuComponent#setName(String) + */ + public String getAccessibleDescription() + { + return MenuComponent.this.getName(); + } + + /** + * Retrieves the index of this component within its parent. + * If no parent exists, -1 is returned. + * + * @return -1 as the parent, a <code>MenuContainer</code> + * is not <code>Accessible</code> + */ + public int getAccessibleIndexInParent() + { + return -1; + } + + /** + * Returns the accessible name of this component. This + * is the name given to the component, which may be null if + * not set using <code>setName()</code>. + * <br /> + * <br /> + * The name property is not the most suitable string to return + * for this method. The string should be localized, and + * relevant to the operation of the component. For example, + * it could be the text of a menu item. However, this can + * not be used at this level of abstraction, so it is the + * responsibility of subclasses to provide a more appropriate + * name. + * + * @return a localized name for this component. Currently, this + * is just the contents of the name property + * + * @see MenuComponent#setName(String) + */ + public String getAccessibleName() + { + return MenuComponent.this.getName(); + } + + /** + * Returns the <code>Accessible</code> parent of this component. + * As the parent of a <code>MenuComponent</code> is a + * <code>MenuContainer</code>, which doesn't implement + * <code>Accessible</code>, this method returns null. + * + * @return null + */ + public Accessible getAccessibleParent() + { + return null; + } + + /** + * Returns the accessible role of this component. + * <br /> + * <br /> + * The abstract implementation of this method returns + * <code>AccessibleRole.AWT_COMPONENT</code>, + * as the abstract component has no specific role. This + * method should be overridden by concrete subclasses, so + * as to return an appropriate role for the component. + * + * @return <code>AccessibleRole.AWT_COMPONENT</code> + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.AWT_COMPONENT; + } + + /** + * Retrieves the <code>AccessibleSelection</code> associated + * with this accessible context and its component. As the + * context itself implements <code>AccessibleSelection</code>, + * this is the return value. + * + * @return the context itself + */ + public AccessibleSelection getAccessibleSelection() + { + return this; + } + + /** + * Retrieves the <code>Accessible</code> selected child + * at the specified index. If there are no selected children + * or the index is outside the range of selected children, + * null is returned. Please note that the index refers + * to the index of the child in the list of <strong>selected + * children</strong>, and not the index of the child in + * the list of all <code>Accessible</code> children. + * <br /> + * <br /> + * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + * + * @param index the index of the selected <code>Accessible</code> + * child + */ + public Accessible getAccessibleSelection(int index) + { + return null; + } + + /** + * Returns a count of the number of <code>Accessible</code> + * children of this component which are currently selected. + * If there are no children currently selected, 0 is returned. + * <br /> + * <br /> + * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + * + * @return 0 + */ + public int getAccessibleSelectionCount() + { + return 0; + } + + /** + * Retrieves the current state of this component + * in an accessible form. For example, a given component + * may be visible, selected, disabled, etc. + * <br /> + * <br /> + * As this class tells us virtually nothing about the component, + * except for its name and font, no state information can be + * provided. This implementation thus returns an empty + * state set, and it is left to concrete subclasses to provide + * a more acceptable and relevant state set. Changes to these + * properties also need to be handled using + * <code>PropertyChangeListener</code>s. + * + * @return an empty <code>AccessibleStateSet</code> + */ + public AccessibleStateSet getAccessibleStateSet() + { + return new AccessibleStateSet(); + } + + /** + * Returns the background color of the component, or null + * if this property is unsupported. + * <br /> + * <br /> + * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply returns the + * default system background color used for rendering menus. + * Concrete subclasses which handle the drawing of an onscreen + * menu component should override this method and provide + * the appropriate information. + * + * @return the default system background color for menus + * + * @see #setBackground(java.awt.Color) + */ + public Color getBackground() + { + return SystemColor.menu; + } + + /** + * Returns a <code>Rectangle</code> which represents the + * bounds of this component. The returned rectangle has the + * height and width of the component's bounds, and is positioned + * at a location relative to this component's parent, the + * <code>MenuContainer</code>. null is returned if bounds + * are not supported by the component. + * <br /> + * <br /> + * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply returns null. + * Concrete subclasses which handle the drawing of an onscreen + * menu component should override this method and provide + * the appropriate information. + * + * @return null + * + * @see #setBounds(java.awt.Rectangle) + */ + public Rectangle getBounds() + { + return null; + } + + /** + * Returns the <code>Cursor</code> displayed when the pointer + * is positioned over this component. Alternatively, null + * is returned if the component doesn't support the cursor + * property. + * <br /> + * <br /> + * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply returns the default + * system cursor. Concrete subclasses which handle the drawing + * of an onscreen menu component may override this method and provide + * the appropriate information. + * + * @return the default system cursor + * + * @see #setCursor(java.awt.Cursor) + */ + public Cursor getCursor() + { + return Cursor.getDefaultCursor(); + } + + /** + * Returns the <code>Font</code> used for text created by this component. + * + * @return the current font + * + * @see #setFont(java.awt.Font) + */ + public Font getFont() + { + return MenuComponent.this.getFont(); + } + + /** + * Retrieves information on the rendering and metrics of the supplied + * font. If font metrics are not supported by this component, null + * is returned. + * <br /> + * <br /> + * The abstract implementation of this method simply uses the toolkit + * to obtain the <code>FontMetrics</code>. Concrete subclasses may + * find it more efficient to invoke their peer class directly, if one + * is available. + * + * @param font the font about which to retrieve rendering and metric + * information + * + * @return the metrics of the given font, as provided by the system + * toolkit + * + * @throws NullPointerException if the supplied font was null + */ + public FontMetrics getFontMetrics(Font font) + { + return MenuComponent.this.getToolkit().getFontMetrics(font); + } + + /** + * Returns the foreground color of the component, or null + * if this property is unsupported. + * <br /> + * <br /> + * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply returns the + * default system text color used for rendering menus. + * Concrete subclasses which handle the drawing of an onscreen + * menu component should override this method and provide + * the appropriate information. + * + * @return the default system text color for menus + * + * @see #setForeground(java.awt.Color) + */ + public Color getForeground() + { + return SystemColor.menuText; + } + + /** + * Returns the locale currently in use by this component. + * <br /> + * <br /> + * This abstract class has no property relating to the + * locale used by the component, so this method simply + * returns the default locale for the current instance + * of the Java Virtual Machine (JVM). Concrete subclasses + * which maintain such a property should override this method + * and provide the locale information more accurately. + * + * @return the default locale for this JVM instance + */ + public Locale getLocale() + { + return Locale.getDefault(); + } + + /** + * Returns the location of the component, with co-ordinates + * relative to the parent component and using the co-ordinate + * space of the screen. Thus, the point (0,0) is the upper + * left corner of the parent component. + * <br /> + * <br /> + * Please note that this method depends on a correctly implemented + * version of the <code>getBounds()</code> method. Subclasses + * must provide the bounding rectangle via <code>getBounds()</code> + * in order for this method to work. + * + * @return the location of the component, relative to its parent + * + * @see #setLocation(java.awt.Point) + */ + public Point getLocation() + { + // Simply return the location of the bounding rectangle. + return getBounds().getLocation(); + } + + /** + * Returns the location of the component, with co-ordinates + * relative to the screen. Thus, the point (0,0) is the upper + * left corner of the screen. null is returned if the component + * is either not on screen or if this property is unsupported. + * <br /> + * <br /> + * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply returns null. + * Concrete subclasses which handle the drawing of an onscreen + * menu component should override this method and provide + * the appropriate information. + * + * @return the location of the component, relative to the screen + */ + public Point getLocationOnScreen() + { + return null; + } + + /** + * Returns the size of the component. + * <br /> + * <br /> + * Please note that this method depends on a correctly implemented + * version of the <code>getBounds()</code> method. Subclasses + * must provide the bounding rectangle via <code>getBounds()</code> + * in order for this method to work. + * + * @return the size of the component + * + * @see #setSize(java.awt.Dimension) + */ + public Dimension getSize() + { + // Simply return the size of the bounding rectangle. + return getBounds().getSize(); + } + + /** + * Returns true if the accessible child specified by the supplied index + * is currently selected. + * <br /> + * <br /> + * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + * + * @param index the index of the accessible child to check for selection + * + * @return false + */ + public boolean isAccessibleChildSelected(int index) + { + return false; + } + + /** + * Returns true if this component is currently enabled. + * <br /> + * <br /> + * As this abstract component has no properties related to + * its enabled or disabled state, the implementation of this + * method is left to subclasses. + * + * @return false + * + * @see #setEnabled(boolean) + */ + public boolean isEnabled() + { + return false; + } + + /** + * Returns true if this component is included in the traversal + * of the current focus from one component to the other. + * <br /> + * <br /> + * As this abstract component has no properties related to + * its ability to accept the focus, the implementation of this + * method is left to subclasses. + * + * @return false + */ + public boolean isFocusTraversable() + { + return false; + } + + /** + * Returns true if the component is being shown on screen. + * A component is determined to be shown if it is visible, + * and each parent component is also visible. Please note + * that, even when a component is showing, it may still be + * obscured by other components in front. This method only + * determines if the component is being drawn on the screen. + * <br /> + * <br /> + * As this abstract component and its parent have no properties + * relating to visibility, the implementation of this method is + * left to subclasses. + * + * @return false + * + * @see #isVisible() + */ + public boolean isShowing() + { + return false; + } + + /** + * Returns true if the component is visible. A component may + * be visible but not drawn on the screen if one of its parent + * components is not visible. To determine if the component is + * actually drawn on screen, <code>isShowing()</code> should be + * used. + * <br /> + * <br /> + * As this abstract component has no properties relating to its + * visibility, the implementation of this method is left to subclasses. + * + * @return false + * + * @see #isShowing() + * @see #setVisible(boolean) + */ + public boolean isVisible() + { + return false; + } + + /** + * Removes the accessible child specified by the supplied index from + * the list of currently selected children. If the child specified + * is not selected, nothing happens. + * <br /> + * <br /> + * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + * + * @param index the index of the <code>Accessible</code> child + */ + public void removeAccessibleSelection(int index) + { + // Subclasses with children should implement this. + } + + /** + * Removes the specified focus listener from the list of registered + * focus listeners for this component. + * + * @param listener the listener to remove + */ + public void removeFocusListener(FocusListener listener) + { + // Remove the focus listener from the chain. + focusListener = AWTEventMulticaster.remove(focusListener, listener); + } + + /** + * Requests that this component gains focus. This depends on the + * component being focus traversable. + * <br /> + * <br /> + * As this abstract component has no properties relating to its + * focus traversability, or access to a peer with request focusing + * abilities, the implementation of this method is left to subclasses. + */ + public void requestFocus() + { + // Ignored. + } + + /** + * Selects all <code>Accessible</code> children of this component which + * it is possible to select. The component needs to support multiple + * selections. + * <br /> + * <br /> + * This abstract component provides a simplistic implementation of this + * method, which ignores the ability of the component to support multiple + * selections and simply uses <code>addAccessibleSelection</code> to + * add each <code>Accessible</code> child to the selection. The last + * <code>Accessible</code> component is thus selected for components + * which don't support multiple selections. Concrete implementations should + * override this with a more appopriate and efficient implementation, which + * properly takes into account the ability of the component to support multiple + * selections. + */ + public void selectAllAccessibleSelection() + { + // Simply call addAccessibleSelection() on all accessible children. + for (int a = 0; a < getAccessibleChildrenCount(); ++a) + { + addAccessibleSelection(a); + } + } + + /** + * Sets the background color of the component to that specified. + * Unspecified behaviour occurs when null is given as the new + * background color. + * <br /> + * <br /> + * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply ignores the supplied + * color and continues to use the default system color. + * Concrete subclasses which handle the drawing of an onscreen + * menu component should override this method and provide + * the appropriate information. + * + * @param color the new color to use for the background + * + * @see #getBackground() + */ + public void setBackground(Color color) + { + // Ignored. + } + + /** + * Sets the height and width of the component, and its position + * relative to this component's parent, to the values specified + * by the supplied rectangle. Unspecified behaviour occurs when + * null is given as the new bounds. + * <br /> + * <br /> + * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply ignores the new + * rectangle and continues to return null from <code>getBounds()</code>. + * Concrete subclasses which handle the drawing of an onscreen + * menu component should override this method and provide + * the appropriate information. + * + * @param rectangle a rectangle which specifies the new bounds of + * the component + * + * @see #getBounds() + */ + public void setBounds(Rectangle rectangle) + { + // Ignored. + } + + /** + * Sets the <code>Cursor</code> used when the pointer is positioned over the + * component. Unspecified behaviour occurs when null is given as the new + * cursor. + * <br /> + * <br /> + * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply ignores the new cursor + * and continues to return the default system cursor. Concrete + * subclasses which handle the drawing of an onscreen menu component + * may override this method and provide the appropriate information. + * + * @param cursor the new cursor to use + * + * @see #getCursor() + */ + public void setCursor(Cursor cursor) + { + // Ignored. + } + + /** + * Sets the enabled/disabled state of this component. + * <br /> + * <br /> + * As this abstract component has no properties related to + * its enabled or disabled state, the implementation of this + * method is left to subclasses. + * + * @param enabled true if the component should be enabled, + * false otherwise + * + * @see #isEnabled() + */ + public void setEnabled(boolean enabled) + { + // Ignored. + } + + /** + * Sets the <code>Font</code> used for text created by this component. + * Unspecified behaviour occurs when null is given as the new + * font. + * + * @param font the new font to use for text. + * @see #getFont() + */ + public void setFont(Font font) + { + // Call the method of the enclosing component. + MenuComponent.this.setFont(font); + } + + /** + * Sets the foreground color of the component to that specified. + * Unspecified behaviour occurs when null is given as the new + * background color. + * <br /> + * <br /> + * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply ignores the supplied + * color and continues to return the default system text color used + * for rendering menus. + * Concrete subclasses which handle the drawing of an onscreen + * menu component should override this method and provide + * the appropriate information. + * + * @param color the new foreground color + * + * @see #getForeground() + */ + public void setForeground(Color color) + { + // Ignored. + } + + /** + * Sets the location of the component, with co-ordinates + * relative to the parent component and using the co-ordinate + * space of the screen. Thus, the point (0,0) is the upper + * left corner of the parent component. + * <br /> + * <br /> + * Please note that this method depends on a correctly implemented + * version of the <code>getBounds()</code> method. Subclasses + * must provide the bounding rectangle via <code>getBounds()</code> + * in order for this method to work. + * + * @param point the location of the component, relative to its parent + * + * @see #getLocation() + */ + public void setLocation(Point point) + { + getBounds().setLocation(point); + } + + /** + * Sets the size of the component. + * <br /> + * <br /> + * Please note that this method depends on a correctly implemented + * version of the <code>getBounds()</code> method. Subclasses + * must provide the bounding rectangle via <code>getBounds()</code> + * in order for this method to work. + * + * @param size the new size of the component + * + * @see #getSize() + */ + public void setSize(Dimension size) + { + getBounds().setSize(size); + } + + /** + * Sets the visibility state of the component. A component may + * be visible but not drawn on the screen if one of its parent + * components is not visible. To determine if the component is + * actually drawn on screen, <code>isShowing()</code> should be + * used. + * <br /> + * <br /> + * As this abstract component has no properties relating to its + * visibility, the implementation of this method is left to subclasses. + * + * @param visibility the new visibility of the component -- true if + * the component is visible, false if not + * + * @see #isShowing() + * @see #isVisible() + */ + public void setVisible(boolean visibility) + { + // Ignored. + } + + } + +} diff --git a/libjava/classpath/java/awt/MenuContainer.java b/libjava/classpath/java/awt/MenuContainer.java new file mode 100644 index 000000000..c76ec96c2 --- /dev/null +++ b/libjava/classpath/java/awt/MenuContainer.java @@ -0,0 +1,71 @@ +/* MenuContainer.java -- container for menu items + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +/** + * This interface is a container for menu components. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.0 + * @status updated to 1.4 + */ +public interface MenuContainer +{ + /** + * Returns the font in use by this container. + * + * @return the menu font + */ + Font getFont(); + + /** + * Removes the specified menu component from the menu. + * + * @param component the menu component to remove + */ + void remove(MenuComponent component); + + /** + * Posts an event to the listeners. + * + * @param event the event to dispatch + * @deprecated use {@link MenuComponent#dispatchEvent(AWTEvent)} instead + */ + boolean postEvent(Event event); +} // interface MenuContainer diff --git a/libjava/classpath/java/awt/MenuItem.java b/libjava/classpath/java/awt/MenuItem.java new file mode 100644 index 000000000..52d0b4ddf --- /dev/null +++ b/libjava/classpath/java/awt/MenuItem.java @@ -0,0 +1,623 @@ +/* MenuItem.java -- An item in a menu + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.peer.MenuItemPeer; +import java.io.Serializable; +import java.lang.reflect.Array; +import java.util.EventListener; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleValue; + +/** + * This class represents an item in a menu. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class MenuItem extends MenuComponent + implements Serializable, Accessible +{ + +/* + * Static Variables + */ + + + /** + * The number used to generate the name returned by getName. + */ + private static transient long next_menuitem_number; + + // Serialization Constant + private static final long serialVersionUID = - 21757335363267194L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * @serial The name of the action command generated by this item. + * This is package-private to avoid an accessor method. + */ +String actionCommand; + +/** + * @serial Indicates whether or not this menu item is enabled. + * This is package-private to avoid an accessor method. + */ +boolean enabled = true; + +/** + * @serial The mask of events that are enabled for this menu item. + */ +long eventMask; + +/** + * @serial This menu item's label + * This is package-private to avoid an accessor method. + */ +String label = ""; + +/** + * @serial The shortcut for this menu item, if any + */ +private MenuShortcut shortcut; + +// The list of action listeners for this menu item. +private transient ActionListener action_listeners; + + protected class AccessibleAWTMenuItem + extends MenuComponent.AccessibleAWTMenuComponent + implements AccessibleAction, AccessibleValue + { + private static final long serialVersionUID = -217847831945965825L; + + /** Constructor */ + protected AccessibleAWTMenuItem() + { + super(); + } + + + + public String getAccessibleName() + { + return label; + } + + public AccessibleAction getAccessibleAction() + { + return this; + } + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.MENU_ITEM; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleAction#getAccessibleActionCount() + */ + public int getAccessibleActionCount() + { + return 1; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleAction#getAccessibleActionDescription(int) + */ + public String getAccessibleActionDescription(int i) + { + if (i == 0) + return label; + else + return null; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleAction#doAccessibleAction(int) + */ + public boolean doAccessibleAction(int i) + { + if (i != 0) + return false; + processActionEvent(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, actionCommand)); + return true; + } + + public AccessibleValue getAccessibleValue() + { + return this; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleValue#getCurrentAccessibleValue() + */ + public Number getCurrentAccessibleValue() + { + return (enabled) ? new Integer(1) : new Integer(0); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleValue#setCurrentAccessibleValue(java.lang.Number) + */ + public boolean setCurrentAccessibleValue(Number number) + { + boolean result = (number.intValue() != 0); + // this. is required by javac 1.3, otherwise it is confused with + // MenuItem.this.setEnabled. + this.setEnabled(result); + return result; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleValue#getMinimumAccessibleValue() + */ + public Number getMinimumAccessibleValue() + { + return new Integer(0); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleValue#getMaximumAccessibleValue() + */ + public Number getMaximumAccessibleValue() + { + return new Integer(0); + } + + } + + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of <code>MenuItem</code> with no label + * and no shortcut. + */ +public +MenuItem() +{ +} + +/*************************************************************************/ + +/** + * Initializes a new instance of <code>MenuItem</code> with the specified + * label and no shortcut. + * + * @param label The label for this menu item. + */ +public +MenuItem(String label) +{ + this.label = label; +} + +/*************************************************************************/ + +/** + * Initializes a new instance of <code>MenuItem</code> with the specified + * label and shortcut. + * + * @param label The label for this menu item. + * @param shortcut The shortcut for this menu item. + */ +public +MenuItem(String label, MenuShortcut shortcut) +{ + this.label = label; + this.shortcut = shortcut; +} + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * Returns the label for this menu item, which may be <code>null</code>. + * + * @return The label for this menu item. + */ +public String +getLabel() +{ + return(label); +} + +/*************************************************************************/ + +/** + * This method sets the label for this menu to the specified value. + * + * @param label The new label for this menu item. + */ +public synchronized void +setLabel(String label) +{ + this.label = label; + if (peer != null) + { + MenuItemPeer mp = (MenuItemPeer) peer; + mp.setLabel (label); + } +} + +/*************************************************************************/ + +/** + * Tests whether or not this menu item is enabled. + * + * @return <code>true</code> if this menu item is enabled, <code>false</code> + * otherwise. + */ +public boolean +isEnabled() +{ + return(enabled); +} + +/*************************************************************************/ + +/** + * Sets the enabled status of this menu item. + * + * @param enabled <code>true</code> to enable this menu item, + * <code>false</code> otherwise. + */ +public synchronized void +setEnabled(boolean enabled) +{ + enable (enabled); +} + +/*************************************************************************/ + +/** + * Sets the enabled status of this menu item. + * + * @param enabled <code>true</code> to enable this menu item, + * <code>false</code> otherwise. + * + * @deprecated This method is deprecated in favor of <code>setEnabled()</code>. + */ +public void +enable(boolean enabled) +{ + if (enabled) + enable (); + else + disable (); +} + +/*************************************************************************/ + +/** + * Enables this menu item. + * + * @deprecated This method is deprecated in favor of <code>setEnabled()</code>. + */ +public void +enable() +{ + if (enabled) + return; + + this.enabled = true; + if (peer != null) + ((MenuItemPeer) peer).setEnabled (true); +} + +/*************************************************************************/ + +/** + * Disables this menu item. + * + * @deprecated This method is deprecated in favor of <code>setEnabled()</code>. + */ +public void +disable() +{ + if (!enabled) + return; + + this.enabled = false; + if (peer != null) + ((MenuItemPeer) peer).setEnabled (false); +} + +/*************************************************************************/ + +/** + * Returns the shortcut for this menu item, which may be <code>null</code>. + * + * @return The shortcut for this menu item. + */ +public MenuShortcut +getShortcut() +{ + return(shortcut); +} + +/*************************************************************************/ + +/** + * Sets the shortcut for this menu item to the specified value. This + * must be done before the native peer is created. + * + * @param shortcut The new shortcut for this menu item. + */ +public void +setShortcut(MenuShortcut shortcut) +{ + this.shortcut = shortcut; +} + +/*************************************************************************/ + +/** + * Deletes the shortcut for this menu item if one exists. This must be + * done before the native peer is created. + */ +public void +deleteShortcut() +{ + shortcut = null; +} + +/*************************************************************************/ + +/** + * Returns the name of the action command in the action events + * generated by this menu item. + * + * @return The action command name + */ +public String +getActionCommand() +{ + if (actionCommand == null) + return label; + else + return actionCommand; +} + +/*************************************************************************/ + +/** + * Sets the name of the action command in the action events generated by + * this menu item. + * + * @param actionCommand The new action command name. + */ +public void +setActionCommand(String actionCommand) +{ + this.actionCommand = actionCommand; +} + +/*************************************************************************/ + +/** + * Enables the specified events. This is done automatically when a + * listener is added and does not normally need to be done by + * application code. + * + * @param events The events to enable, which should be the bit masks + * from <code>AWTEvent</code>. + */ +protected final void +enableEvents(long events) +{ + eventMask |= events; + // TODO: see comment in Component.enableEvents(). +} + +/*************************************************************************/ + +/** + * Disables the specified events. + * + * @param events The events to enable, which should be the bit masks + * from <code>AWTEvent</code>. + */ +protected final void +disableEvents(long events) +{ + eventMask &= ~events; +} + +/*************************************************************************/ + +/** + * Creates the native peer for this object. + */ +public void +addNotify() +{ + if (peer == null) + peer = getToolkit ().createMenuItem (this); +} + +/*************************************************************************/ + +/** + * Adds the specified listener to the list of registered action listeners + * for this component. + * + * @param listener The listener to add. + */ +public synchronized void +addActionListener(ActionListener listener) +{ + action_listeners = AWTEventMulticaster.add(action_listeners, listener); + + enableEvents(AWTEvent.ACTION_EVENT_MASK); +} + +public synchronized void +removeActionListener(ActionListener l) +{ + action_listeners = AWTEventMulticaster.remove(action_listeners, l); +} + + public synchronized ActionListener[] getActionListeners() + { + return (ActionListener[]) + AWTEventMulticaster.getListeners(action_listeners, + ActionListener.class); + } + +/** Returns all registered EventListers of the given listenerType. + * listenerType must be a subclass of EventListener, or a + * ClassClassException is thrown. + * @since 1.3 + */ + public <T extends EventListener> T[] getListeners(Class<T> listenerType) + { + if (listenerType == ActionListener.class) + return (T[]) getActionListeners(); + return (T[]) Array.newInstance(listenerType, 0); + } + +/*************************************************************************/ + +void +dispatchEventImpl(AWTEvent e) +{ + if (e.id <= ActionEvent.ACTION_LAST + && e.id >= ActionEvent.ACTION_FIRST + && (action_listeners != null + || (eventMask & AWTEvent.ACTION_EVENT_MASK) != 0)) + processEvent(e); + + // Send the event to the parent menu if it has not yet been + // consumed. + if (!e.isConsumed ()) + ((Menu) getParent ()).processEvent (e); +} + +/** + * Processes the specified event by calling <code>processActionEvent()</code> + * if it is an instance of <code>ActionEvent</code>. + * + * @param event The event to process. + */ +protected void +processEvent(AWTEvent event) +{ + if (event instanceof ActionEvent) + processActionEvent((ActionEvent)event); +} + +/*************************************************************************/ + +/** + * Processes the specified event by dispatching it to any registered listeners. + * + * @param event The event to process. + */ +protected void +processActionEvent(ActionEvent event) +{ + if (action_listeners != null) + { + event.setSource(this); + action_listeners.actionPerformed(event); + } +} + +/*************************************************************************/ + +/** + * Returns a debugging string for this object. + * + * @return A debugging string for this object. + */ +public String +paramString() +{ + return ("label=" + label + ",enabled=" + enabled + + ",actionCommand=" + actionCommand + "," + super.paramString()); +} + +/** + * Gets the AccessibleContext associated with this <code>MenuItem</code>. + * The context is created, if necessary. + * + * @return the associated context + */ +public AccessibleContext getAccessibleContext() +{ + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTMenuItem(); + return accessibleContext; +} + +/** + * Generate a unique name for this <code>MenuItem</code>. + * + * @return A unique name for this <code>MenuItem</code>. + */ +String generateName() +{ + return "menuitem" + getUniqueLong(); +} + +private static synchronized long getUniqueLong() +{ + return next_menuitem_number++; +} + +} // class MenuItem diff --git a/libjava/classpath/java/awt/MenuShortcut.java b/libjava/classpath/java/awt/MenuShortcut.java new file mode 100644 index 000000000..4939438f1 --- /dev/null +++ b/libjava/classpath/java/awt/MenuShortcut.java @@ -0,0 +1,434 @@ +/* MenuShortcut.java -- A class for menu accelerators + Copyright (C) 1999, 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +/** + * This class implements a keyboard accelerator for a menu item. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class MenuShortcut implements java.io.Serializable +{ + +/* + * Static Variables + */ + +// Serialization Constant +private static final long serialVersionUID = 143448358473180225L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * @serial The virtual keycode for the shortcut. + */ +private int key; + +/** + * @serial <code>true</code> if the shift key was used with this shortcut, + * or <code>false</code> otherwise. + */ +private boolean usesShift; + +private String keyName; + +/*************************************************************************/ + +/** + * Initializes a new instance of <code>MenuShortcut</code> with the + * specified virtual key value. + * + * @param key The virtual keycode for the shortcut. + */ +public +MenuShortcut(int key) +{ + this(key, false); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of <code>MenuShortcut</code> with the + * specified virtual key value and shift setting. + * + * @param key The virtual keycode for the shortcut. + * @param usesShift <code>true</code> if the shift key was pressed, + * <code>false</code> otherwise. + */ +public +MenuShortcut(int key, boolean usesShift) +{ + this.key = key; + this.usesShift = usesShift; + setKeyName(key); +} + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * Returns the virtual keycode for this shortcut. + * + * @return The virtual keycode for this shortcut. + */ +public int +getKey() +{ + return(key); +} + +/*************************************************************************/ + +/** + * Returns the shift setting for this shortcut. + * + * @return <code>true</code> if the shift key was pressed, <code>false</code> + * otherwise. + */ +public boolean +usesShiftModifier() +{ + return(usesShift); +} + +/*************************************************************************/ + +/** + * Tests this object for equality against the specified object. The two + * objects will be considered equal if and only if the specified object + * is an instance of <code>MenuShortcut</code> and has the same key value + * and shift setting as this object. + * + * @param obj The object to test for equality against. + * + * @return <code>true</code> if the two objects are equal, <code>false</code> + * otherwise. + */ +public boolean +equals(MenuShortcut obj) +{ + if (obj == null) + return(false); + + if (obj.key != this.key) + return(false); + + if (obj.usesShift != this.usesShift) + return(false); + + return(true); +} + +public boolean +equals(Object obj) +{ + if (obj instanceof MenuShortcut) + { + MenuShortcut ms = (MenuShortcut) obj; + return (ms.key == key && ms.usesShift == usesShift); + } + return false; +} + +/*************************************************************************/ + +/** + * Returns a string representation of this shortcut. + * + * @return A string representation of this shortcut. + */ +public String +toString() +{ + String temp = "Ctrl+"; + if (usesShift) + temp = temp + "Shift+"; + temp = temp + keyName; + return temp; +} + +public int +hashCode() +{ + // Arbitrary. + return key + (usesShift ? 23 : 57); +} + +/*************************************************************************/ + +/** + * Returns a debugging string for this object. + * + * @return A debugging string for this object. + */ +protected String +paramString() +{ + return "key=" + key + ",usesShift=" + usesShift; +} + +private void +setKeyName(int key) +{ + if (key == '\n') + keyName = "Enter"; + else if (key == '\b') + keyName = "Backspace"; + else if (key == '\t') + keyName = "Tab"; + else if (key == ' ') + keyName = "Space"; + else if (key == ',') + keyName = "Comma"; + else if (key == '.') + keyName = "Period"; + else if (key == '/') + keyName = "Slash"; + else if (key == '\\') + keyName = "Back Slash"; + else if (key == ';') + keyName = "Semicolon"; + else if (key == '=') + keyName = "Equals"; + else if (key == '[') + keyName = "Open Bracket"; + else if (key == ']') + keyName = "Close Bracket"; + else if (key == '0') + keyName = "0"; + else if (key == '1') + keyName = "1"; + else if (key == '2') + keyName = "2"; + else if (key == '3') + keyName = "3"; + else if (key == '4') + keyName = "4"; + else if (key == '5') + keyName = "5"; + else if (key == '6') + keyName = "6"; + else if (key == '7') + keyName = "7"; + else if (key == '8') + keyName = "8"; + else if (key == '9') + keyName = "9"; + else if (key == 'A') + keyName = "A"; + else if (key == 'B') + keyName = "B"; + else if (key == 'C') + keyName = "C"; + else if (key == 'D') + keyName = "D"; + else if (key == 'E') + keyName = "E"; + else if (key == 'F') + keyName = "F"; + else if (key == 'G') + keyName = "G"; + else if (key == 'H') + keyName = "H"; + else if (key == 'I') + keyName = "I"; + else if (key == 'J') + keyName = "J"; + else if (key == 'K') + keyName = "K"; + else if (key == 'L') + keyName = "L"; + else if (key == 'M') + keyName = "M"; + else if (key == 'N') + keyName = "N"; + else if (key == 'O') + keyName = "O"; + else if (key == 'P') + keyName = "P"; + else if (key == 'Q') + keyName = "Q"; + else if (key == 'R') + keyName = "R"; + else if (key == 'S') + keyName = "S"; + else if (key == 'T') + keyName = "T"; + else if (key == 'U') + keyName = "U"; + else if (key == 'V') + keyName = "V"; + else if (key == 'W') + keyName = "W"; + else if (key == 'X') + keyName = "X"; + else if (key == 'Y') + keyName = "Y"; + else if (key == 'Z') + keyName = "Z"; + else if (key == 3) + keyName = "Cancel"; + else if (key == 12) + keyName = "Clear"; + else if (key == 16) + keyName = "Shift"; + else if (key == 17) + keyName = "Ctrl"; + else if (key == 18) + keyName = "Alt"; + else if (key == 19) + keyName = "Pause"; + else if (key == 20) + keyName = "Caps Lock"; + else if (key == 21) + keyName = "Kana"; + else if (key == 24) + keyName = "Final"; + else if (key == 25) + keyName = "Kanji"; + else if (key == 27) + keyName = "Escape"; + else if (key == 28) + keyName = "Convert"; + else if (key == 29) + keyName = "No Convert"; + else if (key == 30) + keyName = "Accept"; + else if (key == 31) + keyName = "Mode Change"; + else if (key == 33) + keyName = "Page Up"; + else if (key == 34) + keyName = "Page Down"; + else if (key == 35) + keyName = "End"; + else if (key == 36) + keyName = "Home"; + else if (key == 37) + keyName = "Left"; + else if (key == 38) + keyName = "Up"; + else if (key == 39) + keyName = "Right"; + else if (key == 40) + keyName = "Down"; + else if (key == 96) + keyName = "NumPad-0"; + else if (key == 97) + keyName = "NumPad-1"; + else if (key == 98) + keyName = "NumPad-2"; + else if (key == 99) + keyName = "NumPad-3"; + else if (key == 100) + keyName = "NumPad-4"; + else if (key == 101) + keyName = "NumPad-5"; + else if (key == 102) + keyName = "NumPad-6"; + else if (key == 103) + keyName = "NumPad-7"; + else if (key == 104) + keyName = "NumPad-8"; + else if (key == 105) + keyName = "NumPad-9"; + else if (key == 106) + keyName = "NumPad *"; + else if (key == 107) + keyName = "NumPad +"; + else if (key == 108) + keyName = "NumPad ,"; + else if (key == 109) + keyName = "NumPad -"; + else if (key == 110) + keyName = "NumPad ."; + else if (key == 111) + keyName = "NumPad /"; + else if (key == 112) + keyName = "F1"; + else if (key == 113) + keyName = "F2"; + else if (key == 114) + keyName = "F3"; + else if (key == 115) + keyName = "F4"; + else if (key == 116) + keyName = "F5"; + else if (key == 117) + keyName = "F6"; + else if (key == 118) + keyName = "F7"; + else if (key == 119) + keyName = "F8"; + else if (key == 120) + keyName = "F9"; + else if (key == 121) + keyName = "F10"; + else if (key == 122) + keyName = "F11"; + else if (key == 123) + keyName = "F12"; + else if (key == 127) + keyName = "Delete"; + else if (key == 144) + keyName = "Num Lock"; + else if (key == 145) + keyName = "Scroll Lock"; + else if (key == 154) + keyName = "Print Screen"; + else if (key == 155) + keyName = "Insert"; + else if (key == 156) + keyName = "Help"; + else if (key == 157) + keyName = "Meta"; + else if (key == 192) + keyName = "Back Quote"; + else if (key == 222) + keyName = "Quote"; +} +} // class MenuShortcut diff --git a/libjava/classpath/java/awt/MouseInfo.java b/libjava/classpath/java/awt/MouseInfo.java new file mode 100644 index 000000000..62d7d3068 --- /dev/null +++ b/libjava/classpath/java/awt/MouseInfo.java @@ -0,0 +1,102 @@ +/* MouseInfo.java -- utility methods for mice. + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt; + +import gnu.java.awt.ClasspathToolkit; +import java.awt.peer.MouseInfoPeer; + +/** + * MouseInfo is a class containing utility functions for mouse information. + * + * @author Sven de Marothy + * @since 1.5 + */ +public class MouseInfo +{ + private static MouseInfoPeer peer; + + /** + * Private constructor to prevent instance creation. + */ + private MouseInfo() + { + } + + /** + * Returns a PointerInfo object containing information about the current + * location of the mouse pointer + * + * @throws HeadlessException if the current GraphicsEnvironment is headless. + * @return a PointerInfo object. + */ + public static PointerInfo getPointerInfo() throws HeadlessException + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission( new AWTPermission("watchMousePointer") ); + + if( GraphicsEnvironment.isHeadless() ) + throw new HeadlessException(); + + if( peer == null ) + peer = Toolkit.getDefaultToolkit().getMouseInfoPeer(); + + Point p = new Point(); + int screen = peer.fillPointWithCoords( p ); + + GraphicsDevice[] gds = GraphicsEnvironment.getLocalGraphicsEnvironment(). + getScreenDevices(); + + return new PointerInfo( gds[ screen ], p ); + } + + /** + * Returns the number of mouse buttons, or -1 if no mouse is connected. + * (mentioned in the 1.5 release notes) + * + * @throws HeadlessException if the current GraphicsEnvironment is headless. + * @return an integer number of buttons. + */ + public static int getNumberOfButtons() throws HeadlessException + { + if( GraphicsEnvironment.isHeadless() ) + throw new HeadlessException(); + return ((ClasspathToolkit)Toolkit.getDefaultToolkit()). + getMouseNumberOfButtons(); + } +} diff --git a/libjava/classpath/java/awt/PageAttributes.java b/libjava/classpath/java/awt/PageAttributes.java new file mode 100644 index 000000000..825d0feb3 --- /dev/null +++ b/libjava/classpath/java/awt/PageAttributes.java @@ -0,0 +1,482 @@ +/* PageAttributes.java -- + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.util.Locale; + +/** + * Missing Documentation + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + * @status updated to 1.4, but missing documentation + */ +public final class PageAttributes implements Cloneable +{ + public static final class ColorType extends AttributeValue + { + private static final String[] NAMES = { "color", "monochrome" }; + public static final ColorType COLOR = new ColorType(0); + public static final ColorType MONOCHROME = new ColorType(1); + private ColorType(int value) + { + super(value, NAMES); + } + } // class ColorType + public static final class MediaType extends AttributeValue + { + private static final String[] NAMES + = { "iso-4a0", "iso-2a0", "iso-a0", "iso-a1", "iso-a2", "iso-a3", + "iso-a4", "iso-a5", "iso-a6", "iso-a7", "iso-a8", "iso-a9", + "iso-a10", "iso-b0", "iso-b1", "iso-b2", "iso-b3", "iso-b4", + "iso-b5", "iso-b6", "iso-b7", "iso-b8", "iso-b9", "iso-b10", + "jis-b0", "jis-b1", "jis-b2", "jis-b3", "jis-b4", "jis-b5", + "jis-b6", "jis-b7", "jis-b8", "jis-b9", "jis-b10", "iso-c0", + "iso-c1", "iso-c2", "iso-c3", "iso-c4", "iso-c5", "iso-c6", + "iso-c7", "iso-c8", "iso-c9", "iso-c10", "iso-designated-long", + "executive", "folio", "invoice", "ledger", "na-letter", "na-legal", + "quarto", "a", "b", "c", "d", "e", "na-10x15-envelope", + "na-10x14-envelope", "na-10x13-envelope", "na-9x12-envelope", + "na-9x11-envelope", "na-7x9-envelope", "na-6x9-envelope", + "na-number-9-envelope", "na-number-10-envelope", + "na-number-11-envelope", "na-number-12-envelope", + "na-number-14-envelope", "invite-envelope", "italy-envelope", + "monarch-envelope", "personal-envelope" }; + public static final MediaType ISO_4A0 = new MediaType(0); + public static final MediaType ISO_2A0 = new MediaType(1); + public static final MediaType ISO_A0 = new MediaType(2); + public static final MediaType ISO_A1 = new MediaType(3); + public static final MediaType ISO_A2 = new MediaType(4); + public static final MediaType ISO_A3 = new MediaType(5); + public static final MediaType ISO_A4 = new MediaType(6); + public static final MediaType ISO_A5 = new MediaType(7); + public static final MediaType ISO_A6 = new MediaType(8); + public static final MediaType ISO_A7 = new MediaType(9); + public static final MediaType ISO_A8 = new MediaType(10); + public static final MediaType ISO_A9 = new MediaType(11); + public static final MediaType ISO_A10 = new MediaType(12); + public static final MediaType ISO_B0 = new MediaType(13); + public static final MediaType ISO_B1 = new MediaType(14); + public static final MediaType ISO_B2 = new MediaType(15); + public static final MediaType ISO_B3 = new MediaType(16); + public static final MediaType ISO_B4 = new MediaType(17); + public static final MediaType ISO_B5 = new MediaType(18); + public static final MediaType ISO_B6 = new MediaType(19); + public static final MediaType ISO_B7 = new MediaType(20); + public static final MediaType ISO_B8 = new MediaType(21); + public static final MediaType ISO_B9 = new MediaType(22); + public static final MediaType ISO_B10 = new MediaType(23); + public static final MediaType JIS_B0 = new MediaType(24); + public static final MediaType JIS_B1 = new MediaType(25); + public static final MediaType JIS_B2 = new MediaType(26); + public static final MediaType JIS_B3 = new MediaType(27); + public static final MediaType JIS_B4 = new MediaType(28); + public static final MediaType JIS_B5 = new MediaType(29); + public static final MediaType JIS_B6 = new MediaType(30); + public static final MediaType JIS_B7 = new MediaType(31); + public static final MediaType JIS_B8 = new MediaType(32); + public static final MediaType JIS_B9 = new MediaType(33); + public static final MediaType JIS_B10 = new MediaType(34); + public static final MediaType ISO_C0 = new MediaType(35); + public static final MediaType ISO_C1 = new MediaType(36); + public static final MediaType ISO_C2 = new MediaType(37); + public static final MediaType ISO_C3 = new MediaType(38); + public static final MediaType ISO_C4 = new MediaType(39); + public static final MediaType ISO_C5 = new MediaType(40); + public static final MediaType ISO_C6 = new MediaType(41); + public static final MediaType ISO_C7 = new MediaType(42); + public static final MediaType ISO_C8 = new MediaType(43); + public static final MediaType ISO_C9 = new MediaType(44); + public static final MediaType ISO_C10 = new MediaType(45); + public static final MediaType ISO_DESIGNATED_LONG = new MediaType(46); + public static final MediaType EXECUTIVE = new MediaType(47); + public static final MediaType FOLIO = new MediaType(48); + public static final MediaType INVOICE = new MediaType(49); + public static final MediaType LEDGER = new MediaType(50); + public static final MediaType NA_LETTER = new MediaType(51); + public static final MediaType NA_LEGAL = new MediaType(52); + public static final MediaType QUARTO = new MediaType(53); + public static final MediaType A = new MediaType(54); + public static final MediaType B = new MediaType(55); + public static final MediaType C = new MediaType(56); + public static final MediaType D = new MediaType(57); + public static final MediaType E = new MediaType(58); + public static final MediaType NA_10X15_ENVELOPE = new MediaType(59); + public static final MediaType NA_10X14_ENVELOPE = new MediaType(60); + public static final MediaType NA_10X13_ENVELOPE = new MediaType(61); + public static final MediaType NA_9X12_ENVELOPE = new MediaType(62); + public static final MediaType NA_9X11_ENVELOPE = new MediaType(63); + public static final MediaType NA_7X9_ENVELOPE = new MediaType(64); + public static final MediaType NA_6X9_ENVELOPE = new MediaType(65); + public static final MediaType NA_NUMBER_9_ENVELOPE = new MediaType(66); + public static final MediaType NA_NUMBER_10_ENVELOPE = new MediaType(67); + public static final MediaType NA_NUMBER_11_ENVELOPE = new MediaType(68); + public static final MediaType NA_NUMBER_12_ENVELOPE = new MediaType(69); + public static final MediaType NA_NUMBER_14_ENVELOPE = new MediaType(70); + public static final MediaType INVITE_ENVELOPE = new MediaType(71); + public static final MediaType ITALY_ENVELOPE = new MediaType(72); + public static final MediaType MONARCH_ENVELOPE = new MediaType(73); + public static final MediaType PERSONAL_ENVELOPE = new MediaType(74); + public static final MediaType A0 = ISO_A0; + public static final MediaType A1 = ISO_A1; + public static final MediaType A2 = ISO_A2; + public static final MediaType A3 = ISO_A3; + public static final MediaType A4 = ISO_A4; + public static final MediaType A5 = ISO_A5; + public static final MediaType A6 = ISO_A6; + public static final MediaType A7 = ISO_A7; + public static final MediaType A8 = ISO_A8; + public static final MediaType A9 = ISO_A9; + public static final MediaType A10 = ISO_A10; + public static final MediaType B0 = ISO_B0; + public static final MediaType B1 = ISO_B1; + public static final MediaType B2 = ISO_B2; + public static final MediaType B3 = ISO_B3; + public static final MediaType B4 = ISO_B4; + public static final MediaType ISO_B4_ENVELOPE = ISO_B4; + public static final MediaType B5 = ISO_B5; + public static final MediaType ISO_B5_ENVELOPE = ISO_B4; + public static final MediaType B6 = ISO_B6; + public static final MediaType B7 = ISO_B7; + public static final MediaType B8 = ISO_B8; + public static final MediaType B9 = ISO_B9; + public static final MediaType B10 = ISO_B10; + public static final MediaType C0 = ISO_B0; + public static final MediaType ISO_C0_ENVELOPE = ISO_C0; + public static final MediaType C1 = ISO_C1; + public static final MediaType ISO_C1_ENVELOPE = ISO_C1; + public static final MediaType C2 = ISO_C2; + public static final MediaType ISO_C2_ENVELOPE = ISO_C2; + public static final MediaType C3 = ISO_C3; + public static final MediaType ISO_C3_ENVELOPE = ISO_C3; + public static final MediaType C4 = ISO_C4; + public static final MediaType ISO_C4_ENVELOPE = ISO_C4; + public static final MediaType C5 = ISO_C5; + public static final MediaType ISO_C5_ENVELOPE = ISO_C5; + public static final MediaType C6 = ISO_C6; + public static final MediaType ISO_C6_ENVELOPE = ISO_C6; + public static final MediaType C7 = ISO_C7; + public static final MediaType ISO_C7_ENVELOPE = ISO_C7; + public static final MediaType C8 = ISO_C8; + public static final MediaType ISO_C8_ENVELOPE = ISO_C8; + public static final MediaType C9 = ISO_C9; + public static final MediaType ISO_C9_ENVELOPE = ISO_C9; + public static final MediaType C10 = ISO_C10; + public static final MediaType ISO_C10_ENVELOPE = ISO_C10; + public static final MediaType ISO_DESIGNATED_LONG_ENVELOPE + = ISO_DESIGNATED_LONG; + public static final MediaType STATEMENT = INVOICE; + public static final MediaType TABLOID = LEDGER; + public static final MediaType LETTER = NA_LETTER; + public static final MediaType NOTE = NA_LETTER; + public static final MediaType LEGAL = NA_LEGAL; + public static final MediaType ENV_10X15 = NA_10X15_ENVELOPE; + public static final MediaType ENV_10X14 = NA_10X14_ENVELOPE; + public static final MediaType ENV_10X13 = NA_10X13_ENVELOPE; + public static final MediaType ENV_9X12 = NA_9X12_ENVELOPE; + public static final MediaType ENV_9X11 = NA_9X11_ENVELOPE; + public static final MediaType ENV_7X9 = NA_7X9_ENVELOPE; + public static final MediaType ENV_6X9 = NA_6X9_ENVELOPE; + public static final MediaType ENV_9 = NA_NUMBER_9_ENVELOPE; + public static final MediaType ENV_10 = NA_NUMBER_10_ENVELOPE; + public static final MediaType ENV_11 = NA_NUMBER_11_ENVELOPE; + public static final MediaType ENV_12 = NA_NUMBER_12_ENVELOPE; + public static final MediaType ENV_14 = NA_NUMBER_14_ENVELOPE; + public static final MediaType ENV_INVITE = INVITE_ENVELOPE; + public static final MediaType ENV_ITALY = ITALY_ENVELOPE; + public static final MediaType ENV_MONARCH = MONARCH_ENVELOPE; + public static final MediaType ENV_PERSONAL = PERSONAL_ENVELOPE; + public static final MediaType INVITE = INVITE_ENVELOPE; + public static final MediaType ITALY = ITALY_ENVELOPE; + public static final MediaType MONARCH = MONARCH_ENVELOPE; + public static final MediaType PERSONAL = PERSONAL_ENVELOPE; + private MediaType(int value) + { + super(value, NAMES); + } + } // class MediaType + public static final class OrientationRequestedType extends AttributeValue + { + private static final String[] NAMES = { "portrait", "landscape" }; + public static final OrientationRequestedType PORTRAIT + = new OrientationRequestedType(0); + public static final OrientationRequestedType LANDSCAPE + = new OrientationRequestedType(1); + private OrientationRequestedType(int value) + { + super(value, NAMES); + } + } // class OrientationRequestedType + public static final class OriginType extends AttributeValue + { + private static final String[] NAMES = { "physical", "printable" }; + public static final OriginType PHYSICAL = new OriginType(0); + public static final OriginType PRINTABLE = new OriginType(1); + private OriginType(int value) + { + super(value, NAMES); + } + } // class OriginType + public static final class PrintQualityType extends AttributeValue + { + private static final String[] NAMES = { "high", "normal", "draft" }; + public static final PrintQualityType HIGH = new PrintQualityType(0); + public static final PrintQualityType NORMAL = new PrintQualityType(1); + public static final PrintQualityType DRAFT = new PrintQualityType(2); + private PrintQualityType(int value) + { + super(value, NAMES); + } + } // class PrintQualityType + + + private ColorType color; + private MediaType media; + private OrientationRequestedType orientation; + private OriginType origin; + private PrintQualityType quality; + private int resolutionX; + private int resolutionY; + private int resolutionScale; + public PageAttributes() + { + color = ColorType.MONOCHROME; + setMediaToDefault(); + orientation = OrientationRequestedType.PORTRAIT; + origin = OriginType.PHYSICAL; + quality = PrintQualityType.NORMAL; + setPrinterResolutionToDefault(); + } + + public PageAttributes(PageAttributes attr) + { + set(attr); + } + + public PageAttributes(ColorType color, MediaType media, + OrientationRequestedType orientation, + OriginType origin, PrintQualityType quality, + int[] resolution) + { + if (color == null || media == null || orientation == null + || origin == null || quality == null) + throw new IllegalArgumentException(); + setPrinterResolution(resolution); + this.color = color; + this.media = media; + this.orientation = orientation; + this.origin = origin; + this.quality = quality; + } + + public Object clone() + { + return new PageAttributes(this); + } + + public void set(PageAttributes attr) + { + color = attr.color; + media = attr.media; + orientation = attr.orientation; + origin = attr.origin; + quality = attr.quality; + resolutionX = attr.resolutionX; + resolutionY = attr.resolutionY; + resolutionScale = attr.resolutionScale; + } + + public ColorType getColor() + { + return color; + } + + public void setColor(ColorType color) + { + if (color == null) + throw new IllegalArgumentException(); + this.color = color; + } + + public MediaType getMedia() + { + return media; + } + + public void setMedia(MediaType media) + { + if (media == null) + throw new IllegalArgumentException(); + this.media = media; + } + + public void setMediaToDefault() + { + String country = Locale.getDefault().getCountry(); + media = ("US".equals(country) || "CA".equals(country)) ? MediaType.LETTER + : MediaType.A4; + } + + public OrientationRequestedType getOrientationRequested() + { + return orientation; + } + + public void setOrientationRequested(OrientationRequestedType orientation) + { + if (orientation == null) + throw new IllegalArgumentException(); + this.orientation = orientation; + } + + public void setOrientationRequested(int orientation) + { + if (orientation == 3) + this.orientation = OrientationRequestedType.PORTRAIT; + else if (orientation == 4) + this.orientation = OrientationRequestedType.LANDSCAPE; + else + throw new IllegalArgumentException(); + } + + public void setOrientationRequestedToDefault() + { + orientation = OrientationRequestedType.PORTRAIT; + } + + public OriginType getOrigin() + { + return origin; + } + + public void setOrigin(OriginType origin) + { + if (origin == null) + throw new IllegalArgumentException(); + this.origin = origin; + } + + public PrintQualityType getPrintQuality() + { + return quality; + } + + public void setPrintQuality(PrintQualityType quality) + { + if (quality == null) + throw new IllegalArgumentException(); + this.quality = quality; + } + + public void setPrintQuality(int quality) + { + if (quality == 3) + this.quality = PrintQualityType.DRAFT; + else if (quality == 4) + this.quality = PrintQualityType.NORMAL; + else if (quality == 5) + this.quality = PrintQualityType.HIGH; + else + throw new IllegalArgumentException(); + } + + public void setPrintQualityToDefault() + { + quality = PrintQualityType.NORMAL; + } + + public int[] getPrinterResolution() + { + return new int[] { resolutionX, resolutionY, resolutionScale }; + } + + public void setPrinterResolution(int[] resolution) + { + if (resolution == null || resolution.length != 3 || resolution[0] <= 0 + || resolution[1] <= 0 || resolution[2] < 3 || resolution[2] > 4) + throw new IllegalArgumentException(); + resolutionX = resolution[0]; + resolutionY = resolution[1]; + resolutionScale = resolution[2]; + } + + public void setPrinterResolution(int resolution) + { + if (resolution <= 0) + throw new IllegalArgumentException(); + resolutionX = resolution; + resolutionY = resolution; + resolutionScale = 3; + } + + public void setPrinterResolutionToDefault() + { + resolutionX = 72; + resolutionY = 72; + resolutionScale = 3; + } + + public boolean equals(Object o) + { + if (this == o) + return true; + if (! (o instanceof PageAttributes)) + return false; + PageAttributes pa = (PageAttributes) o; + return color == pa.color && media == pa.media + && orientation == pa.orientation && origin == pa.origin + && quality == pa.quality && resolutionX == pa.resolutionX + && resolutionY == pa.resolutionY + && resolutionScale == pa.resolutionScale; + } + public int hashCode() + { + return (color.value << 31) ^ (media.value << 24) + ^ (orientation.value << 23) ^ (origin.value << 22) + ^ (quality.value << 20) ^ (resolutionScale << 19) + ^ (resolutionY << 10) ^ resolutionX; + } + public String toString() + { + return "color=" + color + ",media=" + media + ",orientation-requested=" + + orientation + ",origin=" + origin + ",print-quality=" + quality + + ",printer-resolution=[" + resolutionX + ',' + resolutionY + ',' + + resolutionScale + ']'; + } +} // class PageAttributes diff --git a/libjava/classpath/java/awt/Paint.java b/libjava/classpath/java/awt/Paint.java new file mode 100644 index 000000000..0f099cc0b --- /dev/null +++ b/libjava/classpath/java/awt/Paint.java @@ -0,0 +1,79 @@ +/* Paint.java -- generate colors for Graphics2D operations + Copyright (C) 2000, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; + +/** + * Defines how color patterns are generated for Graphics2D operations. This + * is used to perform the <code>draw</code> and <code>fill</code> methods + * of the graphics object. Instances must be immutable, because the graphics + * object does not clone them. + * + * @author Warren Levy (warrenl@cygnus.com) + * @see PaintContext + * @see Color + * @see GradientPaint + * @see TexturePaint + * @see Graphics2D#setPaint(Paint) + * @since 1.1 + * @status updated to 1.4 + */ +public interface Paint extends Transparency +{ + /** + * Create the context necessary for performing the color pattern generation. + * The color model is a hint, and may be null for Classpath implementations; + * however some legacy code may throw a NullPointerException when passed a + * null. Leaving the color model null provides the most efficiency and leeway + * in the generation of the color pattern. + * + * @param cm the color model, used as a hint + * @param deviceBounds the device space bounding box of the painted area + * @param userBounds the user space bounding box of the painted area + * @param xform the transformation from user space to device space + * @param hints any hints for choosing between rendering alternatives + * @return the context for performing the paint + */ + PaintContext createContext(ColorModel cm, Rectangle deviceBounds, + Rectangle2D userBounds, AffineTransform xform, + RenderingHints hints); +} // interface Paint diff --git a/libjava/classpath/java/awt/PaintContext.java b/libjava/classpath/java/awt/PaintContext.java new file mode 100644 index 000000000..3d5fdcdf0 --- /dev/null +++ b/libjava/classpath/java/awt/PaintContext.java @@ -0,0 +1,76 @@ +/* PaintContext.java -- the environment for performing a paint operation + Copyright (C) 2000, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.image.ColorModel; +import java.awt.image.Raster; + +/** + * @author Warren Levy (warrenl@cygnus.com) + * @see Paint + * @since 1.1 + * @status updated to 1.4 + */ +public interface PaintContext +{ + /** + * Release the resources allocated for the paint. + */ + void dispose(); + + /** + * Return the color model of this context. It may be different from the + * hint specified during createContext, as not all contexts can generate + * color patterns in an arbitrary model. + * + * @return the context color model + */ + ColorModel getColorModel(); + + /** + * Return a raster containing the colors for the graphics operation. + * + * @param x the x-coordinate, in device space + * @param y the y-coordinate, in device space + * @param w the width, in device space + * @param h the height, in device space + * @return a raster for the given area and color + */ + Raster getRaster(int x, int y, int w, int h); +} // interface PaintContext diff --git a/libjava/classpath/java/awt/Panel.java b/libjava/classpath/java/awt/Panel.java new file mode 100644 index 000000000..cc17eef22 --- /dev/null +++ b/libjava/classpath/java/awt/Panel.java @@ -0,0 +1,173 @@ +/* Panel.java -- Simple container object + Copyright (C) 1999, 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; + +/** + * A panel is a simple container class. It's default layout is the + * <code>FlowLayout</code> manager. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see FlowLayout + * @since 1.0 + * @status updated to 1.4 + */ +public class Panel extends Container implements Accessible +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -2728009084054400034L; + + /** The cached accessible context. */ + private transient AccessibleContext context; + + /** Flag set when the first system-requested paint event is + dispatched. */ + private transient boolean initialSystemUpdateDone; + + /** Flag set when the first application-requested paint event is + consumed. */ + private transient boolean initialUpdateConsumed; + + /* + * The number used to generate the name returned by getName. + */ + private static transient long next_panel_number; + + /** + * Initializes a new instance of <code>Panel</code> that has a default + * layout manager of <code>FlowLayout</code>. + */ + public Panel() + { + this(new FlowLayout()); + } + + /** + * Initializes a new instance of <code>Panel</code> with the specified + * layout manager. + * + * @param layoutManager the layout manager for this object + * @since 1.1 + */ + public Panel(LayoutManager layoutManager) + { + setLayout(layoutManager); + } + + /** + * Notifies this object to create its native peer. + * + * @see #isDisplayable() + * @see #removeNotify() + */ + public void addNotify() + { + if (peer == null) + peer = getToolkit().createPanel(this); + super.addNotify(); + } + + /** + * Gets the AccessibleContext associated with this panel, creating one if + * necessary. This always returns an instance of {@link AccessibleAWTPanel}. + * + * @return the accessibility context of this panel + * @since 1.3 + */ + public AccessibleContext getAccessibleContext() + { + if (context == null) + context = new AccessibleAWTPanel(); + return context; + } + + /** + * This class provides accessibility support for Panels, and is the + * runtime type returned by {@link #getAccessibleContext()}. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + */ + protected class AccessibleAWTPanel extends AccessibleAWTContainer + { + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = -6409552226660031050L; + + /** + * The default constructor. + */ + protected AccessibleAWTPanel() + { + } + + /** + * Get the role of this accessible object, a panel. + * + * @return the role of the object + * @see AccessibleRole#PANEL + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.PANEL; + } + } + + /** + * Generate a unique name for this panel. + * + * @return A unique name for this panel. + */ + String generateName () + { + return "panel" + getUniqueLong (); + } + + private static synchronized long getUniqueLong () + { + return next_panel_number++; + } +} diff --git a/libjava/classpath/java/awt/Point.java b/libjava/classpath/java/awt/Point.java new file mode 100644 index 000000000..871202491 --- /dev/null +++ b/libjava/classpath/java/awt/Point.java @@ -0,0 +1,250 @@ +/* Point.java -- represents a point in 2-D space + Copyright (C) 1999, 2002, 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.geom.Point2D; +import java.io.Serializable; + +/** + * This class represents a point on the screen using cartesian coordinates. + * Remember that in screen coordinates, increasing x values go from left to + * right, and increasing y values go from top to bottom. + * + * <p>There are some public fields; if you mess with them in an inconsistent + * manner, it is your own fault when you get invalid results. Also, this + * class is not threadsafe. + * + * @author Per Bothner (bothner@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status updated to 1.4 + */ +public class Point extends Point2D implements Serializable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -5276940640259749850L; + + /** + * The x coordinate. + * + * @see #getLocation() + * @see #move(int, int) + * @serial the X coordinate of the point + */ + public int x; + + /** + * The y coordinate. + * + * @see #getLocation() + * @see #move(int, int) + * @serial The Y coordinate of the point + */ + public int y; + + /** + * Initializes a new instance of <code>Point</code> representing the + * coordinates (0, 0). + * + * @since 1.1 + */ + public Point() + { + } + + /** + * Initializes a new instance of <code>Point</code> with coordinates + * identical to the coordinates of the specified point. + * + * @param p the point to copy the coordinates from + * @throws NullPointerException if p is null + */ + public Point(Point p) + { + x = p.x; + y = p.y; + } + + /** + * Initializes a new instance of <code>Point</code> with the specified + * coordinates. + * + * @param x the X coordinate + * @param y the Y coordinate + */ + public Point(int x, int y) + { + this.x = x; + this.y = y; + } + + /** + * Get the x coordinate. + * + * @return the value of x, as a double + */ + public double getX() + { + return x; + } + + /** + * Get the y coordinate. + * + * @return the value of y, as a double + */ + public double getY() + { + return y; + } + + /** + * Returns the location of this point. A pretty useless method, as this + * is already a point. + * + * @return a copy of this point + * @see #setLocation(Point) + * @since 1.1 + */ + public Point getLocation() + { + return new Point(x, y); + } + + /** + * Sets this object's coordinates to match those of the specified point. + * + * @param p the point to copy the coordinates from + * @throws NullPointerException if p is null + * @since 1.1 + */ + public void setLocation(Point p) + { + x = p.x; + y = p.y; + } + + /** + * Sets this object's coordinates to the specified values. This method + * is identical to the <code>move()</code> method. + * + * @param x the new X coordinate + * @param y the new Y coordinate + */ + public void setLocation(int x, int y) + { + this.x = x; + this.y = y; + } + + /** + * Sets this object's coordinates to the specified values. This method + * rounds to the nearest integer coordinates by adding 0.5 and calling + * {@link Math#floor(double)}. + * + * @param x the new X coordinate + * @param y the new Y coordinate + */ + public void setLocation(double x, double y) + { + this.x = (int) Math.floor(x + 0.5); + this.y = (int) Math.floor(y + 0.5); + } + + /** + * Sets this object's coordinates to the specified values. This method + * is identical to the <code>setLocation(int, int)</code> method. + * + * @param x the new X coordinate + * @param y the new Y coordinate + */ + public void move(int x, int y) + { + this.x = x; + this.y = y; + } + + /** + * Changes the coordinates of this point such that the specified + * <code>dx</code> parameter is added to the existing X coordinate and + * <code>dy</code> is added to the existing Y coordinate. + * + * @param dx the amount to add to the X coordinate + * @param dy the amount to add to the Y coordinate + */ + public void translate(int dx, int dy) + { + x += dx; + y += dy; + } + + /** + * Tests whether or not this object is equal to the specified object. + * This will be true if and only if the specified object is an instance + * of Point2D and has the same X and Y coordinates. + * + * @param obj the object to test against for equality + * @return true if the specified object is equal + */ + public boolean equals(Object obj) + { + // NOTE: No special hashCode() method is required for this class, + // as this equals() implementation is functionally equivalent to + // super.equals(), which does define a proper hashCode(). + + if (! (obj instanceof Point2D)) + return false; + Point2D p = (Point2D) obj; + return x == p.getX() && y == p.getY(); + } + + /** + * Returns a string representation of this object. The format is: + * <code>getClass().getName() + "[x=" + x + ",y=" + y + ']'</code>. + * + * @return a string representation of this object + */ + public String toString() + { + return getClass().getName() + "[x=" + x + ",y=" + y + ']'; + } +} // class Point diff --git a/libjava/classpath/java/awt/PointerInfo.java b/libjava/classpath/java/awt/PointerInfo.java new file mode 100644 index 000000000..2bbd97677 --- /dev/null +++ b/libjava/classpath/java/awt/PointerInfo.java @@ -0,0 +1,84 @@ +/* PointerInfo.java -- mouse pointer data + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt; + +/** + * PointerInfo represents information about the mouse pointer, + * i.e. its GraphicsDevice and location. + * + * PointerInfo objects cannot be instantiated directly, but are + * retrieved from MouseInfo.getPointerInfo(). PointerInfo objects + * are immutable and will not be updated for future mouse motions. + * + * @since 1.5 + * @author Sven de Marothy + */ +public class PointerInfo +{ + private GraphicsDevice gd; + private Point p; + + /** + * Package-private constructor used by MouseInfo. + */ + PointerInfo( GraphicsDevice gd, Point p ) + { + this.gd = gd; + this.p = p; + } + + /** + * Returns the GraphicsDevice on which the mouse pointer was located + * + * @return a GraphicsDevice object. + */ + public GraphicsDevice getDevice() + { + return gd; + } + + /** + * Returns the coordinates of the mouse pointer. + * + * @return a Point object containing the pointer coordinates. + */ + public Point getLocation() + { + return p; + } +} diff --git a/libjava/classpath/java/awt/Polygon.java b/libjava/classpath/java/awt/Polygon.java new file mode 100644 index 000000000..03e91f8bd --- /dev/null +++ b/libjava/classpath/java/awt/Polygon.java @@ -0,0 +1,611 @@ +/* Polygon.java -- class representing a polygon + Copyright (C) 1999, 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Line2D; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.io.Serializable; + +/** + * This class represents a polygon, a closed, two-dimensional region in a + * coordinate space. The region is bounded by an arbitrary number of line + * segments, between (x,y) coordinate vertices. The polygon has even-odd + * winding, meaning that a point is inside the shape if it crosses the + * boundary an odd number of times on the way to infinity. + * + * <p>There are some public fields; if you mess with them in an inconsistent + * manner, it is your own fault when you get NullPointerException, + * ArrayIndexOutOfBoundsException, or invalid results. Also, this class is + * not threadsafe. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status updated to 1.4 + */ +public class Polygon implements Shape, Serializable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -6460061437900069969L; + + /** + * This total number of endpoints. + * + * @serial the number of endpoints, possibly less than the array sizes + */ + public int npoints; + + /** + * The array of X coordinates of endpoints. This should not be null. + * + * @see #addPoint(int, int) + * @serial the x coordinates + */ + public int[] xpoints; + + /** + * The array of Y coordinates of endpoints. This should not be null. + * + * @see #addPoint(int, int) + * @serial the y coordinates + */ + public int[] ypoints; + + /** + * The bounding box of this polygon. This is lazily created and cached, so + * it must be invalidated after changing points. + * + * @see #getBounds() + * @serial the bounding box, or null + */ + protected Rectangle bounds; + + /** A big number, but not so big it can't survive a few float operations */ + private static final double BIG_VALUE = java.lang.Double.MAX_VALUE / 10.0; + + /** + * Initializes an empty polygon. + */ + public Polygon() + { + // Leave room for growth. + xpoints = new int[4]; + ypoints = new int[4]; + } + + /** + * Create a new polygon with the specified endpoints. The arrays are copied, + * so that future modifications to the parameters do not affect the polygon. + * + * @param xpoints the array of X coordinates for this polygon + * @param ypoints the array of Y coordinates for this polygon + * @param npoints the total number of endpoints in this polygon + * @throws NegativeArraySizeException if npoints is negative + * @throws IndexOutOfBoundsException if npoints exceeds either array + * @throws NullPointerException if xpoints or ypoints is null + */ + public Polygon(int[] xpoints, int[] ypoints, int npoints) + { + this.xpoints = new int[npoints]; + this.ypoints = new int[npoints]; + System.arraycopy(xpoints, 0, this.xpoints, 0, npoints); + System.arraycopy(ypoints, 0, this.ypoints, 0, npoints); + this.npoints = npoints; + } + + /** + * Reset the polygon to be empty. The arrays are left alone, to avoid object + * allocation, but the number of points is set to 0, and all cached data + * is discarded. If you are discarding a huge number of points, it may be + * more efficient to just create a new Polygon. + * + * @see #invalidate() + * @since 1.4 + */ + public void reset() + { + npoints = 0; + invalidate(); + } + + /** + * Invalidate or flush all cached data. After direct manipulation of the + * public member fields, this is necessary to avoid inconsistent results + * in methods like <code>contains</code>. + * + * @see #getBounds() + * @since 1.4 + */ + public void invalidate() + { + bounds = null; + } + + /** + * Translates the polygon by adding the specified values to all X and Y + * coordinates. This updates the bounding box, if it has been calculated. + * + * @param dx the amount to add to all X coordinates + * @param dy the amount to add to all Y coordinates + * @since 1.1 + */ + public void translate(int dx, int dy) + { + int i = npoints; + while (--i >= 0) + { + xpoints[i] += dx; + ypoints[i] += dy; + } + if (bounds != null) + { + bounds.x += dx; + bounds.y += dy; + } + } + + /** + * Adds the specified endpoint to the polygon. This updates the bounding + * box, if it has been created. + * + * @param x the X coordinate of the point to add + * @param y the Y coordiante of the point to add + */ + public void addPoint(int x, int y) + { + if (npoints + 1 > xpoints.length) + { + int[] newx = new int[npoints + 1]; + System.arraycopy(xpoints, 0, newx, 0, npoints); + xpoints = newx; + } + if (npoints + 1 > ypoints.length) + { + int[] newy = new int[npoints + 1]; + System.arraycopy(ypoints, 0, newy, 0, npoints); + ypoints = newy; + } + xpoints[npoints] = x; + ypoints[npoints] = y; + npoints++; + if (bounds != null) + { + if (npoints == 1) + { + bounds.x = x; + bounds.y = y; + } + else + { + if (x < bounds.x) + { + bounds.width += bounds.x - x; + bounds.x = x; + } + else if (x > bounds.x + bounds.width) + bounds.width = x - bounds.x; + if (y < bounds.y) + { + bounds.height += bounds.y - y; + bounds.y = y; + } + else if (y > bounds.y + bounds.height) + bounds.height = y - bounds.y; + } + } + } + + /** + * Returns the bounding box of this polygon. This is the smallest + * rectangle with sides parallel to the X axis that will contain this + * polygon. + * + * @return the bounding box for this polygon + * @see #getBounds2D() + * @since 1.1 + */ + public Rectangle getBounds() + { + return getBoundingBox(); + } + + /** + * Returns the bounding box of this polygon. This is the smallest + * rectangle with sides parallel to the X axis that will contain this + * polygon. + * + * @return the bounding box for this polygon + * @see #getBounds2D() + * @deprecated use {@link #getBounds()} instead + */ + public Rectangle getBoundingBox() + { + if (bounds == null) + { + if (npoints == 0) + return bounds = new Rectangle(); + int i = npoints - 1; + int minx = xpoints[i]; + int maxx = minx; + int miny = ypoints[i]; + int maxy = miny; + while (--i >= 0) + { + int x = xpoints[i]; + int y = ypoints[i]; + if (x < minx) + minx = x; + else if (x > maxx) + maxx = x; + if (y < miny) + miny = y; + else if (y > maxy) + maxy = y; + } + bounds = new Rectangle(minx, miny, maxx - minx, maxy - miny); + } + return bounds; + } + + /** + * Tests whether or not the specified point is inside this polygon. + * + * @param p the point to test + * @return true if the point is inside this polygon + * @throws NullPointerException if p is null + * @see #contains(double, double) + */ + public boolean contains(Point p) + { + return contains(p.getX(), p.getY()); + } + + /** + * Tests whether or not the specified point is inside this polygon. + * + * @param x the X coordinate of the point to test + * @param y the Y coordinate of the point to test + * @return true if the point is inside this polygon + * @see #contains(double, double) + * @since 1.1 + */ + public boolean contains(int x, int y) + { + return contains((double) x, (double) y); + } + + /** + * Tests whether or not the specified point is inside this polygon. + * + * @param x the X coordinate of the point to test + * @param y the Y coordinate of the point to test + * @return true if the point is inside this polygon + * @see #contains(double, double) + * @deprecated use {@link #contains(int, int)} instead + */ + public boolean inside(int x, int y) + { + return contains((double) x, (double) y); + } + + /** + * Returns a high-precision bounding box of this polygon. This is the + * smallest rectangle with sides parallel to the X axis that will contain + * this polygon. + * + * @return the bounding box for this polygon + * @see #getBounds() + * @since 1.2 + */ + public Rectangle2D getBounds2D() + { + // For polygons, the integer version is exact! + return getBounds(); + } + + /** + * Tests whether or not the specified point is inside this polygon. + * + * @param x the X coordinate of the point to test + * @param y the Y coordinate of the point to test + * @return true if the point is inside this polygon + * @since 1.2 + */ + public boolean contains(double x, double y) + { + return ((evaluateCrossings(x, y, false, BIG_VALUE) & 1) != 0); + } + + /** + * Tests whether or not the specified point is inside this polygon. + * + * @param p the point to test + * @return true if the point is inside this polygon + * @throws NullPointerException if p is null + * @see #contains(double, double) + * @since 1.2 + */ + public boolean contains(Point2D p) + { + return contains(p.getX(), p.getY()); + } + + /** + * Test if a high-precision rectangle intersects the shape. This is true + * if any point in the rectangle is in the shape. This implementation is + * precise. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle, treated as point if negative + * @param h the height of the rectangle, treated as point if negative + * @return true if the rectangle intersects this shape + * @since 1.2 + */ + public boolean intersects(double x, double y, double w, double h) + { + /* Does any edge intersect? */ + if (evaluateCrossings(x, y, false, w) != 0 /* top */ + || evaluateCrossings(x, y + h, false, w) != 0 /* bottom */ + || evaluateCrossings(x + w, y, true, h) != 0 /* right */ + || evaluateCrossings(x, y, true, h) != 0) /* left */ + return true; + + /* No intersections, is any point inside? */ + if ((evaluateCrossings(x, y, false, BIG_VALUE) & 1) != 0) + return true; + + return false; + } + + /** + * Test if a high-precision rectangle intersects the shape. This is true + * if any point in the rectangle is in the shape. This implementation is + * precise. + * + * @param r the rectangle + * @return true if the rectangle intersects this shape + * @throws NullPointerException if r is null + * @see #intersects(double, double, double, double) + * @since 1.2 + */ + public boolean intersects(Rectangle2D r) + { + return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Test if a high-precision rectangle lies completely in the shape. This is + * true if all points in the rectangle are in the shape. This implementation + * is precise. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle, treated as point if negative + * @param h the height of the rectangle, treated as point if negative + * @return true if the rectangle is contained in this shape + * @since 1.2 + */ + public boolean contains(double x, double y, double w, double h) + { + if (! getBounds2D().intersects(x, y, w, h)) + return false; + + /* Does any edge intersect? */ + if (evaluateCrossings(x, y, false, w) != 0 /* top */ + || evaluateCrossings(x, y + h, false, w) != 0 /* bottom */ + || evaluateCrossings(x + w, y, true, h) != 0 /* right */ + || evaluateCrossings(x, y, true, h) != 0) /* left */ + return false; + + /* No intersections, is any point inside? */ + if ((evaluateCrossings(x, y, false, BIG_VALUE) & 1) != 0) + return true; + + return false; + } + + /** + * Test if a high-precision rectangle lies completely in the shape. This is + * true if all points in the rectangle are in the shape. This implementation + * is precise. + * + * @param r the rectangle + * @return true if the rectangle is contained in this shape + * @throws NullPointerException if r is null + * @see #contains(double, double, double, double) + * @since 1.2 + */ + public boolean contains(Rectangle2D r) + { + return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Return an iterator along the shape boundary. If the optional transform + * is provided, the iterator is transformed accordingly. Each call returns + * a new object, independent from others in use. This class is not + * threadsafe to begin with, so the path iterator is not either. + * + * @param transform an optional transform to apply to the iterator + * @return a new iterator over the boundary + * @since 1.2 + */ + public PathIterator getPathIterator(final AffineTransform transform) + { + return new PathIterator() + { + /** The current vertex of iteration. */ + private int vertex; + + public int getWindingRule() + { + return WIND_EVEN_ODD; + } + + public boolean isDone() + { + return vertex > npoints; + } + + public void next() + { + vertex++; + } + + public int currentSegment(float[] coords) + { + if (vertex >= npoints) + return SEG_CLOSE; + coords[0] = xpoints[vertex]; + coords[1] = ypoints[vertex]; + if (transform != null) + transform.transform(coords, 0, coords, 0, 1); + return vertex == 0 ? SEG_MOVETO : SEG_LINETO; + } + + public int currentSegment(double[] coords) + { + if (vertex >= npoints) + return SEG_CLOSE; + coords[0] = xpoints[vertex]; + coords[1] = ypoints[vertex]; + if (transform != null) + transform.transform(coords, 0, coords, 0, 1); + return vertex == 0 ? SEG_MOVETO : SEG_LINETO; + } + }; + } + + /** + * Return an iterator along the flattened version of the shape boundary. + * Since polygons are already flat, the flatness parameter is ignored, and + * the resulting iterator only has SEG_MOVETO, SEG_LINETO and SEG_CLOSE + * points. If the optional transform is provided, the iterator is + * transformed accordingly. Each call returns a new object, independent + * from others in use. This class is not threadsafe to begin with, so the + * path iterator is not either. + * + * @param transform an optional transform to apply to the iterator + * @param flatness the maximum distance for deviation from the real boundary + * @return a new iterator over the boundary + * @since 1.2 + */ + public PathIterator getPathIterator(AffineTransform transform, + double flatness) + { + return getPathIterator(transform); + } + + /** + * Helper for contains, intersects, calculates the number of intersections + * between the polygon and a line extending from the point (x, y) along + * the positive X, or Y axis, within a given interval. + * + * @return the winding number. + * @see #contains(double, double) + */ + private int evaluateCrossings(double x, double y, boolean useYaxis, + double distance) + { + double x0; + double x1; + double y0; + double y1; + double epsilon = 0.0; + int crossings = 0; + int[] xp; + int[] yp; + + if (useYaxis) + { + xp = ypoints; + yp = xpoints; + double swap; + swap = y; + y = x; + x = swap; + } + else + { + xp = xpoints; + yp = ypoints; + } + + /* Get a value which is small but not insignificant relative the path. */ + epsilon = 1E-7; + + x0 = xp[0] - x; + y0 = yp[0] - y; + for (int i = 1; i < npoints; i++) + { + x1 = xp[i] - x; + y1 = yp[i] - y; + + if (y0 == 0.0) + y0 -= epsilon; + if (y1 == 0.0) + y1 -= epsilon; + if (y0 * y1 < 0) + if (Line2D.linesIntersect(x0, y0, x1, y1, epsilon, 0.0, distance, 0.0)) + ++crossings; + + x0 = xp[i] - x; + y0 = yp[i] - y; + } + + // end segment + x1 = xp[0] - x; + y1 = yp[0] - y; + if (y0 == 0.0) + y0 -= epsilon; + if (y1 == 0.0) + y1 -= epsilon; + if (y0 * y1 < 0) + if (Line2D.linesIntersect(x0, y0, x1, y1, epsilon, 0.0, distance, 0.0)) + ++crossings; + + return crossings; + } +} // class Polygon diff --git a/libjava/classpath/java/awt/PopupMenu.java b/libjava/classpath/java/awt/PopupMenu.java new file mode 100644 index 000000000..8595300f1 --- /dev/null +++ b/libjava/classpath/java/awt/PopupMenu.java @@ -0,0 +1,190 @@ +/* PopupMenu.java -- An AWT popup menu + Copyright (C) 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.peer.PopupMenuPeer; + +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; + +/** + * This class implement an AWT popup menu widget + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class PopupMenu extends Menu +{ + +/* + * Static Variables + */ + + /** + * The number used to generate the name returned by getName. + */ + private static transient long next_popup_number; + + // Serialization Constant + private static final long serialVersionUID = - 4620452533522760060L; + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of <code>PopupMenu</code>. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ +public +PopupMenu() +{ +} + +/*************************************************************************/ + +/** + * Initializes a new instance of <code>PopupMenu</code> with the specified + * label. + * + * @param label The label for this popup menu. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ +public +PopupMenu(String label) +{ + super(label); + + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException (); +} + +/*************************************************************************/ + +/* + * Instance Methods + */ + +/** + * Creates this object's native peer. + */ +public void +addNotify() +{ + if (peer == null) + peer = getToolkit ().createPopupMenu (this); + super.addNotify (); +} + +/*************************************************************************/ + +/** + * Displays this popup menu at the specified coordinates relative to + * the specified component. + * + * @param component The component to which the display coordinates are relative. + * @param x The X coordinate of the menu. + * @param y The Y coordinate of the menu. + */ +public void +show(Component component, int x, int y) +{ + if (getPeer() == null) + this.addNotify(); + PopupMenuPeer pmp = (PopupMenuPeer)getPeer(); + if (pmp != null) + { + /* XXX + Event e = new Event (component, Event.ACTION_EVENT, component); + e.x = x; + e.y = y;*/ + pmp.show (component, x, y); + } +} + + protected class AccessibleAWTPopupMenu extends AccessibleAWTMenu + { + private static final long serialVersionUID = -4282044795947239955L; + + protected AccessibleAWTPopupMenu() + { + } + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.POPUP_MENU; + } + + } + + /** + * Gets the AccessibleContext associated with this <code>PopupMenu</code>. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTPopupMenu(); + return accessibleContext; + } + + /** + * Generate a unique name for this <code>PopupMenu</code>. + * + * @return A unique name for this <code>PopupMenu</code>. + */ + String generateName() + { + return "popup" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_popup_number++; + } + +} // class PopupMenu diff --git a/libjava/classpath/java/awt/PrintGraphics.java b/libjava/classpath/java/awt/PrintGraphics.java new file mode 100644 index 000000000..e7f857797 --- /dev/null +++ b/libjava/classpath/java/awt/PrintGraphics.java @@ -0,0 +1,57 @@ +/* PrintGraphics.java -- a print graphics context + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +/** + * This interface allows the originating print job to be obtained. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.0 + * @status updated to 1.4 + */ +public interface PrintGraphics +{ + /** + * Returns the <code>PrintJob</code> that this object is being + * managed by. + * + * @return the print job for this object + */ + PrintJob getPrintJob(); +} // interface PrintGraphics diff --git a/libjava/classpath/java/awt/PrintJob.java b/libjava/classpath/java/awt/PrintJob.java new file mode 100644 index 000000000..62aa8b195 --- /dev/null +++ b/libjava/classpath/java/awt/PrintJob.java @@ -0,0 +1,104 @@ +/* PrintJob.java -- A print job class + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.util.Properties; + +/** + * This abstract class represents a print job. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see Toolkit#getPrintJob(Frame, String, Properties) + * @since 1.0 + * @status updated to 1.4 + */ +public abstract class PrintJob +{ + /** + * Create a new PrintJob. + */ + public PrintJob() + { + } + + /** + * Returns a graphics context suitable for rendering the next page. The + * return must also implement {@link PrintGraphics}. + * + * @return a graphics context for printing the next page + */ + public abstract Graphics getGraphics(); + + /** + * Returns the dimension of the page in pixels. The resolution will be + * chosen to be similar to the on screen image. + * + * @return the page dimensions + */ + public abstract Dimension getPageDimension(); + + /** + * Returns the resolution of the page in pixels per inch. Note that this is + * not necessarily the printer's resolution. + * + * @return the resolution of the page in pixels per inch + */ + public abstract int getPageResolution(); + + /** + * Tests whether or not the last page will be printed first. + * + * @return true if the last page prints first + */ + public abstract boolean lastPageFirst(); + + /** + * Informs the print job that printing is complete or should be aborted. + */ + public abstract void end(); + + /** + * This method explicitly ends the print job in the event the job + * becomes un-referenced without the application having done so. + */ + public void finalize() + { + end(); + } +} // class PrintJob diff --git a/libjava/classpath/java/awt/Rectangle.java b/libjava/classpath/java/awt/Rectangle.java new file mode 100644 index 000000000..1d5a8da07 --- /dev/null +++ b/libjava/classpath/java/awt/Rectangle.java @@ -0,0 +1,753 @@ +/* Rectangle.java -- represents a graphics rectangle + Copyright (C) 1999, 2000, 2001, 2002, 2006, Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.geom.Rectangle2D; +import java.io.Serializable; + +/** + * This class represents a rectangle and all the interesting things you + * might want to do with it. Note that the coordinate system uses + * the origin (0,0) as the top left of the screen, with the x and y + * values increasing as they move to the right and down respectively. + * + * <p>It is valid for a rectangle to have negative width or height; but it + * is considered to have no area or internal points. Therefore, the behavior + * in methods like <code>contains</code> or <code>intersects</code> is + * undefined unless the rectangle has positive width and height. + * + * <p>There are some public fields; if you mess with them in an inconsistent + * manner, it is your own fault when you get NullPointerException, + * ArrayIndexOutOfBoundsException, or invalid results. Also, this class is + * not threadsafe. + * + * @author Warren Levy (warrenl@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status updated to 1.4 + */ +public class Rectangle extends Rectangle2D implements Shape, Serializable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -4345857070255674764L; + + /** + * The X coordinate of the top-left corner of the rectangle. + * + * @see #setLocation(int, int) + * @see #getLocation() + * @serial the x coordinate + */ + public int x; + + /** + * The Y coordinate of the top-left corner of the rectangle. + * + * @see #setLocation(int, int) + * @see #getLocation() + * @serial the y coordinate + */ + public int y; + + /** + * The width of the rectangle. + * + * @see #setSize(int, int) + * @see #getSize() + * @serial + */ + public int width; + + /** + * The height of the rectangle. + * + * @see #setSize(int, int) + * @see #getSize() + * @serial + */ + public int height; + + /** + * Initializes a new instance of <code>Rectangle</code> with a top + * left corner at (0,0) and a width and height of 0. + */ + public Rectangle() + { + } + + /** + * Initializes a new instance of <code>Rectangle</code> from the + * coordinates of the specified rectangle. + * + * @param r the rectangle to copy from + * @since 1.1 + */ + public Rectangle(Rectangle r) + { + x = r.x; + y = r.y; + width = r.width; + height = r.height; + } + + /** + * Initializes a new instance of <code>Rectangle</code> from the specified + * inputs. + * + * @param x the X coordinate of the top left corner + * @param y the Y coordinate of the top left corner + * @param width the width of the rectangle + * @param height the height of the rectangle + */ + public Rectangle(int x, int y, int width, int height) + { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + /** + * Initializes a new instance of <code>Rectangle</code> with the specified + * width and height. The upper left corner of the rectangle will be at + * the origin (0,0). + * + * @param width the width of the rectangle + * @param height the height of the rectange + */ + public Rectangle(int width, int height) + { + this.width = width; + this.height = height; + } + + /** + * Initializes a new instance of <code>Rectangle</code> with a top-left + * corner represented by the specified point and the width and height + * represented by the specified dimension. + * + * @param p the upper left corner of the rectangle + * @param d the width and height of the rectangle + */ + public Rectangle(Point p, Dimension d) + { + x = p.x; + y = p.y; + width = d.width; + height = d.height; + } + + /** + * Initializes a new instance of <code>Rectangle</code> with a top left + * corner at the specified point and a width and height of zero. + * + * @param p the upper left corner of the rectangle + */ + public Rectangle(Point p) + { + x = p.x; + y = p.y; + } + + /** + * Initializes a new instance of <code>Rectangle</code> with an + * upper left corner at the origin (0,0) and a width and height represented + * by the specified dimension. + * + * @param d the width and height of the rectangle + */ + public Rectangle(Dimension d) + { + width = d.width; + height = d.height; + } + + /** + * Get the X coordinate of the upper-left corner. + * + * @return the value of x, as a double + */ + public double getX() + { + return x; + } + + /** + * Get the Y coordinate of the upper-left corner. + * + * @return the value of y, as a double + */ + public double getY() + { + return y; + } + + /** + * Get the width of the rectangle. + * + * @return the value of width, as a double + */ + public double getWidth() + { + return width; + } + + /** + * Get the height of the rectangle. + * + * @return the value of height, as a double + */ + public double getHeight() + { + return height; + } + + /** + * Returns the bounds of this rectangle. A pretty useless method, as this + * is already a rectangle; it is included to mimic the + * <code>getBounds</code> method in Component. + * + * @return a copy of this rectangle + * @see #setBounds(Rectangle) + * @since 1.1 + */ + public Rectangle getBounds() + { + return new Rectangle(this); + } + + /** + * Returns the high-precision bounds of this rectangle. A pretty useless + * method, as this is already a rectangle. + * + * @return a copy of this rectangle + * @see #setBounds(Rectangle) + * @since 1.2 + */ + public Rectangle2D getBounds2D() + { + return new Rectangle(x, y, width, height); + } + + /** + * Updates this rectangle to match the dimensions of the specified + * rectangle. + * + * @param r the rectangle to update from + * @throws NullPointerException if r is null + * @see #setBounds(int, int, int, int) + * @since 1.1 + */ + public void setBounds(Rectangle r) + { + setBounds (r.x, r.y, r.width, r.height); + } + + /** + * Updates this rectangle to have the specified dimensions. + * + * @param x the new X coordinate of the upper left hand corner + * @param y the new Y coordinate of the upper left hand corner + * @param width the new width of this rectangle + * @param height the new height of this rectangle + * @since 1.1 + */ + public void setBounds(int x, int y, int width, int height) + { + reshape (x, y, width, height); + } + + /** + * Updates this rectangle to have the specified dimensions, rounded to the + * integer precision used by this class (the values are rounded "outwards" so + * that the stored rectangle completely encloses the specified double + * precision rectangle). + * + * @param x the new X coordinate of the upper left hand corner + * @param y the new Y coordinate of the upper left hand corner + * @param width the new width of this rectangle + * @param height the new height of this rectangle + * @since 1.2 + */ + public void setRect(double x, double y, double width, double height) + { + this.x = (int) Math.floor(x); + this.y = (int) Math.floor(y); + this.width = (int) Math.ceil(x + width) - this.x; + this.height = (int) Math.ceil(y + height) - this.y; + } + + /** + * Updates this rectangle to have the specified dimensions. + * + * @param x the new X coordinate of the upper left hand corner + * @param y the new Y coordinate of the upper left hand corner + * @param width the new width of this rectangle + * @param height the new height of this rectangle + * @deprecated use {@link #setBounds(int, int, int, int)} instead + */ + public void reshape(int x, int y, int width, int height) + { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + /** + * Returns the location of this rectangle, which is the coordinates of + * its upper left corner. + * + * @return the point where this rectangle is located + * @see #setLocation(Point) + * @since 1.1 + */ + public Point getLocation() + { + return new Point(x,y); + } + + /** + * Moves the location of this rectangle by setting its upper left + * corner to the specified point. + * + * @param p the point to move the rectangle to + * @throws NullPointerException if p is null + * @see #getLocation() + * @since 1.1 + */ + public void setLocation(Point p) + { + setLocation (p.x, p.y); + } + + /** + * Moves the location of this rectangle by setting its upper left + * corner to the specified coordinates. + * + * @param x the new X coordinate for this rectangle + * @param y the new Y coordinate for this rectangle + * @since 1.1 + */ + public void setLocation(int x, int y) + { + move (x, y); + } + + /** + * Moves the location of this rectangle by setting its upper left + * corner to the specified coordinates. + * + * @param x the new X coordinate for this rectangle + * @param y the new Y coordinate for this rectangle + * @deprecated use {@link #setLocation(int, int)} instead + */ + public void move(int x, int y) + { + this.x = x; + this.y = y; + } + + /** + * Translate the location of this rectangle by the given amounts. + * + * @param dx the x distance to move by + * @param dy the y distance to move by + * @see #setLocation(int, int) + */ + public void translate(int dx, int dy) + { + x += dx; + y += dy; + } + + /** + * Returns the size of this rectangle. + * + * @return the size of this rectangle + * @see #setSize(Dimension) + * @since 1.1 + */ + public Dimension getSize() + { + return new Dimension(width, height); + } + + /** + * Sets the size of this rectangle based on the specified dimensions. + * + * @param d the new dimensions of the rectangle + * @throws NullPointerException if d is null + * @see #getSize() + * @since 1.1 + */ + public void setSize(Dimension d) + { + setSize (d.width, d.height); + } + + /** + * Sets the size of this rectangle based on the specified dimensions. + * + * @param width the new width of the rectangle + * @param height the new height of the rectangle + * @since 1.1 + */ + public void setSize(int width, int height) + { + resize (width, height); + } + + /** + * Sets the size of this rectangle based on the specified dimensions. + * + * @param width the new width of the rectangle + * @param height the new height of the rectangle + * @deprecated use {@link #setSize(int, int)} instead + */ + public void resize(int width, int height) + { + this.width = width; + this.height = height; + } + + /** + * Tests whether or not the specified point is inside this rectangle. + * According to the contract of Shape, a point on the border is in only if + * it has an adjacent point inside the rectangle in either the increasing + * x or y direction. + * + * @param p the point to test + * @return true if the point is inside the rectangle + * @throws NullPointerException if p is null + * @see #contains(int, int) + * @since 1.1 + */ + public boolean contains(Point p) + { + return contains (p.x, p.y); + } + + /** + * Tests whether or not the specified point is inside this rectangle. + * According to the contract of Shape, a point on the border is in only if + * it has an adjacent point inside the rectangle in either the increasing + * x or y direction. + * + * @param x the X coordinate of the point to test + * @param y the Y coordinate of the point to test + * @return true if the point is inside the rectangle + * @since 1.1 + */ + public boolean contains(int x, int y) + { + return inside (x, y); + } + + /** + * Checks whether all points in the given rectangle are contained in this + * rectangle. + * + * @param r the rectangle to check + * @return true if r is contained in this rectangle + * @throws NullPointerException if r is null + * @see #contains(int, int, int, int) + * @since 1.1 + */ + public boolean contains(Rectangle r) + { + return contains (r.x, r.y, r.width, r.height); + } + + /** + * Checks whether all points in the given rectangle are contained in this + * rectangle. + * + * @param x the x coordinate of the rectangle to check + * @param y the y coordinate of the rectangle to check + * @param w the width of the rectangle to check + * @param h the height of the rectangle to check + * @return true if the parameters are contained in this rectangle + * @since 1.1 + */ + public boolean contains(int x, int y, int w, int h) + { + return width > 0 && height > 0 && w > 0 && h > 0 + && x >= this.x && x + w <= this.x + this.width + && y >= this.y && y + h <= this.y + this.height; + } + + /** + * Tests whether or not the specified point is inside this rectangle. + * + * @param x the X coordinate of the point to test + * @param y the Y coordinate of the point to test + * @return true if the point is inside the rectangle + * @deprecated use {@link #contains(int, int)} instead + */ + public boolean inside(int x, int y) + { + return width > 0 && height > 0 + && x >= this.x && x < this.x + width + && y >= this.y && y < this.y + height; + } + + /** + * Tests whether or not the specified rectangle intersects this rectangle. + * This means the two rectangles share at least one internal point. + * + * @param r the rectangle to test against + * @return true if the specified rectangle intersects this one + * @throws NullPointerException if r is null + * @since 1.2 + */ + public boolean intersects(Rectangle r) + { + return r.width > 0 && r.height > 0 && width > 0 && height > 0 + && r.x < x + width && r.x + r.width > x + && r.y < y + height && r.y + r.height > y; + } + + /** + * Determines the rectangle which is formed by the intersection of this + * rectangle with the specified rectangle. If the two do not intersect, + * an empty rectangle will be returned (meaning the width and/or height + * will be non-positive). + * + * @param r the rectange to calculate the intersection with + * @return a new rectangle bounding the intersection + * @throws NullPointerException if r is null + */ + public Rectangle intersection(Rectangle r) + { + Rectangle res = new Rectangle(); + intersect(this, r, res); + return res; + } + + /** + * Returns the smallest rectangle that contains both this rectangle + * and the specified rectangle. + * + * @param r the rectangle to compute the union with + * @return the smallest rectangle containing both rectangles + * @throws NullPointerException if r is null + */ + public Rectangle union(Rectangle r) + { + Rectangle res = new Rectangle(); + union(this, r, res); + return res; + } + + /** + * Modifies this rectangle so that it represents the smallest rectangle + * that contains both the existing rectangle and the specified point. + * However, if the point falls on one of the two borders which are not + * inside the rectangle, a subsequent call to <code>contains</code> may + * return false. + * + * @param x the X coordinate of the point to add to this rectangle + * @param y the Y coordinate of the point to add to this rectangle + */ + public void add(int x, int y) + { + add((double) x, (double) y); + } + + /** + * Modifies this rectangle so that it represents the smallest rectangle + * that contains both the existing rectangle and the specified point. + * However, if the point falls on one of the two borders which are not + * inside the rectangle, a subsequent call to <code>contains</code> may + * return false. + * + * @param p the point to add to this rectangle + * @throws NullPointerException if p is null + */ + public void add(Point p) + { + add((double) p.x, (double) p.y); + } + + /** + * Modifies this rectangle so that it represents the smallest rectangle + * that contains both the existing rectangle and the specified rectangle. + * + * @param r the rectangle to add to this rectangle + * @throws NullPointerException if r is null + * @see #union(Rectangle) + */ + public void add(Rectangle r) + { + union(this, r, this); + } + + /** + * Expands the rectangle by the specified amount. The horizontal + * and vertical expansion values are applied both to the X,Y coordinate + * of this rectangle, and its width and height. Thus the width and + * height will increase by 2h and 2v accordingly. + * + * @param h the horizontal expansion value + * @param v the vertical expansion value + */ + public void grow(int h, int v) + { + x -= h; + y -= v; + width += h + h; + height += v + v; + } + + /** + * Tests whether or not this rectangle is empty. An empty rectangle + * has a non-positive width or height. + * + * @return true if the rectangle is empty + */ + public boolean isEmpty() + { + return width <= 0 || height <= 0; + } + + /** + * Determine where the point lies with respect to this rectangle. The + * result will be the binary OR of the appropriate bit masks. + * + * @param x the x coordinate to check + * @param y the y coordinate to check + * @return the binary OR of the result + * @see #OUT_LEFT + * @see #OUT_TOP + * @see #OUT_RIGHT + * @see #OUT_BOTTOM + * @since 1.2 + */ + public int outcode(double x, double y) + { + int result = 0; + if (width <= 0) + result |= OUT_LEFT | OUT_RIGHT; + else if (x < this.x) + result |= OUT_LEFT; + else if (x > this.x + width) + result |= OUT_RIGHT; + if (height <= 0) + result |= OUT_BOTTOM | OUT_TOP; + else if (y < this.y) // Remember that +y heads top-to-bottom. + result |= OUT_TOP; + else if (y > this.y + height) + result |= OUT_BOTTOM; + return result; + } + + /** + * Determines the rectangle which is formed by the intersection of this + * rectangle with the specified rectangle. If the two do not intersect, + * an empty rectangle will be returned (meaning the width and/or height + * will be non-positive). + * + * @param r the rectange to calculate the intersection with + * @return a new rectangle bounding the intersection + * @throws NullPointerException if r is null + * @since 1.2 + */ + public Rectangle2D createIntersection(Rectangle2D r) + { + // Favor runtime type of other rectangle. + Rectangle2D res = r.getBounds2D(); + intersect(this, r, res); + return res; + } + + /** + * Returns the smallest rectangle that contains both this rectangle + * and the specified rectangle. + * + * @param r the rectangle to compute the union with + * @return the smallest rectangle containing both rectangles + * @throws NullPointerException if r is null + * @since 1.2 + */ + public Rectangle2D createUnion(Rectangle2D r) + { + // Favor runtime type of other rectangle. + Rectangle2D res = r.getBounds2D(); + union(this, r, res); + return res; + } + + /** + * Tests this rectangle for equality against the specified object. This + * will be true if an only if the specified object is an instance of + * Rectangle2D with the same coordinates and dimensions. + * + * @param obj the object to test against for equality + * @return true if the specified object is equal to this one + */ + public boolean equals(Object obj) + { + // NOTE: No special hashCode() method is required for this class, + // as this equals() implementation is functionally equivalent to + // super.equals(), which does define a proper hashCode(). + + if (! (obj instanceof Rectangle2D)) + return false; + Rectangle2D r = (Rectangle2D) obj; + return r.getX() == x && r.getY() == y + && r.getWidth() == width && r.getHeight() == height; + } + + /** + * Returns a string representation of this rectangle. This is in the form + * <code>getClass().getName() + "[x=" + x + ",y=" + y + ",width=" + width + * + ",height=" + height + ']'</code>. + * + * @return a string representation of this rectangle + */ + public String toString() + { + return getClass().getName() + "[x=" + x + ",y=" + y + ",width=" + width + + ",height=" + height + ']'; + } +} // class Rectangle diff --git a/libjava/classpath/java/awt/RenderingHints.java b/libjava/classpath/java/awt/RenderingHints.java new file mode 100644 index 000000000..5de6a608f --- /dev/null +++ b/libjava/classpath/java/awt/RenderingHints.java @@ -0,0 +1,804 @@ +/* RenderingHints.java -- + Copyright (C) 2000, 2001, 2002, 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * A collection of (key, value) items that provide 'hints' for the + * {@link java.awt.Graphics2D} rendering pipeline. Because these + * items are hints only, they may be ignored by a particular + * {@link java.awt.Graphics2D} implementation. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + * @author Eric Blake (ebb9@email.byu.edu) + */ +public class RenderingHints + implements Map<Object,Object>, Cloneable +{ + /** + * The base class used to represent keys. + */ + public abstract static class Key + { + private final int key; + + /** + * Creates a new key. + * + * @param privateKey the private key. + */ + protected Key(int privateKey) + { + key = privateKey; + } + + /** + * Returns <code>true</code> if the specified value is compatible with + * this key, and <code>false</code> otherwise. + * + * @param value the value (<code>null</code> permitted). + * + * @return A boolean. + */ + public abstract boolean isCompatibleValue(Object value); + + /** + * Returns the private key for this instance. + * + * @return The private key. + */ + protected final int intKey() + { + return key; + } + + /** + * Returns a hash code for the key. + * + * @return A hash code. + */ + public final int hashCode() + { + return System.identityHashCode(this); + } + + /** + * Checks this key for equality with an arbitrary object. + * + * @param other the object (<code>null</code> permitted) + * + * @return A boolean. + */ + public final boolean equals(Object other) + { + return this == other; + } + } // class Key + + private static final class KeyImpl extends Key + { + final String description; + final Object v1; + final Object v2; + final Object v3; + + KeyImpl(int privateKey, String description, + Object v1, Object v2, Object v3) + { + super(privateKey); + this.description = description; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; + } + + /** + * Returns <code>true</code> if the specified value is compatible with + * this key, and <code>false</code> otherwise. + * + * @param value the value (<code>null</code> permitted). + * + * @return A boolean. + */ + public boolean isCompatibleValue(Object value) + { + return value == v1 || value == v2 || value == v3; + } + + /** + * Returns a string representation of the key. + * + * @return A string. + */ + public String toString() + { + return description; + } + } // class KeyImpl + + private HashMap<Object,Object> hintMap = new HashMap<Object,Object>(); + + /** + * A key for the 'antialiasing' hint. Permitted values are: + * <p> + * <table> + * <tr> + * <td>{@link #VALUE_ANTIALIAS_OFF}</td> + * <td>Render without antialiasing (better speed).</td> + * </tr> + * <tr> + * <td>{@link #VALUE_ANTIALIAS_ON}</td> + * <td>Render with antialiasing (better quality).</td> + * </tr> + * <tr> + * <td>{@link #VALUE_ANTIALIAS_DEFAULT}</td> + * <td>Use the default value for antialiasing.</td> + * </tr> + * </table> + */ + public static final Key KEY_ANTIALIASING; + + /** + * This value is for use with the {@link #KEY_ANTIALIASING} key. + */ + public static final Object VALUE_ANTIALIAS_ON + = "Antialiased rendering mode"; + + /** + * This value is for use with the {@link #KEY_ANTIALIASING} key. + */ + public static final Object VALUE_ANTIALIAS_OFF + = "Nonantialiased rendering mode"; + + /** + * This value is for use with the {@link #KEY_ANTIALIASING} key. + */ + public static final Object VALUE_ANTIALIAS_DEFAULT + = "Default antialiasing rendering mode"; + + /** + * A key for the 'rendering' hint. Permitted values are: + * <p> + * <table> + * <tr> + * <td>{@link #VALUE_RENDER_SPEED}</td> + * <td>Prefer speed over quality when rendering.</td> + * </tr> + * <tr> + * <td>{@link #VALUE_RENDER_QUALITY}</td> + * <td>Prefer quality over speed when rendering.</td> + * </tr> + * <tr> + * <td>{@link #VALUE_RENDER_DEFAULT}</td> + * <td>Use the default value for quality vs. speed when rendering.</td> + * </tr> + * </table> + */ + public static final Key KEY_RENDERING; + + /** + * This value is for use with the {@link #KEY_RENDERING} key. + */ + public static final Object VALUE_RENDER_SPEED + = "Fastest rendering methods"; + + /** + * This value is for use with the {@link #KEY_RENDERING} key. + */ + public static final Object VALUE_RENDER_QUALITY + = "Highest quality rendering methods"; + + /** + * This value is for use with the {@link #KEY_RENDERING} key. + */ + public static final Object VALUE_RENDER_DEFAULT + = "Default rendering methods"; + + /** + * A key for the 'dithering' hint. Permitted values are: + * <p> + * <table> + * <tr> + * <td>{@link #VALUE_DITHER_DISABLE}</td> + * <td>Disable dithering.</td> + * </tr> + * <tr> + * <td>{@link #VALUE_DITHER_ENABLE}</td> + * <td>Enable dithering.</td> + * </tr> + * <tr> + * <td>{@link #VALUE_DITHER_DEFAULT}</td> + * <td>Use the default value for dithering.</td> + * </tr> + * </table> + */ + public static final Key KEY_DITHERING; + + /** + * This value is for use with the {@link #KEY_DITHERING} key. + */ + public static final Object VALUE_DITHER_DISABLE + = "Nondithered rendering mode"; + + /** + * This value is for use with the {@link #KEY_DITHERING} key. + */ + public static final Object VALUE_DITHER_ENABLE + = "Dithered rendering mode"; + + /** + * This value is for use with the {@link #KEY_DITHERING} key. + */ + public static final Object VALUE_DITHER_DEFAULT + = "Default dithering mode"; + + /** + * A key for the 'text antialiasing' hint. Permitted values are: + * <p> + * <table> + * <tr> + * <td>{@link #VALUE_TEXT_ANTIALIAS_ON}</td> + * <td>Render text with antialiasing (better quality usually).</td> + * </tr> + * <tr> + * <td>{@link #VALUE_TEXT_ANTIALIAS_OFF}</td> + * <td>Render test without antialiasing (better speed).</td> + * </tr> + * <tr> + * <td>{@link #VALUE_TEXT_ANTIALIAS_DEFAULT}</td> + * <td>Use the default value for text antialiasing.</td> + * </tr> + * </table> + */ + public static final Key KEY_TEXT_ANTIALIASING; + + /** + * This value is for use with the {@link #KEY_TEXT_ANTIALIASING} key. + */ + public static final Object VALUE_TEXT_ANTIALIAS_ON + = "Antialiased text mode"; + + /** + * This value is for use with the {@link #KEY_TEXT_ANTIALIASING} key. + */ + public static final Object VALUE_TEXT_ANTIALIAS_OFF + = "Nonantialiased text mode"; + + /** + * This value is for use with the {@link #KEY_TEXT_ANTIALIASING} key. + */ + public static final Object VALUE_TEXT_ANTIALIAS_DEFAULT + = "Default antialiasing text mode"; + + /** + * A key for the 'fractional metrics' hint. Permitted values are: + * <p> + * <table> + * <tr> + * <td>{@link #VALUE_FRACTIONALMETRICS_OFF}</td> + * <td>Render text with fractional metrics off.</td> + * </tr> + * <tr> + * <td>{@link #VALUE_FRACTIONALMETRICS_ON}</td> + * <td>Render text with fractional metrics on.</td> + * </tr> + * <tr> + * <td>{@link #VALUE_FRACTIONALMETRICS_DEFAULT}</td> + * <td>Use the default value for fractional metrics.</td> + * </tr> + * </table> + */ + public static final Key KEY_FRACTIONALMETRICS; + + /** + * This value is for use with the {@link #KEY_FRACTIONALMETRICS} key. + */ + public static final Object VALUE_FRACTIONALMETRICS_OFF + = "Integer text metrics mode"; + + /** + * This value is for use with the {@link #KEY_FRACTIONALMETRICS} key. + */ + public static final Object VALUE_FRACTIONALMETRICS_ON + = "Fractional text metrics mode"; + + /** + * This value is for use with the {@link #KEY_FRACTIONALMETRICS} key. + */ + public static final Object VALUE_FRACTIONALMETRICS_DEFAULT + = "Default fractional text metrics mode"; + + /** + * A key for the 'interpolation' hint. Permitted values are: + * <p> + * <table> + * <tr> + * <td>{@link #VALUE_INTERPOLATION_NEAREST_NEIGHBOR}</td> + * <td>Use nearest neighbour interpolation.</td> + * </tr> + * <tr> + * <td>{@link #VALUE_INTERPOLATION_BILINEAR}</td> + * <td>Use bilinear interpolation.</td> + * </tr> + * <tr> + * <td>{@link #VALUE_INTERPOLATION_BICUBIC}</td> + * <td>Use bicubic interpolation.</td> + * </tr> + * </table> + */ + public static final Key KEY_INTERPOLATION; + + /** + * This value is for use with the {@link #KEY_INTERPOLATION} key. + */ + public static final Object VALUE_INTERPOLATION_NEAREST_NEIGHBOR + = "Nearest Neighbor image interpolation mode"; + + /** + * This value is for use with the {@link #KEY_INTERPOLATION} key. + */ + public static final Object VALUE_INTERPOLATION_BILINEAR + = "Bilinear image interpolation mode"; + + /** + * This value is for use with the {@link #KEY_INTERPOLATION} key. + */ + public static final Object VALUE_INTERPOLATION_BICUBIC + = "Bicubic image interpolation mode"; + + /** + * A key for the 'alpha interpolation' hint. Permitted values are: + * <p> + * <table> + * <tr> + * <td>{@link #VALUE_ALPHA_INTERPOLATION_SPEED}</td> + * <td>Prefer speed over quality.</td> + * </tr> + * <tr> + * <td>{@link #VALUE_ALPHA_INTERPOLATION_QUALITY}</td> + * <td>Prefer quality over speed.</td> + * </tr> + * <tr> + * <td>{@link #VALUE_ALPHA_INTERPOLATION_DEFAULT}</td> + * <td>Use the default setting.</td> + * </tr> + * </table> + */ + public static final Key KEY_ALPHA_INTERPOLATION; + + /** + * This value is for use with the {@link #KEY_ALPHA_INTERPOLATION} key. + */ + public static final Object VALUE_ALPHA_INTERPOLATION_SPEED + = "Fastest alpha blending methods"; + + /** + * This value is for use with the {@link #KEY_ALPHA_INTERPOLATION} key. + */ + public static final Object VALUE_ALPHA_INTERPOLATION_QUALITY + = "Highest quality alpha blending methods"; + + /** + * This value is for use with the {@link #KEY_ALPHA_INTERPOLATION} key. + */ + public static final Object VALUE_ALPHA_INTERPOLATION_DEFAULT + = "Default alpha blending methods"; + + /** + * A key for the 'color rendering' hint. Permitted values are: + * <p> + * <table> + * <tr> + * <td>{@link #VALUE_COLOR_RENDER_SPEED}</td> + * <td>Prefer speed over quality.</td> + * </tr> + * <tr> + * <td>{@link #VALUE_COLOR_RENDER_QUALITY}</td> + * <td>Prefer quality over speed.</td> + * </tr> + * <tr> + * <td>{@link #VALUE_COLOR_RENDER_DEFAULT}</td> + * <td>Use the default setting.</td> + * </tr> + * </table> + */ + public static final Key KEY_COLOR_RENDERING; + + /** + * This value is for use with the {@link #KEY_COLOR_RENDERING} key. + */ + public static final Object VALUE_COLOR_RENDER_SPEED + = "Fastest color rendering mode"; + + /** + * This value is for use with the {@link #KEY_COLOR_RENDERING} key. + */ + public static final Object VALUE_COLOR_RENDER_QUALITY + = "Highest quality color rendering mode"; + + /** + * This value is for use with the {@link #KEY_COLOR_RENDERING} key. + */ + public static final Object VALUE_COLOR_RENDER_DEFAULT + = "Default color rendering mode"; + + /** + * A key for the 'stroke control' hint. Permitted values are: + * <p> + * <table> + * <tr> + * <td>{@link #VALUE_STROKE_DEFAULT}</td> + * <td>Use the default setting.</td> + * </tr> + * <tr> + * <td>{@link #VALUE_STROKE_NORMALIZE}</td> + * <td>XXX</td> + * </tr> + * <tr> + * <td>{@link #VALUE_STROKE_PURE}</td> + * <td>XXX</td> + * </tr> + * </table> + */ + public static final Key KEY_STROKE_CONTROL; + + /** + * This value is for use with the {@link #KEY_STROKE_CONTROL} key. + */ + public static final Object VALUE_STROKE_DEFAULT + = "Default stroke normalization"; + + /** + * This value is for use with the {@link #KEY_STROKE_CONTROL} key. + */ + public static final Object VALUE_STROKE_NORMALIZE + = "Normalize strokes for consistent rendering"; + + /** + * This value is for use with the {@link #KEY_STROKE_CONTROL} key. + */ + public static final Object VALUE_STROKE_PURE + = "Pure stroke conversion for accurate paths"; + + static + { + KEY_ANTIALIASING = new KeyImpl(1, "Global antialiasing enable key", + VALUE_ANTIALIAS_ON, + VALUE_ANTIALIAS_OFF, + VALUE_ANTIALIAS_DEFAULT); + KEY_RENDERING = new KeyImpl(2, "Global rendering quality key", + VALUE_RENDER_SPEED, + VALUE_RENDER_QUALITY, + VALUE_RENDER_DEFAULT); + KEY_DITHERING = new KeyImpl(3, "Dithering quality key", + VALUE_DITHER_DISABLE, + VALUE_DITHER_ENABLE, + VALUE_DITHER_DEFAULT); + KEY_TEXT_ANTIALIASING + = new KeyImpl(4, "Text-specific antialiasing enable key", + VALUE_TEXT_ANTIALIAS_ON, + VALUE_TEXT_ANTIALIAS_OFF, + VALUE_TEXT_ANTIALIAS_DEFAULT); + KEY_FRACTIONALMETRICS = new KeyImpl(5, "Fractional metrics enable key", + VALUE_FRACTIONALMETRICS_OFF, + VALUE_FRACTIONALMETRICS_ON, + VALUE_FRACTIONALMETRICS_DEFAULT); + KEY_INTERPOLATION = new KeyImpl(6, "Image interpolation method key", + VALUE_INTERPOLATION_NEAREST_NEIGHBOR, + VALUE_INTERPOLATION_BILINEAR, + VALUE_INTERPOLATION_BICUBIC); + KEY_ALPHA_INTERPOLATION + = new KeyImpl(7, "Alpha blending interpolation method key", + VALUE_ALPHA_INTERPOLATION_SPEED, + VALUE_ALPHA_INTERPOLATION_QUALITY, + VALUE_ALPHA_INTERPOLATION_DEFAULT); + KEY_COLOR_RENDERING = new KeyImpl(8, "Color rendering quality key", + VALUE_COLOR_RENDER_SPEED, + VALUE_COLOR_RENDER_QUALITY, + VALUE_COLOR_RENDER_DEFAULT); + KEY_STROKE_CONTROL = new KeyImpl(9, "Stroke normalization control key", + VALUE_STROKE_DEFAULT, + VALUE_STROKE_NORMALIZE, + VALUE_STROKE_PURE); + } + + /** + * Creates a new collection of hints containing all the (key, value) pairs + * in the specified map. + * + * @param init a map containing a collection of hints (<code>null</code> + * permitted). + */ + public RenderingHints(Map<Key,?> init) + { + if (init != null) + putAll(init); + } + + /** + * Creates a new collection containing a single (key, value) pair. + * + * @param key the key. + * @param value the value. + */ + public RenderingHints(Key key, Object value) + { + put(key, value); + } + + /** + * Returns the number of hints in the collection. + * + * @return The number of hints. + */ + public int size() + { + return hintMap.size(); + } + + /** + * Returns <code>true</code> if there are no hints in the collection, + * and <code>false</code> otherwise. + * + * @return A boolean. + */ + public boolean isEmpty() + { + return hintMap.isEmpty(); + } + + /** + * Returns <code>true</code> if the collection of hints contains the + * specified key, and <code>false</code> otherwise. + * + * @param key the key (<code>null</code> not permitted). + * + * @return A boolean. + * + * @throws NullPointerException if <code>key</code> is <code>null</code>. + * @throws ClassCastException if <code>key</code> is not a {@link Key}. + */ + public boolean containsKey(Object key) + { + if (key == null) + throw new NullPointerException(); + // don't remove the cast, it is necessary to throw the required exception + return hintMap.containsKey((Key) key); + } + + /** + * Returns <code>true</code> if the collection of hints contains the + * specified value, and <code>false</code> otherwise. + * + * @param value the value. + * + * @return A boolean. + */ + public boolean containsValue(Object value) + { + return hintMap.containsValue(value); + } + + /** + * Returns the value associated with the specified key, or <code>null</code> + * if there is no value defined for the key. + * + * @param key the key (<code>null</code> permitted). + * + * @return The value (possibly <code>null</code>). + * + * @throws ClassCastException if <code>key</code> is not a {@link Key}. + * + * @see #containsKey(Object) + */ + public Object get(Object key) + { + // don't remove the cast, it is necessary to throw the required exception + return hintMap.get((Key) key); + } + + /** + * Adds a (key, value) pair to the collection of hints (if the + * collection already contains the specified key, then the + * value is updated). + * + * @param key the key. + * @param value the value. + * + * @return the previous value of the key or <code>null</code> if the key + * didn't have a value yet. + */ + public Object put(Object key, Object value) + { + if (key == null || value == null) + throw new NullPointerException(); + if (! ((Key) key).isCompatibleValue(value)) + throw new IllegalArgumentException(); + return hintMap.put(key, value); + } + + /** + * Adds all the hints from a collection to this collection. + * + * @param hints the hint collection. + */ + public void add(RenderingHints hints) + { + hintMap.putAll(hints); + } + + /** + * Clears all the hints from this collection. + */ + public void clear() + { + hintMap.clear(); + } + + /** + * Removes a hint from the collection. + * + * @param key the key. + * + * @return The value that was associated with the key, or <code>null</code> if + * the key was not part of the collection + * + * @throws ClassCastException if the key is not a subclass of + * {@link RenderingHints.Key}. + */ + public Object remove(Object key) + { + // don't remove the (Key) cast, it is necessary to throw the exception + // required by the spec + return hintMap.remove((Key) key); + } + + /** + * Adds a collection of (key, value) pairs to the collection. + * + * @param m a map containing (key, value) items. + * + * @throws ClassCastException if the map contains a key that is not + * a subclass of {@link RenderingHints.Key}. + * @throws IllegalArgumentException if the map contains a value that is + * not compatible with its key. + */ + public void putAll(Map<?,?> m) + { + // preprocess map to generate appropriate exceptions + Iterator iterator = m.keySet().iterator(); + while (iterator.hasNext()) + { + Key key = (Key) iterator.next(); + if (!key.isCompatibleValue(m.get(key))) + throw new IllegalArgumentException(); + } + // map is OK, update + hintMap.putAll(m); + } + + /** + * Returns a set containing the keys from this collection. + * + * @return A set of keys. + */ + public Set<Object> keySet() + { + return hintMap.keySet(); + } + + /** + * Returns a collection of the values from this hint collection. The + * collection is backed by the <code>RenderingHints</code> instance, + * so updates to one will affect the other. + * + * @return A collection of values. + */ + public Collection<Object> values() + { + return hintMap.values(); + } + + /** + * Returns a set of entries from the collection. + * + * @return A set of entries. + */ + public Set<Map.Entry<Object,Object>> entrySet() + { + return Collections.unmodifiableSet(hintMap.entrySet()); + } + + /** + * Checks this collection for equality with an arbitrary object. + * + * @param o the object (<code>null</code> permitted) + * + * @return A boolean. + */ + public boolean equals(Object o) + { + return hintMap.equals(o); + } + + /** + * Returns a hash code for the collection of hints. + * + * @return A hash code. + */ + public int hashCode() + { + return hintMap.hashCode(); + } + + /** + * Creates a clone of this instance. + * + * @return A clone. + */ + public Object clone() + { + try + { + RenderingHints copy = (RenderingHints) super.clone(); + copy.hintMap = new HashMap<Object,Object>(hintMap); + return copy; + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } + + /** + * Returns a string representation of this instance. + * + * @return A string. + */ + public String toString() + { + return hintMap.toString(); + } +} // class RenderingHints diff --git a/libjava/classpath/java/awt/Robot.java b/libjava/classpath/java/awt/Robot.java new file mode 100644 index 000000000..30de5ca84 --- /dev/null +++ b/libjava/classpath/java/awt/Robot.java @@ -0,0 +1,423 @@ +/* Robot.java -- a native input event generator + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import gnu.java.awt.ClasspathToolkit; + +import java.lang.reflect.InvocationTargetException; +import java.awt.event.InputEvent; +import java.awt.image.BufferedImage; +import java.awt.peer.RobotPeer; + +/** + * The Robot class is used to simulate user interaction with graphical + * programs. It can generate native windowing system input events and + * retrieve image data from the current screen. Robot is used to test + * the AWT and Swing library implementations; it can also be used to + * create self-running demo programs. + * + * Since Robot generates native windowing system events, rather than + * simply inserting {@link AWTEvent}s on the AWT event queue, its use + * is not restricted to Java programs. It can be used to + * programatically drive any graphical application. + * + * This implementation requires an X server that supports the XTest + * extension. + * + * @author Thomas Fitzsimmons (fitzsim@redhat.com) + * + * @since 1.3 + */ +public class Robot +{ + private boolean waitForIdle; + private int autoDelay; + private RobotPeer peer; + + /** + * Construct a Robot object that operates on the default screen. + * + * @exception AWTException if GraphicsEnvironment.isHeadless() + * returns true or if the X server does not support the XTest + * extension + * @exception SecurityException if createRobot permission is not + * granted + */ + public Robot () throws AWTException + { + if (GraphicsEnvironment.isHeadless ()) + throw new AWTException ("Robot: headless graphics environment"); + + SecurityManager sm = System.getSecurityManager (); + if (sm != null) + sm.checkPermission (new AWTPermission ("createRobot")); + + ClasspathToolkit tk = (ClasspathToolkit) Toolkit.getDefaultToolkit (); + + // createRobot will throw AWTException if XTest is not supported. + peer = tk.createRobot (GraphicsEnvironment.getLocalGraphicsEnvironment () + .getDefaultScreenDevice ()); + } + + /** + * Construct a Robot object that operates on the specified screen. + * + * @exception AWTException if GraphicsEnvironment.isHeadless() + * returns true or if the X server does not support the XTest + * extension + * @exception IllegalArgumentException if screen is not a screen + * GraphicsDevice + * @exception SecurityException if createRobot permission is not + * granted + */ + public Robot (GraphicsDevice screen) throws AWTException + { + if (GraphicsEnvironment.isHeadless ()) + throw new AWTException ("Robot: headless graphics environment"); + + if (screen.getType () != GraphicsDevice.TYPE_RASTER_SCREEN) + throw new IllegalArgumentException ("Robot: graphics" + + " device is not a screen"); + + SecurityManager sm = System.getSecurityManager (); + if (sm != null) + sm.checkPermission (new AWTPermission ("createRobot")); + + ClasspathToolkit tk = (ClasspathToolkit) Toolkit.getDefaultToolkit (); + + // createRobot will throw AWTException if XTest is not supported. + peer = tk.createRobot (screen); + } + + /** + * Move the mouse pointer to absolute coordinates (x, y). + * + * @param x the destination x coordinate + * @param y the destination y coordinate + */ + public void mouseMove(int x, int y) + { + peer.mouseMove (x, y); + + if (waitForIdle) + waitForIdle (); + + if (autoDelay > 0) + delay (autoDelay); + } + + /** + * Press one or more mouse buttons. + * + * @param buttons the buttons to press; a bitmask of one or more of + * these {@link InputEvent} fields: + * + * <ul> + * <li>BUTTON1_MASK</li> + * <li>BUTTON2_MASK</li> + * <li>BUTTON3_MASK</li> + * </ul> + * + * @exception IllegalArgumentException if the button mask is invalid + */ + public void mousePress (int buttons) + { + if ((buttons & InputEvent.BUTTON1_MASK) == 0 + && (buttons & InputEvent.BUTTON2_MASK) == 0 + && (buttons & InputEvent.BUTTON3_MASK) == 0) + throw new IllegalArgumentException ("Robot: mousePress:" + + " invalid button mask"); + + peer.mousePress (buttons); + + if (waitForIdle) + waitForIdle (); + + if (autoDelay > 0) + delay (autoDelay); + } + + /** + * Release one or more mouse buttons. + * + * @param buttons the buttons to release; a bitmask of one or more + * of these {@link InputEvent} fields: + * + * <ul> + * <li>BUTTON1_MASK</li> + * <li>BUTTON2_MASK</li> + * <li>BUTTON3_MASK</li> + * </ul> + * + * @exception IllegalArgumentException if the button mask is invalid + */ + public void mouseRelease(int buttons) + { + if ((buttons & InputEvent.BUTTON1_MASK) == 0 + && (buttons & InputEvent.BUTTON2_MASK) == 0 + && (buttons & InputEvent.BUTTON3_MASK) == 0) + throw new IllegalArgumentException ("Robot: mouseRelease:" + + " invalid button mask"); + + peer.mouseRelease (buttons); + + if (waitForIdle) + waitForIdle (); + + if (autoDelay > 0) + delay (autoDelay); + } + + /** + * Rotate the mouse scroll wheel. + * + * @param wheelAmt number of steps to rotate mouse wheel. negative + * to rotate wheel up (away from the user), positive to rotate wheel + * down (toward the user). + * + * @since 1.4 + */ + public void mouseWheel (int wheelAmt) + { + peer.mouseWheel (wheelAmt); + + if (waitForIdle) + waitForIdle (); + + if (autoDelay > 0) + delay (autoDelay); + } + + /** + * Press a key. + * + * @param keycode key to press, a {@link java.awt.event.KeyEvent} VK_ constant + * + * @exception IllegalArgumentException if keycode is not a valid key + */ + public void keyPress (int keycode) + { + peer.keyPress (keycode); + + if (waitForIdle) + waitForIdle (); + + if (autoDelay > 0) + delay (autoDelay); + } + + /** + * Release a key. + * + * @param keycode key to release, a {@link java.awt.event.KeyEvent} VK_ + * constant + * + * @exception IllegalArgumentException if keycode is not a valid key + */ + public void keyRelease (int keycode) + { + peer.keyRelease (keycode); + + if (waitForIdle) + waitForIdle (); + + if (autoDelay > 0) + delay (autoDelay); + } + + /** + * Return the color of the pixel at the given screen coordinates. + * + * @param x the x coordinate of the pixel + * @param y the y coordinate of the pixel + * + * @return the Color of the pixel at screen coodinates <code>(x, y)</code> + */ + public Color getPixelColor (int x, int y) + { + return new Color (peer.getRGBPixel (x, y)); + } + + /** + * Create an image containing pixels read from the screen. The + * image does not include the mouse pointer. + * + * @param screenRect the rectangle of pixels to capture, in screen + * coordinates + * + * @return a BufferedImage containing the requested pixels + * + * @exception IllegalArgumentException if requested width and height + * are not both greater than zero + * @exception SecurityException if readDisplayPixels permission is + * not granted + */ + public BufferedImage createScreenCapture (Rectangle screenRect) + { + if (screenRect.width <= 0) + throw new IllegalArgumentException ("Robot: capture width is <= 0"); + + if (screenRect.height <= 0) + throw new IllegalArgumentException ("Robot: capture height is <= 0"); + + SecurityManager sm = System.getSecurityManager (); + if (sm != null) + sm.checkPermission (new AWTPermission ("readDisplayPixels")); + + int[] pixels = peer.getRGBPixels (screenRect); + + BufferedImage bufferedImage = + new BufferedImage (screenRect.width, screenRect.height, + BufferedImage.TYPE_INT_ARGB); + + bufferedImage.setRGB (0, 0, screenRect.width, screenRect.height, + pixels, 0, screenRect.width); + + return bufferedImage; + } + + /** + * Check if this Robot automatically calls {@link #waitForIdle()} after + * generating an event. + * + * @return true if waitForIdle is automatically called + */ + public boolean isAutoWaitForIdle () + { + return waitForIdle; + } + + /** + * Set whether or not this Robot automatically calls {@link + * #waitForIdle()} after generating an event. + * + * @param isOn true if waitForIdle should be called automatically + */ + public void setAutoWaitForIdle (boolean isOn) + { + waitForIdle = isOn; + } + + /** + * Retrieve the length of time this Robot sleeps after generating an + * event. + * + * @return the length of time in milliseconds + */ + public int getAutoDelay () + { + return autoDelay; + } + + /** + * Set the length of time this Robot sleeps after generating an + * event. + * + * @param ms the length of time in milliseconds + * + * @exception IllegalArgumentException if ms is not between 0 and + * 60,000 milliseconds inclusive + */ + public void setAutoDelay (int ms) + { + if (ms <= 0 || ms >= 60000) + throw new IllegalArgumentException ("Robot: delay length out-of-bounds"); + + autoDelay = ms; + } + + /** + * Sleep for a specified length of time. + * + * @param ms the length of time in milliseconds + * + * @exception IllegalArgumentException if ms is not between 0 and + * 60,000 milliseconds inclusive + */ + public void delay (int ms) + { + if (ms < 0 || ms > 60000) + throw new IllegalArgumentException ("Robot: delay length out-of-bounds"); + + try + { + Thread.sleep (ms); + } + catch (InterruptedException e) + { + System.err.println ("Robot: delay interrupted"); + } + } + + /** + * Wait until all events currently on the event queue have been + * dispatched. + */ + public void waitForIdle () + { + if (EventQueue.isDispatchThread ()) + throw new IllegalThreadStateException ("Robot: waitForIdle called from " + + "the event dispatch thread"); + + try + { + EventQueue.invokeAndWait (new Runnable () { public void run () { } }); + } + catch (InterruptedException e) + { + System.err.println ("Robot: waitForIdle interrupted"); + } + catch (InvocationTargetException e) + { + System.err.println ("Robot: waitForIdle cannot invoke target"); + } + } + + /** + * Return a string representation of this Robot. + * + * @return a string representation + */ + public String toString () + { + return getClass ().getName () + + "[ autoDelay = " + autoDelay + ", autoWaitForIdle = " + + waitForIdle + " ]"; + } +} diff --git a/libjava/classpath/java/awt/ScrollPane.java b/libjava/classpath/java/awt/ScrollPane.java new file mode 100644 index 000000000..14d15f648 --- /dev/null +++ b/libjava/classpath/java/awt/ScrollPane.java @@ -0,0 +1,680 @@ +/* ScrollPane.java -- Scrolling window + Copyright (C) 1999, 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.MouseEvent; +import java.awt.peer.ComponentPeer; +import java.awt.peer.ScrollPanePeer; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; + + +/** + * This widget provides a scrollable region that allows a single + * subcomponent to be viewed through a smaller window. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class ScrollPane extends Container implements Accessible +{ + +/* + * Static Variables + */ + +/** + * Constant indicating that scrollbars are created as needed in this + * windows. + */ +public static final int SCROLLBARS_AS_NEEDED = 0; + +/** + * Constant indicating that scrollbars are always displayed in this + * window. + */ +public static final int SCROLLBARS_ALWAYS = 1; + +/** + * Constant indicating that scrollbars are never displayed in this window. + */ +public static final int SCROLLBARS_NEVER = 2; + +/** + * The number used to generate the name returned by getName. + */ +private static transient long next_scrollpane_number; + +// Serialization constant +private static final long serialVersionUID = 7956609840827222915L; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * @serial The horizontal scrollbar for this window. The methods + * <code>setMinimum()</code>, <code>setMaximum</code>, and + * <code>setVisibleAmount</code> must not be called on this scrollbar. + */ +private ScrollPaneAdjustable hAdjustable; + +/** + * @serial The vertical scrollbar for this window. The methods + * <code>setMinimum()</code>, <code>setMaximum</code>, and + * <code>setVisibleAmount</code> must not be called on this scrollbar. + */ +private ScrollPaneAdjustable vAdjustable; + +/** + * @serial Indicates when scrollbars are displayed in this window, will + * be one of the constants from this class. + */ +private int scrollbarDisplayPolicy; + +// Current scroll position +private Point scrollPosition = new Point(0, 0); + +private boolean wheelScrollingEnabled; + +/*************************************************************************/ + +/* + * Constructors + */ + +/** + * Initializes a new instance of <code>ScrollPane</code> with a default + * scrollbar policy of <code>SCROLLBARS_AS_NEEDED</code>. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ +public +ScrollPane() +{ + this(SCROLLBARS_AS_NEEDED); +} + +/*************************************************************************/ + +/** + * Initializes a new instance of <code>ScrollPane</code> with the + * specified scrollbar policy. + * + * @param scrollbarDisplayPolicy When to display scrollbars, which must + * be one of the constants defined in this class. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ +public +ScrollPane(int scrollbarDisplayPolicy) +{ + if (GraphicsEnvironment.isHeadless ()) + throw new HeadlessException (); + + this.scrollbarDisplayPolicy = scrollbarDisplayPolicy; + + if (scrollbarDisplayPolicy != SCROLLBARS_ALWAYS + && scrollbarDisplayPolicy != SCROLLBARS_AS_NEEDED + && scrollbarDisplayPolicy != SCROLLBARS_NEVER) + throw new IllegalArgumentException("Bad scrollbarDisplayPolicy: " + + scrollbarDisplayPolicy); + + if (scrollbarDisplayPolicy != SCROLLBARS_NEVER) + { + hAdjustable = new ScrollPaneAdjustable (this, Scrollbar.HORIZONTAL); + vAdjustable = new ScrollPaneAdjustable (this, Scrollbar.VERTICAL); + } + + wheelScrollingEnabled = true; + + // Default size. + setSize(100,100); +} + +/*************************************************************************/ + +/* + * Instance Variables + */ + +/** + * Returns the current scrollbar display policy. + * + * @return The current scrollbar display policy. + */ +public int +getScrollbarDisplayPolicy() +{ + return(scrollbarDisplayPolicy); +} + +/*************************************************************************/ + +/** + * Returns the horizontal scrollbar for this object. If the scrollbar + * display policy is set to <code>SCROLLBARS_NEVER</code> then this + * will be <code>null</code>. + * + * @return The horizontal scrollbar for this window. + */ +public Adjustable +getHAdjustable() +{ + return(hAdjustable); +} + +/*************************************************************************/ + +/** + * Returns the vertical scrollbar for this object. If the scrollbar + * display policy is set to <code>SCROLLBARS_NEVER</code> then this + * will be <code>null</code>. + * + * @return The horizontal scrollbar for this window. + */ +public Adjustable +getVAdjustable() +{ + return(vAdjustable); +} + +/*************************************************************************/ + +/** + * Returns the current viewport size. The viewport is the region of + * this object's window where the child is actually displayed. + * + * @return The viewport size. + */ +public Dimension getViewportSize () +{ + Dimension viewsize = getSize (); + Insets insets = getInsets (); + + viewsize.width -= (insets.left + insets.right); + viewsize.height -= (insets.top + insets.bottom); + + Component[] list = getComponents(); + if ((list == null) || (list.length <= 0)) + return viewsize; + + Dimension dim = list[0].getPreferredSize(); + + if (dim.width <= 0 && dim.height <= 0) + return viewsize; + + int vScrollbarWidth = getVScrollbarWidth (); + int hScrollbarHeight = getHScrollbarHeight (); + + if (scrollbarDisplayPolicy == SCROLLBARS_ALWAYS) + { + viewsize.width -= vScrollbarWidth; + viewsize.height -= hScrollbarHeight; + return viewsize; + } + + if (scrollbarDisplayPolicy == SCROLLBARS_NEVER) + return viewsize; + + // The scroll policy is SCROLLBARS_AS_NEEDED, so we need to see if + // either scrollbar is needed. + + // Assume we don't need either scrollbar. + boolean mayNeedVertical = false; + boolean mayNeedHorizontal = false; + + boolean needVertical = false; + boolean needHorizontal = false; + + // Check if we need vertical scrollbars. If we do, then we need to + // subtract the width of the vertical scrollbar from the viewport's + // width. + if (dim.height > viewsize.height) + needVertical = true; + else if (dim.height > (viewsize.height - hScrollbarHeight)) + // This is tricky. In this case the child is tall enough that its + // bottom edge would be covered by a horizontal scrollbar, if one + // were present. This means that if there's a horizontal + // scrollbar then we need a vertical scrollbar. + mayNeedVertical = true; + + if (dim.width > viewsize.width) + needHorizontal = true; + else if (dim.width > (viewsize.width - vScrollbarWidth)) + mayNeedHorizontal = true; + + if (needVertical && mayNeedHorizontal) + needHorizontal = true; + + if (needHorizontal && mayNeedVertical) + needVertical = true; + + if (needHorizontal) + viewsize.height -= hScrollbarHeight; + + if (needVertical) + viewsize.width -= vScrollbarWidth; + + return viewsize; +} + +/*************************************************************************/ + +/** + * Returns the height of a horizontal scrollbar. + * + * @return The height of a horizontal scrollbar. + */ +public int +getHScrollbarHeight() +{ + ScrollPanePeer spp = (ScrollPanePeer)getPeer(); + if (spp != null) + return(spp.getHScrollbarHeight()); + else + return(0); // FIXME: What to do here? +} + +/*************************************************************************/ + +/** + * Returns the width of a vertical scrollbar. + * + * @return The width of a vertical scrollbar. + */ +public int +getVScrollbarWidth() +{ + ScrollPanePeer spp = (ScrollPanePeer)getPeer(); + if (spp != null) + return(spp.getVScrollbarWidth()); + else + return(0); // FIXME: What to do here? +} + +/*************************************************************************/ + +/** + * Returns the current scroll position of the viewport. + * + * @return The current scroll position of the viewport. + * + * @throws NullPointerException if the scrollpane does have a child. + */ +public Point +getScrollPosition() +{ + if (getComponentCount() == 0) + throw new NullPointerException(); + + int x = 0; + int y = 0; + + Adjustable v = getVAdjustable(); + Adjustable h = getHAdjustable(); + + if (v != null) + y = v.getValue(); + if (h != null) + x = h.getValue(); + + return(new Point(x, y)); +} + +/*************************************************************************/ + +/** + * Sets the scroll position to the specified value. + * + * @param scrollPosition The new scrollPosition. + * + * @exception IllegalArgumentException If the specified value is outside + * the legal scrolling range. + */ +public void +setScrollPosition(Point scrollPosition) throws IllegalArgumentException +{ + setScrollPosition(scrollPosition.x, scrollPosition.y); +} + +/*************************************************************************/ + +/** + * Sets the scroll position to the specified value. + * + * @param x The new X coordinate of the scroll position. + * @param y The new Y coordinate of the scroll position. + * + * @throws NullPointerException if scrollpane does not have a child. + * + * @exception IllegalArgumentException If the specified value is outside + * the legal scrolling range. + */ +public void +setScrollPosition(int x, int y) +{ + if (getComponentCount() == 0) + throw new NullPointerException("child is null"); + + if (x > (int) (getComponent(0).getWidth() - getViewportSize().getWidth())) + x = (int) (getComponent(0).getWidth() - getViewportSize().getWidth()); + if (y > (int) (getComponent(0).getHeight() - getViewportSize().getHeight())) + y = (int) (getComponent(0).getHeight() - getViewportSize().getHeight()); + + if (x < 0) + x = 0; + if (y < 0) + y = 0; + + Adjustable h = getHAdjustable(); + Adjustable v = getVAdjustable(); + + if (h != null) + h.setValue(x); + if (v != null) + v.setValue(y); + + ScrollPanePeer spp = (ScrollPanePeer)getPeer(); + if (spp != null) + spp.setScrollPosition(x, y); +} + +/*************************************************************************/ + +/** + * Notifies this object that it should create its native peer. + */ +public void +addNotify() +{ + if (peer != null) + return; + + setPeer((ComponentPeer)getToolkit().createScrollPane(this)); + super.addNotify(); + + Component[] list = getComponents(); + if (list != null && list.length > 0 && list[0].isLightweight()) + { + Panel panel = new Panel(); + panel.setLayout(new BorderLayout()); + panel.add(list[0], BorderLayout.CENTER); + add(panel); + } +} + +/*************************************************************************/ + +/** + * Notifies this object that it should destroy its native peers. + */ +public void +removeNotify() +{ + super.removeNotify(); +} + +/*************************************************************************/ + +/** + * Adds the specified child component to this container. A + * <code>ScrollPane</code> can have at most one child, so if a second + * one is added, then first one is removed. + * + * @param component The component to add to this container. + * @param constraints A list of layout constraints for this object. + * @param index The index at which to add the child, which is ignored + * in this implementation. + */ + protected final void addImpl (Component component, Object constraints, + int index) +{ + Component[] list = getComponents(); + if ((list != null) && (list.length > 0)) + remove(list[0]); + + super.addImpl(component, constraints, index); +} + +/*************************************************************************/ + +/** + * Lays out this component. This consists of resizing the sole child + * component to its perferred size. + */ +public void +doLayout() +{ + layout (); +} + +/*************************************************************************/ + +/** + * Lays out this component. This consists of resizing the sole child + * component to its perferred size. + * + * @deprecated This method is deprecated in favor of + * <code>doLayout()</code>. + */ +public void +layout() +{ + Component[] list = getComponents (); + if ((list != null) && (list.length > 0)) + { + Dimension dim = list[0].getPreferredSize (); + Dimension vp = getViewportSize (); + + if (dim.width < vp.width) + dim.width = vp.width; + + if (dim.height < vp.height) + dim.height = vp.height; + + ScrollPanePeer peer = (ScrollPanePeer) getPeer (); + if (peer != null) + peer.childResized (dim.width, dim.height); + + list[0].setSize (dim); + + Point p = getScrollPosition (); + if (p.x > dim.width) + p.x = dim.width; + if (p.y > dim.height) + p.y = dim.height; + + setScrollPosition (p); + + list[0].setLocation(new Point()); + } +} + +/*************************************************************************/ + +/** + * This method overrides its superclass method to ensure no layout + * manager is set for this container. <code>ScrollPane</code>'s do + * not have layout managers. + * + * @param layoutManager Ignored + * @throws AWTError Always throws this error when called. + */ +public final void +setLayout(LayoutManager layoutManager) +{ + throw new AWTError("ScrollPane controls layout"); +} + +/*************************************************************************/ + +/** + * Prints all of the components in this container. + * + * @param graphics The desired graphics context for printing. + */ +public void +printComponents(Graphics graphics) +{ + super.printComponents(graphics); +} + +/*************************************************************************/ + +/** + * Returns a debug string for this object. + * + * @return A debug string for this object. + */ +public String +paramString() +{ + Insets insets = getInsets(); + return getName() + "," + + getX() + "," + + getY() + "," + + getWidth() + "x" + getHeight() + "," + + getIsValidString() + "," + + "ScrollPosition=(" + scrollPosition.x + "," + + scrollPosition.y + ")," + + "Insets=(" + insets.top + "," + + insets.left + "," + + insets.bottom + "," + + insets.right + ")," + + "ScrollbarDisplayPolicy=" + getScrollbarDisplayPolicyString() + "," + + "wheelScrollingEnabled=" + isWheelScrollingEnabled(); +} + +private String +getScrollbarDisplayPolicyString() +{ + if (getScrollbarDisplayPolicy() == 0) + return "as-needed"; + else if (getScrollbarDisplayPolicy() == 1) + return "always"; + else + return "never"; +} + +private String +getIsValidString() +{ + if (isValid()) + return "valid"; + else + return "invalid"; +} + + /** + * Tells whether or not an event is enabled. + * + * @since 1.4 + */ + protected boolean eventTypeEnabled (int type) + { + if (type == MouseEvent.MOUSE_WHEEL) + return wheelScrollingEnabled; + + return super.eventTypeEnabled (type); + } + + /** + * Tells whether or not wheel scrolling is enabled. + * + * @since 1.4 + */ + public boolean isWheelScrollingEnabled () + { + return wheelScrollingEnabled; + } + + /** + * Enables/disables wheel scrolling. + * + * @since 1.4 + */ + public void setWheelScrollingEnabled (boolean enable) + { + wheelScrollingEnabled = enable; + } + + protected class AccessibleAWTScrollPane extends AccessibleAWTContainer + { + private static final long serialVersionUID = 6100703663886637L; + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.SCROLL_PANE; + } + } + + /** + * Gets the AccessibleContext associated with this <code>ScrollPane</code>. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTScrollPane(); + return accessibleContext; + } + + /** + * Generate a unique name for this <code>ScrollPane</code>. + * + * @return A unique name for this <code>ScrollPane</code>. + */ + String generateName() + { + return "scrollpane" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_scrollpane_number++; + } + +} // class ScrollPane diff --git a/libjava/classpath/java/awt/ScrollPaneAdjustable.java b/libjava/classpath/java/awt/ScrollPaneAdjustable.java new file mode 100644 index 000000000..0f2986d59 --- /dev/null +++ b/libjava/classpath/java/awt/ScrollPaneAdjustable.java @@ -0,0 +1,241 @@ +/* ScrollPaneAdjustable.java -- Scrollbars for a ScrollPane + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.AdjustmentListener; +import java.io.Serializable; + +/** + * Need this class since the serialization spec for ScrollPane + * uses it. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.4 + */ +public class ScrollPaneAdjustable + implements Adjustable, Serializable +{ + private static final long serialVersionUID = -3359745691033257079L; + + ScrollPane sp; + int orientation; + int value; + int minimum; + int maximum; + int visibleAmount; + int unitIncrement = 1; + int blockIncrement = 1; + AdjustmentListener adjustmentListener; + + private transient boolean valueIsAdjusting = false; + + ScrollPaneAdjustable (ScrollPane sp, int orientation) + { + this.sp = sp; + this.orientation = orientation; + } + + ScrollPaneAdjustable (ScrollPane sp, int orientation, int value, int minimum, + int maximum, int visibleAmount, int unitIncrement, + int blockIncrement) + { + this.sp = sp; + this.orientation = orientation; + this.value = value; + this.minimum = minimum; + this.maximum = maximum; + this.visibleAmount = visibleAmount; + this.unitIncrement = unitIncrement; + this.blockIncrement = blockIncrement; + } + + public void addAdjustmentListener (AdjustmentListener listener) + { + if (listener == null) + return; + adjustmentListener = AWTEventMulticaster.add (adjustmentListener, listener); + } + + public void removeAdjustmentListener (AdjustmentListener listener) + { + if (listener == null) + return; + adjustmentListener = AWTEventMulticaster.remove (adjustmentListener, listener); + } + + public AdjustmentListener[] getAdjustmentListeners () + { + return (AdjustmentListener[]) AWTEventMulticaster.getListeners + (adjustmentListener, AdjustmentListener.class); + } + + public int getBlockIncrement () + { + return blockIncrement; + } + + public int getMaximum () + { + return maximum; + } + + public int getMinimum () + { + return minimum; + } + + public int getOrientation () + { + return orientation; + } + + public int getUnitIncrement () + { + return unitIncrement; + } + + public int getValue () + { + return value; + } + + public int getVisibleAmount () + { + return visibleAmount; + } + + public void setBlockIncrement (int blockIncrement) + { + this.blockIncrement = blockIncrement; + } + + /** + * This method should never be called. + * + * @param maximum The maximum value to be set. + * @throws AWTError Always throws this error when called. + */ + public void setMaximum (int maximum) throws AWTError + { + throw new AWTError("Can be set by scrollpane only"); + } + + /** + * This method should never be called. + * + * @param minimum The minimum value to be set. + * @throws AWTError Always throws this error when called. + */ + public void setMinimum (int minimum) + { + throw new AWTError("Can be set by scrollpane only"); + } + + public void setUnitIncrement (int unitIncrement) + { + this.unitIncrement = unitIncrement; + } + + public void setValue (int value) + { + this.value = value; + + if (value < minimum) + minimum = value; + + if (value > maximum) + maximum = value; + } + + /** + * This method should never be called. + * + * @param visibleAmount The visible amount to be set. + * @throws AWTError Always throws this error when called. + */ + public void setVisibleAmount (int visibleAmount) + { + throw new AWTError("Can be set by scrollpane only"); + } + + public String paramString () + { + return paramStringHelper() + + ",[" + getMinimum() + ".." + getMaximum() + + "],val=" + getValue() + + ",vis=" + getVisibleAmount() + + ",unit=" + getUnitIncrement() + + ",block=" + getBlockIncrement() + + ",isAdjusting=" + valueIsAdjusting; + } + + private String paramStringHelper() + { + if (getOrientation() == HORIZONTAL) + return "horizontal"; + else + return "vertical"; + } + + public String toString() + { + return getClass().getName() + "[" + paramString() + "]"; + } + + /** + * Returns true if the value is in the process of changing. + * + * @since 1.4 + */ + public boolean getValueIsAdjusting () + { + return valueIsAdjusting; + } + + /** + * Sets the value of valueIsAdjusting. + * + * @since 1.4 + */ + public void setValueIsAdjusting (boolean valueIsAdjusting) + { + this.valueIsAdjusting = valueIsAdjusting; + } + +} // class ScrollPaneAdjustable diff --git a/libjava/classpath/java/awt/Scrollbar.java b/libjava/classpath/java/awt/Scrollbar.java new file mode 100644 index 000000000..4a9e36c31 --- /dev/null +++ b/libjava/classpath/java/awt/Scrollbar.java @@ -0,0 +1,815 @@ +/* Scrollbar.java -- AWT Scrollbar widget + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.AdjustmentEvent; +import java.awt.event.AdjustmentListener; +import java.awt.peer.ScrollbarPeer; +import java.util.EventListener; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; +import javax.accessibility.AccessibleValue; + +/** + * This class implements a scrollbar widget. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +public class Scrollbar extends Component implements Accessible, Adjustable +{ + // FIXME: Serialization readObject/writeObject + + /** + * Constant indicating that a scrollbar is horizontal. + */ + public static final int HORIZONTAL = 0; + + /** + * Constant indicating that a scrollbar is vertical. + */ + public static final int VERTICAL = 1; + + /** + * Serialization Constant. + */ + private static final long serialVersionUID = 8451667562882310543L; + + /** + * @serial The amount by which the value of the scrollbar is changed + * when incrementing in line mode. + */ + private int lineIncrement; + + /** + * @serial The amount by which the value of the scrollbar is changed + * when incrementing in page mode. + */ + private int pageIncrement; + + /** + * @serial The maximum value for this scrollbar + */ + private int maximum; + + /** + * @serial The minimum value for this scrollbar + */ + private int minimum; + + /** + * @serial The orientation of this scrollbar, which will be either + * the <code>HORIZONTAL</code> or <code>VERTICAL</code> constant + * from this class. + */ + private int orientation; + + /** + * @serial The current value of this scrollbar. + */ + private int value; + + /** + * @serial The width of the scrollbar's thumb, which is relative + * to the minimum and maximum value of the scrollbar. + */ + private int visibleAmount; + + /** + * List of AdjustmentListener's. + */ + private AdjustmentListener adjustment_listeners; + + /** + * true if the scrollbar is adjusting, false otherwise. + */ + private transient boolean valueIsAdjusting = false; + + /** + * The number used to generate the name returned by getName. + */ + private static transient long next_scrollbar_number; + + /** + * Initializes a new instance of <code>Scrollbar</code> with a + * vertical orientation and default values for all other parameters. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, + */ + public Scrollbar() + { + this(VERTICAL); + } + + /** + * Initializes a new instance of <code>Scrollbar</code> with the + * specified orientation and default values for all other parameters. + * The orientation must be either the constant <code>HORIZONTAL</code> or + * <code>VERTICAL</code> from this class. An incorrect value will throw + * an exception. + * + * @param orientation The orientation of this scrollbar. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, + * @exception IllegalArgumentException If the orientation value is not valid. + */ + public Scrollbar(int orientation) throws IllegalArgumentException + { + this(orientation, 0, 10, 0, 100); + } + + /** + * Initializes a new instance of <code>Scrollbar</code> with the + * specified parameters. The orientation must be either the constant + * <code>HORIZONTAL</code> or <code>VERTICAL</code>. An incorrect value + * will throw an exception. Inconsistent values for other parameters + * are silently corrected to valid values. + * + * @param orientation The orientation of this scrollbar. + * @param value The initial value of the scrollbar. + * @param visibleAmount The width of the scrollbar thumb. + * @param minimum The minimum value of the scrollbar. + * @param maximum The maximum value of the scrollbar. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, + * @exception IllegalArgumentException If the orientation value is not valid. + */ + public Scrollbar(int orientation, int value, int visibleAmount, int minimum, + int maximum) throws IllegalArgumentException + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException(); + + if ((orientation != HORIZONTAL) && (orientation != VERTICAL)) + throw new IllegalArgumentException("Bad orientation value: " + + orientation); + + this.orientation = orientation; + + setValues(value, visibleAmount, minimum, maximum); + + // Default is 1 according to online docs. + lineIncrement = 1; + + // Default is 10 according to javadocs. + pageIncrement = 10; + } + + /** + * Returns the orientation constant for this object. + * + * @return The orientation constant for this object. + */ + public int getOrientation() + { + return orientation; + } + + /** + * Sets the orientation of this scrollbar to the specified value. This + * value must be either the constant <code>HORIZONTAL</code> or + * <code>VERTICAL</code> from this class or an exception will be thrown. + * + * @param orientation The new orientation value. + * + * @exception IllegalArgumentException If the orientation value is not valid. + */ + public void setOrientation(int orientation) + { + if ((orientation != HORIZONTAL) && (orientation != VERTICAL)) + throw new IllegalArgumentException("Bad orientation value: " + + orientation); + + // FIXME: Communicate to peer? Or must this be called before peer creation? + this.orientation = orientation; + } + + /** + * Returns the current value for this scrollbar. + * + * @return The current value for this scrollbar. + */ + public int getValue() + { + return value; + } + + /** + * Sets the current value for this scrollbar to the specified value. + * If this is inconsistent with the minimum and maximum values for this + * scrollbar, the value is silently adjusted. + * + * @param value The new value for this scrollbar. + */ + public void setValue(int value) + { + setValues(value, visibleAmount, minimum, maximum); + } + + /** + * Returns the maximum value for this scrollbar. + * + * @return The maximum value for this scrollbar. + */ + public int getMaximum() + { + return maximum; + } + + /** + * Sets the maximum value for this scrollbar to the specified value. + * If the value is less than the current minimum value, it is silent + * set to equal the minimum value. + * + * @param maximum The new maximum value for this scrollbar. + */ + public void setMaximum(int maximum) + { + setValues(value, visibleAmount, minimum, maximum); + } + + /** + * Returns the minimum value for this scrollbar. + * + * @return The minimum value for this scrollbar. + */ + public int getMinimum() + { + return minimum; + } + + /** + * Sets the minimum value for this scrollbar to the specified value. If + * this is not consistent with the current value and maximum, it is + * silently adjusted to be consistent. + * + * @param minimum The new minimum value for this scrollbar. + */ + public void setMinimum(int minimum) + { + setValues(value, visibleAmount, minimum, maximum); + } + + /** + * Returns the width of the scrollbar's thumb, in units relative to the + * maximum and minimum value of the scrollbar. + * + * @return The width of the scrollbar's thumb. + */ + public int getVisibleAmount() + { + return getVisible(); + } + + /** + * Returns the width of the scrollbar's thumb, in units relative to the + * maximum and minimum value of the scrollbar. + * + * @return The width of the scrollbar's thumb. + * + * @deprecated This method is deprecated in favor of + * <code>getVisibleAmount()</code>. + */ + public int getVisible() + { + return visibleAmount; + } + + /** + * Sets the width of the scrollbar's thumb, in units relative to the + * maximum and minimum value of the scrollbar. + * + * @param visibleAmount The new visible amount value of the scrollbar. + */ + public void setVisibleAmount(int visibleAmount) + { + setValues(value, visibleAmount, minimum, maximum); + } + + /** + * Sets the current value, visible amount, minimum, and maximum for this + * scrollbar. These values are adjusted to be internally consistent + * if necessary. + * + * @param value The new value for this scrollbar. + * @param visibleAmount The new visible amount for this scrollbar. + * @param minimum The new minimum value for this scrollbar. + * @param maximum The new maximum value for this scrollbar. + */ + public synchronized void setValues(int value, int visibleAmount, + int minimum, int maximum) + { + if (visibleAmount <= 0) + visibleAmount = 1; + + if (maximum <= minimum) + maximum = minimum + 1; + + if (value < minimum) + value = minimum; + + if (visibleAmount > maximum - minimum) + visibleAmount = maximum - minimum; + + // According to documentation, the actual maximum + // value is (maximum - visibleAmount) + if (value > maximum - visibleAmount) + value = maximum - visibleAmount; + + ScrollbarPeer peer = (ScrollbarPeer) getPeer(); + if (peer != null + && (this.value != value || this.visibleAmount != visibleAmount + || this.minimum != minimum || this.maximum != maximum)) + peer.setValues(value, visibleAmount, minimum, maximum); + + this.value = value; + this.visibleAmount = visibleAmount; + this.minimum = minimum; + this.maximum = maximum; + } + + /** + * Returns the value added or subtracted when the user activates the scrollbar + * scroll by a "unit" amount. + * + * @return The unit increment value. + */ + public int getUnitIncrement() + { + return getLineIncrement(); + } + + /** + * Returns the value added or subtracted when the user selects the scrollbar + * scroll by a "unit" amount control. + * + * @return The unit increment value. + * + * @deprecated This method is deprecated in favor of + * <code>getUnitIncrement()</code>. + */ + public int getLineIncrement() + { + return lineIncrement; + } + + /** + * Sets the value added or subtracted to the scrollbar value when the + * user selects the scroll by a "unit" amount control. + * + * @param unitIncrement The new unit increment amount. + */ + public synchronized void setUnitIncrement(int unitIncrement) + { + setLineIncrement(unitIncrement); + } + + /** + * Sets the value added or subtracted to the scrollbar value when the + * user selects the scroll by a "unit" amount control. + * + * @param lineIncrement The new unit increment amount. + * + * @deprecated This method is deprecated in favor of + * <code>setUnitIncrement()</code>. + */ + public void setLineIncrement(int lineIncrement) + { + if (lineIncrement < 0) + throw new IllegalArgumentException("Unit increment less than zero."); + + if (lineIncrement == 0) + lineIncrement = 1; + + if (lineIncrement == this.lineIncrement) + return; + + this.lineIncrement = lineIncrement; + + ScrollbarPeer peer = (ScrollbarPeer) getPeer(); + if (peer != null) + peer.setLineIncrement(this.lineIncrement); + } + + /** + * Returns the value added or subtracted when the user activates the scrollbar + * scroll by a "block" amount. + * + * @return The block increment value. + */ + public int getBlockIncrement() + { + return getPageIncrement(); + } + + /** + * Returns the value added or subtracted when the user selects the scrollbar + * scroll by a "block" amount control. + * + * @return The block increment value. + * + * @deprecated This method is deprecated in favor of + * <code>getBlockIncrement()</code>. + */ + public int getPageIncrement() + { + return pageIncrement; + } + + /** + * Sets the value added or subtracted to the scrollbar value when the + * user selects the scroll by a "block" amount control. + * + * @param blockIncrement The new block increment amount. + */ + public synchronized void setBlockIncrement(int blockIncrement) + { + setPageIncrement(blockIncrement); + } + + /** + * Sets the value added or subtracted to the scrollbar value when the + * user selects the scroll by a "block" amount control. + * + * @param pageIncrement The new block increment amount. + * + * @deprecated This method is deprecated in favor of + * <code>setBlockIncrement()</code>. + */ + public void setPageIncrement(int pageIncrement) + { + if (pageIncrement < 0) + throw new IllegalArgumentException("Block increment less than zero."); + + if (pageIncrement == 0) + pageIncrement = 1; + + if (pageIncrement == this.pageIncrement) + return; + + this.pageIncrement = pageIncrement; + + ScrollbarPeer peer = (ScrollbarPeer) getPeer(); + if (peer != null) + peer.setPageIncrement(this.pageIncrement); + } + + /** + * Notifies this object to create its native peer. + */ + public synchronized void addNotify() + { + if (peer == null) + peer = getToolkit().createScrollbar(this); + super.addNotify(); + } + + /** + * Adds a new adjustment listener to the list of registered listeners + * for this object. + * + * @param listener The listener to add. + */ + public synchronized void addAdjustmentListener(AdjustmentListener listener) + { + adjustment_listeners = AWTEventMulticaster.add(adjustment_listeners, + listener); + enableEvents(AWTEvent.ADJUSTMENT_EVENT_MASK); + } + + /** + * Removes the specified listener from the list of registered listeners + * for this object. + * + * @param listener The listener to remove. + */ + public synchronized void removeAdjustmentListener(AdjustmentListener listener) + { + adjustment_listeners = AWTEventMulticaster.remove(adjustment_listeners, + listener); + } + + /** + * Processes events for this scrollbar. It does this by calling + * <code>processAdjustmentEvent()</code> if the event is an instance of + * <code>AdjustmentEvent</code>, otherwise it calls the superclass to + * process the event. + * + * @param event The event to process. + */ + protected void processEvent(AWTEvent event) + { + if (event instanceof AdjustmentEvent) + processAdjustmentEvent((AdjustmentEvent) event); + else + super.processEvent(event); + } + + /** + * Processes adjustment events for this object by dispatching them to + * any registered listeners. Note that this method will only be called + * if adjustment events are enabled. This will happen automatically if + * any listeners are registered. Otherwise, it can be enabled by a + * call to <code>enableEvents()</code>. + * + * @param event The event to process. + */ + protected void processAdjustmentEvent(AdjustmentEvent event) + { + value = event.getValue(); + if (adjustment_listeners != null) + adjustment_listeners.adjustmentValueChanged(event); + } + + /** + * Package private method to determine whether to call + * processEvent() or not. Will handle events from peer and update + * the current value. + */ + void dispatchEventImpl(AWTEvent e) + { + if (e.id <= AdjustmentEvent.ADJUSTMENT_LAST + && e.id >= AdjustmentEvent.ADJUSTMENT_FIRST) + { + AdjustmentEvent ae = (AdjustmentEvent) e; + boolean adjusting = ae.getValueIsAdjusting(); + if (adjusting) + setValueIsAdjusting(true); + try + { + setValue(((AdjustmentEvent) e).getValue()); + if (adjustment_listeners != null + || (eventMask & AWTEvent.ADJUSTMENT_EVENT_MASK) != 0) + processEvent(e); + } + finally + { + if (adjusting) + setValueIsAdjusting(false); + } + } + else + super.dispatchEventImpl(e); + } + + /** + * Returns a debugging string for this object. + * + * @return A debugging string for this object. + */ + protected String paramString() + { + return ("value=" + getValue() + ",visibleAmount=" + getVisibleAmount() + + ",minimum=" + getMinimum() + ",maximum=" + getMaximum() + + ",pageIncrement=" + pageIncrement + ",lineIncrement=" + + lineIncrement + ",orientation=" + + (orientation == HORIZONTAL ? "HORIZONTAL" : "VERTICAL") + + super.paramString()); + } + + /** + * Returns an array of all the objects currently registered as FooListeners + * upon this <code>Scrollbar</code>. FooListeners are registered using the + * addFooListener method. + * + * @exception ClassCastException If listenerType doesn't specify a class or + * interface that implements java.util.EventListener. + */ + public <T extends EventListener> T[] getListeners(Class<T> listenerType) + { + if (listenerType == AdjustmentListener.class) + return AWTEventMulticaster.getListeners(adjustment_listeners, + listenerType); + + return super.getListeners(listenerType); + } + + /** + * Returns an array of all registered adjustment listeners. + */ + public AdjustmentListener[] getAdjustmentListeners() + { + return (AdjustmentListener[]) getListeners(AdjustmentListener.class); + } + + /** + * Returns true if the value is in the process of changing. + * + * @since 1.4 + */ + public boolean getValueIsAdjusting() + { + return valueIsAdjusting; + } + + /** + * Sets the value of valueIsAdjusting. + * + * @since 1.4 + */ + public void setValueIsAdjusting(boolean valueIsAdjusting) + { + this.valueIsAdjusting = valueIsAdjusting; + } + + /** + * Generate a unique name for this scroll bar. + * + * @return A unique name for this scroll bar. + */ + String generateName() + { + return "scrollbar" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_scrollbar_number++; + } + + /** + * This class provides accessibility support for the + * scrollbar. + * + * @author Jerry Quinn (jlquinn@optonline.net) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ + protected class AccessibleAWTScrollBar extends AccessibleAWTComponent + implements AccessibleValue + { + /** + * Serialization constant to match JDK 1.5 + */ + private static final long serialVersionUID = -344337268523697807L; + + /** + * Returns the role of this accessible object. + * + * @return the instance of <code>AccessibleRole</code>, + * which describes this object. + * + * @see javax.accessibility.AccessibleRole + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.SCROLL_BAR; + } + + /** + * Returns the state set of this accessible object. + * + * @return a set of <code>AccessibleState</code>s which + * represent the current state of the accessible object. + * + * @see javax.accessibility.AccessibleState + * @see javax.accessibility.AccessibleStateSet + */ + public AccessibleStateSet getAccessibleStateSet() + { + AccessibleStateSet states = super.getAccessibleStateSet(); + if (getOrientation() == HORIZONTAL) + states.add(AccessibleState.HORIZONTAL); + else + states.add(AccessibleState.VERTICAL); + if (getValueIsAdjusting()) + states.add(AccessibleState.BUSY); + return states; + } + + /** + * Returns an implementation of the <code>AccessibleValue</code> + * interface for this accessible object. In this case, the + * current instance is simply returned (with a more appropriate + * type), as it also implements the accessible value as well as + * the context. + * + * @return the accessible value associated with this context. + * + * @see javax.accessibility.AccessibleValue + */ + public AccessibleValue getAccessibleValue() + { + return this; + } + + /** + * Returns the current value of this accessible object. + * In this case, this is the same as the value for + * the scrollbar, wrapped in an <code>Integer</code> + * object. + * + * @return the numeric value of this scrollbar. + * + * @see javax.accessibility.AccessibleValue#getCurrentAccessibleValue() + */ + public Number getCurrentAccessibleValue() + { + return new Integer(getValue()); + } + + /** + * Sets the current value of this accessible object + * to that supplied. In this case, the value of the + * scrollbar is set, and this method always returns + * true. + * + * @param number the new accessible value. + * + * @return true if the value was set. + * + * @see javax.accessibility.AccessibleValue#setCurrentAccessibleValue(java.lang.Number) + */ + public boolean setCurrentAccessibleValue(Number number) + { + setValue(number.intValue()); + return true; + } + + /** + * Returns the minimum acceptable accessible value used + * by this object. In this case, this is the same as + * the minimum value of the scrollbar, wrapped in an + * object. + * + * @return the minimum value of this scrollbar. + * + * @see javax.accessibility.AccessibleValue#getMinimumAccessibleValue() + */ + public Number getMinimumAccessibleValue() + { + return new Integer(getMinimum()); + } + + /** + * Returns the maximum acceptable accessible value used + * by this object. In this case, this is the same as + * the maximum value of the scrollbar, wrapped in an + * object. + * + * @return the maximum value of this scrollbar. + * + * @see javax.accessibility.AccessibleValue#getMaximumAccessibleValue() + */ + public Number getMaximumAccessibleValue() + { + return new Integer(getMaximum()); + } + } + + /** + * Gets the AccessibleContext associated with this <code>Scrollbar</code>. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTScrollBar(); + + return accessibleContext; + } +} diff --git a/libjava/classpath/java/awt/Shape.java b/libjava/classpath/java/awt/Shape.java new file mode 100644 index 000000000..495a980cb --- /dev/null +++ b/libjava/classpath/java/awt/Shape.java @@ -0,0 +1,205 @@ +/* Shape.java -- the classic Object-Oriented shape interface + Copyright (C) 1999, 2002, 2005, 2006, Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.geom.AffineTransform; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * This interface represents an abstract shape. The shape is described by + * a {@link PathIterator}, and has callbacks for determining bounding box, + * where points and rectangles lie in relation to the shape, and tracing + * the trajectory. + * + * <p>A point is inside if it is completely inside, or on the boundary and + * adjacent points in the increasing x or y direction are completely inside. + * Unclosed shapes are considered as implicitly closed when performing + * <code>contains</code> or <code>intersects</code>. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see PathIterator + * @see AffineTransform + * @see java.awt.geom.FlatteningPathIterator + * @see java.awt.geom.GeneralPath + * @since 1.0 + * @status updated to 1.4 + */ +public interface Shape +{ + /** + * Returns a <code>Rectange</code> that bounds the shape. There is no + * guarantee that this is the minimum bounding box, particularly if + * the shape overflows the finite integer range of a bound. Generally, + * <code>getBounds2D</code> returns a tighter bound. + * + * @return the shape's bounding box + * @see #getBounds2D() + */ + Rectangle getBounds(); + + /** + * Returns a high precision bounding box of the shape. There is no guarantee + * that this is the minimum bounding box, but at least it never overflows. + * + * @return the shape's bounding box + * @see #getBounds() + * @since 1.2 + */ + Rectangle2D getBounds2D(); + + /** + * Test if the coordinates lie in the shape. + * + * @param x the x coordinate + * @param y the y coordinate + * @return true if (x,y) lies inside the shape + * @since 1.2 + */ + boolean contains(double x, double y); + + /** + * Test if the point lie in the shape. + * + * @param p the high-precision point + * @return true if p lies inside the shape + * @throws NullPointerException if p is null + * @since 1.2 + */ + boolean contains(Point2D p); + + /** + * Test if a high-precision rectangle intersects the shape. This is true + * if any point in the rectangle is in the shape, with the caveat that the + * operation may include high probability estimates when the actual + * calculation is prohibitively expensive. The {@link java.awt.geom.Area} + * class can be used for more precise answers. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle, undefined results if negative + * @param h the height of the rectangle, undefined results if negative + * @return true if the rectangle intersects this shape + * @see java.awt.geom.Area + * @since 1.2 + */ + boolean intersects(double x, double y, double w, double h); + + /** + * Test if a high-precision rectangle intersects the shape. This is true + * if any point in the rectangle is in the shape, with the caveat that the + * operation may include high probability estimates when the actual + * calculation is prohibitively expensive. The {@link java.awt.geom.Area} + * class can be used for more precise answers. + * + * @param r the rectangle + * @return true if the rectangle intersects this shape + * @throws NullPointerException if r is null + * @see #intersects(double, double, double, double) + * @since 1.2 + */ + boolean intersects(Rectangle2D r); + + /** + * Test if a high-precision rectangle lies completely in the shape. This is + * true if all points in the rectangle are in the shape, with the caveat + * that the operation may include high probability estimates when the actual + * calculation is prohibitively expensive. The {@link java.awt.geom.Area} + * class can be used for more precise answers. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle, undefined results if negative + * @param h the height of the rectangle, undefined results if negative + * @return true if the rectangle is contained in this shape + * @see java.awt.geom.Area + * @since 1.2 + */ + boolean contains(double x, double y, double w, double h); + + /** + * Test if a high-precision rectangle lies completely in the shape. This is + * true if all points in the rectangle are in the shape, with the caveat + * that the operation may include high probability estimates when the actual + * calculation is prohibitively expensive. The {@link java.awt.geom.Area} + * class can be used for more precise answers. + * + * @param r the rectangle + * @return true if the rectangle is contained in this shape + * @throws NullPointerException if r is null + * @see #contains(double, double, double, double) + * @since 1.2 + */ + boolean contains(Rectangle2D r); + + /** + * Return an iterator along the shape boundary. If the optional transform + * is provided, the iterator is transformed accordingly. Each call returns + * a new object, independent from others in use. It is recommended, but + * not required, that the Shape isolate iterations from future changes to + * the boundary, and document this fact. + * + * @param transform an optional transform to apply to the + * iterator (<code>null</code> permitted). + * @return a new iterator over the boundary + * @since 1.2 + */ + PathIterator getPathIterator(AffineTransform transform); + + /** + * Return an iterator along the flattened version of the shape boundary. + * Only SEG_MOVETO, SEG_LINETO, and SEG_CLOSE points are returned in the + * iterator. The flatness parameter controls how far points are allowed to + * differ from the real curve; although a limit on accuracy may cause this + * parameter to be enlarged if needed. + * + * <p>If the optional transform is provided, the iterator is transformed + * accordingly. Each call returns a new object, independent from others in + * use. It is recommended, but not required, that the Shape isolate + * iterations from future changes to the boundary, and document this fact. + * + * @param transform an optional transform to apply to the + * iterator (<code>null</code> permitted). + * @param flatness the maximum distance for deviation from the real boundary + * @return a new iterator over the boundary + * @since 1.2 + */ + PathIterator getPathIterator(AffineTransform transform, double flatness); +} diff --git a/libjava/classpath/java/awt/Stroke.java b/libjava/classpath/java/awt/Stroke.java new file mode 100644 index 000000000..1a4c61cfb --- /dev/null +++ b/libjava/classpath/java/awt/Stroke.java @@ -0,0 +1,65 @@ +/* Stroke.java -- a stroked outline of a shape + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +/** + * This interface allows a Graphics2D to grab the outline of a shape, as if + * stroked by a marking pen of appropriate size and shape. The area inked + * by the pen is the area of this stroke. Anything in the graphic which + * traces an outline will use this stroke, such as <code>drawLine</code>. + * Strokes must be immutable, because the graphics object does not clone + * them. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see BasicStroke + * @see Graphics2D#setStroke(Stroke) + * @since 1.1 + * @status updated to 1.4 + */ +public interface Stroke +{ + /** + * Returns a shape which outlines the boundary of the given shape, in + * effect converting the infinitely thin line into a new shape. + * + * @param s the shape to stroke + * @return the stroked outline shape + */ + Shape createStrokedShape(Shape s); +} // interface Stroke diff --git a/libjava/classpath/java/awt/SystemColor.java b/libjava/classpath/java/awt/SystemColor.java new file mode 100644 index 000000000..95bcaa696 --- /dev/null +++ b/libjava/classpath/java/awt/SystemColor.java @@ -0,0 +1,462 @@ +/* SystemColor.java -- access dynamic system color values + Copyright (C) 1999, 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; +import java.io.Serializable; + +/** + * This class contains the various "system colors" in use by the native + * windowing system. The <code>getRGB()</code> method is dynamic on systems + * which support dynamic system color changes, and most methods in the + * superclass are written to use this dynamic value when reporting colors. + * However, the <code>equals()</code> method is not dynamic, and does not + * track the actual color of instances in this class. This means that equals + * may give surprising results; you are better off relying on getRGB. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.1 + * @status updated to 1.4 + */ +public final class SystemColor extends Color implements Serializable +{ + // Implementation note: To be serial compatible with JDK, this class must + // violate the semantic meaning of super.value to be one of the + // NUM_COLORS constants instead of the actual RGB value. Hence there are + // a lot of ugly workarounds in Color and in this class. I would have + // designed it MUCH differently, making a separate id field in this class. + + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 4503142729533789064L; + + /** + * Array index of the desktop color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #desktop + */ + public static final int DESKTOP = 0; + + /** + * Array index of the active caption color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #activeCaption + */ + public static final int ACTIVE_CAPTION = 1; + + /** + * Array index of the active caption text color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #activeCaptionText + */ + public static final int ACTIVE_CAPTION_TEXT = 2; + + /** + * Array index of the active caption border color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #activeCaptionBorder + */ + public static final int ACTIVE_CAPTION_BORDER = 3; + + /** + * Array index of the inactive caption color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #inactiveCaption + */ + public static final int INACTIVE_CAPTION = 4; + + /** + * Array index of the inactive caption text color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #inactiveCaptionText + */ + public static final int INACTIVE_CAPTION_TEXT = 5; + + /** + * Array index of the inactive caption border color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #inactiveCaptionBorder + */ + public static final int INACTIVE_CAPTION_BORDER = 6; + + /** + * Array index of the window background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #window + */ + public static final int WINDOW = 7; + + /** + * Array index of the window border color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #windowBorder + */ + public static final int WINDOW_BORDER = 8; + + /** + * Array index of the window text color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #windowText + */ + public static final int WINDOW_TEXT = 9; + + /** + * Array index of the menu background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #menu + */ + public static final int MENU = 10; + + /** + * Array index of the menu text color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #menuText + */ + public static final int MENU_TEXT = 11; + + /** + * Array index of the text background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #text + */ + public static final int TEXT = 12; + + /** + * Array index of the text foreground color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #textText + */ + public static final int TEXT_TEXT = 13; + + /** + * Array index of the highlighted text background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #textHighlight + */ + public static final int TEXT_HIGHLIGHT = 14; + + /** + * Array index of the highlighted text foreground color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #textHighlightText + */ + public static final int TEXT_HIGHLIGHT_TEXT = 15; + + /** + * Array index of the inactive text foreground color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #textInactiveText + */ + public static final int TEXT_INACTIVE_TEXT = 16; + + /** + * Array index of the control background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #control + */ + public static final int CONTROL = 17; + + /** + * Array index of the control text color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #controlText + */ + public static final int CONTROL_TEXT = 18; + + /** + * Array index of the highlighted control background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #controlHighlight + */ + public static final int CONTROL_HIGHLIGHT = 19; + + /** + * Array index of the lightly highlighted control background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #controlLtHighlight + */ + public static final int CONTROL_LT_HIGHLIGHT = 20; + + /** + * Array index of the shadowed control background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #controlShadow + */ + public static final int CONTROL_SHADOW = 21; + + /** + * Array index of the darkly shadowed control background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #controlDkShadow + */ + public static final int CONTROL_DK_SHADOW = 22; + + /** + * Array index of the scrollbar background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #scrollbar + */ + public static final int SCROLLBAR = 23; + + /** + * Array index of the info background color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #info + */ + public static final int INFO = 24; + + /** + * Array index of the info text color. Used by + * {@link Toolkit#loadSystemColors(int[])}. + * + * @see #infoText + */ + public static final int INFO_TEXT = 25; + + /** + * The number of system colors. Used by + * {@link Toolkit#loadSystemColors(int[])}. + */ + public static final int NUM_COLORS = 26; + + /** + * The internal array used to dynamically update <code>getRGB()</code>. + */ + private static final int[] colors = new int[NUM_COLORS]; + + /** The desktop color. */ + public static final SystemColor desktop + = new SystemColor(DESKTOP); + + /** The active caption background color. */ + public static final SystemColor activeCaption + = new SystemColor(ACTIVE_CAPTION); + + /** The active caption text color. */ + public static final SystemColor activeCaptionText + = new SystemColor(ACTIVE_CAPTION_TEXT); + + /** The active caption border color. */ + public static final SystemColor activeCaptionBorder + = new SystemColor(ACTIVE_CAPTION_BORDER); + + /** The inactive caption background color. */ + public static final SystemColor inactiveCaption + = new SystemColor(INACTIVE_CAPTION); + + /** The inactive caption text color. */ + public static final SystemColor inactiveCaptionText + = new SystemColor(INACTIVE_CAPTION_TEXT); + + /** The inactive caption border color. */ + public static final SystemColor inactiveCaptionBorder + = new SystemColor(INACTIVE_CAPTION_BORDER); + + /** The window background color. */ + public static final SystemColor window + = new SystemColor(WINDOW); + + /** The window border color. */ + public static final SystemColor windowBorder + = new SystemColor(WINDOW_BORDER); + + /** The window text color. */ + public static final SystemColor windowText + = new SystemColor(WINDOW_TEXT); + + /** The menu background color. */ + public static final SystemColor menu + = new SystemColor(MENU); + + /** The menu text color. */ + public static final SystemColor menuText + = new SystemColor(MENU_TEXT); + + /** The text background color. */ + public static final SystemColor text + = new SystemColor(TEXT); + + /** The text foreground color. */ + public static final SystemColor textText + = new SystemColor(TEXT_TEXT); + + /** The highlighted text background color. */ + public static final SystemColor textHighlight + = new SystemColor(TEXT_HIGHLIGHT); + + /** The highlighted text foreground color. */ + public static final SystemColor textHighlightText + = new SystemColor(TEXT_HIGHLIGHT_TEXT); + + /** The inactive text color. */ + public static final SystemColor textInactiveText + = new SystemColor(TEXT_INACTIVE_TEXT); + + /** The control background color. */ + public static final SystemColor control + = new SystemColor(CONTROL); + + /** The control text color. */ + public static final SystemColor controlText + = new SystemColor(CONTROL_TEXT); + + /** The control highlight color. */ + public static final SystemColor controlHighlight + = new SystemColor(CONTROL_HIGHLIGHT); + + /** The control light highlight color. */ + public static final SystemColor controlLtHighlight + = new SystemColor(CONTROL_LT_HIGHLIGHT); + + /** The control shadow color. */ + public static final SystemColor controlShadow + = new SystemColor(CONTROL_SHADOW); + + /** The control dark shadow color. */ + public static final SystemColor controlDkShadow + = new SystemColor(CONTROL_DK_SHADOW); + + /** The scrollbar color. */ + public static final SystemColor scrollbar + = new SystemColor(SCROLLBAR); + + /** The info text background color. */ + public static final SystemColor info + = new SystemColor(INFO); + + /** The info text foreground color. */ + public static final SystemColor infoText + = new SystemColor(INFO_TEXT); + + /** + * Construct a system color which is dynamically updated. + * + * @param id the color id + */ + private SystemColor(int id) + { + // Note: See Color#Color(int, boolean) to explain why we use this + // particular constructor. + super(id, true); + } + + /** + * Returns the RGB value for this color, in the sRGB color space. The blue + * value will be in bits 0-7, green in 8-15, red in 6-23, and the alpha + * value (bits 24-31) is 0xff. This is dynamically updated, so it may not + * match the results of <code>getRed()</code>, <code>getGreen()</code>, or + * <code>getBlue()</code>. + * + * @return the current RGB value + */ + public int getRGB() + { + Toolkit.getDefaultToolkit().loadSystemColors(colors); + return colors[value] | ALPHA_MASK; + } + + /** + * Returns a paint context, used for filling areas of a raster scan with + * the current value of this system color. Since the system colors may be + * dynamically updated, the returned value may not always be the same; but + * as the system color is solid, the context does not need any of the + * passed parameters to do its job. + * + * @param cm the requested color model + * @param deviceBounds the bounding box in device coordinates, ignored + * @param userBounds the bounding box in user coordinates, ignored + * @param xform the bounds transformation, ignored + * @param hints any rendering hints, ignored + * @return a context for painting this solid color + */ + public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, + Rectangle2D userBounds, + AffineTransform xform, + RenderingHints hints) + { + Toolkit.getDefaultToolkit().loadSystemColors(colors); + int color = colors[value] | ALPHA_MASK; + if (context == null || color != context.color || !context.getColorModel().equals(cm)) + context = new ColorPaintContext(cm,color); + return context; + } + + /** + * Returns a string describing this color. This is in the format + * "java.awt.SystemColor[i=" + index + ']', where index is one of the + * integer constants of this class. Unfortunately, this description + * does not describe the current value of the color; for that you should + * use <code>new Color(syscolor.getRGB()).toString()</code>. + * + * @return a string describing this color + */ + public String toString() + { + return "java.awt.SystemColor[i=" + value + ']'; + } +} // class SystemColor diff --git a/libjava/classpath/java/awt/TextArea.java b/libjava/classpath/java/awt/TextArea.java new file mode 100644 index 000000000..265f8c8b6 --- /dev/null +++ b/libjava/classpath/java/awt/TextArea.java @@ -0,0 +1,631 @@ +/* TextArea.java -- A multi-line text entry component + Copyright (C) 1999, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.KeyEvent; +import java.awt.peer.ComponentPeer; +import java.awt.peer.TextAreaPeer; +import java.util.HashSet; +import java.util.Set; + +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleStateSet; + + +/** + * A TextArea is a text component capable of displaying multiple lines + * of user-editable text. A TextArea handles its own scrolling and + * can display vertical and horizontal scrollbars as navigation aids. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class TextArea extends TextComponent implements java.io.Serializable +{ + /** + * Display both horiztonal and vertical scroll bars. + */ + public static final int SCROLLBARS_BOTH = 0; + + /** + * Display vertical scroll bar only. + */ + public static final int SCROLLBARS_VERTICAL_ONLY = 1; + + /** + * Display horizatonal scroll bar only. + */ + public static final int SCROLLBARS_HORIZONTAL_ONLY = 2; + + /** + * Do not display scrollbars. + */ + public static final int SCROLLBARS_NONE = 3; + + /** + * Serialization constant. + */ + private static final long serialVersionUID = 3692302836626095722L; + + /** + * @serial The number of columns used in this text area's preferred + * and minimum size calculations. + */ + private int columns; + + /** + * @serial The number of rows used in this text area's preferred and + * minimum size calculations. + */ + private int rows; + + /** + * @serial The scrollbar display policy. One of SCROLLBARS_BOTH, + * SCROLLBARS_VERTICAL_ONLY, SCROLLBARS_HORIZONTAL_ONLY, + * SCROLLBARS_NONE. + */ + private int scrollbarVisibility; + + /* + * The number used to generate the name returned by getName. + */ + private static transient long next_text_number; + + /** + * Initialize a new instance of <code>TextArea</code> that is empty. + * Conceptually the <code>TextArea</code> has 0 rows and 0 columns + * but its initial bounds are defined by its peer or by the + * container in which it is packed. Both horizontal and vertical + * scrollbars will be displayed. + * + * @exception HeadlessException if GraphicsEnvironment.isHeadless () is true + */ + public TextArea () + { + this ("", 0, 0, SCROLLBARS_BOTH); + } + + /** + * Initialize a new instance of <code>TextArea</code> that contains + * the specified text. Conceptually the <code>TextArea</code> has 0 + * rows and 0 columns but its initial bounds are defined by its peer + * or by the container in which it is packed. Both horizontal and + * veritcal scrollbars will be displayed. The TextArea initially contains + * the specified text. If text specified as <code>null<code>, it will + * be set to "". + * + * @param text The text to display in this text area (<code>null</code> permitted). + * + * @exception HeadlessException if GraphicsEnvironment.isHeadless () is true + */ + public TextArea (String text) + { + this (text, 0, 0, SCROLLBARS_BOTH); + } + + /** + * Initialize a new instance of <code>TextArea</code> that is empty + * and can display the specified number of rows and columns of text, + * without the need to scroll. Both horizontal and vertical + * scrollbars will be displayed. + * + * @param rows The number of rows in this text area. + * @param columns The number of columns in this text area. + * + * @exception HeadlessException if GraphicsEnvironment.isHeadless () is true + */ + public TextArea (int rows, int columns) + { + this ("", rows, columns, SCROLLBARS_BOTH); + } + + /** + * Initialize a new instance of <code>TextArea</code> that can + * display the specified number of rows and columns of text, without + * the need to scroll. The TextArea initially contains the + * specified text. If text specified as <code>null<code>, it will + * be set to "". + * + * @param text The text to display in this text area (<code>null</code> permitted). + * @param rows The number of rows in this text area. + * @param columns The number of columns in this text area. + * + * @exception HeadlessException if GraphicsEnvironment.isHeadless () is true + */ + public TextArea (String text, int rows, int columns) + { + this (text, rows, columns, SCROLLBARS_BOTH); + } + + /** + * Initialize a new instance of <code>TextArea</code> that initially + * contains the specified text. The TextArea can display the + * specified number of rows and columns of text, without the need to + * scroll. This constructor allows specification of the scroll bar + * display policy. The TextArea initially contains the specified text. + * If text specified as <code>null<code>, it will be set to "". + * + * @param text The text to display in this text area (<code>null</code> permitted). + * @param rows The number of rows in this text area. + * @param columns The number of columns in this text area. + * @param scrollbarVisibility The scroll bar display policy. One of + * SCROLLBARS_BOTH, SCROLLBARS_VERTICAL_ONLY, + * SCROLLBARS_HORIZONTAL_ONLY, SCROLLBARS_NONE. + * + * @exception HeadlessException if GraphicsEnvironment.isHeadless () is true + */ + public TextArea (String text, int rows, int columns, int scrollbarVisibility) + { + super (text); + + if (GraphicsEnvironment.isHeadless ()) + throw new HeadlessException (); + + if (rows < 0) + this.rows = 0; + else + this.rows = rows; + + if (columns < 0) + this.columns = 0; + else + this.columns = columns; + + if (scrollbarVisibility < 0 || scrollbarVisibility > 4) + this.scrollbarVisibility = SCROLLBARS_BOTH; + else + this.scrollbarVisibility = scrollbarVisibility; + + // TextAreas need to receive tab key events so we override the + // default forward and backward traversal key sets. + Set s = new HashSet (); + s.add (AWTKeyStroke.getAWTKeyStroke (KeyEvent.VK_TAB, + KeyEvent.CTRL_DOWN_MASK)); + setFocusTraversalKeys (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, s); + s = new HashSet (); + s.add (AWTKeyStroke.getAWTKeyStroke (KeyEvent.VK_TAB, + KeyEvent.SHIFT_DOWN_MASK + | KeyEvent.CTRL_DOWN_MASK)); + setFocusTraversalKeys (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, s); + } + + /** + * Retrieve the number of columns that this text area would prefer + * to display. This value may or may not correspond to the number + * of columns that are actually displayed. + * + * @return The preferred number of columns. + */ + public int getColumns () + { + return columns; + } + + /** + * Set the preferred number of columns for this text area. This + * method does not cause the number of columns displayed by the text + * area to be updated, if the text area is currently visible. + * + * @param columns The preferred number of columns. + * + * @exception IllegalArgumentException If columns is less than zero. + */ + public synchronized void setColumns (int columns) + { + if (columns < 0) + throw new IllegalArgumentException ("Value is less than zero: " + + columns); + + this.columns = columns; + } + + /** + * Retrieve the number of rows that this text area would prefer to + * display. This value may or may not correspond to the number of + * rows that are actually displayed. + * + * @return The preferred number of rows. + */ + public int getRows () + { + return rows; + } + + /** + * Set the preferred number of rows for this text area. This method + * does not cause the number of columns displayed by the text area + * to be updated, if the text area is currently visible. + * + * @param rows The preferred number of rows. + * + * @exception IllegalArgumentException If rows is less than zero. + */ + public synchronized void setRows (int rows) + { + if (rows < 1) + throw new IllegalArgumentException ("Value is less than one: " + rows); + + this.rows = rows; + } + + /** + * Retrieve the minimum size for this text area. + * + * @return The minimum size for this text field. + */ + public Dimension getMinimumSize () + { + return getMinimumSize (getRows (), getColumns ()); + } + + /** + * Retrieve the minimum size for this text area. If the minimum + * size has been set, then rows and columns are used in the calculation. + * + * @param rows The number of rows to use in the minimum size + * calculation. + * @param columns The number of columns to use in the minimum size + * calculation. + * + * @return The minimum size for this text area. + */ + public Dimension getMinimumSize (int rows, int columns) + { + return minimumSize (rows, columns); + } + + /** + * Retrieve the minimum size for this text area. + * + * @return The minimum size for this text area. + * + * @deprecated This method is deprecated in favor of + * <code>getMinimumSize ()</code>. + */ + public Dimension minimumSize () + { + return minimumSize (getRows (), getColumns ()); + } + + /** + * Retrieve the minimum size for this text area. If the minimum + * size has been set, then rows and columns are used in the calculation. + * + * @param rows The number of rows to use in the minimum size + * calculation. + * @param columns The number of columns to use in the minimum size + * calculation. + * + * @return The minimum size for this text area. + * + * @deprecated This method is deprecated in favor of + * <code>getMinimumSize (int, int)</code>. + */ + public Dimension minimumSize (int rows, int columns) + { + if (isMinimumSizeSet()) + return new Dimension(minSize); + + TextAreaPeer peer = (TextAreaPeer) getPeer (); + if (peer == null) + return new Dimension (getWidth(), getHeight()); + + return peer.getMinimumSize (rows, columns); + } + + /** + * Retrieve the preferred size for this text area. + * + * @return The preferred size for this text field. + */ + public Dimension getPreferredSize () + { + return getPreferredSize (getRows (), getColumns ()); + } + + /** + * Retrieve the preferred size for this text area. If the preferred + * size has been set, then rows and columns are used in the calculation. + * + * @param rows The number of rows to use in the preferred size + * calculation. + * @param columns The number of columns to use in the preferred size + * calculation. + * + * @return The preferred size for this text area. + */ + public Dimension getPreferredSize (int rows, int columns) + { + return preferredSize (rows, columns); + } + + /** + * Retrieve the preferred size for this text area. + * + * @return The preferred size for this text field. + * + * @deprecated This method is deprecated in favor of + * <code>getPreferredSize ()</code>. + */ + public Dimension preferredSize () + { + return preferredSize (getRows (), getColumns ()); + } + + /** + * Retrieve the preferred size for this text area. If the preferred + * size has been set, then rows and columns are used in the calculation. + * + * @param rows The number of rows to use in the preferred size + * calculation. + * @param columns The number of columns to use in the preferred size + * calculation. + * + * @return The preferred size for this text area. + * + * @deprecated This method is deprecated in favor of + * <code>getPreferredSize (int, int)</code>. + */ + public Dimension preferredSize (int rows, int columns) + { + if (isPreferredSizeSet()) + return new Dimension(prefSize); + + TextAreaPeer peer = (TextAreaPeer) getPeer (); + if (peer == null) + return new Dimension (getWidth(), getHeight()); + + return peer.getPreferredSize (rows, columns); + } + + /** + * Retrieve the scroll bar display policy -- one of SCROLLBARS_BOTH, + * SCROLLBARS_VERTICAL_ONLY, SCROLLBARS_HORIZONTAL_ONLY, + * SCROLLBARS_NONE. + * + * @return The current scroll bar display policy. + */ + public int getScrollbarVisibility () + { + return scrollbarVisibility; + } + + /** + * Notify this object that it should create its native peer. + */ + public void addNotify () + { + if (getPeer () == null) + setPeer ((ComponentPeer) getToolkit().createTextArea (this)); + } + + /** + * Append the specified text to the end of the current text. + * + * @param str The text to append. + */ + public void append (String str) + { + appendText (str); + } + + /** + * Append the specified text to the end of the current text. + * + * @param str The text to append. + * + * @deprecated This method is deprecated in favor of + * <code>append ()</code>. + */ + public void appendText (String str) + { + TextAreaPeer peer = (TextAreaPeer) getPeer (); + + if (peer != null) + peer.insert (str, peer.getText().length ()); + else + setText(getText() + str); + } + + /** + * Insert the specified text at the specified position. The first + * character in the text area is at position zero. + * + * @param str The text to insert. + * @param pos The position at which to insert text. + */ + public void insert (String str, int pos) + { + insertText (str, pos); + } + + /** + * Insert the specified text at the specified position. The first + * character in the text area is at position zero. + * + * @param str The text to insert. + * @param pos The position at which to insert text. + * + * @deprecated This method is deprecated in favor of + * <code>insert ()</code>. + */ + public void insertText (String str, int pos) + { + String tmp1 = null; + String tmp2 = null; + + TextAreaPeer peer = (TextAreaPeer) getPeer (); + + if (peer != null) + peer.insert (str, pos); + else + { + tmp1 = getText().substring(0, pos); + tmp2 = getText().substring(pos, getText().length()); + setText(tmp1 + str + tmp2); + } + } + + /** + * Replace a range of characters with the specified text. The + * character at the start position will be replaced, unless start == + * end. The character at the end posistion will not be replaced. + * The first character in the text area is at position zero. The + * length of the replacement text may differ from the length of the + * text that is replaced. + * + * @param str The new text for the range. + * @param start The start position of the replacement range. + * @param end The end position of the replacement range. + */ + public void replaceRange (String str, int start, int end) + { + replaceText (str, start, end); + } + + /** + * Replace a range of characters with the specified text. The + * character at the start position will be replaced, unless start == + * end. The character at the end posistion will not be replaced. + * The first character in the text area is at position zero. The + * length of the replacement text may differ from the length of the + * text that is replaced. + * + * @param str The new text for the range. + * @param start The start position of the replacement range. + * @param end The end position of the replacement range. + * + * @deprecated This method is deprecated in favor of + * <code>replaceRange ()</code>. + */ + public void replaceText (String str, int start, int end) + { + String tmp1 = null; + String tmp2 = null; + + TextAreaPeer peer = (TextAreaPeer) getPeer(); + + if (peer != null) + peer.replaceRange(str, start, end); + else + { + tmp1 = getText().substring(0, start); + tmp2 = getText().substring(end, getText().length()); + setText(tmp1 + str + tmp2); + } + } + + /** + * Retrieve a debugging string for this text area. + * + * @return A debugging string for this text area. + */ + protected String paramString () + { + String sbVisibility = ""; + + switch (scrollbarVisibility) + { + case SCROLLBARS_BOTH: + sbVisibility = "both"; + break; + case SCROLLBARS_VERTICAL_ONLY: + sbVisibility = "vertical-only"; + break; + case SCROLLBARS_HORIZONTAL_ONLY: + sbVisibility = "horizontal-only"; + break; + case SCROLLBARS_NONE: + sbVisibility = "none"; + break; + } + + String editable = ""; + if (isEditable ()) + editable = "editable,"; + + return getName () + "," + getX () + "," + getY () + "," + getWidth () + + "x" + getHeight () + "," + "text=" + getText () + "," + editable + + "selection=" + getSelectionStart () + "-" + getSelectionEnd () + + ",rows=" + rows + ",columns=" + columns + ",scrollbarVisibility=" + + sbVisibility; + } + + /** + * Generate a unique name for this text area. + * + * @return A unique name for this text area. + */ + String generateName () + { + return "text" + getUniqueLong (); + } + + private static synchronized long getUniqueLong () + { + return next_text_number++; + } + + protected class AccessibleAWTTextArea extends AccessibleAWTTextComponent + { + private static final long serialVersionUID = 3472827823632144419L; + + protected AccessibleAWTTextArea() + { + } + + public AccessibleStateSet getAccessibleStateSet() + { + return super.getAccessibleStateSet(); + } + } + + /** + * Gets the AccessibleContext associated with this <code>TextArea</code>. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTTextArea(); + return accessibleContext; + } +} diff --git a/libjava/classpath/java/awt/TextComponent.java b/libjava/classpath/java/awt/TextComponent.java new file mode 100644 index 000000000..31ea3f5de --- /dev/null +++ b/libjava/classpath/java/awt/TextComponent.java @@ -0,0 +1,676 @@ +/* TextComponent.java -- Widgets for entering text + Copyright (C) 1999, 2002, 2003, 2006, Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.TextEvent; +import java.awt.event.TextListener; +import java.awt.peer.TextComponentPeer; +import java.io.Serializable; +import java.text.BreakIterator; +import java.util.EventListener; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; +import javax.accessibility.AccessibleText; +import javax.swing.text.AttributeSet; + +/** + * This class provides common functionality for widgets than + * contain text. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class TextComponent extends Component + implements Serializable, Accessible +{ + + private static final long serialVersionUID = -2214773872412987419L; + + /** + * @serial Indicates whether or not this component is editable. + * This is package-private to avoid an accessor method. + */ + boolean editable; + + /** + * @serial The starting position of the selected text region. + * This is package-private to avoid an accessor method. + */ + int selectionStart; + + /** + * @serial The ending position of the selected text region. + * This is package-private to avoid an accessor method. + */ + int selectionEnd; + + /** + * @serial The text in the component + * This is package-private to avoid an accessor method. + */ + String text; + + /** + * A list of listeners that will receive events from this object. + */ + protected transient TextListener textListener; + + protected class AccessibleAWTTextComponent + extends AccessibleAWTComponent + implements AccessibleText, TextListener + { + private static final long serialVersionUID = 3631432373506317811L; + + // Constructor + // Adds a listener for tracking caret changes + public AccessibleAWTTextComponent() + { + TextComponent.this.addTextListener(this); + } + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.TEXT; + } + + public AccessibleStateSet getAccessibleStateSet() + { + // TODO: Docs say PropertyChangeEvent will fire if this state changes. + // That means that the event has to fire when editable changes. + AccessibleStateSet ss = super.getAccessibleStateSet(); + if (editable) + ss.add(AccessibleState.EDITABLE); + return ss; + } + + public AccessibleText getAccessibleText() + { + return this; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getIndexAtPoint(java.awt.Point) + */ + public int getIndexAtPoint(Point point) + { + return TextComponent.this.getIndexAtPoint(point); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getCharacterBounds(int) + */ + public Rectangle getCharacterBounds(int index) + { + return TextComponent.this.getCharacterBounds(index); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getCharCount() + */ + public int getCharCount() + { + return text.length(); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getCaretPosition() + */ + public int getCaretPosition() + { + return TextComponent.this.getCaretPosition(); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getAtIndex(int, int) + */ + public String getAtIndex(int part, int index) + { + if (index < 0 || index >= text.length()) + return null; + BreakIterator it = null; + switch (part) + { + case CHARACTER: + return text.substring(index, index + 1); + case WORD: + it = BreakIterator.getWordInstance(); + break; + case SENTENCE: + it = BreakIterator.getSentenceInstance(); + break; + default: + return null; + } + it.setText(text); + int start = index; + if (!it.isBoundary(index)) + start = it.preceding(index); + int end = it.following(index); + if (end == -1) + return text.substring(index); + else + return text.substring(index, end); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getAfterIndex(int, int) + */ + public String getAfterIndex(int part, int index) { + if (index < 0 || index >= text.length()) + return null; + BreakIterator it = null; + switch (part) + { + case CHARACTER: + return text.substring(index, index + 1); + case WORD: + it = BreakIterator.getWordInstance(); + break; + case SENTENCE: + it = BreakIterator.getSentenceInstance(); + break; + default: + return null; + } + it.setText(text); + int start = index; + if (!it.isBoundary(index)) + start = it.following(index); + // Make sure there was a complete unit. I.e. if index is in the middle + // of a word, return null if there is no word after the that one. + if (start == -1) + return null; + int end = it.following(start); + if (end == -1) + return text.substring(index); + else + return text.substring(index, end); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getBeforeIndex(int, int) + */ + public String getBeforeIndex(int part, int index) + { + if (index < 1 || index >= text.length()) + return null; + BreakIterator it = null; + switch (part) + { + case CHARACTER: + return text.substring(index - 1, index); + case WORD: + it = BreakIterator.getWordInstance(); + break; + case SENTENCE: + it = BreakIterator.getSentenceInstance(); + break; + default: + return null; + } + it.setText(text); + int end = index; + if (!it.isBoundary(index)) + end = it.preceding(index); + // Make sure there was a complete unit. I.e. if index is in the middle + // of a word, return null if there is no word before that one. + if (end == -1) + return null; + int start = it.preceding(end); + if (start == -1) + return text.substring(0, end); + else + return text.substring(start, end); + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getCharacterAttribute(int) + */ + public AttributeSet getCharacterAttribute(int index) + { + // FIXME: I suspect this really gets filled in by subclasses. + return null; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getSelectionStart() + */ + public int getSelectionStart() { + // TODO Auto-generated method stub + return selectionStart; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getSelectionEnd() + */ + public int getSelectionEnd() + { + return selectionEnd; + } + + /* (non-Javadoc) + * @see javax.accessibility.AccessibleText#getSelectedText() + */ + public String getSelectedText() + { + if (selectionEnd - selectionStart > 0) + return text.substring(selectionStart, selectionEnd); + else + return null; + } + + /* (non-Javadoc) + * @see java.awt.event.TextListener#textValueChanged(java.awt.event.TextEvent) + */ + public void textValueChanged(TextEvent event) + { + // TODO Auto-generated method stub + + } + + } + + + TextComponent(String text) + { + if (text == null) + this.text = ""; + else + this.text = text; + + this.editable = true; + } + + + /** + * Returns the text in this component + * + * @return The text in this component. + */ + public synchronized String getText() + { + TextComponentPeer tcp = (TextComponentPeer) getPeer(); + if (tcp != null) + text = tcp.getText(); + + return(text); + } + + /** + * Sets the text in this component to the specified string. + * + * @param text The new text for this component. + */ + public synchronized void setText(String text) + { + if (text == null) + text = ""; + + this.text = text; + + TextComponentPeer tcp = (TextComponentPeer) getPeer(); + if (tcp != null) + tcp.setText(text); + setCaretPosition(0); + } + + /** + * Returns a string that contains the text that is currently selected. + * + * @return The currently selected text region. + */ + public synchronized String getSelectedText() + { + String alltext = getText(); + int start = getSelectionStart(); + int end = getSelectionEnd(); + + return(alltext.substring(start, end)); + } + + /** + * Returns the starting position of the selected text region. + * If the text is not selected then caret position is returned. + * + * @return The starting position of the selected text region. + */ + public synchronized int getSelectionStart() + { + TextComponentPeer tcp = (TextComponentPeer) getPeer(); + if (tcp != null) + selectionStart = tcp.getSelectionStart(); + + return(selectionStart); + } + + /** + * Sets the starting position of the selected region to the + * specified value. If the specified value is out of range, then it + * will be silently changed to the nearest legal value. + * + * @param selectionStart The new start position for selected text. + */ + public synchronized void setSelectionStart(int selectionStart) + { + select(selectionStart, + (getSelectionEnd() < selectionStart) + ? selectionStart : getSelectionEnd()); + } + + /** + * Returns the ending position of the selected text region. + * If the text is not selected, then caret position is returned + * + * @return The ending position of the selected text region. + */ + public synchronized int getSelectionEnd() + { + TextComponentPeer tcp = (TextComponentPeer) getPeer(); + if (tcp != null) + selectionEnd = tcp.getSelectionEnd(); + + return(selectionEnd); + } + + /** + * Sets the ending position of the selected region to the + * specified value. If the specified value is out of range, then it + * will be silently changed to the nearest legal value. + * + * @param selectionEnd The new start position for selected text. + */ + public synchronized void setSelectionEnd(int selectionEnd) + { + select(getSelectionStart(), selectionEnd); + } + + /** + * This method sets the selected text range to the text between the + * specified start and end positions. Illegal values for these + * positions are silently fixed. + * + * @param selectionStart The new start position for the selected text. + * @param selectionEnd The new end position for the selected text. + */ + public synchronized void select(int selectionStart, int selectionEnd) + { + if (selectionStart < 0) + selectionStart = 0; + + if (selectionStart > getText().length()) + selectionStart = text.length(); + + if (selectionEnd > text.length()) + selectionEnd = text.length(); + + if (selectionStart > selectionEnd) + selectionStart = selectionEnd; + + this.selectionStart = selectionStart; + this.selectionEnd = selectionEnd; + + TextComponentPeer tcp = (TextComponentPeer) getPeer(); + if (tcp != null) + tcp.select(selectionStart, selectionEnd); + } + + /** + * Selects all of the text in the component. + */ + public synchronized void selectAll() + { + select(0, getText().length()); + } + + /** + * Returns the current caret position in the text. + * + * @return The caret position in the text. + */ + public synchronized int getCaretPosition() + { + TextComponentPeer tcp = (TextComponentPeer) getPeer(); + if (tcp != null) + return(tcp.getCaretPosition()); + else + return(0); + } + + /** + * Sets the caret position to the specified value. + * + * @param caretPosition The new caret position. + * + * @exception IllegalArgumentException If the value supplied for position + * is less than zero. + * + * @since 1.1 + */ + public synchronized void setCaretPosition(int caretPosition) + { + if (caretPosition < 0) + throw new IllegalArgumentException(); + + TextComponentPeer tcp = (TextComponentPeer) getPeer(); + if (tcp != null) + tcp.setCaretPosition(caretPosition); + } + + /** + * Tests whether or not this component's text can be edited. + * + * @return <code>true</code> if the text can be edited, <code>false</code> + * otherwise. + */ + public boolean isEditable() + { + return(editable); + } + + /** + * Sets whether or not this component's text can be edited. + * + * @param editable <code>true</code> to enable editing of the text, + * <code>false</code> to disable it. + */ + public synchronized void setEditable(boolean editable) + { + this.editable = editable; + + TextComponentPeer tcp = (TextComponentPeer) getPeer(); + if (tcp != null) + tcp.setEditable(editable); + } + + /** + * Notifies the component that it should destroy its native peer. + */ + public void removeNotify() + { + super.removeNotify(); + } + + /** + * Adds a new listener to the list of text listeners for this + * component. + * + * @param listener The listener to be added. + */ + public synchronized void addTextListener(TextListener listener) + { + textListener = AWTEventMulticaster.add(textListener, listener); + + enableEvents(AWTEvent.TEXT_EVENT_MASK); + } + + /** + * Removes the specified listener from the list of listeners + * for this component. + * + * @param listener The listener to remove. + */ + public synchronized void removeTextListener(TextListener listener) + { + textListener = AWTEventMulticaster.remove(textListener, listener); + } + + /** + * Processes the specified event for this component. Text events are + * processed by calling the <code>processTextEvent()</code> method. + * All other events are passed to the superclass method. + * + * @param event The event to process. + */ + protected void processEvent(AWTEvent event) + { + if (event instanceof TextEvent) + processTextEvent((TextEvent)event); + else + super.processEvent(event); + } + + /** + * Processes the specified text event by dispatching it to any listeners + * that are registered. Note that this method will only be called + * if text event's are enabled. This will be true if there are any + * registered listeners, or if the event has been specifically + * enabled using <code>enableEvents()</code>. + * + * @param event The text event to process. + */ + protected void processTextEvent(TextEvent event) + { + if (textListener != null) + textListener.textValueChanged(event); + } + + void dispatchEventImpl(AWTEvent e) + { + if (e.id <= TextEvent.TEXT_LAST + && e.id >= TextEvent.TEXT_FIRST + && (textListener != null + || (eventMask & AWTEvent.TEXT_EVENT_MASK) != 0)) + processEvent(e); + else + super.dispatchEventImpl(e); + } + + /** + * Returns a debugging string. + * + * @return A debugging string. + */ + protected String paramString() + { + return(getClass().getName() + "(text=" + getText() + ")"); + } + + /** + * Returns an array of all the objects currently registered as FooListeners + * upon this <code>TextComponent</code>. FooListeners are registered using + * the addFooListener method. + * + * @exception ClassCastException If listenerType doesn't specify a class or + * interface that implements java.util.EventListener. + */ + public <T extends EventListener> T[] getListeners(Class<T> listenerType) + { + if (listenerType == TextListener.class) + return AWTEventMulticaster.getListeners(textListener, listenerType); + + return super.getListeners(listenerType); + } + + /** + * Returns all text listeners registered to this object. + */ + public TextListener[] getTextListeners() + { + return (TextListener[]) getListeners(TextListener.class); + } + + /** + * Gets the AccessibleContext associated with this <code>TextComponent</code>. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTTextComponent(); + return accessibleContext; + } + + + // Provide AccessibleAWTTextComponent access to several peer functions that + // aren't publicly exposed. This is package-private to avoid an accessor + // method. + synchronized int getIndexAtPoint(Point p) + { + TextComponentPeer tcp = (TextComponentPeer) getPeer(); + if (tcp != null) + return tcp.getIndexAtPoint(p.x, p.y); + return -1; + } + + synchronized Rectangle getCharacterBounds(int i) + { + TextComponentPeer tcp = (TextComponentPeer) getPeer(); + if (tcp != null) + return tcp.getCharacterBounds(i); + return null; + } + + /** + * All old mouse events for this component should + * be ignored. + * + * @return true to ignore all old mouse events. + */ + static boolean ignoreOldMouseEvents() + { + return true; + } + +} // class TextComponent diff --git a/libjava/classpath/java/awt/TextField.java b/libjava/classpath/java/awt/TextField.java new file mode 100644 index 000000000..5a58b440d --- /dev/null +++ b/libjava/classpath/java/awt/TextField.java @@ -0,0 +1,484 @@ +/* TextField.java -- A one line text entry field + Copyright (C) 1999, 2002, 2004, 2006, Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.peer.ComponentPeer; +import java.awt.peer.TextFieldPeer; +import java.util.EventListener; + +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleStateSet; + +/** + * This class implements a single line text entry field widget + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class TextField extends TextComponent +{ + + /** + * The number used to generate the name returned by getName. + */ + private static transient long next_textfield_number; + + + private static final long serialVersionUID = -2966288784432217853L; + + + /** + * @serial The number of columns in the text entry field. + */ + private int columns; + + /** + * @serial The character that is echoed when doing protected input + */ + private char echoChar; + + // List of registered ActionListener's for this object. + private ActionListener action_listeners; + + /** + * Initializes a new instance of <code>TextField</code> that is empty + * and has one column. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, + */ + public TextField() + { + this("", 0); + } + + /** + * Initializes a new instance of <code>TextField</code> containing + * the specified text. The number of columns will be equal to the + * length of the text string. + * + * @param text The text to display in the field. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, + */ + public TextField(String text) + { + this(text, (text == null) ? 0 : text.length()); + } + + /** + * Initializes a new instance of <code>TextField</code> that is empty + * and has the specified number of columns. + * + * @param columns The number of columns in the text field. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, + */ + public TextField(int columns) + { + this("", columns); + } + + /** + * Initializes a new instance of <code>TextField</code> with the + * specified text and number of columns. + * + * @param text The text to display in the field. + * @param columns The number of columns in the field. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, + */ + public TextField(String text, int columns) + { + super(text); + + if (columns < 0) + this.columns = 0; + else + this.columns = columns; + + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException (); + } + + /** + * Returns the number of columns in the field. + * + * @return The number of columns in the field. + */ + public int getColumns() + { + return(columns); + } + + /** + * Sets the number of columns in this field to the specified value. + * + * @param columns The new number of columns in the field. + * + * @exception IllegalArgumentException If columns is less than zero. + */ + public synchronized void setColumns(int columns) + { + if (columns < 0) + throw new IllegalArgumentException("Value is less than zero: " + + columns); + + this.columns = columns; + // FIXME: How to we communicate this to our peer? + } + + /** + * Returns the character that is echoed to the screen when a text + * field is protected (such as when a password is being entered). + * + * @return The echo character for this text field. + */ + public char getEchoChar() + { + return(echoChar); + } + + /** + * Sets the character that is echoed when protected input such as + * a password is displayed. + * + * @param echoChar The new echo character. + */ + public void setEchoChar(char echoChar) + { + setEchoCharacter(echoChar); + } + + /** + * Sets the character that is echoed when protected input such as + * a password is displayed. + * + * @param echoChar The new echo character. + * + * @deprecated This method is deprecated in favor of + * <code>setEchoChar()</code> + */ + public void setEchoCharacter(char echoChar) + { + this.echoChar = echoChar; + + TextFieldPeer peer = (TextFieldPeer) getPeer (); + if (peer != null) + peer.setEchoChar (echoChar); + } + + /** + * Tests whether or not this text field has an echo character set + * so that characters the user type are not echoed to the screen. + * + * @return <code>true</code> if an echo character is set, + * <code>false</code> otherwise. + */ + public boolean echoCharIsSet() + { + if (echoChar == '\u0000') + return(false); + else + return(true); + } + + /** + * Returns the minimum size for this text field. + * + * @return The minimum size for this text field. + */ + public Dimension getMinimumSize() + { + return getMinimumSize (getColumns ()); + } + + /** + * Returns the minimum size of a text field with the specified number + * of columns. + * + * @param columns The number of columns to get the minimum size for. + */ + public Dimension getMinimumSize(int columns) + { + return minimumSize(columns); + } + + /** + * Returns the minimum size for this text field. + * + * @return The minimum size for this text field. + * + * @deprecated This method is deprecated in favor of + * <code>getMinimumSize()</code>. + */ + public Dimension minimumSize() + { + return minimumSize(getColumns ()); + } + + /** + * Returns the minimum size of a text field with the specified number + * of columns. + * + * @param columns The number of columns to get the minimum size for. + * + * @deprecated This method is deprecated in favor of + * <code>getMinimumSize(int)</code>. + */ + public Dimension minimumSize(int columns) + { + if (isMinimumSizeSet()) + return new Dimension(minSize); + + TextFieldPeer peer = (TextFieldPeer) getPeer (); + if (peer == null) + return new Dimension(getWidth(), getHeight()); + + return peer.getMinimumSize (columns); + } + + /** + * Returns the preferred size for this text field. + * + * @return The preferred size for this text field. + */ + public Dimension getPreferredSize() + { + return getPreferredSize(getColumns ()); + } + + /** + * Returns the preferred size of a text field with the specified number + * of columns. + * + * @param columns The number of columns to get the preferred size for. + */ + public Dimension getPreferredSize(int columns) + { + return preferredSize(columns); + } + + /** + * Returns the preferred size for this text field. + * + * @return The preferred size for this text field. + * + * @deprecated This method is deprecated in favor of + * <code>getPreferredSize()</code>. + */ + public Dimension preferredSize() + { + return preferredSize(getColumns ()); + } + + /** + * Returns the preferred size of a text field with the specified number + * of columns. + * + * @param columns The number of columns to get the preferred size for. + * + * @deprecated This method is deprecated in favor of + * <code>getPreferredSize(int)</code>. + */ + public Dimension preferredSize(int columns) + { + if (isPreferredSizeSet()) + return new Dimension(prefSize); + + TextFieldPeer peer = (TextFieldPeer) getPeer (); + if (peer == null) + return new Dimension (getWidth(), getHeight()); + + return peer.getPreferredSize (columns); + } + + /** + * Notifies this object that it should create its native peer. + */ + public void addNotify() + { + if (getPeer() != null) + return; + + setPeer((ComponentPeer)getToolkit().createTextField(this)); + super.addNotify(); + } + + /** + * Addes a new listener to the list of action listeners for this + * object. + * + * @param listener The listener to add to the list. + */ + public synchronized void addActionListener(ActionListener listener) + { + action_listeners = AWTEventMulticaster.add(action_listeners, listener); + + enableEvents(AWTEvent.ACTION_EVENT_MASK); + } + + /** + * Removes the specified listener from the list of action listeners + * for this object. + * + * @param listener The listener to remove from the list. + */ + public synchronized void removeActionListener(ActionListener listener) + { + action_listeners = AWTEventMulticaster.remove(action_listeners, listener); + } + + /** + * Processes the specified event. If the event is an instance of + * <code>ActionEvent</code> then <code>processActionEvent()</code> is + * called to process it, otherwise the event is sent to the + * superclass. + * + * @param event The event to process. + */ + protected void processEvent(AWTEvent event) + { + if (event instanceof ActionEvent) + processActionEvent((ActionEvent)event); + else + super.processEvent(event); + } + + /** + * Processes an action event by calling any registered listeners. + * Note to subclasses: This method is not called unless action events + * are enabled on this object. This will be true if any listeners + * are registered, or if action events were specifically enabled + * using <code>enableEvents()</code>. + * + * @param event The event to process. + */ + protected void processActionEvent(ActionEvent event) + { + if (action_listeners != null) + action_listeners.actionPerformed(event); + } + + void dispatchEventImpl(AWTEvent e) + { + if (e.id <= ActionEvent.ACTION_LAST + && e.id >= ActionEvent.ACTION_FIRST + && (action_listeners != null + || (eventMask & AWTEvent.ACTION_EVENT_MASK) != 0)) + processEvent(e); + else + super.dispatchEventImpl(e); + } + + /** + * Returns a debug string for this object. + * + * @return A debug string for this object. + */ + protected String paramString() + { + return(getClass().getName() + "(columns=" + getColumns() + ",echoChar=" + + getEchoChar()); + } + + /** + * Returns an array of all the objects currently registered as FooListeners + * upon this <code>TextField</code>. FooListeners are registered using the + * addFooListener method. + * + * @exception ClassCastException If listenerType doesn't specify a class or + * interface that implements java.util.EventListener. + * + * @since 1.3 + */ + public <T extends EventListener> T[] getListeners (Class<T> listenerType) + { + if (listenerType == ActionListener.class) + return AWTEventMulticaster.getListeners (action_listeners, listenerType); + + return super.getListeners (listenerType); + } + + /** + * Return all ActionListeners register to this <code>TextField</code> object + * as an array. + * + * @since 1.4 + */ + public ActionListener[] getActionListeners () + { + return (ActionListener[]) getListeners (ActionListener.class); + } + + /** + * Generate a unique name for this <code>TextField</code>. + * + * @return A unique name for this <code>TextField</code>. + */ + String generateName() + { + return "textfield" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_textfield_number++; + } + + protected class AccessibleAWTTextField extends AccessibleAWTTextComponent + { + private static final long serialVersionUID = 6219164359235943158L; + + protected AccessibleAWTTextField() + { + } + + public AccessibleStateSet getAccessibleStateSet() + { + return super.getAccessibleStateSet(); + } + } + + public AccessibleContext getAccessibleContext() + { + return new AccessibleAWTTextField(); + } + +} diff --git a/libjava/classpath/java/awt/TexturePaint.java b/libjava/classpath/java/awt/TexturePaint.java new file mode 100644 index 000000000..f88e77b23 --- /dev/null +++ b/libjava/classpath/java/awt/TexturePaint.java @@ -0,0 +1,118 @@ +/* TexturePaint.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import gnu.java.awt.java2d.TexturePaintContext; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; + +/** + * This class provides a way to fill a Shape with a texture that is + * specified by a BufferedImage. + */ +public class TexturePaint implements Paint +{ + private final BufferedImage texture; + private final Rectangle2D anchor; + + /** + * Constructor. + * + * @param texture - the texture + * @param anchor - the shape + */ + public TexturePaint(BufferedImage texture, Rectangle2D anchor) + { + this.texture = texture; + this.anchor = anchor; + } + + /** + * Gets the texture image. + * + * @return the texture + */ + public BufferedImage getImage() + { + return texture; + } + + /** + * Gets the shape anchor. + * + * @return the shape anchor + */ + public Rectangle2D getAnchorRect() + { + return anchor; + } + + /** + * Creates the context used to paint the texture. + * + * @param cm - the ColorModel that receives the Paint data. Used only as a hint. + * @param deviceBounds - the device space being rendered. + * @param userBounds - the user space being rendered + * @param xform - the AffineTransform from user space into device space + * @param hints - a RenderingHints object that is used to specify how the + * pattern is rendered + * @return the paint context used to paint the texture + */ + public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, + Rectangle2D userBounds, + AffineTransform xform, RenderingHints hints) + { + // TODO: Maybe add some hook for providing alternative/accelerated + // implementations of this. + return new TexturePaintContext(this, deviceBounds, userBounds, xform); + } + + /** + * Returns the transparency mode. + * + * @return the transparency mode. + */ + public int getTransparency() + { + return texture.getTransparency(); + } +} // class TexturePaint diff --git a/libjava/classpath/java/awt/Toolkit.java b/libjava/classpath/java/awt/Toolkit.java new file mode 100644 index 000000000..6b1eb9d4b --- /dev/null +++ b/libjava/classpath/java/awt/Toolkit.java @@ -0,0 +1,1429 @@ +/* Toolkit.java -- AWT Toolkit superclass + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import gnu.classpath.SystemProperties; +import gnu.java.awt.AWTUtilities; +import gnu.java.awt.peer.GLightweightPeer; +import gnu.java.awt.peer.headless.HeadlessToolkit; + +import java.awt.datatransfer.Clipboard; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragGestureRecognizer; +import java.awt.dnd.DragSource; +import java.awt.dnd.peer.DragSourceContextPeer; +import java.awt.event.AWTEventListener; +import java.awt.event.AWTEventListenerProxy; +import java.awt.event.KeyEvent; +import java.awt.font.TextAttribute; +import java.awt.im.InputMethodHighlight; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.peer.ButtonPeer; +import java.awt.peer.CanvasPeer; +import java.awt.peer.CheckboxMenuItemPeer; +import java.awt.peer.CheckboxPeer; +import java.awt.peer.ChoicePeer; +import java.awt.peer.DesktopPeer; +import java.awt.peer.DialogPeer; +import java.awt.peer.FileDialogPeer; +import java.awt.peer.FontPeer; +import java.awt.peer.FramePeer; +import java.awt.peer.LabelPeer; +import java.awt.peer.LightweightPeer; +import java.awt.peer.ListPeer; +import java.awt.peer.MenuBarPeer; +import java.awt.peer.MenuItemPeer; +import java.awt.peer.MenuPeer; +import java.awt.peer.MouseInfoPeer; +import java.awt.peer.PanelPeer; +import java.awt.peer.PopupMenuPeer; +import java.awt.peer.ScrollPanePeer; +import java.awt.peer.ScrollbarPeer; +import java.awt.peer.TextAreaPeer; +import java.awt.peer.TextFieldPeer; +import java.awt.peer.WindowPeer; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.File; +import java.io.FileInputStream; +import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Map; +import java.util.Properties; +import java.util.StringTokenizer; + +/** + * The AWT system uses a set of native peer objects to implement its + * widgets. These peers are provided by a peer toolkit, that is accessed + * via a subclass of this superclass. The system toolkit is retrieved + * by the static methods <code>getDefaultToolkit</code>. This method + * determines the system toolkit by examining the system property + * <code>awt.toolkit</code>. That property is set to the name of the + * <code>Toolkit</code> subclass for the specified peer set. If the + * <code>awt.toolkit</code> property is not set, then the default + * toolkit <code>gnu.java.awt.peer.gtk.GtkToolkit</code> is used. This + * toolkit creates its peers using the GTK+ toolkit. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public abstract class Toolkit +{ + /** The default toolkit name. */ + private static String default_toolkit_name + = gnu.classpath.Configuration.default_awt_peer_toolkit; + + /** + * The toolkit in use. Once we load it, we don't ever change it + * if the awt.toolkit property is set. + */ + private static Toolkit toolkit; + + /** The toolkit properties. */ + private static Properties props = new Properties(); + + protected final Map<String,Object> desktopProperties = + new Hashtable<String,Object>(); + + protected final PropertyChangeSupport desktopPropsSupport + = new PropertyChangeSupport(this); + + /** + * All registered AWTEventListener objects. This is package private, so the + * event queue can efficiently access this list. + */ + AWTEventListenerProxy[] awtEventListeners; + + /** + * The shared peer for all lightweight components. + */ + private GLightweightPeer lightweightPeer; + + /** + * Default constructor for subclasses. + */ + public Toolkit() + { + awtEventListeners = new AWTEventListenerProxy[0]; + } + + /** + * + * @param target + * @return + * @throws HeadlessException + */ + protected abstract DesktopPeer createDesktopPeer(Desktop target) + throws HeadlessException; + + /** + * Creates a peer object for the specified <code>Button</code>. + * + * @param target The <code>Button</code> to create the peer for. + * + * @return The peer for the specified <code>Button</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract ButtonPeer createButton(Button target); + + /** + * Creates a peer object for the specified <code>TextField</code>. + * + * @param target The <code>TextField</code> to create the peer for. + * + * @return The peer for the specified <code>TextField</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract TextFieldPeer createTextField(TextField target); + + /** + * Creates a peer object for the specified <code>Label</code>. + * + * @param target The <code>Label</code> to create the peer for. + * + * @return The peer for the specified <code>Label</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract LabelPeer createLabel(Label target); + + /** + * Creates a peer object for the specified <code>List</code>. + * + * @param target The <code>List</code> to create the peer for. + * + * @return The peer for the specified <code>List</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract ListPeer createList(List target); + + /** + * Creates a peer object for the specified <code>Checkbox</code>. + * + * @param target The <code>Checkbox</code> to create the peer for. + * + * @return The peer for the specified <code>Checkbox</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract CheckboxPeer createCheckbox(Checkbox target); + + /** + * Creates a peer object for the specified <code>Scrollbar</code>. + * + * @param target The <code>Scrollbar</code> to create the peer for. + * + * @return The peer for the specified <code>Scrollbar</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract ScrollbarPeer createScrollbar(Scrollbar target); + + /** + * Creates a peer object for the specified <code>ScrollPane</code>. + * + * @param target The <code>ScrollPane</code> to create the peer for. + * + * @return The peer for the specified <code>ScrollPane</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract ScrollPanePeer createScrollPane(ScrollPane target); + + /** + * Creates a peer object for the specified <code>TextArea</code>. + * + * @param target The <code>TextArea</code> to create the peer for. + * + * @return The peer for the specified <code>TextArea</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract TextAreaPeer createTextArea(TextArea target); + + /** + * Creates a peer object for the specified <code>Choice</code>. + * + * @param target The <code>Choice</code> to create the peer for. + * + * @return The peer for the specified <code>Choice</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract ChoicePeer createChoice(Choice target); + + /** + * Creates a peer object for the specified <code>Frame</code>. + * + * @param target The <code>Frame</code> to create the peer for. + * + * @return The peer for the specified <code>Frame</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract FramePeer createFrame(Frame target); + + /** + * Creates a peer object for the specified <code>Canvas</code>. + * + * @param target The <code>Canvas</code> to create the peer for. + * + * @return The peer for the specified <code>Canvas</code> object. + */ + protected abstract CanvasPeer createCanvas(Canvas target); + + /** + * Creates a peer object for the specified <code>Panel</code>. + * + * @param target The <code>Panel</code> to create the peer for. + * + * @return The peer for the specified <code>Panel</code> object. + */ + protected abstract PanelPeer createPanel(Panel target); + + /** + * Creates a peer object for the specified <code>Window</code>. + * + * @param target The <code>Window</code> to create the peer for. + * + * @return The peer for the specified <code>Window</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract WindowPeer createWindow(Window target); + + /** + * Creates a peer object for the specified <code>Dialog</code>. + * + * @param target The dialog to create the peer for + * + * @return The peer for the specified font name. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract DialogPeer createDialog(Dialog target); + + /** + * Creates a peer object for the specified <code>MenuBar</code>. + * + * @param target The <code>MenuBar</code> to create the peer for. + * + * @return The peer for the specified <code>MenuBar</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract MenuBarPeer createMenuBar(MenuBar target); + + /** + * Creates a peer object for the specified <code>Menu</code>. + * + * @param target The <code>Menu</code> to create the peer for. + * + * @return The peer for the specified <code>Menu</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract MenuPeer createMenu(Menu target); + + /** + * Creates a peer object for the specified <code>PopupMenu</code>. + * + * @param target The <code>PopupMenu</code> to create the peer for. + * + * @return The peer for the specified <code>PopupMenu</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract PopupMenuPeer createPopupMenu(PopupMenu target); + + /** + * Creates a peer object for the specified <code>MenuItem</code>. + * + * @param target The <code>MenuItem</code> to create the peer for. + * + * @return The peer for the specified <code>MenuItem</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract MenuItemPeer createMenuItem(MenuItem target); + + /** + * Returns a MouseInfoPeer. + * The default implementation of this method throws + * UnsupportedOperationException. + * + * Toolkit implementations should overload this if possible, however. + */ + protected MouseInfoPeer getMouseInfoPeer() + { + throw new UnsupportedOperationException("No mouse info peer."); + } + + /** + * Creates a peer object for the specified <code>FileDialog</code>. + * + * @param target The <code>FileDialog</code> to create the peer for. + * + * @return The peer for the specified <code>FileDialog</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract FileDialogPeer createFileDialog(FileDialog target); + + /** + * Creates a peer object for the specified <code>CheckboxMenuItem</code>. + * + * @param target The <code>CheckboxMenuItem</code> to create the peer for. + * + * @return The peer for the specified <code>CheckboxMenuItem</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected abstract CheckboxMenuItemPeer + createCheckboxMenuItem(CheckboxMenuItem target); + + /** + * Creates a peer object for the specified <code>Component</code>. The + * peer returned by this method is not a native windowing system peer + * with its own native window. Instead, this method allows the component + * to draw on its parent window as a "lightweight" widget. + * + * @param target The <code>Component</code> to create the peer for. + * + * @return The peer for the specified <code>Component</code> object. + */ + protected LightweightPeer createComponent(Component target) + { + if (lightweightPeer == null) + lightweightPeer = new GLightweightPeer(); + return lightweightPeer; + } + + /** + * Creates a peer object for the specified font name. + * + * @param name The font to create the peer for. + * @param style The font style to create the peer for. + * + * @return The peer for the specified font name. + * + * @deprecated + */ + protected abstract FontPeer getFontPeer(String name, int style); + + /** + * Copies the current system colors into the specified array. This is + * the interface used by the <code>SystemColor</code> class. Although + * this method fills in the array with some default colors a real Toolkit + * should override this method and provide real system colors for the + * native GUI platform. + * + * @param systemColors The array to copy the system colors into. + * It must be at least 26 elements. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + * + * @see java.awt.SystemColor + */ + protected void loadSystemColors(int systemColors[]) + { + systemColors[SystemColor.DESKTOP] = 0xFF005C5C; + systemColors[SystemColor.ACTIVE_CAPTION] = 0xFF000080; + systemColors[SystemColor.ACTIVE_CAPTION_TEXT] = 0xFFFFFFFF; + systemColors[SystemColor.ACTIVE_CAPTION_BORDER] = 0xFFC0C0C0; + systemColors[SystemColor.INACTIVE_CAPTION] = 0xFF808080; + systemColors[SystemColor.INACTIVE_CAPTION_TEXT] = 0xFFC0C0C0; + systemColors[SystemColor.INACTIVE_CAPTION_BORDER] = 0xFFC0C0C0; + systemColors[SystemColor.WINDOW] = 0xFFFFFFFF; + systemColors[SystemColor.WINDOW_BORDER] = 0xFF000000; + systemColors[SystemColor.WINDOW_TEXT] = 0xFF000000; + systemColors[SystemColor.MENU] = 0xFFC0C0C0; + systemColors[SystemColor.MENU_TEXT] = 0xFF000000; + systemColors[SystemColor.TEXT] = 0xFFC0C0C0; + systemColors[SystemColor.TEXT_TEXT] = 0xFF000000; + systemColors[SystemColor.TEXT_HIGHLIGHT] = 0xFF000090; + systemColors[SystemColor.TEXT_HIGHLIGHT_TEXT] = 0xFFFFFFFF; + systemColors[SystemColor.TEXT_INACTIVE_TEXT] = 0xFF808080; + systemColors[SystemColor.CONTROL] = 0xFFC0C0C0; + systemColors[SystemColor.CONTROL_TEXT] = 0xFF000000; + systemColors[SystemColor.CONTROL_HIGHLIGHT] = 0xFFFFFFFF; + systemColors[SystemColor.CONTROL_LT_HIGHLIGHT] = 0xFFE0E0E0; + systemColors[SystemColor.CONTROL_SHADOW] = 0xFF808080; + systemColors[SystemColor.CONTROL_DK_SHADOW] = 0xFF000000; + systemColors[SystemColor.SCROLLBAR] = 0xFFE0E0E0; + systemColors[SystemColor.INFO] = 0xFFE0E000; + systemColors[SystemColor.INFO_TEXT] = 0xFF000000; + } + + /** + * @since 1.4 + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public void setDynamicLayout(boolean dynamic) + { + } + + /** + * @since 1.4 + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + protected boolean isDynamicLayoutSet() + { + return false; + } + + /** + * @since 1.4 + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public boolean isDynamicLayoutActive() + { + return false; + } + + /** + * Returns the dimensions of the screen in pixels. + * + * @return The dimensions of the screen in pixels. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public abstract Dimension getScreenSize(); + + /** + * Returns the screen resolution in dots per square inch. + * + * @return The screen resolution in dots per square inch. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public abstract int getScreenResolution(); + + /** + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + * + * @since 1.4 + */ + public Insets getScreenInsets(GraphicsConfiguration gc) + { + return new Insets(0, 0, 0, 0); + } + + /** + * Returns the color model of the screen. + * + * @return The color model of the screen. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public abstract ColorModel getColorModel(); + + /** + * Returns the names of the available fonts. + * + * @return The names of the available fonts. + * + * @deprecated + */ + public abstract String[] getFontList(); + + /** + * Return the font metrics for the specified font + * + * @param name The name of the font to return metrics for. + * + * @return The requested font metrics. + * + * @deprecated + */ + public abstract FontMetrics getFontMetrics(Font name); + + /** + * Flushes any buffered data to the screen so that it is in sync with + * what the AWT system has drawn to it. + */ + public abstract void sync(); + + /** + * Returns an instance of the default toolkit. The default toolkit is + * the subclass of <code>Toolkit</code> specified in the system property + * <code>awt.toolkit</code>, or <code>gnu.java.awt.peer.gtk.GtkToolkit</code> + * if the property is not set. + * + * @return An instance of the system default toolkit. + * + * @throws AWTError If the toolkit cannot be loaded. + */ + public static synchronized Toolkit getDefaultToolkit() + { + if (toolkit != null) + return toolkit; + + String toolkit_name = SystemProperties.getProperty("awt.toolkit", + default_toolkit_name); + try + { + ClassLoader cl; + cl = (ClassLoader) AccessController.doPrivileged + (new PrivilegedAction() + { + public Object run() + { + return ClassLoader.getSystemClassLoader(); + } + }); + Class cls = Class.forName(toolkit_name, true, cl); + Object obj = cls.newInstance(); + if (!(obj instanceof Toolkit)) + throw new AWTError(toolkit_name + " is not a subclass of " + + "java.awt.Toolkit"); + toolkit = (Toolkit) obj; + + initAccessibility(); + return toolkit; + } + catch (ThreadDeath death) + { + throw death; + } + catch (Throwable t) + { + // Check for the headless property. + if (GraphicsEnvironment.isHeadless()) + { + toolkit = new HeadlessToolkit(); + return toolkit; + } + else + { + AWTError e = new AWTError("Cannot load AWT toolkit: " + + toolkit_name); + throw (AWTError) e.initCause(t); + } + } + } + + /** + * Returns an image from the specified file, which must be in a + * recognized format. Supported formats vary from toolkit to toolkit. + * + * @return name The name of the file to read the image from. + */ + public abstract Image getImage(String name); + + /** + * Returns an image from the specified URL, which must be in a + * recognized format. Supported formats vary from toolkit to toolkit. + * + * @return url The URl to read the image from. + */ + public abstract Image getImage(URL url); + + public abstract Image createImage(String filename); + + public abstract Image createImage(URL url); + + /** + * Readies an image to be rendered on the screen. The width and height + * values can be set to the default sizes for the image by passing -1 + * in those parameters. + * + * @param image The image to prepare for rendering. + * @param width The width of the image. + * @param height The height of the image. + * @param observer The observer to receive events about the preparation + * process. + * + * @return <code>true</code> if the image is already prepared for rendering, + * <code>false</code> otherwise. + */ + public abstract boolean prepareImage(Image image, int width, int height, + ImageObserver observer); + + /** + * Checks the status of specified image as it is being readied for + * rendering. + * + * @param image The image to prepare for rendering. + * @param width The width of the image. + * @param height The height of the image. + * @param observer The observer to receive events about the preparation + * process. + * + * @return A union of the bitmasks from + * <code>java.awt.image.ImageObserver</code> that indicates the current + * state of the imaging readying process. + */ + public abstract int checkImage(Image image, int width, int height, + ImageObserver observer); + + /** + * Creates an image using the specified <code>ImageProducer</code> + * + * @param producer The <code>ImageProducer</code> to create the image from. + * + * @return The created image. + */ + public abstract Image createImage(ImageProducer producer); + + /** + * Creates an image from the specified byte array. The array must be in + * a recognized format. Supported formats vary from toolkit to toolkit. + * + * @param data The raw image data. + * + * @return The created image. + */ + public Image createImage(byte[] data) + { + return createImage(data, 0, data.length); + } + + /** + * Creates an image from the specified portion of the byte array passed. + * The array must be in a recognized format. Supported formats vary from + * toolkit to toolkit. + * + * @param data The raw image data. + * @param offset The offset into the data where the image data starts. + * @param len The length of the image data. + * + * @return The created image. + */ + public abstract Image createImage(byte[] data, int offset, int len); + + /** + * Returns a instance of <code>PrintJob</code> for the specified + * arguments. + * + * @param frame The window initiating the print job. + * @param title The print job title. + * @param props The print job properties. + * + * @return The requested print job, or <code>null</code> if the job + * was cancelled. + * + * @exception NullPointerException If frame is null, + * or GraphicsEnvironment.isHeadless() returns true. + * @exception SecurityException If this thread is not allowed to initiate + * a print job request. + */ + public abstract PrintJob getPrintJob(Frame frame, String title, + Properties props); + + /** + * Returns a instance of <code>PrintJob</code> for the specified + * arguments. + * + * @param frame The window initiating the print job. + * @param title The print job title. + * @param jobAttr A set of job attributes which will control the print job. + * @param pageAttr A set of page attributes which will control the print job. + * + * @exception NullPointerException If frame is null, and either jobAttr is null + * or jobAttr.getDialog() returns JobAttributes.DialogType.NATIVE. + * @exception IllegalArgumentException If pageAttrspecifies differing cross + * feed and feed resolutions, or when GraphicsEnvironment.isHeadless() returns + * true. + * @exception SecurityException If this thread is not allowed to initiate + * a print job request. + * + * @since 1.3 + */ + public PrintJob getPrintJob(Frame frame, String title, + JobAttributes jobAttr, PageAttributes pageAttr) + { + // FIXME: it is possible this check may be removed + // if this method, when written, always delegates to + // getPrintJob(Frame, String, Properties). + SecurityManager sm; + sm = System.getSecurityManager(); + if (sm != null) + sm.checkPrintJobAccess(); + + return null; + } + + /** + * Causes a "beep" tone to be generated. + */ + public abstract void beep(); + + /** + * Returns the system clipboard. + * + * @return THe system clipboard. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public abstract Clipboard getSystemClipboard(); + + /** + * Gets the singleton instance of the system selection as a + * Clipboard object. The system selection contains the selected text + * of the last component/widget that had focus and a text selection. + * The default implementation returns null. + * + * @return The Clipboard holding the system (text) selection or null + * if the Toolkit or system doesn't support a selection clipboard. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * is true. + * @exception SecurityException If the current security manager + * checkSystemClipboardAccess() doesn't allow access. + * + * @since 1.4 + */ + public Clipboard getSystemSelection() + { + return null; + } + + /** + * Returns the accelerator key mask for menu shortcuts. The default is + * <code>Event.CTRL_MASK</code>. A toolkit must override this method + * to change the default. + * + * @return The key mask for the menu accelerator key. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public int getMenuShortcutKeyMask() + { + return Event.CTRL_MASK; + } + + /** + * Returns whether the given locking key on the keyboard is currently in its + * "on" state. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + * @exception IllegalArgumentException If keyCode is not one of the valid keys. + * @exception UnsupportedOperationException If the host system doesn't allow + * getting the state of this key programmatically, or if the keyboard doesn't + * have this key. + */ + public boolean getLockingKeyState(int keyCode) + { + if (AWTUtilities.isValidKey(keyCode)) + throw new UnsupportedOperationException + ("cannot get locking state of key code " + keyCode); + + throw new IllegalArgumentException("invalid key code " + keyCode); + } + + /** + * Sets the state of the given locking key on the keyboard. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + * @exception IllegalArgumentException If keyCode is not one of the valid keys. + * @exception UnsupportedOperationException If the host system doesn't allow + * getting the state of this key programmatically, or if the keyboard doesn't + * have this key. + */ + public void setLockingKeyState(int keyCode, boolean on) + { + if (keyCode != KeyEvent.VK_CAPS_LOCK + && keyCode != KeyEvent.VK_NUM_LOCK + && keyCode != KeyEvent.VK_SCROLL_LOCK) + throw new IllegalArgumentException(); + + throw new UnsupportedOperationException(); + } + + /** + * Returns the native container object of the specified component. This + * method is necessary because the parent component might be a lightweight + * component. + * + * @param component The component to fetch the native container for. + * + * @return The native container object for this component. + */ + protected static Container getNativeContainer(Component component) + { + component = component.getParent(); + while (true) + { + if (component == null) + return null; + if (! (component instanceof Container)) + { + component = component.getParent(); + continue; + } + if (component.getPeer() instanceof LightweightPeer) + { + component = component.getParent(); + continue; + } + return (Container) component; + } + } + + /** + * Creates a new custom cursor object. + * + * @exception IndexOutOfBoundsException If the hotSpot values are outside + * the bounds of the cursor. + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public Cursor createCustomCursor(Image cursor, Point hotSpot, String name) + { + // Presumably the only reason this isn't abstract is for backwards + // compatibility? FIXME? + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException("No custom cursor in an headless graphics " + + "environment."); + return null; + } + + /** + * Returns the supported cursor dimension which is closest to the + * desired sizes. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public Dimension getBestCursorSize(int preferredWidth, int preferredHeight) + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException("No best cursor size in an headless " + + "graphics environment."); + return new Dimension (0,0); + } + + /** + * Returns the maximum number of colors the Toolkit supports in a custom + * cursor palette. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public int getMaximumCursorColors() + { + return 0; + } + + /** + * Returns whether Toolkit supports this state for Frames. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + * + * @since 1.4 + */ + public boolean isFrameStateSupported(int state) + { + return false; + } + + /** + * Returns the value of the property with the specified name, or the + * default value if the property does not exist. + * + * @param key The name of the property to retrieve. + * @param def The default value of the property. + */ + public static String getProperty(String key, String def) + { + return props.getProperty(key, def); + } + + + /** + * Returns the event queue that is suitable for the calling context. + * + * <p>Despite the word “System” in the name of this + * method, a toolkit may provide different event queues for each + * applet. There is no guarantee that the same queue is shared + * system-wide. + * + * <p>The implementation first checks whether a + * SecurityManager has been installed. If so, its {@link + * java.lang.SecurityManager#checkAwtEventQueueAccess()} method gets + * called. The security manager will throw a SecurityException if it + * does not grant the permission to access the event queue. + * + * <p>Next, the call is delegated to {@link + * #getSystemEventQueueImpl()}. + * + * @return The event queue for this applet (or application). + * + * @throws SecurityException if a security manager has been + * installed, and it does not grant the permission to access the + * event queue. + */ + public final EventQueue getSystemEventQueue() + { + SecurityManager sm; + + sm = System.getSecurityManager(); + if (sm != null) + sm.checkAwtEventQueueAccess(); + + return getSystemEventQueueImpl(); + } + + + /** + * Returns the event queue that is suitable for the calling context. + * + * <p>Despite the word “System” in the name of this + * method, a toolkit may provide different event queues for each + * applet. There is no guarantee that the same queue is shared + * system-wide. + * + * <p>No security checks are performed, which is why this method + * may only be called by Toolkits. + * + * @see #getSystemEventQueue() + */ + protected abstract EventQueue getSystemEventQueueImpl(); + + + /** + * @since 1.3 + */ + public abstract DragSourceContextPeer + createDragSourceContextPeer(DragGestureEvent e); + + /** + * @since 1.3 + */ + public <T extends DragGestureRecognizer> T + createDragGestureRecognizer(Class<T> recognizer, DragSource ds, + Component comp, int actions, + DragGestureListener l) + { + return null; + } + + public final Object getDesktopProperty(String propertyName) + { + return desktopProperties.get(propertyName); + } + + protected final void setDesktopProperty(String name, Object newValue) + { + Object oldValue = getDesktopProperty(name); + desktopProperties.put(name, newValue); + desktopPropsSupport.firePropertyChange(name, oldValue, newValue); + } + + protected Object lazilyLoadDesktopProperty(String name) + { + // FIXME - what is this?? + return null; + } + + protected void initializeDesktopProperties() + { + // Overridden by toolkit implementation? + } + + public void addPropertyChangeListener(String name, + PropertyChangeListener pcl) + { + desktopPropsSupport.addPropertyChangeListener(name, pcl); + } + + public void removePropertyChangeListener(String name, + PropertyChangeListener pcl) + { + desktopPropsSupport.removePropertyChangeListener(name, pcl); + } + + /** + * @since 1.4 + */ + public PropertyChangeListener[] getPropertyChangeListeners() + { + return desktopPropsSupport.getPropertyChangeListeners(); + } + + /** + * @since 1.4 + */ + public PropertyChangeListener[] getPropertyChangeListeners(String name) + { + return desktopPropsSupport.getPropertyChangeListeners(name); + } + + /** + * Adds an AWTEventListener to this toolkit. This listener is informed about + * all events that pass the eventqueue that match the specified + * <code>evenMask</code>. The <code>eventMask</code> is an ORed combination + * of event masks as defined in {@link AWTEvent}. + * + * If a security manager is installed, it is asked first if an + * <code>AWTPermission("listenToAllAWTEvents")</code> is allowed. + * This may result in a <code>SecurityException</code> beeing thrown. + * + * It is not recommended to use this kind of notification for normal + * applications. It is intended solely for the purpose of debugging and to + * support special facilities. + * + * @param listener the listener to add + * @param eventMask the event mask of event types which the listener is + * interested in + * + * @since 1.2 + * + * @throws SecurityException if there is a <code>SecurityManager</code> that + * doesn't grant + * <code>AWTPermission("listenToAllAWTEvents")</code> + * + * @see #getAWTEventListeners() + * @see #getAWTEventListeners(long) + * @see #removeAWTEventListener(AWTEventListener) + */ + public void addAWTEventListener(AWTEventListener listener, long eventMask) + { + // First we must check the security permissions. + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkPermission(new AWTPermission("listenToAllAWTEvents")); + + // Go through the list and check if the requested listener is already + // registered. + boolean found = false; + for (int i = 0; i < awtEventListeners.length; ++i) + { + AWTEventListenerProxy proxy = awtEventListeners[i]; + if (proxy.getListener() == listener) + { + found = true; + // Modify the proxies event mask to include the new event mask. + AWTEventListenerProxy newProxy = + new AWTEventListenerProxy(proxy.getEventMask() | eventMask, + listener); + awtEventListeners[i] = newProxy; + break; + } + } + + // If that listener was not found, then add it. + if (! found) + { + AWTEventListenerProxy proxy = + new AWTEventListenerProxy(eventMask, listener); + AWTEventListenerProxy[] newArray = + new AWTEventListenerProxy[awtEventListeners.length + 1]; + System.arraycopy(awtEventListeners, 0, newArray, 0, + awtEventListeners.length); + newArray[newArray.length - 1] = proxy; + awtEventListeners = newArray; + } + } + + /** + * Removes an AWT event listener from this toolkit. This listener is no + * longer informed of any event types it was registered in. + * + * If a security manager is installed, it is asked first if an + * <code>AWTPermission("listenToAllAWTEvents")</code> is allowed. + * This may result in a <code>SecurityException</code> beeing thrown. + * + * It is not recommended to use this kind of notification for normal + * applications. It is intended solely for the purpose of debugging and to + * support special facilities. + * + * @param listener the listener to remove + * + * @throws SecurityException if there is a <code>SecurityManager</code> that + * doesn't grant + * <code>AWTPermission("listenToAllAWTEvents")</code> + * + * @since 1.2 + * + * @see #addAWTEventListener(AWTEventListener, long) + * @see #getAWTEventListeners() + * @see #getAWTEventListeners(long) + */ + public void removeAWTEventListener(AWTEventListener listener) + { + // First we must check the security permissions. + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkPermission(new AWTPermission("listenToAllAWTEvents")); + + + // Find the index of the listener. + int index = -1; + for (int i = 0; i < awtEventListeners.length; ++i) + { + AWTEventListenerProxy proxy = awtEventListeners[i]; + if (proxy.getListener() == listener) + { + index = i; + break; + } + } + + // Copy over the arrays and leave out the removed element. + if (index != -1) + { + AWTEventListenerProxy[] newArray = + new AWTEventListenerProxy[awtEventListeners.length - 1]; + if (index > 0) + System.arraycopy(awtEventListeners, 0, newArray, 0, index); + if (index < awtEventListeners.length - 1) + System.arraycopy(awtEventListeners, index + 1, newArray, index, + awtEventListeners.length - index - 1); + awtEventListeners = newArray; + } + } + + /** + * Returns all registered AWT event listeners. This method returns a copy of + * the listener array, so that application cannot trash the listener list. + * + * If a security manager is installed, it is asked first if an + * <code>AWTPermission("listenToAllAWTEvents")</code> is allowed. + * This may result in a <code>SecurityException</code> beeing thrown. + * + * It is not recommended to use this kind of notification for normal + * applications. It is intended solely for the purpose of debugging and to + * support special facilities. + * + * @return all registered AWT event listeners + * + * @throws SecurityException if there is a <code>SecurityManager</code> that + * doesn't grant + * <code>AWTPermission("listenToAllAWTEvents")</code> + * + * @since 1.4 + * + * @see #addAWTEventListener(AWTEventListener, long) + * @see #removeAWTEventListener(AWTEventListener) + * @see #getAWTEventListeners(long) + */ + public AWTEventListener[] getAWTEventListeners() + { + // First we must check the security permissions. + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkPermission(new AWTPermission("listenToAllAWTEvents")); + + // Create a copy of the array. + AWTEventListener[] copy = new AWTEventListener[awtEventListeners.length]; + System.arraycopy(awtEventListeners, 0, copy, 0, awtEventListeners.length); + return copy; + } + + /** + * Returns all registered AWT event listeners that listen for events with + * the specified <code>eventMask</code>. This method returns a copy of + * the listener array, so that application cannot trash the listener list. + * + * If a security manager is installed, it is asked first if an + * <code>AWTPermission("listenToAllAWTEvents")</code> is allowed. + * This may result in a <code>SecurityException</code> beeing thrown. + * + * It is not recommended to use this kind of notification for normal + * applications. It is intended solely for the purpose of debugging and to + * support special facilities. + * + * @param mask the event mask + * + * @throws SecurityException if there is a <code>SecurityManager</code> that + * doesn't grant + * <code>AWTPermission("listenToAllAWTEvents")</code> + * + * + * @since 1.4 + * + * @see #addAWTEventListener(AWTEventListener, long) + * @see #removeAWTEventListener(AWTEventListener) + * @see #getAWTEventListeners() + */ + public AWTEventListener[] getAWTEventListeners(long mask) + { + // First we must check the security permissions. + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkPermission(new AWTPermission("listenToAllAWTEvents")); + + // Create a copy of the array with only the requested listeners in it. + ArrayList l = new ArrayList(awtEventListeners.length); + for (int i = 0; i < awtEventListeners.length; ++i) + { + if ((awtEventListeners[i].getEventMask() & mask) != 0) + l.add(awtEventListeners[i]); + } + + return (AWTEventListener[] ) l.toArray(new AWTEventListener[l.size()]); + } + + + /** + * Dispatches events to listeners registered to this Toolkit. This is called + * by {@link Component#dispatchEventImpl(AWTEvent)} in order to dispatch + * events globally. + * + * @param ev the event to dispatch + */ + void globalDispatchEvent(AWTEvent ev) + { + // We do not use the accessor methods here because they create new + // arrays each time. We must be very efficient, so we access this directly. + for (int i = 0; i < awtEventListeners.length; ++i) + { + AWTEventListenerProxy proxy = awtEventListeners[i]; + if ((proxy.getEventMask() & AWTEvent.eventIdToMask(ev.getID())) != 0) + proxy.eventDispatched(ev); + } + } + + /** + * @since 1.3 + */ + public abstract Map<TextAttribute,?> + mapInputMethodHighlight(InputMethodHighlight highlight); + + public abstract boolean isModalExclusionTypeSupported + (Dialog.ModalExclusionType modalExclusionType); + + public abstract boolean isModalityTypeSupported + (Dialog.ModalityType modalityType); + + /** + * Initializes the accessibility framework. In particular, this loads the + * properties javax.accessibility.screen_magnifier_present and + * javax.accessibility.screen_reader_present and loads + * the classes specified in javax.accessibility.assistive_technologies. + */ + private static void initAccessibility() + { + AccessController.doPrivileged + (new PrivilegedAction() + { + public Object run() + { + Properties props = new Properties(); + String sep = File.separator; + + // Try the user configuration. + try + { + File propsFile = new File(System.getProperty("user.home") + sep + + ".accessibility.properties"); + FileInputStream in = new FileInputStream(propsFile); + props.load(in); + in.close(); + } + catch (Exception ex) + { + // User configuration not present, ignore. + } + + // Try the system configuration if there was no user configuration. + if (props.size() == 0) + { + try + { + File propsFile = + new File(System.getProperty("gnu.classpath.home.url") + + sep + "accessibility.properties"); + FileInputStream in = new FileInputStream(propsFile); + props.load(in); + in.close(); + } + catch (Exception ex) + { + // System configuration not present, ignore. + } + } + + // Fetch the screen_magnifier_present property. Check systen properties + // first, then fallback to the configuration file. + String magPresent = SystemProperties.getProperty + ("javax.accessibility.screen_magnifier_present"); + if (magPresent == null) + { + magPresent = props.getProperty("screen_magnifier_present"); + if (magPresent != null) + { + SystemProperties.setProperty + ("javax.accessibility.screen_magnifier_present", magPresent); + } + } + + // Fetch the screen_reader_present property. Check systen properties + // first, then fallback to the configuration file. + String readerPresent = SystemProperties.getProperty + ("javax.accessibility.screen_reader_present"); + if (readerPresent == null) + { + readerPresent = props.getProperty("screen_reader_present"); + if (readerPresent != null) + { + SystemProperties.setProperty + ("javax.accessibility.screen_reader_present", readerPresent); + } + } + + // Fetch the list of classes to be loaded. + String classes = SystemProperties.getProperty + ("javax.accessibility.assistive_technologies"); + if (classes == null) + { + classes = props.getProperty("assistive_technologies"); + if (classes != null) + { + SystemProperties.setProperty + ("javax.accessibility.assistive_technologies", classes); + } + } + + // Try to load the assisitive_technologies classes. + if (classes != null) + { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + StringTokenizer tokenizer = new StringTokenizer(classes, ","); + while (tokenizer.hasMoreTokens()) + { + String className = tokenizer.nextToken(); + try + { + Class atClass = cl.loadClass(className); + atClass.newInstance(); + } + catch (ClassNotFoundException ex) + { + AWTError err = new AWTError("Assistive Technology class not" + + " found: " + className); + err.initCause(ex); + throw err; + } + catch (InstantiationException ex) + { + AWTError err = + new AWTError("Assistive Technology class cannot be " + + "instantiated: " + className); + err.initCause(ex); + throw err; + } + catch (IllegalAccessException ex) + { + AWTError err = + new AWTError("Assistive Technology class cannot be " + + "accessed: " + className); + err.initCause(err); + throw err; + } + } + } + return null; + } + }); + + } + +} // class Toolkit diff --git a/libjava/classpath/java/awt/Transparency.java b/libjava/classpath/java/awt/Transparency.java new file mode 100644 index 000000000..888587176 --- /dev/null +++ b/libjava/classpath/java/awt/Transparency.java @@ -0,0 +1,67 @@ +/* Transparency.java -- common transparency modes in graphics + Copyright (C) 2000, 2002, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt; + +/** + * A common transparency mode for layering graphics. + * + * @author Warren Levy (warrenl@cygnus.com) + * @since 1.1 + * @status updated to 1.4 + */ +public interface Transparency +{ + /** Image data which is completely opaque, for an alpha value of 1.0. */ + int OPAQUE = 1; + + /** + * Image data which is either completely opaque or transparent, for an + * exact integer alpha value. + */ + int BITMASK = 2; + + /** Image data which is translucent, for a non-integer alpha value. */ + int TRANSLUCENT = 3; + + /** + * Return the transparency type. + * + * @return One of {@link #OPAQUE}, {@link #BITMASK}, or {@link #TRANSLUCENT}. + */ + int getTransparency(); +} // interface Transparency diff --git a/libjava/classpath/java/awt/Window.java b/libjava/classpath/java/awt/Window.java new file mode 100644 index 000000000..986d1304a --- /dev/null +++ b/libjava/classpath/java/awt/Window.java @@ -0,0 +1,1286 @@ +/* Window.java -- + Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.awt.event.ComponentEvent; +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; +import java.awt.event.WindowListener; +import java.awt.event.WindowStateListener; +import java.awt.image.BufferStrategy; +import java.awt.peer.WindowPeer; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.util.EventListener; +import java.util.Iterator; +import java.util.Locale; +import java.util.ResourceBundle; +import java.util.Vector; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; + +/** + * This class represents a top-level window with no decorations. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public class Window extends Container implements Accessible +{ + private static final long serialVersionUID = 4497834738069338734L; + + // Serialized fields, from Sun's serialization spec. + private String warningString = null; + private int windowSerializedDataVersion = 0; // FIXME + /** @since 1.2 */ + // private FocusManager focusMgr; // FIXME: what is this? + /** @since 1.2 */ + private int state = 0; + /** @since 1.4 */ + private boolean focusableWindowState = true; + /** @since 1.5 */ + private boolean alwaysOnTop = false; + + // A list of other top-level windows owned by this window. + private transient Vector ownedWindows = new Vector(); + + private transient WindowListener windowListener; + private transient WindowFocusListener windowFocusListener; + private transient WindowStateListener windowStateListener; + + private transient boolean shown; + + // This is package-private to avoid an accessor method. + transient Component windowFocusOwner; + + /* + * The number used to generate the name returned by getName. + */ + private static transient long next_window_number; + + protected class AccessibleAWTWindow extends AccessibleAWTContainer + { + private static final long serialVersionUID = 4215068635060671780L; + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.WINDOW; + } + + public AccessibleStateSet getAccessibleStateSet() + { + AccessibleStateSet states = super.getAccessibleStateSet(); + if (isActive()) + states.add(AccessibleState.ACTIVE); + return states; + } + } + + /** + * This (package access) constructor is used by subclasses that want + * to build windows that do not have parents. Eg. toplevel + * application frames. Subclasses cannot call super(null), since + * null is an illegal argument. + */ + Window() + { + visible = false; + // Windows are the only Containers that default to being focus + // cycle roots. + focusCycleRoot = true; + setLayout(new BorderLayout()); + + GraphicsEnvironment g = GraphicsEnvironment.getLocalGraphicsEnvironment(); + graphicsConfig = g.getDefaultScreenDevice().getDefaultConfiguration(); + } + + Window(GraphicsConfiguration gc) + { + this(); + graphicsConfig = gc; + } + + /** + * Initializes a new instance of <code>Window</code> with the specified + * parent. The window will initially be invisible. + * + * @param owner The owning <code>Frame</code> of this window. + * + * @exception IllegalArgumentException If the owner's GraphicsConfiguration + * is not from a screen device, or if owner is null; this exception is always + * thrown when GraphicsEnvironment.isHeadless returns true. + */ + public Window(Frame owner) + { + this (owner, owner.getGraphicsConfiguration ()); + } + + /** + * Initializes a new instance of <code>Window</code> with the specified + * parent. The window will initially be invisible. + * + * @exception IllegalArgumentException If the owner's GraphicsConfiguration + * is not from a screen device, or if owner is null; this exception is always + * thrown when GraphicsEnvironment.isHeadless returns true. + * + * @since 1.2 + */ + public Window(Window owner) + { + this (owner, owner.getGraphicsConfiguration ()); + } + + /** + * Initializes a new instance of <code>Window</code> with the specified + * parent. The window will initially be invisible. + * + * @exception IllegalArgumentException If owner is null or if gc is not from a + * screen device; this exception is always thrown when + * GraphicsEnvironment.isHeadless returns true. + * + * @since 1.3 + */ + public Window(Window owner, GraphicsConfiguration gc) + { + this (); + + synchronized (getTreeLock()) + { + if (owner == null) + throw new IllegalArgumentException ("owner must not be null"); + + parent = owner; + owner.ownedWindows.add(new WeakReference(this)); + } + + // FIXME: make this text visible in the window. + SecurityManager s = System.getSecurityManager(); + if (s != null && ! s.checkTopLevelWindow(this)) + warningString = System.getProperty("awt.appletWarning"); + + if (gc != null + && gc.getDevice().getType() != GraphicsDevice.TYPE_RASTER_SCREEN) + throw new IllegalArgumentException ("gc must be from a screen device"); + + if (gc == null) + graphicsConfig = GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice() + .getDefaultConfiguration(); + else + graphicsConfig = gc; + } + + /** + * Creates the native peer for this window. + */ + public void addNotify() + { + if (peer == null) + peer = getToolkit().createWindow(this); + super.addNotify(); + } + + /** + * Relays out this window's child components at their preferred size. + * + * @specnote pack() doesn't appear to be called internally by show(), so + * we duplicate some of the functionality. + */ + public void pack() + { + if (parent != null && !parent.isDisplayable()) + parent.addNotify(); + if (peer == null) + addNotify(); + + setSize(getPreferredSize()); + + validate(); + } + + /** + * Shows on-screen this window and any of its owned windows for whom + * isVisible returns true. + * @specnote: Deprecated starting in 1.5. + */ + @Deprecated + public void show() + { + synchronized (getTreeLock()) + { + if (peer == null) + addNotify(); + + validate(); + if (visible) + toFront(); + else + { + super.show(); + // Show visible owned windows. + Iterator e = ownedWindows.iterator(); + while (e.hasNext()) + { + Window w = (Window) (((Reference) e.next()).get()); + if (w != null) + { + if (w.isVisible()) + w.getPeer().setVisible(true); + } + else + // Remove null weak reference from ownedWindows. + // Unfortunately this can't be done in the Window's + // finalize method because there is no way to guarantee + // synchronous access to ownedWindows there. + e.remove(); + } + } + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); + manager.setGlobalFocusedWindow(this); + + if (! shown) + { + FocusTraversalPolicy policy = getFocusTraversalPolicy(); + Component initialFocusOwner = null; + + if (policy != null) + initialFocusOwner = policy.getInitialComponent(this); + + if (initialFocusOwner != null) + initialFocusOwner.requestFocusInWindow(); + + // Post WINDOW_OPENED from here. + if (windowListener != null + || (eventMask & AWTEvent.WINDOW_EVENT_MASK) != 0) + { + WindowEvent ev = new WindowEvent(this, + WindowEvent.WINDOW_OPENED); + Toolkit tk = Toolkit.getDefaultToolkit(); + tk.getSystemEventQueue().postEvent(ev); + } + shown = true; + } + } + } + + /** + * @specnote: Deprecated starting in 1.5. + */ + @Deprecated + public void hide() + { + // Hide visible owned windows. + synchronized (getTreeLock ()) + { + Iterator e = ownedWindows.iterator(); + while(e.hasNext()) + { + Window w = (Window)(((Reference) e.next()).get()); + if (w != null) + { + if (w.isVisible() && w.getPeer() != null) + w.getPeer().setVisible(false); + } + else + e.remove(); + } + } + super.hide(); + } + + /** + * Destroys any resources associated with this window. This includes + * all components in the window and all owned top-level windows. + */ + public void dispose() + { + hide(); + + synchronized (getTreeLock ()) + { + Iterator e = ownedWindows.iterator(); + while(e.hasNext()) + { + Window w = (Window)(((Reference) e.next()).get()); + if (w != null) + w.dispose(); + else + // Remove null weak reference from ownedWindows. + e.remove(); + } + + for (int i = 0; i < ncomponents; ++i) + component[i].removeNotify(); + this.removeNotify(); + + // Post WINDOW_CLOSED from here. + if (windowListener != null + || (eventMask & AWTEvent.WINDOW_EVENT_MASK) != 0) + { + WindowEvent ev = new WindowEvent(this, + WindowEvent.WINDOW_CLOSED); + Toolkit tk = Toolkit.getDefaultToolkit(); + tk.getSystemEventQueue().postEvent(ev); + } + } + } + + /** + * Sends this window to the back so that all other windows display in + * front of it. + * + * If the window is set to be always-on-top, this will remove its + * always-on-top status. + */ + public void toBack() + { + if (peer != null) + { + if( alwaysOnTop ) + setAlwaysOnTop( false ); + ( (WindowPeer) peer ).toBack(); + } + } + + /** + * Brings this window to the front so that it displays in front of + * any other windows. + */ + public void toFront() + { + if (peer != null) + ( (WindowPeer) peer ).toFront(); + } + + /** + * Returns the toolkit used to create this window. + * + * @return The toolkit used to create this window. + * + * @specnote Unlike Component.getToolkit, this implementation always + * returns the value of Toolkit.getDefaultToolkit(). + */ + public Toolkit getToolkit() + { + return Toolkit.getDefaultToolkit(); + } + + /** + * Returns the warning string that will be displayed if this window is + * popped up by an unsecure applet or application. + * + * @return The unsecure window warning message. + */ + public final String getWarningString() + { + return warningString; + } + + /** + * Returns the locale that this window is configured for. + * + * @return The locale this window is configured for. + */ + public Locale getLocale() + { + return locale == null ? Locale.getDefault() : locale; + } + + /* + /** @since 1.2 + public InputContext getInputContext() + { + // FIXME + } + */ + + /** + * Sets the cursor for this window to the specifiec cursor. + * + * @param cursor The new cursor for this window. + */ + public void setCursor(Cursor cursor) + { + super.setCursor(cursor); + } + + public Window getOwner() + { + return (Window) parent; + } + + /** @since 1.2 */ + public Window[] getOwnedWindows() + { + Window [] trimmedList; + synchronized (getTreeLock ()) + { + // Windows with non-null weak references in ownedWindows. + Window [] validList = new Window [ownedWindows.size()]; + + Iterator e = ownedWindows.iterator(); + int numValid = 0; + while (e.hasNext()) + { + Window w = (Window)(((Reference) e.next()).get()); + if (w != null) + validList[numValid++] = w; + else + // Remove null weak reference from ownedWindows. + e.remove(); + } + + if (numValid != validList.length) + { + trimmedList = new Window [numValid]; + System.arraycopy (validList, 0, trimmedList, 0, numValid); + } + else + trimmedList = validList; + } + return trimmedList; + } + + /** + * Adds the specified listener to the list of <code>WindowListeners</code> + * that will receive events for this window. + * + * @param listener The <code>WindowListener</code> to add. + */ + public synchronized void addWindowListener(WindowListener listener) + { + if (listener != null) + { + newEventsOnly = true; + windowListener = AWTEventMulticaster.add(windowListener, listener); + } + } + + /** + * Removes the specified listener from the list of + * <code>WindowListeners</code> that will receive events for this window. + * + * @param listener The <code>WindowListener</code> to remove. + */ + public synchronized void removeWindowListener(WindowListener listener) + { + windowListener = AWTEventMulticaster.remove(windowListener, listener); + } + + /** + * Returns an array of all the window listeners registered on this window. + * + * @since 1.4 + */ + public synchronized WindowListener[] getWindowListeners() + { + return (WindowListener[]) + AWTEventMulticaster.getListeners(windowListener, + WindowListener.class); + } + + /** + * Returns an array of all the window focus listeners registered on this + * window. + * + * @since 1.4 + */ + public synchronized WindowFocusListener[] getWindowFocusListeners() + { + return (WindowFocusListener[]) + AWTEventMulticaster.getListeners(windowFocusListener, + WindowFocusListener.class); + } + + /** + * Returns an array of all the window state listeners registered on this + * window. + * + * @since 1.4 + */ + public synchronized WindowStateListener[] getWindowStateListeners() + { + return (WindowStateListener[]) + AWTEventMulticaster.getListeners(windowStateListener, + WindowStateListener.class); + } + + /** + * Adds the specified listener to this window. + */ + public void addWindowFocusListener (WindowFocusListener wfl) + { + if (wfl != null) + { + newEventsOnly = true; + windowFocusListener = AWTEventMulticaster.add (windowFocusListener, + wfl); + } + } + + /** + * Adds the specified listener to this window. + * + * @since 1.4 + */ + public void addWindowStateListener (WindowStateListener wsl) + { + if (wsl != null) + { + newEventsOnly = true; + windowStateListener = AWTEventMulticaster.add (windowStateListener, + wsl); + } + } + + /** + * Removes the specified listener from this window. + */ + public void removeWindowFocusListener (WindowFocusListener wfl) + { + windowFocusListener = AWTEventMulticaster.remove (windowFocusListener, wfl); + } + + /** + * Removes the specified listener from this window. + * + * @since 1.4 + */ + public void removeWindowStateListener (WindowStateListener wsl) + { + windowStateListener = AWTEventMulticaster.remove (windowStateListener, wsl); + } + + /** + * Returns an array of all the objects currently registered as FooListeners + * upon this Window. FooListeners are registered using the addFooListener + * method. + * + * @exception ClassCastException If listenerType doesn't specify a class or + * interface that implements java.util.EventListener. + * + * @since 1.3 + */ + public <T extends EventListener> T[] getListeners(Class<T> listenerType) + { + if (listenerType == WindowListener.class) + return (T[]) getWindowListeners(); + return super.getListeners(listenerType); + } + + void dispatchEventImpl(AWTEvent e) + { + if (e.getID() == ComponentEvent.COMPONENT_RESIZED) + { + invalidate(); + validate(); + } + super.dispatchEventImpl(e); + } + + /** + * Processes the specified event for this window. If the event is an + * instance of <code>WindowEvent</code>, then + * <code>processWindowEvent()</code> is called to process the event, + * otherwise the superclass version of this method is invoked. + * + * @param evt The event to process. + */ + protected void processEvent(AWTEvent evt) + { + if (evt instanceof WindowEvent) + { + WindowEvent we = (WindowEvent) evt; + switch (evt.getID()) + { + case WindowEvent.WINDOW_OPENED: + case WindowEvent.WINDOW_CLOSED: + case WindowEvent.WINDOW_CLOSING: + case WindowEvent.WINDOW_ICONIFIED: + case WindowEvent.WINDOW_DEICONIFIED: + case WindowEvent.WINDOW_ACTIVATED: + case WindowEvent.WINDOW_DEACTIVATED: + processWindowEvent(we); + break; + case WindowEvent.WINDOW_GAINED_FOCUS: + case WindowEvent.WINDOW_LOST_FOCUS: + processWindowFocusEvent(we); + break; + case WindowEvent.WINDOW_STATE_CHANGED: + processWindowStateEvent(we); + break; + } + } + else + super.processEvent(evt); + } + + /** + * Dispatches this event to any listeners that are listening for + * <code>WindowEvents</code> on this window. This method only gets + * invoked if it is enabled via <code>enableEvents()</code> or if + * a listener has been added. + * + * @param evt The event to process. + */ + protected void processWindowEvent(WindowEvent evt) + { + if (windowListener != null) + { + switch (evt.getID()) + { + case WindowEvent.WINDOW_ACTIVATED: + windowListener.windowActivated(evt); + break; + case WindowEvent.WINDOW_CLOSED: + windowListener.windowClosed(evt); + break; + case WindowEvent.WINDOW_CLOSING: + windowListener.windowClosing(evt); + break; + case WindowEvent.WINDOW_DEACTIVATED: + windowListener.windowDeactivated(evt); + break; + case WindowEvent.WINDOW_DEICONIFIED: + windowListener.windowDeiconified(evt); + break; + case WindowEvent.WINDOW_ICONIFIED: + windowListener.windowIconified(evt); + break; + case WindowEvent.WINDOW_OPENED: + windowListener.windowOpened(evt); + break; + } + } + } + + /** + * Identifies if this window is active. The active window is a Frame or + * Dialog that has focus or owns the active window. + * + * @return true if active, else false. + * @since 1.4 + */ + public boolean isActive() + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + return manager.getActiveWindow() == this; + } + + /** + * Identifies if this window is focused. A window is focused if it is the + * focus owner or it contains the focus owner. + * + * @return true if focused, else false. + * @since 1.4 + */ + public boolean isFocused() + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + return manager.getFocusedWindow() == this; + } + + /** + * Returns the child window that has focus if this window is active. + * This method returns <code>null</code> if this window is not active + * or no children have focus. + * + * @return The component that has focus, or <code>null</code> if no + * component has focus. + */ + public Component getFocusOwner () + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + Window activeWindow = manager.getActiveWindow (); + + // The currently-focused Component belongs to the active Window. + if (activeWindow == this) + return manager.getFocusOwner (); + else + return null; + } + + /** + * Returns the child component of this window that would receive + * focus if this window were to become focused. If the window + * already has the top-level focus, then this method returns the + * same component as getFocusOwner. If no child component has + * requested focus within the window, then the initial focus owner + * is returned. If this is a non-focusable window, this method + * returns null. + * + * @return the child component of this window that most recently had + * the focus, or <code>null</code> + * @since 1.4 + */ + public Component getMostRecentFocusOwner () + { + return windowFocusOwner; + } + + /** + * Set the focus owner for this window. This method is used to + * remember which component was focused when this window lost + * top-level focus, so that when it regains top-level focus the same + * child component can be refocused. + * + * @param windowFocusOwner the component in this window that owns + * the focus. + */ + void setFocusOwner (Component windowFocusOwner) + { + this.windowFocusOwner = windowFocusOwner; + } + + /** + * Post a Java 1.0 event to the event queue. + * + * @param e The event to post. + * + * @deprecated + */ + public boolean postEvent(Event e) + { + return handleEvent (e); + } + + /** + * Tests whether or not this window is visible on the screen. + * + * In contrast to the normal behaviour of Container, which is that + * a container is showing if its parent is visible and showing, a Window + * is even showing, if its parent (i.e. an invisible Frame) is not showing. + * + * @return <code>true</code> if this window is visible, <code>false</code> + * otherwise. + */ + public boolean isShowing() + { + return isVisible(); + } + + public void setLocationRelativeTo(Component c) + { + int x = 0; + int y = 0; + + if (c == null || !c.isShowing()) + { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + Point center = ge.getCenterPoint(); + x = center.x - (width / 2); + y = center.y - (height / 2); + } + else + { + int cWidth = c.getWidth(); + int cHeight = c.getHeight(); + Dimension screenSize = getToolkit().getScreenSize(); + + x = c.getLocationOnScreen().x; + y = c.getLocationOnScreen().y; + + // If bottom of component is cut off, window placed + // on the left or the right side of component + if ((y + cHeight) > screenSize.height) + { + // If the right side of the component is closer to the center + if ((screenSize.width / 2 - x) <= 0) + { + if ((x - width) >= 0) + x -= width; + else + x = 0; + } + else + { + if ((x + cWidth + width) <= screenSize.width) + x += cWidth; + else + x = screenSize.width - width; + } + + y = screenSize.height - height; + } + else if (cWidth > width || cHeight > height) + { + // If right side of component is cut off + if ((x + width) > screenSize.width) + x = screenSize.width - width; + // If left side of component is cut off + else if (x < 0) + x = 0; + else + x += (cWidth - width) / 2; + + y += (cHeight - height) / 2; + } + else + { + // If right side of component is cut off + if ((x + width) > screenSize.width) + x = screenSize.width - width; + // If left side of component is cut off + else if (x < 0 || (x - (width - cWidth) / 2) < 0) + x = 0; + else + x -= (width - cWidth) / 2; + + if ((y - (height - cHeight) / 2) > 0) + y -= (height - cHeight) / 2; + else + y = 0; + } + } + + setLocation(x, y); + } + + /** + * A BltBufferStrategy for windows. + */ + private class WindowBltBufferStrategy extends BltBufferStrategy + { + /** + * Creates a block transfer strategy for this window. + * + * @param numBuffers the number of buffers in this strategy + * @param accelerated true if the buffer should be accelerated, + * false otherwise + */ + WindowBltBufferStrategy(int numBuffers, boolean accelerated) + { + super(numBuffers, + new BufferCapabilities(new ImageCapabilities(accelerated), + new ImageCapabilities(accelerated), + BufferCapabilities.FlipContents.COPIED)); + } + } + + /** + * A FlipBufferStrategy for windows. + */ + private class WindowFlipBufferStrategy extends FlipBufferStrategy + { + /** + * Creates a flip buffer strategy for this window. + * + * @param numBuffers the number of buffers in this strategy + * + * @throws AWTException if the requested number of buffers is not + * supported + */ + WindowFlipBufferStrategy(int numBuffers) + throws AWTException + { + super(numBuffers, + new BufferCapabilities(new ImageCapabilities(true), + new ImageCapabilities(true), + BufferCapabilities.FlipContents.COPIED)); + } + } + + /** + * Creates a buffering strategy that manages how this window is + * repainted. This method attempts to create the optimum strategy + * based on the desired number of buffers. Hardware or software + * acceleration may be used. + * + * createBufferStrategy attempts different levels of optimization, + * but guarantees that some strategy with the requested number of + * buffers will be created even if it is not optimal. First it + * attempts to create a page flipping strategy, then an accelerated + * blitting strategy, then an unaccelerated blitting strategy. + * + * Calling this method causes any existing buffer strategy to be + * destroyed. + * + * @param numBuffers the number of buffers in this strategy + * + * @throws IllegalArgumentException if requested number of buffers + * is less than one + * @throws IllegalStateException if this window is not displayable + * + * @since 1.4 + */ + public void createBufferStrategy(int numBuffers) + { + if (numBuffers < 1) + throw new IllegalArgumentException("Window.createBufferStrategy: number" + + " of buffers is less than one"); + + if (!isDisplayable()) + throw new IllegalStateException("Window.createBufferStrategy: window is" + + " not displayable"); + + BufferStrategy newStrategy = null; + + // try a flipping strategy + try + { + newStrategy = new WindowFlipBufferStrategy(numBuffers); + } + catch (AWTException e) + { + } + + // fall back to an accelerated blitting strategy + if (newStrategy == null) + newStrategy = new WindowBltBufferStrategy(numBuffers, true); + + bufferStrategy = newStrategy; + } + + /** + * Creates a buffering strategy that manages how this window is + * repainted. This method attempts to create a strategy based on + * the specified capabilities and throws an exception if the + * requested strategy is not supported. + * + * Calling this method causes any existing buffer strategy to be + * destroyed. + * + * @param numBuffers the number of buffers in this strategy + * @param caps the requested buffering capabilities + * + * @throws AWTException if the requested capabilities are not + * supported + * @throws IllegalArgumentException if requested number of buffers + * is less than one or if caps is null + * + * @since 1.4 + */ + public void createBufferStrategy(int numBuffers, BufferCapabilities caps) + throws AWTException + { + if (numBuffers < 1) + throw new IllegalArgumentException("Window.createBufferStrategy: number" + + " of buffers is less than one"); + + if (caps == null) + throw new IllegalArgumentException("Window.createBufferStrategy:" + + " capabilities object is null"); + + // a flipping strategy was requested + if (caps.isPageFlipping()) + bufferStrategy = new WindowFlipBufferStrategy(numBuffers); + else + bufferStrategy = new WindowBltBufferStrategy(numBuffers, true); + } + + /** + * Returns the buffer strategy used by the window. + * + * @return the buffer strategy. + * @since 1.4 + */ + public BufferStrategy getBufferStrategy() + { + return bufferStrategy; + } + + /** + * @since 1.2 + * + * @deprecated replaced by Component.applyComponentOrientation. + */ + public void applyResourceBundle(ResourceBundle rb) + { + applyComponentOrientation(ComponentOrientation.getOrientation(rb)); + } + + /** + * @since 1.2 + * + * @deprecated + */ + public void applyResourceBundle(String rbName) + { + ResourceBundle rb = ResourceBundle.getBundle(rbName, Locale.getDefault(), + ClassLoader.getSystemClassLoader()); + if (rb != null) + applyResourceBundle(rb); + } + + /** + * Gets the AccessibleContext associated with this <code>Window</code>. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTWindow(); + return accessibleContext; + } + + /** + * Get graphics configuration. The implementation for Window will + * not ask any parent containers, since Window is a toplevel + * window and not actually embedded in the parent component. + */ + public GraphicsConfiguration getGraphicsConfiguration() + { + GraphicsConfiguration conf = graphicsConfig; + if (conf == null) + { + conf = GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + graphicsConfig = conf; + } + return conf; + } + + protected void processWindowFocusEvent(WindowEvent event) + { + if (windowFocusListener != null) + { + switch (event.getID ()) + { + case WindowEvent.WINDOW_GAINED_FOCUS: + windowFocusListener.windowGainedFocus (event); + break; + + case WindowEvent.WINDOW_LOST_FOCUS: + windowFocusListener.windowLostFocus (event); + break; + + default: + break; + } + } + } + + /** + * @since 1.4 + */ + protected void processWindowStateEvent(WindowEvent event) + { + if (windowStateListener != null + && event.getID () == WindowEvent.WINDOW_STATE_CHANGED) + windowStateListener.windowStateChanged (event); + } + + /** + * Returns whether this <code>Window</code> can get the focus or not. + * + * @since 1.4 + */ + public final boolean isFocusableWindow () + { + if (getFocusableWindowState () == false) + return false; + + if (this instanceof Dialog + || this instanceof Frame) + return true; + + // FIXME: Implement more possible cases for returning true. + + return false; + } + + /** + * Returns the value of the focusableWindowState property. + * + * @since 1.4 + */ + public boolean getFocusableWindowState () + { + return focusableWindowState; + } + + /** + * Sets the value of the focusableWindowState property. + * + * @since 1.4 + */ + public void setFocusableWindowState (boolean focusableWindowState) + { + this.focusableWindowState = focusableWindowState; + } + + /** + * Check whether this Container is a focus cycle root. + * Returns always <code>true</code> as Windows are the + * root of the focus cycle. + * + * @return Always <code>true</code>. + * + * @since 1.4 + */ + public final boolean isFocusCycleRoot() + { + return true; + } + + /** + * Set whether or not this Container is the root of a focus + * traversal cycle. Windows are the root of the focus cycle + * and therefore this method does nothing. + * + * @param focusCycleRoot ignored. + * + * @since 1.4 + */ + public final void setFocusCycleRoot(boolean focusCycleRoot) + { + // calls to the method are ignored + } + + /** + * Returns the root container that owns the focus cycle where this + * component resides. Windows have no ancestors and this method + * returns always <code>null</code>. + * + * @return Always <code>null</code>. + * @since 1.4 + */ + public final Container getFocusCycleRootAncestor() + { + return null; + } + + /** + * Returns whether the Windows is an always-on-top window, + * meaning whether the window can be obscured by other windows or not. + * + * @return <code>true</code> if the windows is always-on-top, + * <code>false</code> otherwise. + * @since 1.5 + */ + public final boolean isAlwaysOnTop() + { + return alwaysOnTop; + } + + /** + * Sets the always-on-top state of this window (if supported). + * + * Setting a window to always-on-top means it will not be obscured + * by any other windows (with the exception of other always-on-top + * windows). Not all platforms may support this. + * + * If an window's always-on-top status is changed to false, the window + * will remain at the front but not be anchored there. + * + * Calling toBack() on an always-on-top window will change its + * always-on-top status to false. + * + * @since 1.5 + */ + public final void setAlwaysOnTop(boolean alwaysOnTop) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission( new AWTPermission("setWindowAlwaysOnTop") ); + + if( this.alwaysOnTop == alwaysOnTop ) + return; + + if( alwaysOnTop ) + toFront(); + + firePropertyChange("alwaysOnTop", this.alwaysOnTop, alwaysOnTop ); + this.alwaysOnTop = alwaysOnTop; + + if (peer != null) + ( (WindowPeer) peer).updateAlwaysOnTop(); + else + System.out.println("Null peer?!"); + } + + /** + * Generate a unique name for this window. + * + * @return A unique name for this window. + */ + String generateName() + { + return "win" + getUniqueLong(); + } + + /** + * Overridden to handle WindowEvents. + * + * @return <code>true</code> when the specified event type is enabled, + * <code>false</code> otherwise + */ + boolean eventTypeEnabled(int type) + { + boolean enabled = false; + switch (type) + { + case WindowEvent.WINDOW_OPENED: + case WindowEvent.WINDOW_CLOSED: + case WindowEvent.WINDOW_CLOSING: + case WindowEvent.WINDOW_ICONIFIED: + case WindowEvent.WINDOW_DEICONIFIED: + case WindowEvent.WINDOW_ACTIVATED: + case WindowEvent.WINDOW_DEACTIVATED: + enabled = ((eventMask & AWTEvent.WINDOW_EVENT_MASK) != 0) + || windowListener != null; + break; + case WindowEvent.WINDOW_GAINED_FOCUS: + case WindowEvent.WINDOW_LOST_FOCUS: + enabled = ((eventMask & AWTEvent.WINDOW_FOCUS_EVENT_MASK) != 0) + || windowFocusListener != null; + break; + case WindowEvent.WINDOW_STATE_CHANGED: + enabled = ((eventMask & AWTEvent.WINDOW_STATE_EVENT_MASK) != 0) + || windowStateListener != null; + break; + default: + enabled = super.eventTypeEnabled(type); + } + return enabled; + } + + private static synchronized long getUniqueLong() + { + return next_window_number++; + } +} diff --git a/libjava/classpath/java/awt/color/CMMException.java b/libjava/classpath/java/awt/color/CMMException.java new file mode 100644 index 000000000..ab328ec84 --- /dev/null +++ b/libjava/classpath/java/awt/color/CMMException.java @@ -0,0 +1,63 @@ +/* CMMException.java -- error in the native CMM + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.color; + +/** + * Thrown when there is an error in the native CMM. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @status updated to 1.4 + */ +public class CMMException extends RuntimeException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 5775558044142994965L; + + /** + * Create a new instance with a specified detailed error message. + * + * @param message the message + */ + public CMMException(String message) + { + super(message); + } +} // class CMMException diff --git a/libjava/classpath/java/awt/color/ColorSpace.java b/libjava/classpath/java/awt/color/ColorSpace.java new file mode 100644 index 000000000..79369da71 --- /dev/null +++ b/libjava/classpath/java/awt/color/ColorSpace.java @@ -0,0 +1,183 @@ +/* ColorSpace.java -- transforms between color spaces + Copyright (C) 2000, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.color; + +import java.io.Serializable; + +/** + * NEEDS DOCUMENTATION + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + * @since 1.2 + */ +public abstract class ColorSpace implements Serializable +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -409452704308689724L; + + public static final int TYPE_XYZ = 0; + public static final int TYPE_Lab = 1; + public static final int TYPE_Luv = 2; + public static final int TYPE_YCbCr = 3; + public static final int TYPE_Yxy = 4; + public static final int TYPE_RGB = 5; + public static final int TYPE_GRAY = 6; + public static final int TYPE_HSV = 7; + public static final int TYPE_HLS = 8; + public static final int TYPE_CMYK = 9; + // mysterious gap in the enumeration sequenece + public static final int TYPE_CMY = 11; + public static final int TYPE_2CLR = 12; + public static final int TYPE_3CLR = 13; + public static final int TYPE_4CLR = 14; + public static final int TYPE_5CLR = 15; + public static final int TYPE_6CLR = 16; + public static final int TYPE_7CLR = 17; + public static final int TYPE_8CLR = 18; + public static final int TYPE_9CLR = 19; + public static final int TYPE_ACLR = 20; + public static final int TYPE_BCLR = 21; + public static final int TYPE_CCLR = 22; + public static final int TYPE_DCLR = 23; + public static final int TYPE_ECLR = 24; + public static final int TYPE_FCLR = 25; + + public static final int CS_sRGB = 1000; + public static final int CS_LINEAR_RGB = 1004; + public static final int CS_CIEXYZ = 1001; + public static final int CS_PYCC = 1002; + public static final int CS_GRAY = 1003; + + private static final int CS_BASE = CS_sRGB; + private static final int CS_END = CS_LINEAR_RGB + 1; + private static final int CS_COUNT = CS_END - CS_BASE; + + // Instances are lazily instantiated + private static final ColorSpace[] INSTANCES = new ColorSpace[CS_COUNT]; + + /** + * @serial + */ + // Visible in subclass. + final int type; + + /** + * @serial + */ + // Visible in subclass. + final int numComponents; + + protected ColorSpace(int type, int numcomponents) + { + this.type = type; + numComponents = numcomponents; + } + + public static ColorSpace getInstance(int colorspace) + { + if ((colorspace >= CS_BASE) && (colorspace < CS_END)) + { + int instanceIndex = colorspace - CS_BASE; + if (INSTANCES[instanceIndex] == null) + { + ICC_Profile profile = new ICC_Profile(colorspace); + INSTANCES[instanceIndex] = new ICC_ColorSpace(profile); + } + return INSTANCES[instanceIndex]; + } + throw new IllegalArgumentException("unknown/unsupported colorspace"); + } + + public boolean isCS_sRGB() + { + return type == CS_sRGB; + } + + /** + * Transforms a color value assumed to be in this ColorSpace into a value in + * the default CS_sRGB color space. + * + * @exception ArrayIndexOutOfBoundsException If array length is not at least + * the number of components in this ColorSpace. + */ + public abstract float[] toRGB(float[] colorvalue); + + public abstract float[] fromRGB(float[] rgbvalue); + + public abstract float[] toCIEXYZ(float[] colorvalue); + + public abstract float[] fromCIEXYZ(float[] colorvalue); + + public int getType() + { + return type; + } + + public int getNumComponents() + { + return numComponents; + } + + public String getName(int idx) + { + return "type " + type; + } + + /** + * @since 1.4 + */ + public float getMinValue(int idx) + { + if (idx < 0 || idx >= numComponents) + throw new IllegalArgumentException(); + return 0; + } + + /** + * @since 1.4 + */ + public float getMaxValue(int idx) + { + if (idx < 0 || idx >= numComponents) + throw new IllegalArgumentException(); + return 1; + } +} // class ColorSpace diff --git a/libjava/classpath/java/awt/color/ICC_ColorSpace.java b/libjava/classpath/java/awt/color/ICC_ColorSpace.java new file mode 100644 index 000000000..ac636fb26 --- /dev/null +++ b/libjava/classpath/java/awt/color/ICC_ColorSpace.java @@ -0,0 +1,314 @@ +/* ICC_ColorSpace.java -- the canonical color space implementation + Copyright (C) 2000, 2002, 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.color; + +import gnu.java.awt.color.CieXyzConverter; +import gnu.java.awt.color.ClutProfileConverter; +import gnu.java.awt.color.ColorSpaceConverter; +import gnu.java.awt.color.GrayProfileConverter; +import gnu.java.awt.color.GrayScaleConverter; +import gnu.java.awt.color.LinearRGBConverter; +import gnu.java.awt.color.PyccConverter; +import gnu.java.awt.color.RgbProfileConverter; +import gnu.java.awt.color.SrgbConverter; + +import java.io.IOException; +import java.io.ObjectInputStream; + +/** + * ICC_ColorSpace - an implementation of ColorSpace + * + * While an ICC_Profile class abstracts the data in an ICC profile file + * an ICC_ColorSpace performs the color space conversions defined by + * an ICC_Profile instance. + * + * Typically, an ICC_Profile will either be created using getInstance, + * either from the built-in colorspaces, or from an ICC profile file. + * Then a ICC_Colorspace will be used to perform transforms from the + * device colorspace to and from the profile color space. + * + * The PCS used by ColorSpace is CIE XYZ relative a D50 white point. + * (Profiles using a CIE Lab PCS will have their input and output converted + * to D50 CIE XYZ accordingly. + * + * Note that a valid profile may not contain transforms in both directions, + * in which case the output may be undefined. + * All built-in colorspaces have bidirectional transforms, but developers + * using an ICC profile file may want to check the profile class using + * the ICC_Profile.getProfileClass() method. Input class profiles are + * guaranteed to have transforms to the PCS, output class profiles are + * guaranteed to have transforms from the PCS to device space. + * + * @author Sven de Marothy + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + * @since 1.2 + */ +public class ICC_ColorSpace extends ColorSpace +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 3455889114070431483L; + + /** + * @serial + */ + private ICC_Profile thisProfile; + + /** + * @serial + */ + private float[] minVal; + + /** + * @serial + */ + private float[] maxVal; + + /** + * @serial + */ + private float[] diffMinMax; + + /** + * @serial + */ + private float[] invDiffMinMax; + + /** + * @serial + */ + private boolean needScaleInit; + + /** + * Tells us if the PCS is CIE LAB (must be CIEXYZ otherwise) + */ + private transient int type; + private transient int nComponents; + private transient ColorSpaceConverter converter; + + /** + * Constructs a new ICC_ColorSpace from an ICC_Profile object. + * + * @exception IllegalArgumentException If profile is inappropriate for + * representing a ColorSpace. + */ + public ICC_ColorSpace(ICC_Profile profile) + { + super(profile.getColorSpaceType(), profile.getNumComponents()); + + converter = getConverter(profile); + thisProfile = profile; + nComponents = profile.getNumComponents(); + type = profile.getColorSpaceType(); + makeArrays(); + } + + /** + * Return the profile + */ + public ICC_Profile getProfile() + { + return thisProfile; + } + + /** + * Transforms a color value assumed to be in this ColorSpace into a value in + * the default CS_sRGB color space. + * + * @exception ArrayIndexOutOfBoundsException If array length is not at least + * the number of components in this ColorSpace. + */ + public float[] toRGB(float[] colorvalue) + { + return converter.toRGB(colorvalue); + } + + /** + * Transforms a color value assumed to be in the default CS_sRGB color space + * into this ColorSpace. + * + * @exception ArrayIndexOutOfBoundsException If array length is not at + * least 3. + */ + public float[] fromRGB(float[] rgbvalue) + { + return converter.fromRGB(rgbvalue); + } + + /** + * Transforms a color value assumed to be in this ColorSpace into the + * CS_CIEXYZ conversion color space. + * + * @exception ArrayIndexOutOfBoundsException If array length is not at + * least the number of components in this ColorSpace. + */ + public float[] toCIEXYZ(float[] colorvalue) + { + return converter.toCIEXYZ(colorvalue); + } + + /** + * Transforms a color value assumed to be in the CS_CIEXYZ conversion color + * space into this ColorSpace. + * + * @exception ArrayIndexOutOfBoundsException If array length is not at + * least 3. + */ + public float[] fromCIEXYZ(float[] colorvalue) + { + return converter.fromCIEXYZ(colorvalue); + } + + public boolean isCS_sRGB() + { + return converter instanceof SrgbConverter; + } + + /** + * Returns the minimum normalized color component value for the specified + * component. + * + * @exception IllegalArgumentException If component is less than 0 or greater + * than numComponents - 1. + * + * @since 1.4 + */ + public float getMinValue(int idx) + { + // FIXME: Not 100% certain of this. + if (type == ColorSpace.TYPE_Lab && (idx == 1 || idx == 2)) + return -128f; + + if (idx < 0 || idx >= nComponents) + throw new IllegalArgumentException(); + return 0; + } + + /** + * Returns the maximum normalized color component value for the specified + * component. + * + * @exception IllegalArgumentException If component is less than 0 or greater + * than numComponents - 1. + * + * @since 1.4 + */ + public float getMaxValue(int idx) + { + if (type == ColorSpace.TYPE_XYZ && idx >= 0 && idx <= 2) + return 1 + 32767 / 32768f; + else if (type == ColorSpace.TYPE_Lab) + { + if (idx == 0) + return 100; + if (idx == 1 || idx == 2) + return 127; + } + if (idx < 0 || idx >= nComponents) + throw new IllegalArgumentException(); + return 1; + } + + /** + * Returns a colorspace converter suitable for a given profile + */ + private ColorSpaceConverter getConverter(ICC_Profile profile) + { + ColorSpaceConverter converter; + switch (profile.isPredefined()) + { + case CS_sRGB: + converter = new SrgbConverter(); + break; + case CS_CIEXYZ: + converter = new CieXyzConverter(); + break; + case CS_GRAY: + converter = new GrayScaleConverter(); + break; + case CS_LINEAR_RGB: + converter = new LinearRGBConverter(); + break; + case CS_PYCC: + converter = new PyccConverter(); + break; + default: + if (profile instanceof ICC_ProfileRGB) + converter = new RgbProfileConverter((ICC_ProfileRGB) profile); + else if (profile instanceof ICC_ProfileGray) + converter = new GrayProfileConverter((ICC_ProfileGray) profile); + else + converter = new ClutProfileConverter(profile); + break; + } + return converter; + } + + /** + * Serialization compatibility requires these variable to be set, + * although we don't use them. Perhaps we should? + */ + private void makeArrays() + { + minVal = new float[nComponents]; + maxVal = new float[nComponents]; + + invDiffMinMax = diffMinMax = null; + for (int i = 0; i < nComponents; i++) + { + minVal[i] = getMinValue(i); + maxVal[i] = getMaxValue(i); + } + needScaleInit = true; + } + + /** + * Deserializes the object + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + // set up objects + converter = getConverter(thisProfile); + nComponents = thisProfile.getNumComponents(); + type = thisProfile.getColorSpaceType(); + } +} // class ICC_ColorSpace diff --git a/libjava/classpath/java/awt/color/ICC_Profile.java b/libjava/classpath/java/awt/color/ICC_Profile.java new file mode 100644 index 000000000..0eef22e49 --- /dev/null +++ b/libjava/classpath/java/awt/color/ICC_Profile.java @@ -0,0 +1,1249 @@ +/* ICC_Profile.java -- color space profiling + Copyright (C) 2000, 2002, 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.color; + +import gnu.java.awt.color.ProfileHeader; +import gnu.java.awt.color.TagEntry; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; +import java.io.OutputStream; +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.util.Enumeration; +import java.util.Hashtable; + +/** + * ICC Profile - represents an ICC Color profile. + * The ICC profile format is a standard file format which maps the transform + * from a device color space to a standard Profile Color Space (PCS), which + * can either be CIE L*a*b or CIE XYZ. + * (With the exception of device link profiles which map from one device space + * to another) + * + * ICC profiles calibrated to specific input/output devices are used when color + * fidelity is of importance. + * + * An instance of ICC_Profile can be created using the getInstance() methods, + * either using one of the predefined color spaces enumerated in ColorSpace, + * or from an ICC profile file, or from an input stream. + * + * An ICC_ColorSpace object can then be created to transform color values + * through the profile. + * + * The ICC_Profile class implements the version 2 format specified by + * International Color Consortium Specification ICC.1:1998-09, + * and its addendum ICC.1A:1999-04, April 1999 + * (available at www.color.org) + * + * @author Sven de Marothy + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + * @since 1.2 + */ +public class ICC_Profile implements Serializable +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -3938515861990936766L; + + /** + * ICC Profile classes + */ + public static final int CLASS_INPUT = 0; + public static final int CLASS_DISPLAY = 1; + public static final int CLASS_OUTPUT = 2; + public static final int CLASS_DEVICELINK = 3; + public static final int CLASS_COLORSPACECONVERSION = 4; + public static final int CLASS_ABSTRACT = 5; + public static final int CLASS_NAMEDCOLOR = 6; + + /** + * ICC Profile class signatures + */ + public static final int icSigInputClass = 0x73636e72; // 'scnr' + public static final int icSigDisplayClass = 0x6d6e7472; // 'mntr' + public static final int icSigOutputClass = 0x70727472; // 'prtr' + public static final int icSigLinkClass = 0x6c696e6b; // 'link' + public static final int icSigColorSpaceClass = 0x73706163; // 'spac' + public static final int icSigAbstractClass = 0x61627374; // 'abst' + public static final int icSigNamedColorClass = 0x6e6d636c; // 'nmcl' + + /** + * Color space signatures + */ + public static final int icSigXYZData = 0x58595A20; // 'XYZ ' + public static final int icSigLabData = 0x4C616220; // 'Lab ' + public static final int icSigLuvData = 0x4C757620; // 'Luv ' + public static final int icSigYCbCrData = 0x59436272; // 'YCbr' + public static final int icSigYxyData = 0x59787920; // 'Yxy ' + public static final int icSigRgbData = 0x52474220; // 'RGB ' + public static final int icSigGrayData = 0x47524159; // 'GRAY' + public static final int icSigHsvData = 0x48535620; // 'HSV ' + public static final int icSigHlsData = 0x484C5320; // 'HLS ' + public static final int icSigCmykData = 0x434D594B; // 'CMYK' + public static final int icSigCmyData = 0x434D5920; // 'CMY ' + public static final int icSigSpace2CLR = 0x32434C52; // '2CLR' + public static final int icSigSpace3CLR = 0x33434C52; // '3CLR' + public static final int icSigSpace4CLR = 0x34434C52; // '4CLR' + public static final int icSigSpace5CLR = 0x35434C52; // '5CLR' + public static final int icSigSpace6CLR = 0x36434C52; // '6CLR' + public static final int icSigSpace7CLR = 0x37434C52; // '7CLR' + public static final int icSigSpace8CLR = 0x38434C52; // '8CLR' + public static final int icSigSpace9CLR = 0x39434C52; // '9CLR' + public static final int icSigSpaceACLR = 0x41434C52; // 'ACLR' + public static final int icSigSpaceBCLR = 0x42434C52; // 'BCLR' + public static final int icSigSpaceCCLR = 0x43434C52; // 'CCLR' + public static final int icSigSpaceDCLR = 0x44434C52; // 'DCLR' + public static final int icSigSpaceECLR = 0x45434C52; // 'ECLR' + public static final int icSigSpaceFCLR = 0x46434C52; // 'FCLR' + + /** + * Rendering intents + */ + public static final int icPerceptual = 0; + public static final int icRelativeColorimetric = 1; + public static final int icSaturation = 2; + public static final int icAbsoluteColorimetric = 3; + + /** + * Tag signatures + */ + public static final int icSigAToB0Tag = 0x41324230; // 'A2B0' + public static final int icSigAToB1Tag = 0x41324231; // 'A2B1' + public static final int icSigAToB2Tag = 0x41324232; // 'A2B2' + public static final int icSigBlueColorantTag = 0x6258595A; // 'bXYZ' + public static final int icSigBlueTRCTag = 0x62545243; // 'bTRC' + public static final int icSigBToA0Tag = 0x42324130; // 'B2A0' + public static final int icSigBToA1Tag = 0x42324131; // 'B2A1' + public static final int icSigBToA2Tag = 0x42324132; // 'B2A2' + public static final int icSigCalibrationDateTimeTag = 0x63616C74; // 'calt' + public static final int icSigCharTargetTag = 0x74617267; // 'targ' + public static final int icSigCopyrightTag = 0x63707274; // 'cprt' + public static final int icSigCrdInfoTag = 0x63726469; // 'crdi' + public static final int icSigDeviceMfgDescTag = 0x646D6E64; // 'dmnd' + public static final int icSigDeviceModelDescTag = 0x646D6464; // 'dmdd' + public static final int icSigDeviceSettingsTag = 0x64657673; // 'devs' + public static final int icSigGamutTag = 0x67616D74; // 'gamt' + public static final int icSigGrayTRCTag = 0x6b545243; // 'kTRC' + public static final int icSigGreenColorantTag = 0x6758595A; // 'gXYZ' + public static final int icSigGreenTRCTag = 0x67545243; // 'gTRC' + public static final int icSigLuminanceTag = 0x6C756d69; // 'lumi' + public static final int icSigMeasurementTag = 0x6D656173; // 'meas' + public static final int icSigMediaBlackPointTag = 0x626B7074; // 'bkpt' + public static final int icSigMediaWhitePointTag = 0x77747074; // 'wtpt' + public static final int icSigNamedColor2Tag = 0x6E636C32; // 'ncl2' + public static final int icSigOutputResponseTag = 0x72657370; // 'resp' + public static final int icSigPreview0Tag = 0x70726530; // 'pre0' + public static final int icSigPreview1Tag = 0x70726531; // 'pre1' + public static final int icSigPreview2Tag = 0x70726532; // 'pre2' + public static final int icSigProfileDescriptionTag = 0x64657363; // 'desc' + public static final int icSigProfileSequenceDescTag = 0x70736571; // 'pseq' + public static final int icSigPs2CRD0Tag = 0x70736430; // 'psd0' + public static final int icSigPs2CRD1Tag = 0x70736431; // 'psd1' + public static final int icSigPs2CRD2Tag = 0x70736432; // 'psd2' + public static final int icSigPs2CRD3Tag = 0x70736433; // 'psd3' + public static final int icSigPs2CSATag = 0x70733273; // 'ps2s' + public static final int icSigPs2RenderingIntentTag = 0x70733269; // 'ps2i' + public static final int icSigRedColorantTag = 0x7258595A; // 'rXYZ' + public static final int icSigRedTRCTag = 0x72545243; // 'rTRC' + public static final int icSigScreeningDescTag = 0x73637264; // 'scrd' + public static final int icSigScreeningTag = 0x7363726E; // 'scrn' + public static final int icSigTechnologyTag = 0x74656368; // 'tech' + public static final int icSigUcrBgTag = 0x62666420; // 'bfd ' + public static final int icSigViewingCondDescTag = 0x76756564; // 'vued' + public static final int icSigViewingConditionsTag = 0x76696577; // 'view' + public static final int icSigChromaticityTag = 0x6368726D; // 'chrm' + + /** + * Non-ICC tag 'head' for use in retrieving the header with getData() + */ + public static final int icSigHead = 0x68656164; + + /** + * Header offsets + */ + public static final int icHdrSize = 0; + public static final int icHdrCmmId = 4; + public static final int icHdrVersion = 8; + public static final int icHdrDeviceClass = 12; + public static final int icHdrColorSpace = 16; + public static final int icHdrPcs = 20; + public static final int icHdrDate = 24; + public static final int icHdrMagic = 36; + public static final int icHdrPlatform = 40; + public static final int icHdrFlags = 44; + public static final int icHdrManufacturer = 48; + public static final int icHdrModel = 52; + public static final int icHdrAttributes = 56; + public static final int icHdrRenderingIntent = 64; + public static final int icHdrIlluminant = 68; + public static final int icHdrCreator = 80; + + /** + * + */ + public static final int icTagType = 0; + public static final int icTagReserved = 4; + public static final int icCurveCount = 8; + public static final int icCurveData = 12; + public static final int icXYZNumberX = 8; + + /** + * offset of the Tag table + */ + private static final int tagTableOffset = 128; + + /** + * @serial + */ + private static final int iccProfileSerializedDataVersion = 1; + + /** + * Constants related to generating profiles for + * built-in colorspace profiles + */ + /** + * Copyright notice to stick into built-in-profile files. + */ + private static final String copyrightNotice = "Generated by GNU Classpath."; + + /** + * Resolution of the TRC to use for predefined profiles. + * 1024 should suffice. + */ + private static final int TRC_POINTS = 1024; + + /** + * CIE 1931 D50 white point (in Lab coordinates) + */ + private static final float[] D50 = { 0.96422f, 1.00f, 0.82521f }; + + /** + * Color space profile ID + * Set to the predefined profile class (e.g. CS_sRGB) if a predefined + * color space is used, set to -1 otherwise. + * (or if the profile has been modified) + */ + private transient int profileID; + + /** + * The profile header data + */ + private transient ProfileHeader header; + + /** + * A hashtable containing the profile tags as TagEntry objects + */ + private transient Hashtable tagTable; + + /** + * Contructor for predefined colorspaces + */ + ICC_Profile(int profileID) + { + header = null; + tagTable = null; + createProfile(profileID); + } + + /** + * Constructs an ICC_Profile from a header and a table of loaded tags. + */ + ICC_Profile(ProfileHeader h, Hashtable tags) throws IllegalArgumentException + { + header = h; + tagTable = tags; + profileID = -1; // Not a predefined color space + } + + /** + * Constructs an ICC_Profile from a byte array of data. + */ + ICC_Profile(byte[] data) throws IllegalArgumentException + { + // get header and verify it + header = new ProfileHeader(data); + header.verifyHeader(data.length); + tagTable = createTagTable(data); + profileID = -1; // Not a predefined color space + } + + /** + * Free up the used memory. + */ + protected void finalize() + { + } + + /** + * Returns an ICC_Profile instance from a byte array of profile data. + * + * An instance of the specialized classes ICC_ProfileRGB or ICC_ProfileGray + * may be returned if appropriate. + * + * @param data - the profile data + * @return An ICC_Profile object + * + * @throws IllegalArgumentException if the profile data is an invalid + * v2 profile. + */ + public static ICC_Profile getInstance(byte[] data) + { + ProfileHeader header = new ProfileHeader(data); + + // verify it as a correct ICC header, including size + header.verifyHeader(data.length); + + Hashtable tags = createTagTable(data); + + if (isRGBProfile(header, tags)) + return new ICC_ProfileRGB(data); + if (isGrayProfile(header, tags)) + return new ICC_ProfileGray(data); + + return new ICC_Profile(header, tags); + } + + /** + * Returns an predefined ICC_Profile instance. + * + * This will construct an ICC_Profile instance from one of the predefined + * color spaces in the ColorSpace class. (e.g. CS_sRGB, CS_GRAY, etc) + * + * An instance of the specialized classes ICC_ProfileRGB or ICC_ProfileGray + * may be returned if appropriate. + * + * @return An ICC_Profile object + */ + public static ICC_Profile getInstance(int cspace) + { + if (cspace == ColorSpace.CS_sRGB || cspace == ColorSpace.CS_LINEAR_RGB) + return new ICC_ProfileRGB(cspace); + if (cspace == ColorSpace.CS_GRAY) + return new ICC_ProfileGray(cspace); + return new ICC_Profile(cspace); + } + + /** + * Returns an ICC_Profile instance from an ICC Profile file. + * + * An instance of the specialized classes ICC_ProfileRGB or ICC_ProfileGray + * may be returned if appropriate. + * + * @param filename - the file name of the profile file. + * @return An ICC_Profile object + * + * @throws IllegalArgumentException if the profile data is an invalid + * v2 profile. + * @throws IOException if the file could not be read. + */ + public static ICC_Profile getInstance(String filename) + throws IOException + { + return getInstance(new FileInputStream(filename)); + } + + /** + * Returns an ICC_Profile instance from an InputStream. + * + * This method can be used for reading ICC profiles embedded in files + * which support this. (JPEG and SVG for instance). + * + * The stream is treated in the following way: The profile header + * (128 bytes) is read first, and the header is validated. If the profile + * header is valid, it will then attempt to read the rest of the profile + * from the stream. The stream is not closed after reading. + * + * An instance of the specialized classes ICC_ProfileRGB or ICC_ProfileGray + * may be returned if appropriate. + * + * @param in - the input stream to read the profile from. + * @return An ICC_Profile object + * + * @throws IllegalArgumentException if the profile data is an invalid + * v2 profile. + * @throws IOException if the stream could not be read. + */ + public static ICC_Profile getInstance(InputStream in) + throws IOException + { + // read the header + byte[] headerData = new byte[ProfileHeader.HEADERSIZE]; + if (in.read(headerData) != ProfileHeader.HEADERSIZE) + throw new IllegalArgumentException("Invalid profile header"); + + ProfileHeader header = new ProfileHeader(headerData); + + // verify it as a correct ICC header, but do not verify the + // size as we are reading from a stream. + header.verifyHeader(-1); + + // get the size + byte[] data = new byte[header.getSize()]; + System.arraycopy(headerData, 0, data, 0, ProfileHeader.HEADERSIZE); + + // read the rest + int totalBytes = header.getSize() - ProfileHeader.HEADERSIZE; + int bytesLeft = totalBytes; + while (bytesLeft > 0) + { + int read = in.read(data, + ProfileHeader.HEADERSIZE + (totalBytes - bytesLeft), + bytesLeft); + bytesLeft -= read; + } + + return getInstance(data); + } + + /** + * Returns the major version number + */ + public int getMajorVersion() + { + return header.getMajorVersion(); + } + + /** + * Returns the minor version number. + * + * Only the least-significant byte contains data, in BCD form: + * the least-significant nibble is the BCD bug fix revision, + * the most-significant nibble is the BCD minor revision number. + * + * (E.g. For a v2.1.0 profile this will return <code>0x10</code>) + */ + public int getMinorVersion() + { + return header.getMinorVersion(); + } + + /** + * Returns the device class of this profile, + * + * (E.g. CLASS_INPUT for a scanner profile, + * CLASS_OUTPUT for a printer) + */ + public int getProfileClass() + { + return header.getProfileClass(); + } + + /** + * Returns the color space of this profile, in terms + * of the color space constants defined in ColorSpace. + * (For example, it may be a ColorSpace.TYPE_RGB) + */ + public int getColorSpaceType() + { + return header.getColorSpace(); + } + + /** + * Returns the color space of this profile's Profile Connection Space (OCS) + * + * In terms of the color space constants defined in ColorSpace. + * This may be TYPE_XYZ or TYPE_Lab + */ + public int getPCSType() + { + return header.getProfileColorSpace(); + } + + /** + * Writes the profile data to an ICC profile file. + * @param filename - The name of the file to write + * @throws IOException if the write failed. + */ + public void write(String filename) throws IOException + { + FileOutputStream out = new FileOutputStream(filename); + write(out); + out.flush(); + out.close(); + } + + /** + * Writes the profile data in ICC profile file-format to a stream. + * This is useful for embedding ICC profiles in file formats which + * support this (such as JPEG and SVG). + * + * The stream is not closed after writing. + * @param out - The outputstream to which the profile data should be written + * @throws IOException if the write failed. + */ + public void write(OutputStream out) throws IOException + { + out.write(getData()); + } + + /** + * Returns the data corresponding to this ICC_Profile as a byte array. + * + * @return The data in a byte array, + * where the first element corresponds to first byte of the profile file. + */ + public byte[] getData() + { + int size = getSize(); + byte[] data = new byte[size]; + + // Header + System.arraycopy(header.getData(size), 0, data, 0, ProfileHeader.HEADERSIZE); + // # of tags + byte[] tt = getTagTable(); + System.arraycopy(tt, 0, data, ProfileHeader.HEADERSIZE, tt.length); + + Enumeration e = tagTable.elements(); + while (e.hasMoreElements()) + { + TagEntry tag = (TagEntry) e.nextElement(); + System.arraycopy(tag.getData(), 0, + data, tag.getOffset(), tag.getSize()); + } + return data; + } + + /** + * Returns the ICC profile tag data + * The non ICC-tag icSigHead is also permitted to request the header data. + * + * @param tagSignature The ICC signature of the requested tag + * @return A byte array containing the tag data + */ + public byte[] getData(int tagSignature) + { + if (tagSignature == icSigHead) + return header.getData(getSize()); + + TagEntry t = (TagEntry) tagTable.get(TagEntry.tagHashKey(tagSignature)); + if (t == null) + return null; + return t.getData(); + } + + /** + * Sets the ICC profile tag data. + * + * Note that an ICC profile can only contain one tag of each type, if + * a tag already exists with the given signature, it is replaced. + * + * @param tagSignature - The signature of the tag to set + * @param data - A byte array containing the tag data + */ + public void setData(int tagSignature, byte[] data) + { + profileID = -1; // Not a predefined color space if modified. + + if (tagSignature == icSigHead) + header = new ProfileHeader(data); + else + { + TagEntry t = new TagEntry(tagSignature, data); + tagTable.put(t.hashKey(), t); + } + } + + /** + * Get the number of components in the profile's device color space. + */ + public int getNumComponents() + { + int[] lookup = + { + ColorSpace.TYPE_RGB, 3, ColorSpace.TYPE_CMY, 3, + ColorSpace.TYPE_CMYK, 4, ColorSpace.TYPE_GRAY, 1, + ColorSpace.TYPE_YCbCr, 3, ColorSpace.TYPE_XYZ, 3, + ColorSpace.TYPE_Lab, 3, ColorSpace.TYPE_HSV, 3, + ColorSpace.TYPE_2CLR, 2, ColorSpace.TYPE_Luv, 3, + ColorSpace.TYPE_Yxy, 3, ColorSpace.TYPE_HLS, 3, + ColorSpace.TYPE_3CLR, 3, ColorSpace.TYPE_4CLR, 4, + ColorSpace.TYPE_5CLR, 5, ColorSpace.TYPE_6CLR, 6, + ColorSpace.TYPE_7CLR, 7, ColorSpace.TYPE_8CLR, 8, + ColorSpace.TYPE_9CLR, 9, ColorSpace.TYPE_ACLR, 10, + ColorSpace.TYPE_BCLR, 11, ColorSpace.TYPE_CCLR, 12, + ColorSpace.TYPE_DCLR, 13, ColorSpace.TYPE_ECLR, 14, + ColorSpace.TYPE_FCLR, 15 + }; + for (int i = 0; i < lookup.length; i += 2) + if (header.getColorSpace() == lookup[i]) + return lookup[i + 1]; + return 3; // should never happen. + } + + /** + * After deserializing we must determine if the class we want + * is really one of the more specialized ICC_ProfileRGB or + * ICC_ProfileGray classes. + */ + protected Object readResolve() throws ObjectStreamException + { + if (isRGBProfile(header, tagTable)) + return new ICC_ProfileRGB(getData()); + if (isGrayProfile(header, tagTable)) + return new ICC_ProfileGray(getData()); + return this; + } + + /** + * Deserializes an instance + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + String predef = (String) s.readObject(); + byte[] data = (byte[]) s.readObject(); + + if (data != null) + { + header = new ProfileHeader(data); + tagTable = createTagTable(data); + profileID = -1; // Not a predefined color space + } + + if (predef != null) + { + predef = predef.intern(); + if (predef.equals("CS_sRGB")) + createProfile(ColorSpace.CS_sRGB); + if (predef.equals("CS_LINEAR_RGB")) + createProfile(ColorSpace.CS_LINEAR_RGB); + if (predef.equals("CS_CIEXYZ")) + createProfile(ColorSpace.CS_CIEXYZ); + if (predef.equals("CS_GRAY")) + createProfile(ColorSpace.CS_GRAY); + if (predef.equals("CS_PYCC")) + createProfile(ColorSpace.CS_PYCC); + } + } + + /** + * Serializes an instance + * The format is a String and a byte array, + * The string is non-null if the instance is one of the built-in profiles. + * Otherwise the byte array is non-null and represents the profile data. + */ + private void writeObject(ObjectOutputStream s) throws IOException + { + s.defaultWriteObject(); + if (profileID == ColorSpace.CS_sRGB) + s.writeObject("CS_sRGB"); + else if (profileID == ColorSpace.CS_LINEAR_RGB) + s.writeObject("CS_LINEAR_RGB"); + else if (profileID == ColorSpace.CS_CIEXYZ) + s.writeObject("CS_CIEXYZ"); + else if (profileID == ColorSpace.CS_GRAY) + s.writeObject("CS_GRAY"); + else if (profileID == ColorSpace.CS_PYCC) + s.writeObject("CS_PYCC"); + else + { + s.writeObject(null); // null string + s.writeObject(getData()); // data + return; + } + s.writeObject(null); // null data + } + + /** + * Sorts a ICC profile byte array into TagEntry objects stored in + * a hash table. + */ + private static Hashtable createTagTable(byte[] data) + throws IllegalArgumentException + { + ByteBuffer buf = ByteBuffer.wrap(data); + int nTags = buf.getInt(tagTableOffset); + + Hashtable tagTable = new Hashtable(); + for (int i = 0; i < nTags; i++) + { + TagEntry te = new TagEntry(buf.getInt(tagTableOffset + + i * TagEntry.entrySize + 4), + buf.getInt(tagTableOffset + + i * TagEntry.entrySize + 8), + buf.getInt(tagTableOffset + + i * TagEntry.entrySize + 12), + data); + + if (tagTable.put(te.hashKey(), te) != null) + throw new IllegalArgumentException("Duplicate tag in profile:" + te); + } + return tagTable; + } + + /** + * Returns the total size of the padded, stored data + * Note: Tags must be stored on 4-byte aligned offsets. + */ + private int getSize() + { + int totalSize = ProfileHeader.HEADERSIZE; // size of header + + int tagTableSize = 4 + tagTable.size() * TagEntry.entrySize; // size of tag table + if ((tagTableSize & 0x0003) != 0) + tagTableSize += 4 - (tagTableSize & 0x0003); // pad + totalSize += tagTableSize; + + Enumeration e = tagTable.elements(); + while (e.hasMoreElements()) + { // tag data + int tagSize = ((TagEntry) e.nextElement()).getSize(); + if ((tagSize & 0x0003) != 0) + tagSize += 4 - (tagSize & 0x0003); // pad + totalSize += tagSize; + } + return totalSize; + } + + /** + * Generates the tag index table + */ + private byte[] getTagTable() + { + int tagTableSize = 4 + tagTable.size() * TagEntry.entrySize; + if ((tagTableSize & 0x0003) != 0) + tagTableSize += 4 - (tagTableSize & 0x0003); // pad + + int offset = 4; + int tagOffset = ProfileHeader.HEADERSIZE + tagTableSize; + ByteBuffer buf = ByteBuffer.allocate(tagTableSize); + buf.putInt(tagTable.size()); // number of tags + + Enumeration e = tagTable.elements(); + while (e.hasMoreElements()) + { + TagEntry tag = (TagEntry) e.nextElement(); + buf.putInt(offset, tag.getSignature()); + buf.putInt(offset + 4, tagOffset); + buf.putInt(offset + 8, tag.getSize()); + tag.setOffset(tagOffset); + int tagSize = tag.getSize(); + if ((tagSize & 0x0003) != 0) + tagSize += 4 - (tagSize & 0x0003); // pad + tagOffset += tagSize; + offset += 12; + } + return buf.array(); + } + + /** + * Returns if the criteria for an ICC_ProfileRGB are met. + * This means: + * Color space is TYPE_RGB + * (r,g,b)ColorantTags included + * (r,g,b)TRCTags included + * mediaWhitePointTag included + */ + private static boolean isRGBProfile(ProfileHeader header, Hashtable tags) + { + if (header.getColorSpace() != ColorSpace.TYPE_RGB) + return false; + if (tags.get(TagEntry.tagHashKey(icSigRedColorantTag)) == null) + return false; + if (tags.get(TagEntry.tagHashKey(icSigGreenColorantTag)) == null) + return false; + if (tags.get(TagEntry.tagHashKey(icSigBlueColorantTag)) == null) + return false; + if (tags.get(TagEntry.tagHashKey(icSigRedTRCTag)) == null) + return false; + if (tags.get(TagEntry.tagHashKey(icSigGreenTRCTag)) == null) + return false; + if (tags.get(TagEntry.tagHashKey(icSigBlueTRCTag)) == null) + return false; + return (tags.get(TagEntry.tagHashKey(icSigMediaWhitePointTag)) != null); + } + + /** + * Returns if the criteria for an ICC_ProfileGray are met. + * This means: + * Colorspace is TYPE_GRAY + * grayTRCTag included + * mediaWhitePointTag included + */ + private static boolean isGrayProfile(ProfileHeader header, Hashtable tags) + { + if (header.getColorSpace() != ColorSpace.TYPE_GRAY) + return false; + if (tags.get(TagEntry.tagHashKey(icSigGrayTRCTag)) == null) + return false; + return (tags.get(TagEntry.tagHashKey(icSigMediaWhitePointTag)) != null); + } + + /** + * Returns curve data for a 'curv'-type tag + * If it's a gamma curve, a single entry will be returned with the + * gamma value (including 1.0 for linear response) + * Otherwise the TRC table is returned. + * + * (Package private - used by ICC_ProfileRGB and ICC_ProfileGray) + */ + short[] getCurve(int signature) + { + byte[] data = getData(signature); + short[] curve; + + // can't find tag? + if (data == null) + return null; + + // not an curve type tag? + ByteBuffer buf = ByteBuffer.wrap(data); + if (buf.getInt(0) != 0x63757276) // 'curv' type + return null; + int count = buf.getInt(8); + if (count == 0) + { + curve = new short[1]; + curve[0] = 0x0100; // 1.00 in u8fixed8 + return curve; + } + if (count == 1) + { + curve = new short[1]; + curve[0] = buf.getShort(12); // other u8fixed8 gamma + return curve; + } + curve = new short[count]; + for (int i = 0; i < count; i++) + curve[i] = buf.getShort(12 + i * 2); + return curve; + } + + /** + * Returns XYZ tristimulus values for an 'XYZ ' type tag + * @return the XYZ values, or null if the tag was not an 'XYZ ' type tag. + * + * (Package private - used by ICC_ProfileXYZ and ICC_ProfileGray) + */ + float[] getXYZData(int signature) + { + byte[] data = getData(signature); + + // can't find tag? + if (data == null) + return null; + + // not an XYZData type tag? + ByteBuffer buf = ByteBuffer.wrap(data); + if (buf.getInt(0) != icSigXYZData) // 'XYZ ' type + return null; + + float[] point = new float[3]; + + // get the X,Y,Z tristimulus values + point[0] = ((float) buf.getInt(8)) / 65536f; + point[1] = ((float) buf.getInt(12)) / 65536f; + point[2] = ((float) buf.getInt(16)) / 65536f; + return point; + } + + /** + * Returns the profile ID if it's a predefined profile + * Or -1 for a profile loaded from an ICC profile + * + * (Package private - used by ICC_ColorSpace) + */ + int isPredefined() + { + return profileID; + } + + /** + * Creates a tag of XYZ-value type. + */ + private byte[] makeXYZData(float[] values) + { + ByteBuffer buf = ByteBuffer.allocate(20); + buf.putInt(0, icSigXYZData); // 'XYZ ' + buf.putInt(4, 0); + buf.putInt(8, (int) (values[0] * 65536.0)); + buf.putInt(12, (int) (values[1] * 65536.0)); + buf.putInt(16, (int) (values[2] * 65536.0)); + return buf.array(); + } + + /** + * Creates a tag of text type + */ + private byte[] makeTextTag(String text) + { + int length = text.length(); + ByteBuffer buf = ByteBuffer.allocate(8 + length + 1); + byte[] data; + try + { + data = text.getBytes("US-ASCII"); + } + catch (UnsupportedEncodingException e) + { + data = new byte[length]; // shouldn't happen + } + + buf.putInt(0, (int) 0x74657874); // 'text' + buf.putInt(4, 0); + for (int i = 0; i < length; i++) + buf.put(8 + i, data[i]); + buf.put(8 + length, (byte) 0); // null-terminate + return buf.array(); + } + + /** + * Creates a tag of textDescriptionType + */ + private byte[] makeDescTag(String text) + { + int length = text.length(); + ByteBuffer buf = ByteBuffer.allocate(90 + length + 1); + buf.putInt(0, (int) 0x64657363); // 'desc' + buf.putInt(4, 0); // reserved + buf.putInt(8, length + 1); // ASCII length, including null termination + byte[] data; + + try + { + data = text.getBytes("US-ASCII"); + } + catch (UnsupportedEncodingException e) + { + data = new byte[length]; // shouldn't happen + } + + for (int i = 0; i < length; i++) + buf.put(12 + i, data[i]); + buf.put(12 + length, (byte) 0); // null-terminate + + for (int i = 0; i < 39; i++) + buf.putShort(13 + length + (i * 2), (short) 0); // 78 bytes we can ignore + + return buf.array(); + } + + /** + * Creates a tag of TRC type (linear curve) + */ + private byte[] makeTRC() + { + ByteBuffer buf = ByteBuffer.allocate(12); + buf.putInt(0, 0x63757276); // 'curv' type + buf.putInt(4, 0); // reserved + buf.putInt(8, 0); + return buf.array(); + } + + /** + * Creates a tag of TRC type (single gamma value) + */ + private byte[] makeTRC(float gamma) + { + short gammaValue = (short) (gamma * 256f); + ByteBuffer buf = ByteBuffer.allocate(14); + buf.putInt(0, 0x63757276); // 'curv' type + buf.putInt(4, 0); // reserved + buf.putInt(8, 1); + buf.putShort(12, gammaValue); // 1.00 in u8fixed8 + return buf.array(); + } + + /** + * Creates a tag of TRC type (TRC curve points) + */ + private byte[] makeTRC(float[] trc) + { + ByteBuffer buf = ByteBuffer.allocate(12 + 2 * trc.length); + buf.putInt(0, 0x63757276); // 'curv' type + buf.putInt(4, 0); // reserved + buf.putInt(8, trc.length); // number of points + + // put the curve values + for (int i = 0; i < trc.length; i++) + buf.putShort(12 + i * 2, (short) (trc[i] * 65535f)); + + return buf.array(); + } + + /** + * Creates an identity color lookup table. + */ + private byte[] makeIdentityClut() + { + final int nIn = 3; + final int nOut = 3; + final int nInEntries = 256; + final int nOutEntries = 256; + final int gridpoints = 16; + + // gridpoints**nIn + final int clutSize = 2 * nOut * gridpoints * gridpoints * gridpoints; + final int totalSize = clutSize + 2 * nInEntries * nIn + + 2 * nOutEntries * nOut + 52; + + ByteBuffer buf = ByteBuffer.allocate(totalSize); + buf.putInt(0, 0x6D667432); // 'mft2' + buf.putInt(4, 0); // reserved + buf.put(8, (byte) nIn); // number input channels + buf.put(9, (byte) nOut); // number output channels + buf.put(10, (byte) gridpoints); // number gridpoints + buf.put(11, (byte) 0); // padding + + // identity matrix + buf.putInt(12, 65536); // = 1 in s15.16 fixed point + buf.putInt(16, 0); + buf.putInt(20, 0); + buf.putInt(24, 0); + buf.putInt(28, 65536); + buf.putInt(32, 0); + buf.putInt(36, 0); + buf.putInt(40, 0); + buf.putInt(44, 65536); + + buf.putShort(48, (short) nInEntries); // input table entries + buf.putShort(50, (short) nOutEntries); // output table entries + + // write the linear input channels, unsigned 16.16 fixed point, + // from 0.0 to FF.FF + for (int channel = 0; channel < 3; channel++) + for (int i = 0; i < nInEntries; i++) + { + short n = (short) ((i << 8) | i); // assumes 256 entries + buf.putShort(52 + (channel * nInEntries + i) * 2, n); + } + int clutOffset = 52 + nInEntries * nIn * 2; + + for (int x = 0; x < gridpoints; x++) + for (int y = 0; y < gridpoints; y++) + for (int z = 0; z < gridpoints; z++) + { + int offset = clutOffset + z * 2 * nOut + y * gridpoints * 2 * nOut + + x * gridpoints * gridpoints * 2 * nOut; + double xf = ((double) x) / ((double) gridpoints - 1.0); + double yf = ((double) y) / ((double) gridpoints - 1.0); + double zf = ((double) z) / ((double) gridpoints - 1.0); + buf.putShort(offset, (short) (xf * 65535.0)); + buf.putShort(offset + 2, (short) (yf * 65535.0)); + buf.putShort(offset + 4, (short) (zf * 65535.0)); + } + + for (int channel = 0; channel < 3; channel++) + for (int i = 0; i < nOutEntries; i++) + { + short n = (short) ((i << 8) | i); // assumes 256 entries + buf.putShort(clutOffset + clutSize + (channel * nOutEntries + i) * 2, + n); + } + + return buf.array(); + } + + /** + * Creates profile data corresponding to the built-in colorspaces. + */ + private void createProfile(int colorSpace) throws IllegalArgumentException + { + this.profileID = colorSpace; + header = new ProfileHeader(); + tagTable = new Hashtable(); + + switch (colorSpace) + { + case ColorSpace.CS_sRGB: + createRGBProfile(); + return; + case ColorSpace.CS_LINEAR_RGB: + createLinearRGBProfile(); + return; + case ColorSpace.CS_CIEXYZ: + createCIEProfile(); + return; + case ColorSpace.CS_GRAY: + createGrayProfile(); + return; + case ColorSpace.CS_PYCC: + createPyccProfile(); + return; + default: + throw new IllegalArgumentException("Not a predefined color space!"); + } + } + + /** + * Creates an ICC_Profile representing the sRGB color space + */ + private void createRGBProfile() + { + header.setColorSpace( ColorSpace.TYPE_RGB ); + header.setProfileColorSpace( ColorSpace.TYPE_XYZ ); + ICC_ColorSpace cs = new ICC_ColorSpace(this); + + float[] r = { 1f, 0f, 0f }; + float[] g = { 0f, 1f, 0f }; + float[] b = { 0f, 0f, 1f }; + float[] black = { 0f, 0f, 0f }; + + // CIE 1931 D50 white point (in Lab coordinates) + float[] white = D50; + + // Get tristimulus values (matrix elements) + r = cs.toCIEXYZ(r); + g = cs.toCIEXYZ(g); + b = cs.toCIEXYZ(b); + + // Generate the sRGB TRC curve, this is the linear->nonlinear + // RGB transform. + cs = new ICC_ColorSpace(getInstance(ICC_ColorSpace.CS_LINEAR_RGB)); + float[] points = new float[TRC_POINTS]; + float[] in = new float[3]; + for (int i = 0; i < TRC_POINTS; i++) + { + in[0] = in[1] = in[2] = ((float) i) / ((float) TRC_POINTS - 1); + in = cs.fromRGB(in); + // Note this value is the same for all components. + points[i] = in[0]; + } + + setData(icSigRedColorantTag, makeXYZData(r)); + setData(icSigGreenColorantTag, makeXYZData(g)); + setData(icSigBlueColorantTag, makeXYZData(b)); + setData(icSigMediaWhitePointTag, makeXYZData(white)); + setData(icSigMediaBlackPointTag, makeXYZData(black)); + setData(icSigRedTRCTag, makeTRC(points)); + setData(icSigGreenTRCTag, makeTRC(points)); + setData(icSigBlueTRCTag, makeTRC(points)); + setData(icSigCopyrightTag, makeTextTag(copyrightNotice)); + setData(icSigProfileDescriptionTag, makeDescTag("Generic sRGB")); + this.profileID = ColorSpace.CS_sRGB; + } + + /** + * Creates an linear sRGB profile + */ + private void createLinearRGBProfile() + { + header.setColorSpace(ColorSpace.TYPE_RGB); + header.setProfileColorSpace(ColorSpace.TYPE_XYZ); + ICC_ColorSpace cs = new ICC_ColorSpace(this); + + float[] r = { 1f, 0f, 0f }; + float[] g = { 0f, 1f, 0f }; + float[] b = { 0f, 0f, 1f }; + float[] black = { 0f, 0f, 0f }; + + float[] white = D50; + + // Get tristimulus values (matrix elements) + r = cs.toCIEXYZ(r); + g = cs.toCIEXYZ(g); + b = cs.toCIEXYZ(b); + + setData(icSigRedColorantTag, makeXYZData(r)); + setData(icSigGreenColorantTag, makeXYZData(g)); + setData(icSigBlueColorantTag, makeXYZData(b)); + + setData(icSigMediaWhitePointTag, makeXYZData(white)); + setData(icSigMediaBlackPointTag, makeXYZData(black)); + + setData(icSigRedTRCTag, makeTRC()); + setData(icSigGreenTRCTag, makeTRC()); + setData(icSigBlueTRCTag, makeTRC()); + setData(icSigCopyrightTag, makeTextTag(copyrightNotice)); + setData(icSigProfileDescriptionTag, makeDescTag("Linear RGB")); + this.profileID = ColorSpace.CS_LINEAR_RGB; + } + + /** + * Creates an CIE XYZ identity profile + */ + private void createCIEProfile() + { + header.setColorSpace( ColorSpace.TYPE_XYZ ); + header.setProfileColorSpace( ColorSpace.TYPE_XYZ ); + header.setProfileClass( CLASS_COLORSPACECONVERSION ); + ICC_ColorSpace cs = new ICC_ColorSpace(this); + + float[] white = D50; + + setData(icSigMediaWhitePointTag, makeXYZData(white)); + setData(icSigAToB0Tag, makeIdentityClut()); + setData(icSigBToA0Tag, makeIdentityClut()); + setData(icSigCopyrightTag, makeTextTag(copyrightNotice)); + setData(icSigProfileDescriptionTag, makeDescTag("CIE XYZ identity profile")); + this.profileID = ColorSpace.CS_CIEXYZ; + } + + /** + * Creates a linear gray ICC_Profile + */ + private void createGrayProfile() + { + header.setColorSpace(ColorSpace.TYPE_GRAY); + header.setProfileColorSpace(ColorSpace.TYPE_XYZ); + + // CIE 1931 D50 white point (in Lab coordinates) + float[] white = D50; + + setData(icSigMediaWhitePointTag, makeXYZData(white)); + setData(icSigGrayTRCTag, makeTRC(1.0f)); + setData(icSigCopyrightTag, makeTextTag(copyrightNotice)); + setData(icSigProfileDescriptionTag, makeDescTag("Linear grayscale")); + this.profileID = ColorSpace.CS_GRAY; + } + + /** + * XXX Implement me + */ + private void createPyccProfile() + { + header.setColorSpace(ColorSpace.TYPE_3CLR); + header.setProfileColorSpace(ColorSpace.TYPE_XYZ); + + // Create CLUTs here. :-) + + setData(icSigCopyrightTag, makeTextTag(copyrightNotice)); + setData(icSigProfileDescriptionTag, makeDescTag("Photo YCC")); + this.profileID = ColorSpace.CS_PYCC; + } +} // class ICC_Profile diff --git a/libjava/classpath/java/awt/color/ICC_ProfileGray.java b/libjava/classpath/java/awt/color/ICC_ProfileGray.java new file mode 100644 index 000000000..f85533cec --- /dev/null +++ b/libjava/classpath/java/awt/color/ICC_ProfileGray.java @@ -0,0 +1,133 @@ +/* ICC_ProfileGray.java -- the ICC profile for a Gray colorspace + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.color; + +/** + * ICC_ProfileGray - a special case of ICC_Profiles. + * + * The ICC_Profile.getInstance() method will return an instance of the + * ICC_ProfileGray subclass when all the following conditions are met: + * The device color space of the profile is TYPE_GRAY. + * The profile contains a gray TRCTag. + * The profile contains a mediaWhitePointTag. + * + * As per the ICC specification, the color space conversion can then + * be done through the following method: + * linearGray = grayTRC[deviceGray] + * + * Note that if the profile contains a CLUT for the color space conversion, + * it should be used instead, and the TRC information ignored. + * + * @author Sven de Marothy + * @since 1.2 + */ +public class ICC_ProfileGray extends ICC_Profile +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -1124721290732002649L; + private transient float[] whitePoint; + + /** + * Package-private constructor used by ICC_ColorSpace for creating an + * ICC_ProfileGray from a predefined ColorSpace (CS_GRAY) + */ + ICC_ProfileGray(int cspace) + { + super(cspace); + whitePoint = getXYZData(icSigMediaWhitePointTag); + } + + /** + * Package-private constructor used by ICC_ColorSpace for creating an + * ICC_ProfileGray from profile data. + */ + ICC_ProfileGray(byte[] data) + { + super(data); + whitePoint = getXYZData(icSigMediaWhitePointTag); + } + + + /** + * Returns the media white point of the profile. + */ + public float[] getMediaWhitePoint() + { + float[] wp = new float[3]; + wp[0] = whitePoint[0]; + wp[1] = whitePoint[1]; + wp[2] = whitePoint[2]; + return wp; + } + + /** + * Returns the TRC gamma value. + * @throws ProfileDataException if the TRC is described by a lookup + * table and not a gamma value. + */ + public float getGamma() + { + short[] data = getCurve(icSigGrayTRCTag); + if (data == null) + throw new IllegalArgumentException("Couldn't read Gray TRC data."); + if (data.length != 1) + throw new ProfileDataException("TRC is a table, not a gamma value."); + + // convert the unsigned 7.8 fixed-point gamma to a float. + double gamma = (double) (data[0] & (0xFFFF)) / 256.0; + return (float) gamma; + } + + /** + * Returns the TRC lookup table. + * @throws ProfileDataException if the TRC is described by a gamma value + * and not a lookup table. + */ + public short[] getTRC() + { + short[] data = getCurve(icSigGrayTRCTag); + if (data == null) + throw new IllegalArgumentException("Couldn't read Gray TRC data."); + if (data.length <= 1) + throw new ProfileDataException("Gamma value, not a TRC table."); + return data; + } +} // class ICC_ProfileGray diff --git a/libjava/classpath/java/awt/color/ICC_ProfileRGB.java b/libjava/classpath/java/awt/color/ICC_ProfileRGB.java new file mode 100644 index 000000000..cfdbf6e54 --- /dev/null +++ b/libjava/classpath/java/awt/color/ICC_ProfileRGB.java @@ -0,0 +1,227 @@ +/* ICC_ProfileRGB.java -- the ICC profile for a RGB colorspace + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.color; + +/** + * ICC_ProfileRGB - a special case of ICC_Profiles. + * + * The ICC_Profile.getInstance() method will return an instance of the + * ICC_ProfileRGB subclass when all the following conditions are met: + * The device color space of the profile is TYPE_RGB. + * The profile contains red, green and blue ColorantTags. + * The profile contains red, green and blue TRCTags. + * The profile contains a mediaWhitePointTag included. + * + * As per the ICC specification, the color space conversion can then + * be done through the following method: + * linearR = redTRC[deviceR] + * linearG = greenTRC[deviceG] + * linearB = blueTRC[deviceB] + * TRC curves are either a single gamma value, or a 1-dimensional lookup table. + * + * Followed by the matrix transform: + * PCS = M*linear + * + * Where PCS is the vector of profile color space (must be XYZ) coordinates, + * linear is the vector of linear RGB coordinates, and the matrix M is + * constructed from the ColorantTags, where the columns are red, green and + * blue respectively, and the rows are X, Y and Z. + * + * Note that if the profile contains a CLUT for the color space conversion, + * it should be used instead, and the TRC information ignored. + * + * @author Sven de Marothy + * @since 1.2 + */ +public class ICC_ProfileRGB extends ICC_Profile +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 8505067385152579334L; + + public static final int REDCOMPONENT = 0; + + public static final int GREENCOMPONENT = 1; + + public static final int BLUECOMPONENT = 2; + + private transient float[][] matrix; + + private transient float[] gamma; + + private transient float[] whitePoint; + + + /** + * Package-private constructor used by ICC_ColorSpace for creating an + * ICC_ProfileRGB from a predefined ColorSpace (CS_LINEAR_RGB and CS_sRGB) + */ + ICC_ProfileRGB(int cspace) + { + super(cspace); + matrix = createMatrix(); + whitePoint = getXYZData(icSigMediaWhitePointTag); + } + + /** + * Package-private constructor used by ICC_ColorSpace for creating an + * ICC_ProfileRGB from profile data. + */ + ICC_ProfileRGB(byte[] data) + { + super(data); + matrix = createMatrix(); + whitePoint = getXYZData(icSigMediaWhitePointTag); + } + + /** + * Returns the media white point of the profile. + */ + public float[] getMediaWhitePoint() + { + float[] wp = new float[3]; + wp[0] = whitePoint[0]; + wp[1] = whitePoint[1]; + wp[2] = whitePoint[2]; + return wp; + } + + /** + * Returns the colorant matrix of the conversion. + */ + public float[][] getMatrix() + { + float[][] mat = new float[3][3]; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + mat[i][j] = matrix[i][j]; + return mat; + } + + /** + * Returns the gamma value of a component + * @throws ProfileDataException if the TRC is described by a lookup + * table and not a gamma value. + */ + public float getGamma(int component) + { + short[] data; + switch (component) + { + case REDCOMPONENT: + data = getCurve(icSigRedTRCTag); + break; + case GREENCOMPONENT: + data = getCurve(icSigGreenTRCTag); + break; + case BLUECOMPONENT: + data = getCurve(icSigBlueTRCTag); + break; + default: + throw new IllegalArgumentException("Not a valid component"); + } + if (data == null) + throw new IllegalArgumentException("Error reading TRC"); + + if (data.length != 1) + throw new ProfileDataException("Not a single-gamma TRC"); + + // convert the unsigned 7.8 fixed-point gamma to a float. + float gamma = (float) (((int) data[0] & 0xFF00) >> 8); + double fraction = ((int) data[0] & 0x00FF) / 256.0; + gamma += (float) fraction; + return gamma; + } + + /** + * Returns the TRC lookup table for a component + * @throws ProfileDataException if the TRC is described by a gamma + * value and not a lookup table. + */ + public short[] getTRC(int component) + { + short[] data; + switch (component) + { + case REDCOMPONENT: + data = getCurve(icSigRedTRCTag); + break; + case GREENCOMPONENT: + data = getCurve(icSigGreenTRCTag); + break; + case BLUECOMPONENT: + data = getCurve(icSigBlueTRCTag); + break; + default: + throw new IllegalArgumentException("Not a valid component"); + } + if (data == null) + throw new IllegalArgumentException("Error reading TRC"); + + if (data.length <= 1) + throw new ProfileDataException("Gamma value, not a TRC table."); + + return data; + } + + /** + * Creates the colorspace conversion matrix from the RGB tristimulus + * values. + */ + private float[][] createMatrix() throws IllegalArgumentException + { + float[][] mat = new float[3][3]; + float[] r; + float[] g; + float[] b; + r = getXYZData(icSigRedColorantTag); + g = getXYZData(icSigGreenColorantTag); + b = getXYZData(icSigBlueColorantTag); + if (r == null || g == null || b == null) + throw new IllegalArgumentException("Error reading colorant tags!"); + for (int i = 0; i < 3; i++) + { + mat[i][0] = r[i]; + mat[i][1] = g[i]; + mat[i][2] = b[i]; + } + return mat; + } +} // class ICC_ProfileRGB diff --git a/libjava/classpath/java/awt/color/ProfileDataException.java b/libjava/classpath/java/awt/color/ProfileDataException.java new file mode 100644 index 000000000..1af23b183 --- /dev/null +++ b/libjava/classpath/java/awt/color/ProfileDataException.java @@ -0,0 +1,64 @@ +/* ProfileDataException.java -- error in processing an ICC_Profile + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.color; + +/** + * Thrown when there is an error accessing or processing an + * <code>ICC_Profile</code>. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @status updated to 1.4 + */ +public class ProfileDataException extends RuntimeException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 7286140888240322498L; + + /** + * Create a new instance with a specified detailed error message. + * + * @param message the message + */ + public ProfileDataException(String message) + { + super(message); + } +} // class ProfileDataException diff --git a/libjava/classpath/java/awt/color/package.html b/libjava/classpath/java/awt/color/package.html new file mode 100644 index 000000000..9a08577c1 --- /dev/null +++ b/libjava/classpath/java/awt/color/package.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in java.awt.color package. + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - java.awt.color</title></head> + +<body> +<p>Classes to represent color spaces and profiles.</p> + +</body> +</html> diff --git a/libjava/classpath/java/awt/datatransfer/Clipboard.java b/libjava/classpath/java/awt/datatransfer/Clipboard.java new file mode 100644 index 000000000..d0a1d3a3f --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/Clipboard.java @@ -0,0 +1,213 @@ +/* Clipboard.java -- Class for transferring data via cut and paste. + Copyright (C) 1999, 2001, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.datatransfer; + +import java.io.IOException; +import java.util.ArrayList; + +/** + * This class allows data to be transferred using a cut and paste type + * mechanism. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Mark J. Wielaard (mark@klomp.org) + */ +public class Clipboard +{ + /** + * The data currently on this clipboard. For use by + * subclasses. Also returned by the public method getContents(). + */ + protected Transferable contents; + + /** + * The owner of this clipboard. + */ + protected ClipboardOwner owner; + + // The clipboard name + private final String name; + + // The flavor listeners (most likely small). + private final ArrayList listeners = new ArrayList(3); + + /** + * Initializes a new instance of <code>Clipboard</code> with the + * specified name. + * + * @param name The clipboard name. + */ + public Clipboard(String name) + { + this.name = name; + } + + /** + * Returns the name of the clipboard. + */ + public String getName() + { + return name; + } + + /** + * Returns the contents of the clipboard. + * + * @param requestor The object requesting the contents. This + * implementation ignores this parameter. + * + * @exception IllegalStateException If the clipboard is currently unavailable + */ + public synchronized Transferable getContents(Object requestor) + { + return contents; + } + + /** + * Sets the content and owner of this clipboard. If the given owner + * is different from the current owner then <code>lostOwnership()</code> + * is called on the current owner with the old contents of the given + * clipboard. + * + * @param contents The new clipboard contents. + * @param owner The new clipboard owner + * + * @exception IllegalStateException If the clipboard is currently unavailable + */ + public synchronized void setContents(Transferable contents, + ClipboardOwner owner) + { + Transferable oldContents = getContents(null); + this.contents = contents; + if (this.owner != owner) + { + ClipboardOwner oldOwner = this.owner; + this.owner = owner; + if (oldOwner != null) + oldOwner.lostOwnership(this, oldContents); + } + + FlavorListener[] fs = getFlavorListeners(); + if (fs.length > 0) + { + // We are a bit optimistic here. We assume DataFlavors will be + // given in the same order. If the number of flavors is + // different or the order of the DataFlavors in the list then + // fire a change event. + boolean newFlavors = ((contents != null && oldContents == null) + || (contents == null && oldContents != null)); + if (!newFlavors && contents != null && oldContents != null) + { + DataFlavor[] df1 = contents.getTransferDataFlavors(); + DataFlavor[] df2 = oldContents.getTransferDataFlavors(); + newFlavors = df1.length != df2.length; + + for (int i = 0; !newFlavors && i < df1.length; i++) + newFlavors = !df1[i].equals(df2[i]); + } + + if (newFlavors) + { + FlavorEvent e = new FlavorEvent(this); + for (int i = 0; i < fs.length; i++) + fs[i].flavorsChanged(e); + } + } + } + + public DataFlavor[] getAvailableDataFlavors() + { + Transferable c = getContents(null); + if (c == null) + return new DataFlavor[0]; + else + return c.getTransferDataFlavors(); + } + + public boolean isDataFlavorAvailable(DataFlavor flavor) + { + DataFlavor[] fs = getAvailableDataFlavors(); + for (int i = 0; i < fs.length; i++) + if (flavor.equals(fs[i])) + return true; + + return false; + } + + public Object getData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException + { + Transferable c = getContents(null); + if (c == null) + throw new UnsupportedFlavorException(flavor); + else + return c.getTransferData(flavor); + } + + public void addFlavorListener(FlavorListener listener) + { + if (listener == null) + return; + + synchronized(listeners) + { + listeners.add(listener); + } + } + + public void removeFlavorListener(FlavorListener listener) + { + if (listener == null) + return; + + synchronized(listeners) + { + listeners.remove(listener); + } + } + + public FlavorListener[] getFlavorListeners() + { + synchronized(listeners) + { + return (FlavorListener[]) + listeners.toArray(new FlavorListener[listeners.size()]); + } + } +} diff --git a/libjava/classpath/java/awt/datatransfer/ClipboardOwner.java b/libjava/classpath/java/awt/datatransfer/ClipboardOwner.java new file mode 100644 index 000000000..b98059a0e --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/ClipboardOwner.java @@ -0,0 +1,56 @@ +/* ClipboardOwner.java -- Interface for clipboard providers + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.datatransfer; + +/** + * This interface is for classes that will own a clipboard object. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface ClipboardOwner +{ + /** + * This method is called to notify this object that it no longer + * has ownership of the specified <code>Clipboard</code>. + * + * @param clipboard The clipboard for which ownership was lost. + * @param contents The contents of the clipboard which are no longer owned. + */ + void lostOwnership (Clipboard clipboard, Transferable contents); +} diff --git a/libjava/classpath/java/awt/datatransfer/DataFlavor.java b/libjava/classpath/java/awt/datatransfer/DataFlavor.java new file mode 100644 index 000000000..e54770434 --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/DataFlavor.java @@ -0,0 +1,1026 @@ +/* DataFlavor.java -- A type of data to transfer via the clipboard. + Copyright (C) 1999, 2001, 2004, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.datatransfer; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.OptionalDataException; +import java.io.Reader; +import java.io.Serializable; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.rmi.Remote; + +/** + * This class represents a particular data format used for transferring + * data via the clipboard. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class DataFlavor implements java.io.Externalizable, Cloneable +{ + static final long serialVersionUID = 8367026044764648243L; + + // FIXME: Serialization: Need to write methods for. + + /** + * This is the data flavor used for tranferring plain text. The MIME + * type is "text/plain; charset=unicode". The representation class + * is <code>java.io.InputStream</code>. + * + * @deprecated The charset unicode is platform specific and InputStream + * deals with bytes not chars. Use <code>getRederForText()</code>. + */ + public static final DataFlavor plainTextFlavor = + new DataFlavor("text/plain; charset=unicode; class=java.io.InputStream", + "plain unicode text"); + + /** + * This is the data flavor used for transferring Java strings. The + * MIME type is "application/x-java-serialized-object" and the + * representation class is <code>java.lang.String</code>. + */ + public static final DataFlavor stringFlavor = + new DataFlavor(java.lang.String.class, "Java Unicode String"); + + /** + * This is a data flavor used for transferring lists of files. The + * representation type is a <code>java.util.List</code>, with each + * element of the list being a <code>java.io.File</code>. + */ + public static final DataFlavor javaFileListFlavor = + new DataFlavor("application/x-java-file-list; class=java.util.List", + "Java File List"); + + /** + * This is an image flavor used for transferring images. The + * representation type is a <code>java.awt.Image</code>. + */ + public static final DataFlavor imageFlavor = + new DataFlavor(java.awt.Image.class, "Java Image"); + + /** + * This is the MIME type used for transferring a serialized object. + * The representation class is the type of object be deserialized. + */ + public static final String javaSerializedObjectMimeType = + "application/x-java-serialized-object"; + + /** + * This is the MIME type used to transfer a Java object reference within + * the same JVM. The representation class is the class of the object + * being transferred. + */ + public static final String javaJVMLocalObjectMimeType = + "application/x-java-jvm-local-objectref"; + + /** + * This is the MIME type used to transfer a link to a remote object. + * The representation class is the type of object being linked to. + */ + public static final String javaRemoteObjectMimeType = + "application/x-java-remote-object"; + + /* + * Instance Variables + */ + + // The MIME type for this flavor + private MimeType mimeType; + + // The representation class for this flavor + private Class<?> representationClass; + + // The human readable name of this flavor + private String humanPresentableName; + + /* + * Static Methods + */ + + /** + * This method attempts to load the named class. The following class + * loaders are searched in order: the bootstrap class loader, the + * system class loader, the context class loader (if it exists), and + * the specified fallback class loader. + * + * @param className The name of the class to load. + * @param classLoader The class loader to use if all others fail, which + * may be <code>null</code>. + * + * @exception ClassNotFoundException If the class cannot be loaded. + */ + protected static final Class<?> tryToLoadClass(String className, + ClassLoader classLoader) + throws ClassNotFoundException + { + // Bootstrap + try + { + return Class.forName(className); + } + catch(ClassNotFoundException cnfe) + { + // Ignored. + } + + // System + try + { + ClassLoader loader = ClassLoader.getSystemClassLoader(); + return Class.forName(className, true, loader); + } + catch(ClassNotFoundException cnfe) + { + // Ignored. + } + + // Context + try + { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + return Class.forName(className, true, loader); + } + catch(ClassNotFoundException cnfe) + { + // Ignored. + } + + if (classLoader != null) + return Class.forName(className, true, classLoader); + + throw new ClassNotFoundException(className); + } + + /** + * XXX - Currently returns <code>plainTextFlavor</code>. + */ + public static final DataFlavor getTextPlainUnicodeFlavor() + { + return plainTextFlavor; + } + + /** + * Selects the best supported text flavor on this implementation. + * Returns <code>null</code> when none of the given flavors is liked. + * + * The <code>DataFlavor</code> returned the first data flavor in the + * array that has either a representation class which is (a subclass of) + * <code>Reader</code> or <code>String</code>, or has a representation + * class which is (a subclass of) <code>InputStream</code> and has a + * primary MIME type of "text" and has an supported encoding. + */ + public static final DataFlavor + selectBestTextFlavor(DataFlavor[] availableFlavors) + { + for(int i = 0; i < availableFlavors.length; i++) + { + DataFlavor df = availableFlavors[i]; + Class c = df.representationClass; + + // A Reader or String is good. + if ((Reader.class.isAssignableFrom(c)) + || (String.class.isAssignableFrom(c))) + return df; + + // A InputStream is good if the mime primary type is "text" + if ((InputStream.class.isAssignableFrom(c)) + && ("text".equals(df.getPrimaryType()))) + { + String encoding = availableFlavors[i].getParameter("charset"); + if (encoding == null) + encoding = "us-ascii"; + Reader r = null; + try + { + // Try to construct a dummy reader with the found encoding + r = new InputStreamReader + (new ByteArrayInputStream(new byte[0]), encoding); + } + catch(UnsupportedEncodingException uee) { /* ignore */ } + + if (r != null) + return df; + } + } + + // Nothing found + return null; + } + + + /* + * Constructors + */ + + /** + * Empty public constructor needed for externalization. + * Should not be used for normal instantiation. + */ + public DataFlavor() + { + // Used for deserialization only, nothing to do here. + } + + /** + * Initializes a new instance of <code>DataFlavor</code>. The class + * and human readable name are specified, the MIME type will be + * "application/x-java-serialized-object". If the human readable name + * is not specified (<code>null</code>) then the human readable name + * will be the same as the MIME type. + * + * @param representationClass The representation class for this object. + * @param humanPresentableName The display name of the object. + */ + public DataFlavor(Class<?> representationClass, String humanPresentableName) + { + if (representationClass == null) + throw new NullPointerException("representationClass must not be null"); + try + { + mimeType = new MimeType(javaSerializedObjectMimeType); + } + catch (MimeTypeParseException ex) + { + // Must not happen as we use a constant string. + assert false; + } + if (humanPresentableName == null) + humanPresentableName = javaSerializedObjectMimeType; + this.humanPresentableName = humanPresentableName; + this.representationClass = representationClass; + } + + /** + * Initializes a new instance of <code>DataFlavor</code> with the + * specified MIME type and description. If the MIME type has a + * "class=<rep class>" parameter then the representation class will + * be the class name specified. Otherwise the class defaults to + * <code>java.io.InputStream</code>. If the human readable name + * is not specified (<code>null</code>) then the human readable name + * will be the same as the MIME type. + * + * @param mimeType The MIME type for this flavor. + * @param humanPresentableName The display name of this flavor. + * @param classLoader The class loader for finding classes if the default + * class loaders do not work. + * + * @exception IllegalArgumentException If the representation class + * specified cannot be loaded. + * @exception ClassNotFoundException If the class is not loaded. + */ + public DataFlavor(String mimeType, String humanPresentableName, + ClassLoader classLoader) + throws ClassNotFoundException + { + init(mimeType, humanPresentableName, classLoader); + } + + /** + * Initializes a new instance of <code>DataFlavor</code> with the + * specified MIME type and description. If the MIME type has a + * "class=<rep class>" parameter then the representation class will + * be the class name specified. Otherwise the class defaults to + * <code>java.io.InputStream</code>. If the human readable name + * is not specified (<code>null</code>) then the human readable name + * will be the same as the MIME type. This is the same as calling + * <code>new DataFlavor(mimeType, humanPresentableName, null)</code>. + * + * @param mimeType The MIME type for this flavor. + * @param humanPresentableName The display name of this flavor. + * + * @exception IllegalArgumentException If the representation class + * specified cannot be loaded. + */ + public DataFlavor(String mimeType, String humanPresentableName) + { + try + { + init(mimeType, humanPresentableName, getClass().getClassLoader()); + } + catch (ClassNotFoundException ex) + { + IllegalArgumentException iae = + new IllegalArgumentException("Class not found: " + ex.getMessage()); + iae.initCause(ex); + throw iae; + } + } + + /** + * Initializes a new instance of <code>DataFlavor</code> with the specified + * MIME type. This type can have a "class=" parameter to specify the + * representation class, and then the class must exist or an exception will + * be thrown. If there is no "class=" parameter then the representation class + * will be <code>java.io.InputStream</code>. This is the same as calling + * <code>new DataFlavor(mimeType, null)</code>. + * + * @param mimeType The MIME type for this flavor. + * + * @exception IllegalArgumentException If a class is not specified in + * the MIME type. + * @exception ClassNotFoundException If the class cannot be loaded. + */ + public DataFlavor(String mimeType) throws ClassNotFoundException + { + init(mimeType, null, getClass().getClassLoader()); + } + + /** + * Called by various constructors to initialize this object. + * + * @param mime the mime string + * @param humanPresentableName the human presentable name + * @param loader the class loader to use for loading the representation + * class + */ + private void init(String mime, String humanPresentableName, + ClassLoader loader) + throws ClassNotFoundException + { + if (mime == null) + throw new NullPointerException("The mime type must not be null"); + try + { + mimeType = new MimeType(mime); + } + catch (MimeTypeParseException ex) + { + IllegalArgumentException iae = + new IllegalArgumentException("Invalid mime type"); + iae.initCause(ex); + throw iae; + } + String className = mimeType.getParameter("class"); + if (className == null) + { + if (mimeType.getBaseType().equals(javaSerializedObjectMimeType)) + throw new IllegalArgumentException("Serialized object type must have" + + " a representation class parameter"); + else + representationClass = java.io.InputStream.class; + } + else + representationClass = tryToLoadClass(className, loader); + mimeType.addParameter("class", representationClass.getName()); + + if (humanPresentableName == null) + { + humanPresentableName = mimeType.getParameter("humanPresentableName"); + if (humanPresentableName == null) + humanPresentableName = mimeType.getBaseType(); + } + this.humanPresentableName = humanPresentableName; + } + + /** + * Returns the MIME type of this flavor. + * + * @return The MIME type for this flavor. + */ + public String getMimeType() + { + return(mimeType.toString()); + } + + /** + * Returns the representation class for this flavor. + * + * @return The representation class for this flavor. + */ + public Class<?> getRepresentationClass() + { + return(representationClass); + } + + /** + * Returns the human presentable name for this flavor. + * + * @return The human presentable name for this flavor. + */ + public String getHumanPresentableName() + { + return(humanPresentableName); + } + + /** + * Returns the primary MIME type for this flavor. + * + * @return The primary MIME type for this flavor. + */ + public String getPrimaryType() + { + return(mimeType.getPrimaryType()); + } + + /** + * Returns the MIME subtype for this flavor. + * + * @return The MIME subtype for this flavor. + */ + public String getSubType() + { + return mimeType.getSubType(); + } + + /** + * Returns the value of the named MIME type parameter, or <code>null</code> + * if the parameter does not exist. + * + * @param paramName The name of the paramter. + * + * @return The value of the parameter. + */ + public String getParameter(String paramName) + { + if ("humanPresentableName".equals(paramName)) + return getHumanPresentableName(); + + return mimeType.getParameter(paramName); + } + + /** + * Sets the human presentable name to the specified value. + * + * @param humanPresentableName The new display name. + */ + public void setHumanPresentableName(String humanPresentableName) + { + this.humanPresentableName = humanPresentableName; + } + + /** + * Tests the MIME type of this object for equality against the specified + * MIME type. Ignores parameters. + * + * @param mimeType The MIME type to test against. + * + * @return <code>true</code> if the MIME type is equal to this object's + * MIME type (ignoring parameters), <code>false</code> otherwise. + * + * @exception NullPointerException If mimeType is null. + */ + public boolean isMimeTypeEqual(String mimeType) + { + if (mimeType == null) + throw new NullPointerException("mimeType must not be null"); + boolean equal = false; + try + { + if (this.mimeType != null) + { + MimeType other = new MimeType(mimeType); + equal = this.mimeType.matches(other); + } + } + catch (MimeTypeParseException ex) + { + // Return false in this case. + } + return equal; + } + + /** + * Tests the MIME type of this object for equality against the specified + * data flavor's MIME type + * + * @param flavor The flavor to test against. + * + * @return <code>true</code> if the flavor's MIME type is equal to this + * object's MIME type, <code>false</code> otherwise. + */ + public final boolean isMimeTypeEqual(DataFlavor flavor) + { + return isMimeTypeEqual(flavor.getMimeType()); + } + + /** + * Tests whether or not this flavor represents a serialized object. + * + * @return <code>true</code> if this flavor represents a serialized + * object, <code>false</code> otherwise. + */ + public boolean isMimeTypeSerializedObject() + { + return isMimeTypeEqual(javaSerializedObjectMimeType); + } + + /** + * Tests whether or not this flavor has a representation class of + * <code>java.io.InputStream</code>. + * + * @return <code>true</code> if the representation class of this flavor + * is <code>java.io.InputStream</code>, <code>false</code> otherwise. + */ + public boolean isRepresentationClassInputStream() + { + return InputStream.class.isAssignableFrom(representationClass); + } + + /** + * Tests whether the representation class for this flavor is + * serializable. + * + * @return <code>true</code> if the representation class is serializable, + * <code>false</code> otherwise. + */ + public boolean isRepresentationClassSerializable() + { + return Serializable.class.isAssignableFrom(representationClass); + } + + /** + * Tests whether the representation class for his flavor is remote. + * + * @return <code>true</code> if the representation class is remote, + * <code>false</code> otherwise. + */ + public boolean isRepresentationClassRemote() + { + return Remote.class.isAssignableFrom (representationClass); + } + + /** + * Tests whether or not this flavor represents a serialized object. + * + * @return <code>true</code> if this flavor represents a serialized + * object, <code>false</code> otherwise. + */ + public boolean isFlavorSerializedObjectType() + { + return isRepresentationClassSerializable() + && isMimeTypeEqual(javaSerializedObjectMimeType); + } + + /** + * Tests whether or not this flavor represents a remote object. + * + * @return <code>true</code> if this flavor represents a remote object, + * <code>false</code> otherwise. + */ + public boolean isFlavorRemoteObjectType() + { + return isRepresentationClassRemote() + && isRepresentationClassSerializable() + && isMimeTypeEqual(javaRemoteObjectMimeType); + } + + /** + * Tests whether or not this flavor represents a list of files. + * + * @return <code>true</code> if this flavor represents a list of files, + * <code>false</code> otherwise. + */ + public boolean isFlavorJavaFileListType() + { + if (getPrimaryType().equals(javaFileListFlavor.getPrimaryType()) + && getSubType().equals(javaFileListFlavor.getSubType()) + && javaFileListFlavor.representationClass + .isAssignableFrom(representationClass)) + return true; + + return false ; + } + + /** + * Returns a copy of this object. + * + * @return A copy of this object. + * + * @exception CloneNotSupportedException If the object's class does not support + * the Cloneable interface. Subclasses that override the clone method can also + * throw this exception to indicate that an instance cannot be cloned. + */ + public Object clone () throws CloneNotSupportedException + { + // FIXME - This cannot be right. + try + { + return super.clone(); + } + catch(Exception e) + { + return null; + } + } + + /** + * This method test the specified <code>DataFlavor</code> for equality + * against this object. This will be true if the MIME type and + * representation class are the equal. If the primary type is 'text' + * then also the value of the charset parameter is compared. In such a + * case when the charset parameter isn't given then the charset is + * assumed to be equal to the default charset of the platform. All + * other parameters are ignored. + * + * @param flavor The <code>DataFlavor</code> to test against. + * + * @return <code>true</code> if the flavor is equal to this object, + * <code>false</code> otherwise. + */ + public boolean equals(DataFlavor flavor) + { + if (flavor == null) + return false; + + String primary = getPrimaryType(); + if (! primary.equals(flavor.getPrimaryType())) + return false; + + String sub = getSubType(); + if (! sub.equals(flavor.getSubType())) + return false; + + if (! this.representationClass.equals(flavor.representationClass)) + return false; + + if (primary.equals("text")) + if (! isRepresentationClassCharBuffer() + && ! isRepresentationClassReader() + && representationClass != java.lang.String.class + && ! (representationClass.isArray() + && representationClass.getComponentType() == Character.TYPE)) + { + String charset = getParameter("charset"); + String otherset = flavor.getParameter("charset"); + String defaultset = Charset.defaultCharset().name(); + + if (charset == null || charset.equals(defaultset)) + return (otherset == null || otherset.equals(defaultset)); + + return charset.equals(otherset); + } + + return true; + } + + /** + * This method test the specified <code>Object</code> for equality + * against this object. This will be true if the following conditions + * are met: + * <p> + * <ul> + * <li>The object is not <code>null</code>.</li> + * <li>The object is an instance of <code>DataFlavor</code>.</li> + * <li>The object's MIME type and representation class are equal to + * this object's.</li> + * </ul> + * + * @param obj The <code>Object</code> to test against. + * + * @return <code>true</code> if the flavor is equal to this object, + * <code>false</code> otherwise. + */ + public boolean equals(Object obj) + { + if (! (obj instanceof DataFlavor)) + return false; + + return equals((DataFlavor) obj); + } + + /** + * Tests whether or not the specified string is equal to the MIME type + * of this object. + * + * @param str The string to test against. + * + * @return <code>true</code> if the string is equal to this object's MIME + * type, <code>false</code> otherwise. + * + * @deprecated Not compatible with <code>hashCode()</code>. + * Use <code>isMimeTypeEqual()</code> + */ + public boolean equals(String str) + { + return isMimeTypeEqual(str); + } + + /** + * Returns the hash code for this data flavor. + * The hash code is based on the (lower case) mime type and the + * representation class. + */ + public int hashCode() + { + return mimeType.toString().hashCode() ^ representationClass.hashCode(); + } + + /** + * Returns <code>true</code> when the given <code>DataFlavor</code> + * matches this one. + */ + public boolean match(DataFlavor dataFlavor) + { + // XXX - How is this different from equals? + return equals(dataFlavor); + } + + /** + * This method exists for backward compatibility. It simply returns + * the same name/value pair passed in. + * + * @param name The parameter name. + * @param value The parameter value. + * + * @return The name/value pair. + * + * @deprecated + */ + protected String normalizeMimeTypeParameter(String name, String value) + { + return name + "=" + value; + } + + /** + * This method exists for backward compatibility. It simply returns + * the MIME type string unchanged. + * + * @param type The MIME type. + * + * @return The MIME type. + * + * @deprecated + */ + protected String normalizeMimeType(String type) + { + return type; + } + + /** + * Serialize this class. + * + * @param stream The <code>ObjectOutput</code> stream to serialize to. + * + * @exception IOException If an error occurs. + */ + public void writeExternal(ObjectOutput stream) + throws IOException + { + if (mimeType != null) + { + mimeType.addParameter("humanPresentableName", humanPresentableName); + stream.writeObject(mimeType); + mimeType.removeParameter("humanPresentableName"); + } + else + stream.writeObject(null); + stream.writeObject(representationClass); + } + + + /** + * De-serialize this class. + * + * @param stream The <code>ObjectInput</code> stream to deserialize from. + * + * @exception IOException If an error ocurs. + * @exception ClassNotFoundException If the class for an object being restored + * cannot be found. + */ + public void readExternal(ObjectInput stream) + throws IOException, ClassNotFoundException + { + mimeType = (MimeType) stream.readObject(); + String className = null; + if (mimeType != null) + { + humanPresentableName = + mimeType.getParameter("humanPresentableName"); + mimeType.removeParameter("humanPresentableName"); + className = mimeType.getParameter("class"); + if (className == null) + throw new IOException("No class in mime type"); + } + try + { + representationClass = (Class) stream.readObject(); + } + catch (OptionalDataException ex) + { + if (ex.eof && ex.length == 0) + { + if (className != null) + representationClass = tryToLoadClass(className, + getClass().getClassLoader()); + } + else + throw ex; + } + } + + /** + * Returns a string representation of this DataFlavor. Including the + * representation class name, MIME type and human presentable name. + */ + public String toString() + { + return (getClass().getName() + + "[representationClass=" + getRepresentationClass().getName() + + ",mimeType=" + getMimeType() + + ",humanPresentableName=" + getHumanPresentableName() + + "]"); + } + + /** + * XXX - Currently returns <code>java.io.InputStream</code>. + * + * @since 1.3 + */ + public final Class<?> getDefaultRepresentationClass() + { + return java.io.InputStream.class; + } + + /** + * XXX - Currently returns <code>java.io.InputStream</code>. + */ + public final String getDefaultRepresentationClassAsString() + { + return getDefaultRepresentationClass().getName(); + } + + /** + * Creates a <code>Reader</code> for a given <code>Transferable</code>. + * + * If the representation class is a (subclass of) <code>Reader</code> + * then an instance of the representation class is returned. If the + * representatation class is a <code>String</code> then a + * <code>StringReader</code> is returned. And if the representation class + * is a (subclass of) <code>InputStream</code> and the primary MIME type + * is "text" then a <code>InputStreamReader</code> for the correct charset + * encoding is returned. + * + * @param transferable The <code>Transferable</code> for which a text + * <code>Reader</code> is requested. + * + * @exception IllegalArgumentException If the representation class is not one + * of the seven listed above or the Transferable has null data. + * @exception NullPointerException If the Transferable is null. + * @exception UnsupportedFlavorException when the transferable doesn't + * support this <code>DataFlavor</code>. Or if the representable class + * isn't a (subclass of) <code>Reader</code>, <code>String</code>, + * <code>InputStream</code> and/or the primary MIME type isn't "text". + * @exception IOException when any IOException occurs. + * @exception UnsupportedEncodingException if the "charset" isn't supported + * on this platform. + */ + public Reader getReaderForText(Transferable transferable) + throws UnsupportedFlavorException, IOException + { + if (!transferable.isDataFlavorSupported(this)) + throw new UnsupportedFlavorException(this); + + if (Reader.class.isAssignableFrom(representationClass)) + return (Reader)transferable.getTransferData(this); + + if (String.class.isAssignableFrom(representationClass)) + return new StringReader((String)transferable.getTransferData(this)); + + if (InputStream.class.isAssignableFrom(representationClass) + && "text".equals(getPrimaryType())) + { + InputStream in = (InputStream)transferable.getTransferData(this); + String encoding = getParameter("charset"); + if (encoding == null) + encoding = "us-ascii"; + return new InputStreamReader(in, encoding); + } + + throw new UnsupportedFlavorException(this); + } + + /** + * Returns whether the representation class for this DataFlavor is + * @see java.nio.ByteBuffer or a subclass thereof. + * + * @since 1.4 + */ + public boolean isRepresentationClassByteBuffer() + { + return ByteBuffer.class.isAssignableFrom(representationClass); + } + + /** + * Returns whether the representation class for this DataFlavor is + * @see java.nio.CharBuffer or a subclass thereof. + * + * @since 1.4 + */ + public boolean isRepresentationClassCharBuffer() + { + return CharBuffer.class.isAssignableFrom(representationClass); + } + + /** + * Returns whether the representation class for this DataFlavor is + * @see java.io.Reader or a subclass thereof. + * + * @since 1.4 + */ + public boolean isRepresentationClassReader() + { + return Reader.class.isAssignableFrom(representationClass); + } + + /** + * Returns whether this <code>DataFlavor</code> is a valid text flavor for + * this implementation of the Java platform. Only flavors equivalent to + * <code>DataFlavor.stringFlavor</code> and <code>DataFlavor</code>s with + * a primary MIME type of "text" can be valid text flavors. + * <p> + * If this flavor supports the charset parameter, it must be equivalent to + * <code>DataFlavor.stringFlavor</code>, or its representation must be + * <code>java.io.Reader</code>, <code>java.lang.String</code>, + * <code>java.nio.CharBuffer</code>, <code>java.io.InputStream</code> or + * <code>java.nio.ByteBuffer</code>, + * If the representation is <code>java.io.InputStream</code> or + * <code>java.nio.ByteBuffer</code>, then this flavor's <code>charset</code> + * parameter must be supported by this implementation of the Java platform. + * If a charset is not specified, then the platform default charset, which + * is always supported, is assumed. + * <p> + * If this flavor does not support the charset parameter, its + * representation must be <code>java.io.InputStream</code>, + * <code>java.nio.ByteBuffer</code>. + * <p> + * See <code>selectBestTextFlavor</code> for a list of text flavors which + * support the charset parameter. + * + * @return <code>true</code> if this <code>DataFlavor</code> is a valid + * text flavor as described above; <code>false</code> otherwise + * @see #selectBestTextFlavor + * @since 1.4 + */ + public boolean isFlavorTextType() { + // FIXME: I'm not 100% sure if this implementation does the same like sun's does + if(equals(DataFlavor.stringFlavor) || getPrimaryType().equals("text")) + { + String charset = getParameter("charset"); + Class c = getRepresentationClass(); + if(charset != null) + { + if(Reader.class.isAssignableFrom(c) + || CharBuffer.class.isAssignableFrom(c) + || String.class.isAssignableFrom(c)) + { + return true; + } + else if(InputStream.class.isAssignableFrom(c) + || ByteBuffer.class.isAssignableFrom(c)) + { + return Charset.isSupported(charset); + } + } + else if(InputStream.class.isAssignableFrom(c) + || ByteBuffer.class.isAssignableFrom(c)) + { + return true; + } + } + return false; + } +} // class DataFlavor diff --git a/libjava/classpath/java/awt/datatransfer/FlavorEvent.java b/libjava/classpath/java/awt/datatransfer/FlavorEvent.java new file mode 100644 index 000000000..8a292f850 --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/FlavorEvent.java @@ -0,0 +1,57 @@ +/* FlavorEvent -- Event indicating a ClipBoard has different flavors available. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.datatransfer; + +import java.util.EventObject; + +/** + * Event indicating a Clipboard has different flavors available. + * Fired by a ClipBoard for registered FlavorListeners. + * + * @author Mark J. Wielaard (mark@klomp.org) + * + * @since 1.5 + */ +public class FlavorEvent extends EventObject +{ + public FlavorEvent(Clipboard board) + { + super(board); + } +} diff --git a/libjava/classpath/java/awt/datatransfer/FlavorListener.java b/libjava/classpath/java/awt/datatransfer/FlavorListener.java new file mode 100644 index 000000000..eb388aa84 --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/FlavorListener.java @@ -0,0 +1,54 @@ +/* FlavorListener -- Interface for tagging an interest in FlavorEvents. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.datatransfer; + +import java.util.EventListener; + +/** + * Interface for tagging an interest in FlavorEvents by a class. The + * flavorsChanged() method will be called with a FlavorEvent pointing + * to the Clipboard which has content in different Flavors available. + * + * @author Mark J. Wielaard (mark@klomp.org) + */ +public interface FlavorListener + extends EventListener +{ + void flavorsChanged(FlavorEvent event); +} diff --git a/libjava/classpath/java/awt/datatransfer/FlavorMap.java b/libjava/classpath/java/awt/datatransfer/FlavorMap.java new file mode 100644 index 000000000..8842c8e55 --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/FlavorMap.java @@ -0,0 +1,75 @@ +/* FlavorMap.java -- Maps between flavor names and MIME types. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.datatransfer; + +import java.util.Map; + +/** + * This interface maps between native platform type names and DataFlavors. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface FlavorMap +{ + /** + * Maps the specified <code>DataFlavor</code> objects to the native + * data type name. The returned <code>Map</code> has keys that are + * the data flavors and values that are strings. The returned map + * may be modified. This can be useful for implementing nested mappings. + * + * @param flavors An array of data flavors to map + * or null for all data flavors. + * + * @return A <code>Map</code> of native data types. + */ + Map<DataFlavor, String> getNativesForFlavors (DataFlavor[] flavors); + + /** + * Maps the specified native type names to <code>DataFlavor</code>'s. + * The returned <code>Map</code> has keys that are strings and values + * that are <code>DataFlavor</code>'s. The returned map may be + * modified. This can be useful for implementing nested mappings. + * + * @param natives An array of native types to map + * or null for all native types. + * + * @return A <code>Map</code> of data flavors. + */ + Map<String, DataFlavor> getFlavorsForNatives (String[] natives); +} diff --git a/libjava/classpath/java/awt/datatransfer/FlavorTable.java b/libjava/classpath/java/awt/datatransfer/FlavorTable.java new file mode 100644 index 000000000..f6c43af83 --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/FlavorTable.java @@ -0,0 +1,73 @@ +/* FlavorTable.java -- A relaxed mapping between flavors + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.datatransfer; + +import java.util.List; + +/** + * A FlavorMap which no longer requires a 1-to-1 mapping between flavors. Any + * native can map to multiple flavors, and any flavor can map to multiple + * natives; although the mappings are usually symmetric. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.4 + * @status updated to 1.4 + */ +public interface FlavorTable extends FlavorMap +{ + /** + * Returns a list of String natives corresponding to the given flavor. The + * list should be sorted from best to worst. The list must be modifiable + * without affecting this table. + * + * @param flavor the flavor to look up, or null to return all natives + * @return the sorted list of natives + */ + List<String> getNativesForFlavor(DataFlavor flavor); + + /** + * Returns a list of flavors corresponding to the given String native. The + * list should be sorted from best to worst. The list must be modifiable + * without affecting this table. + * + * @param name the native name to look up, or null to return all flavors + * @return the sorted list of flavors + */ + List<DataFlavor> getFlavorsForNative(String name); +} diff --git a/libjava/classpath/java/awt/datatransfer/MimeType.java b/libjava/classpath/java/awt/datatransfer/MimeType.java new file mode 100644 index 000000000..143e8700b --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/MimeType.java @@ -0,0 +1,283 @@ +/* MimeType.java -- A helper class for mime handling in DataFlavor + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.datatransfer; + +import gnu.java.lang.CPStringBuilder; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.StringTokenizer; + +/** + * A helper class for mime handling in DataFlavor. + * + * A Mauve test for DataFlavor.writeExternal() shows that a non-public + * class java.awt.datatransfer.MimeType gets serialized. This class + * is mainly here for serialization compatibility. Of course, + * now that we have it here, we can just as well implement some + * mime handling facility here. + */ +class MimeType + implements Externalizable +{ + + /** + * The primary type. + */ + private String primaryType; + + /** + * The subtype. + */ + private String subType; + + /** + * Additional parameters to be appended to the mime string. + */ + private HashMap parameters; + + /** + * This is only here for deserialization. + */ + public MimeType() + { + parameters = new HashMap(); + } + + /** + * Creates a new MimeType object. + * + * @param mime the mime type + */ + MimeType(String mime) + throws MimeTypeParseException + { + this(); + parse(mime); + } + + /** + * Adds a mime parameter. + * + * @param param the parameter key + * @param value the parameter value + */ + void addParameter(String param, String value) + { + parameters.put(param, value); + } + + /** + * Removes the parameter with the specified key. + * + * @param param the parameter to remove + */ + void removeParameter(String param) + { + parameters.remove(param); + } + + /** + * Returns the parameter for the <code>key</code>. + * + * @param key the parameter key + * + * @return the parameter for the <code>key</code> + */ + String getParameter(String key) + { + return (String) parameters.get(key); + } + + /** + * Returns the primary type. + * + * @return the primary type + */ + String getPrimaryType() + { + return primaryType; + } + + String getSubType() + { + return subType; + } + + /** + * Returns the base type of this mime type. This is the primary + * type plus the subtype, separated by '/'. + * + * @return the base type of this mime type + */ + String getBaseType() + { + return primaryType + '/' + subType; + } + + /** + * Returns <code>true</code> if this mime type and another mime type + * match. This will be true when their primary types are equal, and their + * subtypes are equal (or when either subtype is * ). + * + * @param other the other mime type + * + * @return <code>true</code> if the mime types match, <code>false</code> + * otherwise + */ + boolean matches(MimeType other) + { + boolean match = false; + if (other != null) + { + match = primaryType.equals(other.primaryType) + && (subType.equals("*") || other.subType.equals("*") + || subType.equals(other.subType)); + } + return match; + } + + /** + * Serializes the mime type. + * + * @param in the input stream to read from + * + * @throws ClassNotFoundException not thrown here + * @throws IOException when something goes wrong on the input stream, + * or when the mime type can't be parsed + */ + public void readExternal(ObjectInput in) + throws ClassNotFoundException, IOException + { + String mime = in.readUTF(); + parameters.clear(); + try + { + parse(mime); + } + catch (MimeTypeParseException ex) + { + IOException ioEx = new IOException(); + ioEx.initCause(ex); + throw ioEx; + } + } + + /** + * Serializes this mime type. + * + * @param out the output stream + * + * @throws IOException when something goes wrong on the output stream + */ + public void writeExternal(ObjectOutput out) + throws IOException + { + out.writeUTF(toString()); + } + + /** + * Creates a string representation of this mime type. + * + * @return a string representation of this mime type + */ + public String toString() + { + CPStringBuilder s = new CPStringBuilder(); + s.append(primaryType); + s.append('/'); + s.append(subType); + if (parameters.size() > 0) + { + Set entries = parameters.entrySet(); + for (Iterator i = entries.iterator(); i.hasNext();) + { + s.append("; "); + Map.Entry entry = (Map.Entry) i.next(); + s.append(entry.getKey()); + s.append('='); + s.append(entry.getValue()); + } + } + return s.toString(); + } + + /** + * Parses the specified mime type string and initializes the fields + * of this object. + * + * @param mime the mime type string + */ + private void parse(String mime) + throws MimeTypeParseException + { + // FIXME: Maybe implement more sophisticated mime string parsing according + // to RFC 2045 and 2046. + StringTokenizer tokenizer = new StringTokenizer(mime); + try + { + primaryType = tokenizer.nextToken("/"); + subType = tokenizer.nextToken("/;"); + } + catch (NoSuchElementException ex) + { + throw new MimeTypeParseException("Expected / separator"); + } + + // Add any parameters. + while (tokenizer.hasMoreTokens()) + { + String keyValuePair = tokenizer.nextToken(";"); + int i = keyValuePair.indexOf('='); + if (i == -1) + throw new MimeTypeParseException("Expected = as parameter separator"); + String key = keyValuePair.substring(0, i).trim(); + String value = keyValuePair.substring(i + 1).trim(); + parameters.put(key, value); + } + } + +} diff --git a/libjava/classpath/java/awt/datatransfer/MimeTypeParseException.java b/libjava/classpath/java/awt/datatransfer/MimeTypeParseException.java new file mode 100644 index 000000000..6113ab760 --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/MimeTypeParseException.java @@ -0,0 +1,70 @@ +/* MimeTypeParseException.java -- thrown when MIME string couldn't be parsed + Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.datatransfer; + +/** + * MIME string couldn't be parsed correctly. + * + * @author Mark Wielaard (mark@klomp.org) + * @status updated to 1.4 + */ +public class MimeTypeParseException extends Exception +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -5604407764691570741L; + + /** + * Create a new instance without any message. + */ + public MimeTypeParseException() + { + } + + /** + * Create a new instance with a specified detailed error message. + * + * @param message the message + */ + public MimeTypeParseException(String message) + { + super(message); + } +} // class MimeTypeParseException diff --git a/libjava/classpath/java/awt/datatransfer/StringSelection.java b/libjava/classpath/java/awt/datatransfer/StringSelection.java new file mode 100644 index 000000000..4b64cda57 --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/StringSelection.java @@ -0,0 +1,157 @@ +/* StringSelection.java -- Clipboard handler for text. + Copyright (C) 1999, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.datatransfer; + +import java.io.IOException; +import java.io.StringReader; + +/** + * This class transfers a string as plain text using the clipboard. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class StringSelection implements Transferable, ClipboardOwner +{ + +/* + * Class Variables + */ + +// List of flavors we support +// XXX: DataFlavor.plainTextFlavor is deprecated. +static final DataFlavor[] supported_flavors + = { DataFlavor.stringFlavor, + DataFlavor.plainTextFlavor }; + +/*************************************************************************/ + +/* + * Instance Variables + */ + +// This is the data to transfer +private String data; + + /** + * Transfer the specfied string as text. + * + * @param data the data for the string selection + */ + public StringSelection(String data) + { + this.data = data; + } + +/** + * Returns a list of supported data flavors. + * + * @return A list of supported data flavors. + */ +public DataFlavor[] +getTransferDataFlavors() +{ + return(supported_flavors); +} + +/*************************************************************************/ + +/** + * Tests whether or not the specified data flavor is supported. + * + * @param flavor The data flavor to test. + * + * @return <code>true</code> if the data flavor is supported, + * <code>false</code> otherwise. + */ +public boolean +isDataFlavorSupported(DataFlavor flavor) +{ + for (int i = 0; i < supported_flavors.length; i++) + if (supported_flavors[i].equals(flavor)) + return(true); + + return(false); +} + +/*************************************************************************/ + +/** + * This method returns the data in the requested format. + * + * @param flavor The desired data flavor. + * + * @return The transferred data. + * + * @exception UnsupportedFlavorException If the specified flavor is not + * supported. + * @exception IOException If any other error occurs. + */ +public Object +getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, + IOException +{ + if (!isDataFlavorSupported(flavor)) + throw new UnsupportedFlavorException(flavor); + + if (DataFlavor.plainTextFlavor == flavor) + /* The behavior of this method for DataFlavor.plainTextFlavor and + equivalent DataFlavors is inconsistent with the definition of + DataFlavor.plainTextFlavor. We choose to do like Sun's implementation + and return a Reader instead of an InputString. */ + /* return(new StringBufferInputStream(data)); */ + return(new StringReader(data)); + else // DataFlavor.stringFlavor + return data; +} + +/*************************************************************************/ + +/** + * Called when ownership of the clipboard object is lost. + * + * @param clipboard The affected clipboard. + * @param contents The clipboard contents. + */ +public void +lostOwnership(Clipboard clipboard, Transferable contents) +{ + // FIXME: What does this do? +} + +} // class StringSelection diff --git a/libjava/classpath/java/awt/datatransfer/SystemFlavorMap.java b/libjava/classpath/java/awt/datatransfer/SystemFlavorMap.java new file mode 100644 index 000000000..65c14c1ba --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/SystemFlavorMap.java @@ -0,0 +1,561 @@ +/* SystemFlavorMap.java -- Maps between native flavor names and MIME types. + Copyright (C) 2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.datatransfer; + +import java.awt.Toolkit; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.WeakHashMap; + +/** + * This class maps between native platform type names and DataFlavors. + * + * XXX - The current implementation does no mapping at all. + * + * @author Mark Wielaard (mark@klomp.org) + * + * @since 1.2 + */ +public final class SystemFlavorMap implements FlavorMap, FlavorTable +{ + /** + * The map which maps the thread's <code>ClassLoaders</code> to + * <code>SystemFlavorMaps</code>. + */ + private static final Map systemFlavorMaps = new WeakHashMap(); + + /** + * Constant which is used to prefix encode Java MIME types. + */ + private static final String GNU_JAVA_MIME_PREFIX = "gnu.java:"; + + /** + * This map maps native <code>String</code>s to lists of + * <code>DataFlavor</code>s + */ + private HashMap<String,List<DataFlavor>> nativeToFlavorMap = + new HashMap<String,List<DataFlavor>>(); + + /** + * This map maps <code>DataFlavor</code>s to lists of native + * <code>String</code>s + */ + private HashMap<DataFlavor, List<String>> flavorToNativeMap = + new HashMap<DataFlavor, List<String>>(); + + /** + * Private constructor. + */ + private SystemFlavorMap () + { + AccessController.doPrivileged + (new PrivilegedAction<Object>() + { + public Object run() + { + try + { + // Load installed flavormap.properties first. + String sep = File.separator; + File propsFile = + new File(System.getProperty("gnu.classpath.home.url") + + sep + "accessibility.properties"); + InputStream in = new FileInputStream(propsFile); + Properties props = new Properties(); + props.load(in); + in.close(); + + String augmented = Toolkit.getProperty("AWT.DnD.flavorMapFileURL", + null); + if (augmented != null) + { + URL url = new URL(augmented); + in = url.openStream(); + props.load(in); + } + setupMapping(props); + } + catch (IOException ex) + { + // Can't do anything about it. + } + return null; + } + }); + } + + /** + * Sets up the mapping from native to mime types and vice versa as specified + * in the flavormap.properties file. + * + * This is package private to avoid an accessor method. + * + * @param props the properties file + */ + void setupMapping(Properties props) + { + Enumeration propNames = props.propertyNames(); + while (propNames.hasMoreElements()) + { + try + { + String nat = (String) propNames.nextElement(); + String mime = (String) props.getProperty(nat); + // Check valid mime type. + MimeType type = new MimeType(mime); + DataFlavor flav = new DataFlavor(mime); + + List<DataFlavor> flavs = nativeToFlavorMap.get(nat); + if (flavs == null) + { + flavs = new ArrayList<DataFlavor>(); + nativeToFlavorMap.put(nat, flavs); + } + List<String> nats = flavorToNativeMap.get(flav); + if (nats == null) + { + nats = new ArrayList<String>(); + flavorToNativeMap.put(flav, nats); + } + flavs.add(flav); + nats.add(nat); + } + catch (ClassNotFoundException ex) + { + // Skip. + } + catch (MimeTypeParseException ex) + { + // Skip. + } + } + } + + /** + * Maps the specified <code>DataFlavor</code> objects to the native + * data type name. The returned <code>Map</code> has keys that are + * the data flavors and values that are strings. The returned map + * may be modified. This can be useful for implementing nested mappings. + * + * @param flavors An array of data flavors to map + * or null for all data flavors. + * + * @return A <code>Map</code> of native data types to data flavors. + */ + public Map<DataFlavor, String> getNativesForFlavors (DataFlavor[] flavors) + { + return new HashMap<DataFlavor, String>(); + } + + /** + * Maps the specified native type names to <code>DataFlavor</code>'s. + * The returned <code>Map</code> has keys that are strings and values + * that are <code>DataFlavor</code>'s. The returned map may be + * modified. This can be useful for implementing nested mappings. + * + * @param natives An array of native types to map + * or null for all native types. + * + * @return A <code>Map</code> of data flavors to native type names. + */ + public Map<String, DataFlavor> getFlavorsForNatives (String[] natives) + { + return new HashMap<String, DataFlavor>(); + } + + /** + * Returns the (System)FlavorMap for the current thread's + * ClassLoader. + */ + public static FlavorMap getDefaultFlavorMap () + { + ClassLoader classLoader = Thread.currentThread() + .getContextClassLoader(); + + //if ContextClassLoader not set, use system default + if (classLoader == null) + { + classLoader = ClassLoader.getSystemClassLoader(); + } + + synchronized(systemFlavorMaps) + { + FlavorMap map = (FlavorMap) + systemFlavorMaps.get(classLoader); + if (map == null) + { + map = new SystemFlavorMap(); + systemFlavorMaps.put(classLoader, map); + } + return map; + } + } + + /** + * Encodes a MIME type for use as a <code>String</code> native. The format + * of an encoded representation of a MIME type is implementation-dependent. + * The only restrictions are: + * <ul> + * <li>The encoded representation is <code>null</code> if and only if the + * MIME type <code>String</code> is <code>null</code>.</li> + * <li>The encoded representations for two non-<code>null</code> MIME type + * <code>String</code>s are equal if and only if these <code>String</code>s + * are equal according to <code>String.equals(Object)</code>.</li> + * </ul> + * <p> + * The present implementation of this method returns the specified MIME + * type <code>String</code> prefixed with <code>gnu.java:</code>. + * + * @param mime the MIME type to encode + * @return the encoded <code>String</code>, or <code>null</code> if + * mimeType is <code>null</code> + */ + public static String encodeJavaMIMEType (String mime) + { + if (mime != null) + return GNU_JAVA_MIME_PREFIX + mime; + else + return null; + } + + /** + * Encodes a <code>DataFlavor</code> for use as a <code>String</code> + * native. The format of an encoded <code>DataFlavor</code> is + * implementation-dependent. The only restrictions are: + * <ul> + * <li>The encoded representation is <code>null</code> if and only if the + * specified <code>DataFlavor</code> is <code>null</code> or its MIME type + * <code>String</code> is <code>null</code>.</li> + * <li>The encoded representations for two non-<code>null</code> + * <code>DataFlavor</code>s with non-<code>null</code> MIME type + * <code>String</code>s are equal if and only if the MIME type + * <code>String</code>s of these <code>DataFlavor</code>s are equal + * according to <code>String.equals(Object)</code>.</li> + * </ul> + * <p> + * The present implementation of this method returns the MIME type + * <code>String</code> of the specified <code>DataFlavor</code> prefixed + * with <code>gnu.java:</code>. + * + * @param df the <code>DataFlavor</code> to encode + * @return the encoded <code>String</code>, or <code>null</code> if + * flav is <code>null</code> or has a <code>null</code> MIME type + */ + public static String encodeDataFlavor (DataFlavor df) + { + if (df != null) + { + return encodeJavaMIMEType(df.getMimeType()); + } + else + return null; + } + + /** + * Returns true if the native type name can be represented as + * a java mime type. Returns <code>false</code> if parameter is + * <code>null</code>. + */ + public static boolean isJavaMIMEType (String name) + { + return (name != null && name.startsWith(GNU_JAVA_MIME_PREFIX)); + } + + /** + * Decodes a <code>String</code> native for use as a Java MIME type. + * + * @param name the <code>String</code> to decode + * @return the decoded Java MIME type, or <code>null</code> if nat + * is not an encoded <code>String</code> native + */ + public static String decodeJavaMIMEType (String name) + { + if (isJavaMIMEType(name)) + { + return name.substring(GNU_JAVA_MIME_PREFIX.length()); + } + else + return null; + } + + /** + * Returns the data flavor given the native type name + * or null when no such data flavor exists. + */ + public static DataFlavor decodeDataFlavor (String name) + throws ClassNotFoundException + { + String javaMIMEType = decodeJavaMIMEType (name); + + if (javaMIMEType != null) + return new DataFlavor (javaMIMEType); + else + return null; + } + + /** + * Returns a List of <code>DataFlavors</code> to which the specified + * <code>String</code> native can be translated by the data transfer + * subsystem. The <code>List</code> will be sorted from best + * <code>DataFlavor</code> to worst. That is, the first <code>DataFlavor + * </code> will best reflect data in the specified native to a Java + * application. + * <p> + * If the specified native is previously unknown to the data transfer + * subsystem, and that native has been properly encoded, then invoking + * this method will establish a mapping in both directions between the + * specified native and a DataFlavor whose MIME type is a decoded + * version of the native. + */ + public List<DataFlavor> getFlavorsForNative(String nat) + { + List<DataFlavor> ret = new ArrayList<DataFlavor>(); + if (nat == null) + { + Collection<List<DataFlavor>> all = nativeToFlavorMap.values(); + for (List<DataFlavor> list : all) + { + for (DataFlavor flav : list) + { + if (! ret.contains(flav)) + ret.add(flav); + } + } + } + else + { + List<DataFlavor> list = nativeToFlavorMap.get(nat); + if (list != null) + ret.addAll(list); + } + return ret; + } + + public List<String> getNativesForFlavor (DataFlavor flav) + { + List<String> ret = new ArrayList<String>(); + if (flav == null) + { + Collection<List<String>> all = flavorToNativeMap.values(); + for (List<String> list : all) + { + for (String nat : list) + { + if (! ret.contains(nat)) + ret.add(nat); + } + } + } + else + { + List<String> list = flavorToNativeMap.get(flav); + if (list != null) + ret.addAll(list); + } + return ret; + } + + /** + * Adds a mapping from a single <code>String</code> native to a single + * <code>DataFlavor</code>. Unlike <code>getFlavorsForNative</code>, the + * mapping will only be established in one direction, and the native will + * not be encoded. To establish a two-way mapping, call + * <code>addUnencodedNativeForFlavor</code> as well. The new mapping will + * be of lower priority than any existing mapping. + * This method has no effect if a mapping from the specified + * <code>String</code> native to the specified or equal + * <code>DataFlavor</code> already exists. + * + * @param nativeStr the <code>String</code> native key for the mapping + * @param flavor the <code>DataFlavor</code> value for the mapping + * @throws NullPointerException if nat or flav is <code>null</code> + * + * @see #addUnencodedNativeForFlavor + * @since 1.4 + */ + public synchronized void addFlavorForUnencodedNative(String nativeStr, + DataFlavor flavor) + { + if ((nativeStr == null) || (flavor == null)) + throw new NullPointerException(); + List<DataFlavor> flavors = nativeToFlavorMap.get(nativeStr); + if (flavors == null) + { + flavors = new ArrayList<DataFlavor>(); + nativeToFlavorMap.put(nativeStr, flavors); + } + else + { + if (! flavors.contains(flavor)) + flavors.add(flavor); + } + } + + /** + * Adds a mapping from the specified <code>DataFlavor</code> (and all + * <code>DataFlavor</code>s equal to the specified <code>DataFlavor</code>) + * to the specified <code>String</code> native. + * Unlike <code>getNativesForFlavor</code>, the mapping will only be + * established in one direction, and the native will not be encoded. To + * establish a two-way mapping, call + * <code>addFlavorForUnencodedNative</code> as well. The new mapping will + * be of lower priority than any existing mapping. + * This method has no effect if a mapping from the specified or equal + * <code>DataFlavor</code> to the specified <code>String</code> native + * already exists. + * + * @param flavor the <code>DataFlavor</code> key for the mapping + * @param nativeStr the <code>String</code> native value for the mapping + * @throws NullPointerException if flav or nat is <code>null</code> + * + * @see #addFlavorForUnencodedNative + * @since 1.4 + */ + public synchronized void addUnencodedNativeForFlavor(DataFlavor flavor, + String nativeStr) + { + if ((nativeStr == null) || (flavor == null)) + throw new NullPointerException(); + List<String> natives = flavorToNativeMap.get(flavor); + if (natives == null) + { + natives = new ArrayList<String>(); + flavorToNativeMap.put(flavor, natives); + } + else + { + if (! natives.contains(nativeStr)) + natives.add(nativeStr); + } + } + + /** + * Discards the current mappings for the specified <code>DataFlavor</code> + * and all <code>DataFlavor</code>s equal to the specified + * <code>DataFlavor</code>, and creates new mappings to the + * specified <code>String</code> natives. + * Unlike <code>getNativesForFlavor</code>, the mappings will only be + * established in one direction, and the natives will not be encoded. To + * establish two-way mappings, call <code>setFlavorsForNative</code> + * as well. The first native in the array will represent the highest + * priority mapping. Subsequent natives will represent mappings of + * decreasing priority. + * <p> + * If the array contains several elements that reference equal + * <code>String</code> natives, this method will establish new mappings + * for the first of those elements and ignore the rest of them. + * <p> + * It is recommended that client code not reset mappings established by the + * data transfer subsystem. This method should only be used for + * application-level mappings. + * + * @param flavor the <code>DataFlavor</code> key for the mappings + * @param natives the <code>String</code> native values for the mappings + * @throws NullPointerException if flav or natives is <code>null</code> + * or if natives contains <code>null</code> elements + * + * @see #setFlavorsForNative + * @since 1.4 + */ + public synchronized void setNativesForFlavor(DataFlavor flavor, + String[] natives) + { + if ((natives == null) || (flavor == null)) + throw new NullPointerException(); + + flavorToNativeMap.remove(flavor); + for (int i = 0; i < natives.length; i++) + { + addUnencodedNativeForFlavor(flavor, natives[i]); + } + } + + /** + * Discards the current mappings for the specified <code>String</code> + * native, and creates new mappings to the specified + * <code>DataFlavor</code>s. Unlike <code>getFlavorsForNative</code>, the + * mappings will only be established in one direction, and the natives need + * not be encoded. To establish two-way mappings, call + * <code>setNativesForFlavor</code> as well. The first + * <code>DataFlavor</code> in the array will represent the highest priority + * mapping. Subsequent <code>DataFlavor</code>s will represent mappings of + * decreasing priority. + * <p> + * If the array contains several elements that reference equal + * <code>DataFlavor</code>s, this method will establish new mappings + * for the first of those elements and ignore the rest of them. + * <p> + * It is recommended that client code not reset mappings established by the + * data transfer subsystem. This method should only be used for + * application-level mappings. + * + * @param nativeStr the <code>String</code> native key for the mappings + * @param flavors the <code>DataFlavor</code> values for the mappings + * @throws NullPointerException if nat or flavors is <code>null</code> + * or if flavors contains <code>null</code> elements + * + * @see #setNativesForFlavor + * @since 1.4 + */ + public synchronized void setFlavorsForNative(String nativeStr, + DataFlavor[] flavors) + { + if ((nativeStr == null) || (flavors == null)) + throw new NullPointerException(); + + nativeToFlavorMap.remove(nativeStr); + for (int i = 0; i < flavors.length; i++) + { + addFlavorForUnencodedNative(nativeStr, flavors[i]); + } + } + +} // class SystemFlavorMap diff --git a/libjava/classpath/java/awt/datatransfer/Transferable.java b/libjava/classpath/java/awt/datatransfer/Transferable.java new file mode 100644 index 000000000..99239fcc6 --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/Transferable.java @@ -0,0 +1,82 @@ +/* Transferable.java -- Data transfer source + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.datatransfer; + +import java.io.IOException; + +/** + * This interface is implemented by classes that can transfer data. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.1 + * @status updated to 1.4 + */ +public interface Transferable +{ + /** + * This method returns a list of available data flavors for the data being + * transferred. The array returned will be sorted from most preferred + * flavor at the beginning to least preferred at the end. + * + * @return adA list of data flavors for this data + */ + DataFlavor[] getTransferDataFlavors(); + + /** + * Tests whether or not this data can be delivered in the specified data + * flavor. + * + * @param flavor the data flavor to test + * @return true if the data flavor is supported + */ + boolean isDataFlavorSupported(DataFlavor flavor); + + /** + * Returns the data in the specified <code>DataFlavor</code>. + * + * @param flavor the data flavor to return + * @return the data in the appropriate flavor + * @throws UnsupportedFlavorException if the flavor is not supported + * @throws IOException if the data is not available + * @see DataFlavor#getRepresentationClass + */ + Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException; + +} // interface Transferable diff --git a/libjava/classpath/java/awt/datatransfer/UnsupportedFlavorException.java b/libjava/classpath/java/awt/datatransfer/UnsupportedFlavorException.java new file mode 100644 index 000000000..0ca17b2e9 --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/UnsupportedFlavorException.java @@ -0,0 +1,65 @@ +/* UnsupportedFlavorException.java -- ata flavor is not valid + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.datatransfer; + +/** + * The data flavor requested is not supported for the transfer data. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see Transferable#getTransferData(DataFlavor) + * @status updated to 1.4 + */ +public class UnsupportedFlavorException extends Exception +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 5383814944251665601L; + + /** + * Initializes a new instance of <code>UnsupportedDataFlavor</code> + * for the specified data flavor. + * + * @param flavor the data flavor that is not supported + */ + public UnsupportedFlavorException(DataFlavor flavor) + { + super(flavor == null ? null : flavor.getHumanPresentableName()); + } +} // class UnsupportedFlavorException diff --git a/libjava/classpath/java/awt/datatransfer/package.html b/libjava/classpath/java/awt/datatransfer/package.html new file mode 100644 index 000000000..5ab860cdc --- /dev/null +++ b/libjava/classpath/java/awt/datatransfer/package.html @@ -0,0 +1,47 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in java.awt.datatransfer package. + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - java.awt.datatransfer</title></head> + +<body> +<p>Classes to represent different flavors of data for transferring native +and system types through for example a clipboard.</p> + +</body> +</html> diff --git a/libjava/classpath/java/awt/dnd/Autoscroll.java b/libjava/classpath/java/awt/dnd/Autoscroll.java new file mode 100644 index 000000000..094063ce1 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/Autoscroll.java @@ -0,0 +1,69 @@ +/* Autoscroll.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.dnd; + +import java.awt.Insets; +import java.awt.Point; + +/** + * During DnD operations it is possible that a user may wish to drop the + * subject of the operation on a region of a scrollable GUI control that + * is not currently visible to the user. + * + * @author Michael Koch (konqueror@gmx.de) + * @since 1.2 + * @status updated to 1.4 + */ +public interface Autoscroll +{ + /** + * This method returns the Insets describing the autoscrolling region or + * border relative to the geometry of the implementing Component + */ + Insets getAutoscrollInsets (); + + /** + * Notify the Component to autoscroll + * + * @param location A Point indicating the location of the cursor that + * triggered this operation + */ + void autoscroll (Point location); + +} // interface Autoscroll diff --git a/libjava/classpath/java/awt/dnd/DnDConstants.java b/libjava/classpath/java/awt/dnd/DnDConstants.java new file mode 100644 index 000000000..85c9c0528 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DnDConstants.java @@ -0,0 +1,77 @@ +/* DnDConstants.java -- constants for drag-and-drop operations + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.dnd; + +/** + * This class contains various constants used in drag-and-drop operations. + * Why it is not an interface is beyond me. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ +public final class DnDConstants +{ + /** No action takes place. */ + public static final int ACTION_NONE = 0; + + /** The copy action. */ + public static final int ACTION_COPY = 1; + + /** The move action. */ + public static final int ACTION_MOVE = 2; + + /** Either a copy or a move. */ + public static final int ACTION_COPY_OR_MOVE = 3; + + /** + * A link action. This does not copy or move, but creates a reference back + * to the original. However, since platforms differ on how a reference should + * behave, this action is not recommended for common use. + */ + public static final int ACTION_LINK = 1073741824; + + /** A synonym for {@link #ACTION_LINK}. */ + public static final int ACTION_REFERENCE = ACTION_LINK; + + private DnDConstants() + { + // Do nothing here. + } +} diff --git a/libjava/classpath/java/awt/dnd/DnDEventMulticaster.java b/libjava/classpath/java/awt/dnd/DnDEventMulticaster.java new file mode 100644 index 000000000..30594c2c7 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DnDEventMulticaster.java @@ -0,0 +1,74 @@ +/* DnDEventMulticaster.java -- helper class for listener chains in java.awt.dnd + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.dnd; + +import java.awt.AWTEventMulticaster; +import java.util.EventListener; + +class DnDEventMulticaster extends AWTEventMulticaster +{ + protected DnDEventMulticaster (EventListener a, EventListener b) + { + super (a, b); + } + + public static DragSourceListener add (DragSourceListener a, + DragSourceListener b) + { + return (DragSourceListener) addInternal (a, b); + } + + public static DragSourceMotionListener add (DragSourceMotionListener a, + DragSourceMotionListener b) + { + return (DragSourceMotionListener) addInternal (a, b); + } + + public static DragSourceListener remove (DragSourceListener a, + DragSourceListener b) + { + return (DragSourceListener) removeInternal (a, b); + } + + public static DragSourceMotionListener remove (DragSourceMotionListener a, + DragSourceMotionListener b) + { + return (DragSourceMotionListener) removeInternal (a, b); + } +} diff --git a/libjava/classpath/java/awt/dnd/DragGestureEvent.java b/libjava/classpath/java/awt/dnd/DragGestureEvent.java new file mode 100644 index 000000000..e127a7dc1 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragGestureEvent.java @@ -0,0 +1,219 @@ +/* DragGestureEvent.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.dnd; + +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Image; +import java.awt.Point; +import java.awt.datatransfer.Transferable; +import java.awt.event.InputEvent; +import java.util.EventObject; +import java.util.Iterator; +import java.util.List; + +public class DragGestureEvent extends EventObject +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 9080172649166731306L; + + private DragSource dragSource; + private Component component; + private final Point origin; + private final int action; + private List<InputEvent> events; + private DragGestureRecognizer dgr; + + /** + * Constructs a new DragGestureEvent. + * @param dgr - DragGestureRecognizer firing this event + * @param action - user's preferred action + * @param origin - origin of the drag + * @param events - List of events that make up the gesture + * @throws IllegalArgumentException - if input parameters are null + */ + public DragGestureEvent(DragGestureRecognizer dgr, int action, Point origin, + List<? extends InputEvent> events) + { + super(dgr); + if (origin == null || events == null || dgr == null) + throw new IllegalArgumentException(); + + this.origin = origin; + this.action = action; + this.events = (List<InputEvent>) events; + this.dgr = dgr; + this.component = dgr.getComponent(); + this.dragSource = dgr.getDragSource(); + } + + /** + * Returns the source casted as a DragGestureRecognizer. + * + * @return the source casted as a DragGestureRecognizer. + */ + public DragGestureRecognizer getSourceAsDragGestureRecognizer() + { + return (DragGestureRecognizer) getSource(); + } + + /** + * Returns the Component corresponding to this. + * + * @return the Component corresponding to this. + */ + public Component getComponent() + { + return component; + } + + /** + * Gets the DragSource corresponding to this. + * + * @return the DragSource corresponding to this. + */ + public DragSource getDragSource() + { + return dragSource; + } + + /** + * Returns the origin of the drag. + * + * @return the origin of the drag. + */ + public Point getDragOrigin() + { + return origin; + } + + /** + * Gets an iterator representation of the List of events. + * + * @return an iterator representation of the List of events. + */ + public Iterator<InputEvent> iterator() + { + return events.iterator(); + } + + /** + * Gets an array representation of the List of events. + * + * @return an array representation of the List of events. + */ + public Object[] toArray() + { + return events.toArray(); + } + + /** + * Gets an array representation of the List of events. + * + * @param array - the array to store the events in. + * @return an array representation of the List of events. + */ + public Object[] toArray(Object[] array) + { + return events.toArray(array); + } + + /** + * Gets the user's preferred action. + * + * @return the user's preferred action. + */ + public int getDragAction() + { + return action; + } + + /** + * Get the event that triggered this gesture. + * + * @return the event that triggered this gesture. + */ + public InputEvent getTriggerEvent() + { + return dgr.getTriggerEvent(); + } + + /** + * Starts the drag given the initial Cursor to display, the Transferable + * object, and the DragSourceListener to use. + * + * @exception InvalidDnDOperationException If the Drag and Drop system is + * unable to initiate a drag operation, or if the user attempts to start + * a drag while an existing drag operation is still executing. + */ + public void startDrag(Cursor dragCursor, Transferable trans) + { + startDrag(dragCursor, null, null, trans, null); + } + + /** + * Starts the drag given the initial Cursor to display, the Transferable + * object, and the DragSourceListener to use. + * + * @exception InvalidDnDOperationException If the Drag and Drop system is + * unable to initiate a drag operation, or if the user attempts to start + * a drag while an existing drag operation is still executing. + */ + public void startDrag(Cursor dragCursor, Transferable trans, + DragSourceListener l) + { + startDrag(dragCursor, null, null, trans, l); + } + + /** + * Starts the drag given the initial Cursor to display, the Transferable + * object, and the DragSourceListener to use. + * + * @exception InvalidDnDOperationException If the Drag and Drop system is + * unable to initiate a drag operation, or if the user attempts to start + * a drag while an existing drag operation is still executing. + */ + public void startDrag(Cursor dragCursor, Image dragImage, Point imageOffset, + Transferable trans, DragSourceListener l) + { + dragSource.startDrag(this, dragCursor, dragImage, imageOffset, trans, l); + } +} // class DragGestureEvent diff --git a/libjava/classpath/java/awt/dnd/DragGestureListener.java b/libjava/classpath/java/awt/dnd/DragGestureListener.java new file mode 100644 index 000000000..e8befe80f --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragGestureListener.java @@ -0,0 +1,63 @@ +/* DragGestureListener.java -- + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.dnd; + +import java.util.EventListener; + +/** + * This is a listener for starting a drag-and-drop gesture. Upon receiving + * notification, the implementor then starts the drag operation. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see DragGestureRecognizer + * @see DragGestureEvent + * @see DragSource + * @since 1.2 + * @status updated to 1.4 + */ +public interface DragGestureListener extends EventListener +{ + /** + * Called when the native platform notifies the virtual machine that a + * drag-and-drop has been initiated. + * + * @param e the event + */ + void dragGestureRecognized(DragGestureEvent e); +} // interface DragGestureListener diff --git a/libjava/classpath/java/awt/dnd/DragGestureRecognizer.java b/libjava/classpath/java/awt/dnd/DragGestureRecognizer.java new file mode 100644 index 000000000..c41402ca7 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragGestureRecognizer.java @@ -0,0 +1,191 @@ +/* DragGestureRecognizer.java -- + Copyright (C) 2002, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.dnd; + +import java.awt.Component; +import java.awt.Point; +import java.awt.event.InputEvent; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.TooManyListenersException; + +/** + * STUBBED + * @author Michael Koch (konqueror@gmx.de) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.2 + */ +public abstract class DragGestureRecognizer implements Serializable +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 8996673345831063337L; + + protected DragSource dragSource; + protected Component component; + protected transient DragGestureListener dragGestureListener; + protected int sourceActions; + protected ArrayList<InputEvent> events = new ArrayList<InputEvent>(); + + protected DragGestureRecognizer(DragSource ds, Component c, int sa, + DragGestureListener dgl) + { + if (ds == null) + throw new IllegalArgumentException(); + dragSource = ds; + component = c; + sourceActions = sa; + dragGestureListener = dgl; + } + + protected DragGestureRecognizer(DragSource ds, Component c, int sa) + { + this(ds, c, sa, null); + } + + protected DragGestureRecognizer(DragSource ds, Component c) + { + this(ds, c, 0, null); + } + + protected DragGestureRecognizer(DragSource ds) + { + this(ds, null, 0, null); + } + + protected abstract void registerListeners(); + + protected abstract void unregisterListeners(); + + public DragSource getDragSource() + { + return dragSource; + } + + public Component getComponent() + { + return component; + } + + public void setComponent(Component c) + { + component = c; + } + + public int getSourceActions() + { + return sourceActions; + } + + public void setSourceActions(int sa) + { + sourceActions = sa; + } + + public InputEvent getTriggerEvent() + { + return events.size() > 0 ? events.get(0) : null; + } + + /** + * Resets the recognizer. If a gesture is currently recognize, discard it. + */ + public void resetRecognizer() + { + events.clear(); + } + + /** + * Register a new DragGestureListener. + * + * @exception TooManyListenersException If a DragGestureListener has already + * been added. + */ + public void addDragGestureListener(DragGestureListener dgl) + throws TooManyListenersException + { + if (dragGestureListener != null) + throw new TooManyListenersException(); + dragGestureListener = dgl; + } + + public void removeDragGestureListener(DragGestureListener dgl) + { + if (dragGestureListener != dgl) + throw new IllegalArgumentException(); + dragGestureListener = null; + } + + /** + * Fires a <code>DragGestureEvent</code> to the DragGestureListener + * associated with this object, if there is one. + */ + protected void fireDragGestureRecognized(int dragAction, Point p) + { + if(dragGestureListener != null) + dragGestureListener.dragGestureRecognized + (new DragGestureEvent(this, dragAction, p, events)); + resetRecognizer(); + } + + protected void appendEvent(InputEvent e) + { + if (e == null) + return; + events.add(e); + } + + private void readObject(ObjectInputStream s) + throws ClassNotFoundException, IOException + { + s.defaultReadObject(); + dragGestureListener = (DragGestureListener) s.readObject(); + } + + private void writeObject(ObjectOutputStream s) throws IOException + { + s.defaultWriteObject(); + s.writeObject(dragGestureListener instanceof Serializable + ? dragGestureListener : null); + } +} // class DragGestureRecognizer diff --git a/libjava/classpath/java/awt/dnd/DragSource.java b/libjava/classpath/java/awt/dnd/DragSource.java new file mode 100644 index 000000000..af8b37668 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragSource.java @@ -0,0 +1,326 @@ +/* DragSource.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.dnd; + +import gnu.classpath.NotImplementedException; + +import java.awt.Component; +import java.awt.Cursor; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.awt.Image; +import java.awt.Point; +import java.awt.Toolkit; +import java.awt.datatransfer.FlavorMap; +import java.awt.datatransfer.SystemFlavorMap; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.peer.DragSourceContextPeer; +import java.io.Serializable; +import java.util.EventListener; + +/** + * @since 1.2 + */ +public class DragSource implements Serializable +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 6236096958971414066L; + + public static final Cursor DefaultCopyDrop = null; + public static final Cursor DefaultMoveDrop = null; + public static final Cursor DefaultLinkDrop = null; + public static final Cursor DefaultCopyNoDrop = null; + public static final Cursor DefaultMoveNoDrop = null; + public static final Cursor DefaultLinkNoDrop = null; + + private transient FlavorMap flavorMap = SystemFlavorMap.getDefaultFlavorMap (); + private transient DragSourceListener dragSourceListener; + private transient DragSourceMotionListener dragSourceMotionListener; + + private static DragSource ds; + private DragSourceContextPeer peer; + private DragSourceContext context; + + /** + * Initializes the drag source. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public DragSource() + { + if (GraphicsEnvironment.isHeadless()) + { + ds = null; + throw new HeadlessException(); + } + } + + /** + * Gets the default drag source. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public static DragSource getDefaultDragSource() + { + if (GraphicsEnvironment.isHeadless()) + { + ds = null; + throw new HeadlessException(); + } + + if (ds == null) + ds = new DragSource(); + return ds; + } + + public static boolean isDragImageSupported() + { + // In all cases, Sun returns false here. + return false; + } + + /** + * Start a drag, given the DragGestureEvent that initiated the drag. + * + * @exception InvalidDnDOperationException If the Drag and Drop system is + * unable to initiate a drag operation, or if the user attempts to start + * a drag while an existing drag operation is still executing. + */ + public void startDrag(DragGestureEvent trigger, Cursor dragCursor, + Image dragImage, Point imageOffset, + Transferable trans, DragSourceListener dsl, + FlavorMap map) + { + // http://www.javaworld.com/javaworld/jw-03-1999/jw-03-dragndrop.html + + // This function creates a DragSourceContext object. This object tracks the + // state of the operation by listening to a native peer. In this situation, + // the DragSource may be obtained from the event or by an instance variable. + // This function also creates a new DragSourceContextPeer. + + // This function sends the same message to the context, which then forwards + // it to the peer, passing itself as a parameter. Now, the native system has + // access to the Transferable through the context. + + try + { + flavorMap = map; + + if (peer == null) + peer = Toolkit.getDefaultToolkit().createDragSourceContextPeer(trigger); + + if (context == null) + context = createDragSourceContext(peer, trigger, + dragCursor, + dragImage, + imageOffset, trans, + dsl); + + if (peer == null) + throw new InvalidDnDOperationException(); + + peer.startDrag(context, dragCursor, dragImage, imageOffset); + } + catch (Exception e) + { + throw new InvalidDnDOperationException("Drag and Drop system is " + + "unable to initiate a drag operation."); + } + } + + /** + * Start a drag, given the DragGestureEvent that initiated the drag. + * + * @exception InvalidDnDOperationException If the Drag and Drop system is + * unable to initiate a drag operation, or if the user attempts to start + * a drag while an existing drag operation is still executing. + */ + public void startDrag(DragGestureEvent trigger, Cursor dragCursor, + Transferable trans, DragSourceListener dsl, + FlavorMap map) + { + startDrag(trigger, dragCursor, null, null, trans, dsl, map); + } + + /** + * Start a drag, given the DragGestureEvent that initiated the drag. + * + * @exception InvalidDnDOperationException If the Drag and Drop system is + * unable to initiate a drag operation, or if the user attempts to start + * a drag while an existing drag operation is still executing. + */ + public void startDrag(DragGestureEvent trigger, Cursor dragCursor, + Image dragImage, Point imageOffset, + Transferable trans, DragSourceListener dsl) + { + startDrag(trigger, dragCursor, dragImage, imageOffset, trans, dsl, null); + } + + /** + * Start a drag, given the DragGestureEvent that initiated the drag. + * + * @exception InvalidDnDOperationException If the Drag and Drop system is + * unable to initiate a drag operation, or if the user attempts to start + * a drag while an existing drag operation is still executing. + */ + public void startDrag(DragGestureEvent trigger, Cursor dragCursor, + Transferable trans, DragSourceListener dsl) + { + startDrag(trigger, dragCursor, null, null, trans, dsl, null); + } + + /** + * Creates the DragSourceContext to handle this drag. + * + * @exception IllegalArgumentException + * @exception NullPointerException If dscp, dgl, dragImage or t is null. + */ + protected DragSourceContext + createDragSourceContext(DragSourceContextPeer peer, DragGestureEvent dge, + Cursor cursor, Image image, Point offset, + Transferable t, DragSourceListener dsl) + { + return new DragSourceContext(peer, dge, cursor, image, offset, t, dsl); + } + + public FlavorMap getFlavorMap() + { + return flavorMap; + } + + public <T extends DragGestureRecognizer> T + createDragGestureRecognizer(Class<T> recognizer, + Component c, + int actions, + DragGestureListener dgl) + { + return (T) Toolkit.getDefaultToolkit().createDragGestureRecognizer(recognizer, + this, c, + actions, dgl); + } + + public DragGestureRecognizer createDefaultDragGestureRecognizer(Component c, + int actions, + DragGestureListener dgl) + { + return createDragGestureRecognizer(MouseDragGestureRecognizer.class, c, + actions, dgl); + } + + /** + * @since 1.4 + */ + public void addDragSourceListener(DragSourceListener l) + { + DnDEventMulticaster.add (dragSourceListener, l); + } + + /** + * @since 1.4 + */ + public void removeDragSourceListener(DragSourceListener l) + { + DnDEventMulticaster.remove (dragSourceListener, l); + } + + /** + * @since 1.4 + */ + public DragSourceListener[] getDragSourceListeners() + { + return (DragSourceListener[]) getListeners (DragSourceListener.class); + } + + /** + * @since 1.4 + */ + public void addDragSourceMotionListener(DragSourceMotionListener l) + { + DnDEventMulticaster.add (dragSourceMotionListener, l); + } + + /** + * @since 1.4 + */ + public void removeDragSourceMotionListener(DragSourceMotionListener l) + { + DnDEventMulticaster.remove (dragSourceMotionListener, l); + } + + /** + * @since 1.4 + */ + public DragSourceMotionListener[] getDragSourceMotionListeners () + { + return (DragSourceMotionListener[]) getListeners + (DragSourceMotionListener.class); + } + + /** + * @since 1.4 + */ + public <T extends EventListener> T[] getListeners (Class<T> listenerType) + { + if (listenerType == DragSourceListener.class) + return DnDEventMulticaster.getListeners (dragSourceListener, + listenerType); + + if (listenerType == DragSourceMotionListener.class) + return DnDEventMulticaster.getListeners (dragSourceMotionListener, + listenerType); + + // Return an empty EventListener array. + return (T[]) new EventListener [0]; + } + + /** + * TODO + * @return TODO + * + * @since 1.5 + */ + public static int getDragThreshold() + throws NotImplementedException + { + // FIXME: Not implemented. + return 8; + } +} // class DragSource diff --git a/libjava/classpath/java/awt/dnd/DragSourceAdapter.java b/libjava/classpath/java/awt/dnd/DragSourceAdapter.java new file mode 100644 index 000000000..90d9a6983 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragSourceAdapter.java @@ -0,0 +1,126 @@ +/* DragSourceAdapter.java -- drag-and-drop listener adapter + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.dnd; + +/** + * This class implements <code>DragSourceListener</code> and + * <code>DragSourceMotionListener</code>, and implements all methods + * with empty bodies. This allows a listener interested in implementing only + * a subset of these interfaces to extend this class and override only the + * desired methods. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see DragSourceEvent + * @see DragSourceListener + * @see DragSourceMotionListener + * @since 1.4 + * @status updated to 1.4 + */ +public abstract class DragSourceAdapter + implements DragSourceListener, DragSourceMotionListener +{ + /** + * Default constructor. + */ + public DragSourceAdapter() + { + } + + /** + * Called when the cursor hotspot enters a drop site which will accept the + * drag. + * + * @param e the event + */ + public void dragEnter(DragSourceDragEvent e) + { + } + + /** + * Called when the cursor hotspot moves inside of a drop site which will + * accept the drag. + * + * @param e the event + */ + public void dragOver(DragSourceDragEvent e) + { + } + + /** + * Called whenever the mouse is moved during a drag-and-drop operation. + * + * @param e the event + */ + public void dragMouseMoved(DragSourceDragEvent e) + { + } + + /** + * Called when the user modifies the drop gesture. This is often the case + * when additional mouse or key events are received during the drag. + * + * @param e the event + */ + public void dropActionChanged(DragSourceDragEvent e) + { + } + + /** + * Called when the cursor hotspot moves outside of a drop site which will + * accept the drag. This could also happen if the drop site is no longer + * active, or no longer accepts the drag. + * + * @param e the event + */ + public void dragExit(DragSourceEvent e) + { + } + + /** + * Called when the drag and drop operation is complete. After this event, + * <code>getDropSuccess</code> of the event is valid, and + * <code>getDropAction</code> holds the action requested by the drop site. + * Furthermore, the <code>DragSourceContext</code> is invalidated. + * + * @param e the event + */ + public void dragDropEnd(DragSourceDropEvent e) + { + } +} // class DragSourceAdapter diff --git a/libjava/classpath/java/awt/dnd/DragSourceContext.java b/libjava/classpath/java/awt/dnd/DragSourceContext.java new file mode 100644 index 000000000..e21b4fdae --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragSourceContext.java @@ -0,0 +1,383 @@ +/* DragSourceContext.java -- + Copyright (C) 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.dnd; + +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Image; +import java.awt.Point; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.peer.DragSourceContextPeer; +import java.io.Serializable; +import java.util.TooManyListenersException; + +/** + * @since 1.2 + */ +public class DragSourceContext + implements DragSourceListener, DragSourceMotionListener, Serializable +{ + /** + * Compatible with JDK 1.2+ + */ + static final long serialVersionUID = -115407898692194719L; + + protected static final int DEFAULT = 0; + protected static final int ENTER = 1; + protected static final int OVER = 2; + protected static final int CHANGED = 3; + + private DragSourceContextPeer peer; + private Cursor cursor; + private Transferable transferable; + private DragGestureEvent trigger; + private DragSourceListener dragSourceListener; + private boolean useCustomCursor; + private int sourceActions; + private Image image; + private Point offset; + + /** + * Initializes a drag source context. + * + * @exception IllegalArgumentException If Component or DragSource of trigger + * are null, the drag action for the trigger event is DnDConstants.ACTION_NONE + * or if the source actions for the DragGestureRecognizer associated with the + * trigger event are equal to DnDConstants.ACTION_NONE. + * @exception NullPointerException If peer, trans or trigger is null or if the + * image is not null but the offset is. + */ + public DragSourceContext (DragSourceContextPeer peer, + DragGestureEvent trigger, Cursor cursor, + Image image, Point offset, Transferable trans, + DragSourceListener dsl) + { + if (peer == null + || trigger == null || trans == null + || (image != null && offset == null)) + throw new NullPointerException (); + + if (trigger.getComponent () == null + || trigger.getDragSource () == null + || trigger.getDragAction () == DnDConstants.ACTION_NONE + || trigger.getSourceAsDragGestureRecognizer () + .getSourceActions () == DnDConstants.ACTION_NONE) + throw new IllegalArgumentException (); + + this.peer = peer; + this.trigger = trigger; + this.cursor = cursor; + this.image = image; + this.offset = offset; + this.transferable = trans; + this.dragSourceListener = dsl; + this.sourceActions = trigger.getSourceAsDragGestureRecognizer().getSourceActions(); + + setCursor(cursor); + updateCurrentCursor(trigger.getDragAction(), sourceActions, DEFAULT); + } + + /** + * Returns the DragSource object associated with the + * DragGestureEvent. + * + * @return the DragSource associated with the trigger. + */ + public DragSource getDragSource() + { + return trigger.getDragSource (); + } + + /** + * Returns the component associated with this. + * + * @return the component associated with the trigger. + */ + public Component getComponent() + { + return trigger.getComponent (); + } + + /** + * Gets the trigger associated with this. + * + * @return the trigger. + */ + public DragGestureEvent getTrigger() + { + return trigger; + } + + /** + * Returns the source actions for the DragGestureRecognizer. + * + * @return the source actions for DragGestureRecognizer. + */ + public int getSourceActions() + { + if (sourceActions == 0) + sourceActions = trigger.getSourceAsDragGestureRecognizer().getSourceActions(); + return sourceActions; + } + + /** + * Sets the cursor for this drag operation to the specified cursor. + * + * @param cursor c - the Cursor to use, or null to use the default drag + * cursor. + */ + public void setCursor(Cursor cursor) + { + if (cursor == null) + useCustomCursor = false; + else + useCustomCursor = true; + this.cursor = cursor; + peer.setCursor(cursor); + } + + /** + * Returns the current cursor or null if the default + * drag cursor is used. + * + * @return the current cursor or null. + */ + public Cursor getCursor() + { + return cursor; + } + + /** + * Adds a <code>DragSourceListener</code>. + * + * @exception TooManyListenersException If a <code>DragSourceListener</code> + * has already been added. + */ + public void addDragSourceListener (DragSourceListener dsl) + throws TooManyListenersException + { + if (dragSourceListener != null) + throw new TooManyListenersException (); + + dragSourceListener = dsl; + } + + public void removeDragSourceListener (DragSourceListener dsl) + { + if (dragSourceListener == dsl) + dragSourceListener = null; + } + + /** + * This function tells the peer that the DataFlavors have been modified. + */ + public void transferablesFlavorsChanged() + { + peer.transferablesFlavorsChanged(); + } + + /** + * Calls dragEnter on the listeners registered with this + * and with the DragSource. + * + * @param e - the DragSourceDragEvent + */ + public void dragEnter(DragSourceDragEvent e) + { + if (dragSourceListener != null) + dragSourceListener.dragEnter(e); + + DragSource ds = getDragSource(); + DragSourceListener[] dsl = ds.getDragSourceListeners(); + for (int i = 0; i < dsl.length; i++) + dsl[i].dragEnter(e); + + updateCurrentCursor(e.getDropAction(), e.getTargetActions(), ENTER); + } + + /** + * Calls dragOver on the listeners registered with this + * and with the DragSource. + * + * @param e - the DragSourceDragEvent + */ + public void dragOver(DragSourceDragEvent e) + { + if (dragSourceListener != null) + dragSourceListener.dragOver(e); + + DragSource ds = getDragSource(); + DragSourceListener[] dsl = ds.getDragSourceListeners(); + for (int i = 0; i < dsl.length; i++) + dsl[i].dragOver(e); + + updateCurrentCursor(e.getDropAction(), e.getTargetActions(), OVER); + } + + /** + * Calls dragExit on the listeners registered with this + * and with the DragSource. + * + * @param e - the DragSourceEvent + */ + public void dragExit(DragSourceEvent e) + { + if (dragSourceListener != null) + dragSourceListener.dragExit(e); + + DragSource ds = getDragSource(); + DragSourceListener[] dsl = ds.getDragSourceListeners(); + for (int i = 0; i < dsl.length; i++) + dsl[i].dragExit(e); + + updateCurrentCursor(DnDConstants.ACTION_NONE, DnDConstants.ACTION_NONE, + DEFAULT); + } + + /** + * Calls dropActionChanged on the listeners registered with this + * and with the DragSource. + * + * @param e - the DragSourceDragEvent + */ + public void dropActionChanged(DragSourceDragEvent e) + { + if (dragSourceListener != null) + dragSourceListener.dropActionChanged(e); + + DragSource ds = getDragSource(); + DragSourceListener[] dsl = ds.getDragSourceListeners(); + for (int i = 0; i < dsl.length; i++) + dsl[i].dropActionChanged(e); + + updateCurrentCursor(e.getDropAction(), e.getTargetActions(), CHANGED); + } + + /** + * Calls dragDropEnd on the listeners registered with this + * and with the DragSource. + * + * @param e - the DragSourceDropEvent + */ + public void dragDropEnd(DragSourceDropEvent e) + { + if (dragSourceListener != null) + dragSourceListener.dragDropEnd(e); + + DragSource ds = getDragSource(); + DragSourceListener[] dsl = ds.getDragSourceListeners(); + for (int i = 0; i < dsl.length; i++) + dsl[i].dragDropEnd(e); + } + + /** + * Calls dragMouseMoved on the listeners registered with the DragSource. + * + * @param e - the DragSourceDragEvent + */ + public void dragMouseMoved(DragSourceDragEvent e) + { + DragSource ds = getDragSource(); + DragSourceMotionListener[] dsml = ds.getDragSourceMotionListeners(); + for (int i = 0; i < dsml.length; i++) + dsml[i].dragMouseMoved(e); + } + + /** + * Returns the Transferable set with this object. + * + * @return the transferable. + */ + public Transferable getTransferable() + { + return transferable; + } + + /** + * This function sets the drag cursor for the specified operation, actions and + * status if the default drag cursor is active. Otherwise, the cursor is not + * updated in any way. + * + * @param dropOp - the current operation. + * @param targetAct - the supported actions. + * @param status - the status of the cursor (constant). + */ + protected void updateCurrentCursor(int dropOp, int targetAct, int status) + { + if (! useCustomCursor) + { + Cursor newCursor = null; + switch (status) + { + default: + targetAct = DnDConstants.ACTION_NONE; + case ENTER: + case CHANGED: + case OVER: + int action = dropOp & targetAct; + if (action == DnDConstants.ACTION_NONE) + { + if ((dropOp & DnDConstants.ACTION_LINK) != 0) + newCursor = DragSource.DefaultLinkNoDrop; + else if ((dropOp & DnDConstants.ACTION_MOVE) != 0) + newCursor = DragSource.DefaultMoveNoDrop; + else + newCursor = DragSource.DefaultCopyNoDrop; + } + else + { + if ((dropOp & DnDConstants.ACTION_LINK) != 0) + newCursor = DragSource.DefaultLinkDrop; + else if ((dropOp & DnDConstants.ACTION_MOVE) != 0) + newCursor = DragSource.DefaultMoveDrop; + else + newCursor = DragSource.DefaultCopyDrop; + } + } + + if (cursor == null || ! cursor.equals(newCursor)) + { + cursor = newCursor; + DragSourceContextPeer p = peer; + if (p != null) + p.setCursor(cursor); + } + } + } +} // class DragSourceContext diff --git a/libjava/classpath/java/awt/dnd/DragSourceDragEvent.java b/libjava/classpath/java/awt/dnd/DragSourceDragEvent.java new file mode 100644 index 000000000..511700b61 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragSourceDragEvent.java @@ -0,0 +1,102 @@ +/* DragSourceDragEvent.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.dnd; + +import gnu.java.awt.EventModifier; + +/** + * @author Michael Koch + * @since 1.2 + */ +public class DragSourceDragEvent extends DragSourceEvent +{ + /** + * Compatible with JDK 1.2+ + */ + private static final long serialVersionUID = 481346297933902471L; + + private final int dropAction; + private final int targetActions; + private final int gestureModifiers; + + public DragSourceDragEvent(DragSourceContext context, int dropAction, + int actions, int modifiers) + { + super(context); + this.dropAction = dropAction; + targetActions = actions; + gestureModifiers = EventModifier.extend(modifiers); + } + + public DragSourceDragEvent(DragSourceContext context, int dropAction, + int actions, int modifiers, int x, int y) + { + super(context, x, y); + this.dropAction = dropAction; + targetActions = actions; + gestureModifiers = EventModifier.extend(modifiers); + } + + public int getTargetActions() + { + return targetActions; + } + + public int getGestureModifiers() + { + return EventModifier.revert(gestureModifiers); + } + + public int getGestureModifiersEx() + { + return gestureModifiers; + } + + public int getUserAction() + { + return dropAction; + } + + public int getDropAction() + { + return (dropAction + & targetActions + & ((DragSourceContext) source).getSourceActions()); + } +} // class DragSourceDragEvent diff --git a/libjava/classpath/java/awt/dnd/DragSourceDropEvent.java b/libjava/classpath/java/awt/dnd/DragSourceDropEvent.java new file mode 100644 index 000000000..4df984994 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragSourceDropEvent.java @@ -0,0 +1,89 @@ +/* DragSourceDragEvent.java -- + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.dnd; + +/** + * @author Michael Koch (konqueror@gmx.de) + * @since 1.2 + * + * Written using JDK 1.4.1 Online API + * Status: JDK 1.4 complete + */ +public class DragSourceDropEvent extends DragSourceEvent +{ + /** + * Compatible with JDK 1.2+ + */ + private static final long serialVersionUID = -5571321229470821891L; + + private final int dropAction; + private final boolean dropSuccess; + + public DragSourceDropEvent (DragSourceContext context) + { + super (context); + this.dropAction = 0; + this.dropSuccess = false; + } + + public DragSourceDropEvent (DragSourceContext context, int dropAction, + boolean dropSuccess) + { + super (context); + this.dropAction = dropAction; + this.dropSuccess = dropSuccess; + } + + public DragSourceDropEvent (DragSourceContext context, int dropAction, + boolean dropSuccess, int x, int y) + { + super (context, x, y); + this.dropAction = dropAction; + this.dropSuccess = dropSuccess; + } + + public int getDropAction() + { + return dropAction & ((DragSourceContext) source).getSourceActions(); + } + + public boolean getDropSuccess() + { + return dropSuccess; + } +} // class DragSourceDropEvent diff --git a/libjava/classpath/java/awt/dnd/DragSourceEvent.java b/libjava/classpath/java/awt/dnd/DragSourceEvent.java new file mode 100644 index 000000000..c9e18d712 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragSourceEvent.java @@ -0,0 +1,93 @@ +/* DragSourceEvent.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.dnd; + +import java.awt.Point; +import java.util.EventObject; + +/** + * @since 1.2 + */ +public class DragSourceEvent extends EventObject +{ + /** + * Compatible with JDK 1.2+ + */ + private static final long serialVersionUID = -763287114604032641L; + + private final boolean locationSpecified; + private final int x; + private final int y; + + public DragSourceEvent(DragSourceContext context) + { + super(context); + locationSpecified = false; + x = 0; + y = 0; + } + + public DragSourceEvent(DragSourceContext context, int x, int y) + { + super(context); + locationSpecified = true; + this.x = x; + this.y = y; + } + + public DragSourceContext getDragSourceContext() + { + return (DragSourceContext) source; + } + + public Point getLocation() + { + return locationSpecified ? new Point(x, y) : null; + } + + public int getX() + { + return x; + } + + public int getY() + { + return y; + } +} // class DragSourceEvent diff --git a/libjava/classpath/java/awt/dnd/DragSourceListener.java b/libjava/classpath/java/awt/dnd/DragSourceListener.java new file mode 100644 index 000000000..aac6e94eb --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragSourceListener.java @@ -0,0 +1,97 @@ +/* DragSourceListener.java -- listen to events during the drag + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.dnd; + +import java.util.EventListener; + +/** + * This class allows an object to listen for drag and drop events. It can + * be used to provide appropriate feedback for "drag over" actions. You can + * also use a <code>DragSourceAdapter</code> to filter the events you are + * interested in. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ +public interface DragSourceListener extends EventListener +{ + /** + * Called when the cursor hotspot enters a drop site which will accept the + * drag. + * + * @param e the drag source drag event + */ + void dragEnter(DragSourceDragEvent e); + + /** + * Called when the cursor hotspot moves inside of a drop site which will + * accept the drag. + * + * @param e the drag source drag event + */ + void dragOver(DragSourceDragEvent e); + + /** + * Called when the user modifies the drop gesture. This is often the case + * when additional mouse or key events are received during the drag. + * + * @param e the drag source drag event + */ + void dropActionChanged(DragSourceDragEvent e); + + /** + * Called when the cursor hotspot moves outside of a drop site which will + * accept the drag. This could also happen if the drop site is no longer + * active, or no longer accepts the drag. + * + * @param e the drag source drag event + */ + void dragExit(DragSourceEvent e); + + /** + * Called when the drag and drop operation is complete. After this event, + * <code>getDropSuccess</code> of the event is valid, and + * <code>getDropAction</code> holds the action requested by the drop site. + * Furthermore, the <code>DragSourceContext</code> is invalidated. + * + * @param e the drag source drag event + */ + void dragDropEnd(DragSourceDropEvent e); +} // interface DragSourceListener diff --git a/libjava/classpath/java/awt/dnd/DragSourceMotionListener.java b/libjava/classpath/java/awt/dnd/DragSourceMotionListener.java new file mode 100644 index 000000000..5d04c2271 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DragSourceMotionListener.java @@ -0,0 +1,64 @@ +/* DragSourceMotionListener.java -- tracks motion in the drag source + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.dnd; + +import java.util.EventListener; + +/** + * This is a listener for mouse motion in the drag source before the drop + * event occurs. You can also use a <code>DragSourceAdapter</code> to filter + * the events you are interested in. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see DragSourceDragEvent + * @see DragSource + * @see DragSourceListener + * @see DragSourceAdapter + * @since 1.4 + * @status updated to 1.4 + */ +public interface DragSourceMotionListener extends EventListener +{ + /** + * Called whenever the mouse is moved during a drag-and-drop operation. + * + * @param e the event + */ + void dragMouseMoved(DragSourceDragEvent e); +} // interface DragSourceMotionListener diff --git a/libjava/classpath/java/awt/dnd/DropTarget.java b/libjava/classpath/java/awt/dnd/DropTarget.java new file mode 100644 index 000000000..e5180d074 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DropTarget.java @@ -0,0 +1,438 @@ +/* DropTarget.java -- + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.dnd; + +import java.awt.Component; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.datatransfer.FlavorMap; +import java.awt.datatransfer.SystemFlavorMap; +import java.awt.dnd.peer.DropTargetPeer; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.peer.ComponentPeer; +import java.awt.peer.LightweightPeer; +import java.io.Serializable; +import java.util.EventListener; +import java.util.TooManyListenersException; + +import javax.swing.Timer; + +/** + * @author Michael Koch + * @since 1.2 + */ +public class DropTarget + implements DropTargetListener, EventListener, Serializable +{ + /** + * Compatible with JDK 1.2+ + */ + private static final long serialVersionUID = -6283860791671019047L; + + protected static class DropTargetAutoScroller + implements ActionListener + { + /** + * The threshold that keeps the autoscroller running. + */ + private static final int HYSTERESIS = 10; + + /** + * The initial timer delay. + */ + private static final int DELAY = 100; + + private Component component; + private Point point; + + /** + * The timer that triggers autoscrolling. + */ + private Timer timer; + + /** + * The outer region of the scroller. This is the component's size. + */ + private Rectangle outer; + + /** + * The inner region of the scroller. This is the component size without + * the autoscroll insets. + */ + private Rectangle inner; + + protected DropTargetAutoScroller (Component c, Point p) + { + component = c; + point = p; + timer = new Timer(DELAY, this); + timer.setCoalesce(true); + timer.start(); + } + + protected void updateLocation (Point newLocn) + { + Point previous = point; + point = newLocn; + if (Math.abs(point.x - previous.x) > HYSTERESIS + || Math.abs(point.y - previous.y) > HYSTERESIS) + { + if (timer.isRunning()) + timer.stop(); + } + else + { + if (! timer.isRunning()) + timer.start(); + } + } + + protected void stop () + { + timer.start(); + } + + public void actionPerformed (ActionEvent e) + { + Autoscroll autoScroll = (Autoscroll) component; + + // First synchronize the inner and outer rectangles. + Insets i = autoScroll.getAutoscrollInsets(); + int width = component.getWidth(); + int height = component.getHeight(); + if (width != outer.width || height != outer.height) + outer.setBounds(0, 0, width, height); + if (inner.x != i.left || inner.y != i.top) + inner.setLocation(i.left, i.top); + int inWidth = width - i.left - i.right; + int inHeight = height - i.top - i.bottom; + if (inWidth != inner.width || inHeight != inner.height) + inner.setSize(inWidth, inHeight); + + // Scroll if the outer rectangle contains the location, but the + // inner doesn't. + if (outer.contains(point) && ! inner.contains(point)) + autoScroll.autoscroll(point); + } + } + + private Component component; + private FlavorMap flavorMap; + private int actions; + private DropTargetPeer peer; + private DropTargetContext dropTargetContext; + private DropTargetListener dropTargetListener; + private DropTarget.DropTargetAutoScroller autoscroller; + private boolean active = true; + + /** + * Creates a <code>DropTarget</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ + public DropTarget () + { + this (null, DnDConstants.ACTION_COPY_OR_MOVE, null, true, null); + } + + /** + * Creates a <code>DropTarget</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ + public DropTarget (Component c, DropTargetListener dtl) + { + this (c, DnDConstants.ACTION_COPY_OR_MOVE, dtl, true, null); + } + + /** + * Creates a <code>DropTarget</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ + public DropTarget (Component c, int i, DropTargetListener dtl) + { + this (c, i, dtl, true, null); + } + + /** + * Creates a <code>DropTarget</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ + public DropTarget (Component c, int i, DropTargetListener dtl, boolean b) + { + this (c, i, dtl, b, null); + } + + /** + * Creates a <code>DropTarget</code> object. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * returns true. + */ + public DropTarget (Component c, int i, DropTargetListener dtl, boolean b, + FlavorMap fm) + { + if (GraphicsEnvironment.isHeadless ()) + throw new HeadlessException (); + + setComponent(c); + setDefaultActions(i); + dropTargetListener = dtl; + + if (fm == null) + flavorMap = SystemFlavorMap.getDefaultFlavorMap(); + else + flavorMap = fm; + + setActive (b); + + if (c != null) + c.setDropTarget(this); + } + + /** + * Sets the component associated with this drop target object. + */ + public void setComponent (Component c) + { + if (component != null) + clearAutoscroll(); + component = c; + } + + /** + * Returns the component associated with this drop target object. + */ + public Component getComponent () + { + return component; + } + + /** + * Sets the default actions. + */ + public void setDefaultActions (int ops) + { + actions = ops; + } + + /** + * Returns the default actions. + */ + public int getDefaultActions () + { + return actions; + } + + public void setActive (boolean active) + { + this.active = active; + if (! active) + clearAutoscroll(); + } + + public boolean isActive() + { + return active; + } + + /** + * Adds a new <code>DropTargetListener</code>. + * + * @exception TooManyListenersException Sun's JDK does not, despite + * documentation, throw this exception here when you install an additional + * <code>DropTargetListener</code>. So to be compatible, we do the same + * thing. + */ + public void addDropTargetListener (DropTargetListener dtl) + throws TooManyListenersException + { + if (dtl == null) + return; + + if (dtl.equals(this)) + throw new IllegalArgumentException(); + + if (dropTargetListener != null) + throw new TooManyListenersException(); + + dropTargetListener = dtl; + } + + public void removeDropTargetListener(DropTargetListener dtl) + { + if (dropTargetListener != null) + dropTargetListener = null; + } + + public void dragEnter(DropTargetDragEvent dtde) + { + if (active) + { + if (dropTargetListener != null) + dropTargetListener.dragEnter(dtde); + initializeAutoscrolling(dtde.getLocation()); + } + } + + public void dragOver(DropTargetDragEvent dtde) + { + if (active) + { + if (dropTargetListener != null) + dropTargetListener.dragOver(dtde); + updateAutoscroll(dtde.getLocation()); + } + } + + public void dropActionChanged(DropTargetDragEvent dtde) + { + if (active) + { + if (dropTargetListener != null) + dropTargetListener.dropActionChanged(dtde); + updateAutoscroll(dtde.getLocation()); + } + } + + public void dragExit(DropTargetEvent dte) + { + if (active) + { + if (dropTargetListener != null) + dropTargetListener.dragExit(dte); + clearAutoscroll(); + } + } + + public void drop(DropTargetDropEvent dtde) + { + clearAutoscroll(); + if (dropTargetListener != null) + dropTargetListener.drop(dtde); + } + + public FlavorMap getFlavorMap() + { + return flavorMap; + } + + public void setFlavorMap(FlavorMap fm) + { + flavorMap = fm; + } + + public void addNotify(ComponentPeer p) + { + Component c = component; + while (c != null && p instanceof LightweightPeer) + { + p = c.getPeer(); + c = c.getParent(); + } + + if (p instanceof DropTargetPeer) + { + peer = ((DropTargetPeer) p); + peer.addDropTarget(this); + } + else + peer = null; + } + + public void removeNotify(ComponentPeer p) + { + ((DropTargetPeer) peer).removeDropTarget(this); + peer = null; + p = null; + } + + public DropTargetContext getDropTargetContext() + { + if (dropTargetContext == null) + dropTargetContext = createDropTargetContext (); + + return dropTargetContext; + } + + protected DropTargetContext createDropTargetContext() + { + if (dropTargetContext == null) + dropTargetContext = new DropTargetContext (this); + + return dropTargetContext; + } + + protected DropTarget.DropTargetAutoScroller createDropTargetAutoScroller + (Component c, Point p) + { + return new DropTarget.DropTargetAutoScroller (c, p); + } + + protected void initializeAutoscrolling(Point p) + { + if (component instanceof Autoscroll) // Checks for null too. + autoscroller = createDropTargetAutoScroller (component, p); + } + + protected void updateAutoscroll(Point dragCursorLocn) + { + if (autoscroller != null) + autoscroller.updateLocation(dragCursorLocn); + } + + protected void clearAutoscroll() + { + if (autoscroller != null) + { + autoscroller.stop(); + autoscroller = null; + } + } +} // class DropTarget diff --git a/libjava/classpath/java/awt/dnd/DropTargetAdapter.java b/libjava/classpath/java/awt/dnd/DropTargetAdapter.java new file mode 100644 index 000000000..13c6b9f4b --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DropTargetAdapter.java @@ -0,0 +1,100 @@ +/* DragSourceAdapter.java -- drag-and-drop listener adapter + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.dnd; + +/** + * This class implements <code>DropTargetListener</code>, and implements all methods + * with empty bodies. This allows a listener interested in implementing only + * a subset of these interfaces to extend this class and override only the + * desired methods. + * + * @author Michael Koch (konqueror@gmx.de) + * @since 1.4 + * @status updated to 1.4 + */ +public abstract class DropTargetAdapter + implements DropTargetListener +{ + /** + * Default constructor. + */ + public DropTargetAdapter() + { + } + + /** + * Called when the cursor hotspot enters a drop site which will accept the + * drag. + * + * @param e the event + */ + public void dragEnter (DropTargetDragEvent e) + { + } + + /** + * Called when the cursor hotspot moves inside of a drop site which will + * accept the drag. + * + * @param e the event + */ + public void dragOver (DropTargetDragEvent e) + { + } + + /** + * Called when the user modifies the drop gesture. This is often the case + * when additional mouse or key events are received during the drag. + * + * @param e the event + */ + public void dropActionChanged (DropTargetDragEvent e) + { + } + + /** + * Called when the cursor hotspot moves outside of a drop site which will + * accept the drag. This could also happen if the drop site is no longer + * active, or no longer accepts the drag. + * + * @param e the event + */ + public void dragExit(DropTargetEvent e) + { + } +} // class DropTargetAdapter diff --git a/libjava/classpath/java/awt/dnd/DropTargetContext.java b/libjava/classpath/java/awt/dnd/DropTargetContext.java new file mode 100644 index 000000000..4c21a6e8a --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DropTargetContext.java @@ -0,0 +1,197 @@ +/* DropTargetContext.java -- + Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.dnd; + +import java.awt.Component; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.peer.DropTargetContextPeer; +import java.io.IOException; +import java.io.Serializable; +import java.util.Arrays; +import java.util.List; + +/** + * @author Michael Koch (konqueror@gmx.de) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.2 + */ +public class DropTargetContext implements Serializable +{ + static final long serialVersionUID = -634158968993743371L; + + protected class TransferableProxy implements Transferable + { + protected boolean isLocal; + protected Transferable transferable; + + TransferableProxy(Transferable t, boolean local) + { + this.transferable = t; + this.isLocal = local; + } + + public DataFlavor[] getTransferDataFlavors() + { + return transferable.getTransferDataFlavors(); + } + + public boolean isDataFlavorSupported(DataFlavor flavor) + { + return transferable.isDataFlavorSupported(flavor); + } + + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException + { + return transferable.getTransferData (flavor); + } + } + + private DropTarget dropTarget; + private int targetActions; + private DropTargetContextPeer dtcp; + + // package private + DropTargetContext(DropTarget dropTarget) + { + this.dropTarget = dropTarget; + } + + public DropTarget getDropTarget() + { + return dropTarget; + } + + public Component getComponent() + { + return dropTarget.getComponent(); + } + + public void addNotify(DropTargetContextPeer dtcp) + { + this.dtcp = dtcp; + } + + public void removeNotify() + { + this.dtcp = null; + } + + protected void setTargetActions(int actions) + { + targetActions = actions; + } + + protected int getTargetActions() + { + return targetActions; + } + + /** + * Signals that the drop is completed. + * + * @exception InvalidDnDOperationException If a drop is not outstanding. + */ + public void dropComplete (boolean success) + { + if (dtcp != null) + dtcp.dropComplete(success); + } + + protected void acceptDrag (int dragOperation) + { + if (dtcp != null) + dtcp.acceptDrag(dragOperation); + } + + protected void rejectDrag () + { + if (dtcp != null) + dtcp.rejectDrag(); + } + + protected void acceptDrop (int dropOperation) + { + if (dtcp != null) + dtcp.acceptDrop(dropOperation); + } + + protected void rejectDrop () + { + if (dtcp != null) + dtcp.rejectDrop(); + } + + protected DataFlavor[] getCurrentDataFlavors () + { + if (dtcp != null) + dtcp.getTransferDataFlavors(); + return null; + } + + protected List<DataFlavor> getCurrentDataFlavorsAsList () + { + return Arrays.asList(getCurrentDataFlavors ()); + } + + protected boolean isDataFlavorSupported (DataFlavor flavor) + { + return getCurrentDataFlavorsAsList().contains (flavor); + } + + /** + * Return the <code>Transferable</code> operandof this operation. + * + * @exception InvalidDnDOperationException If a drag is not outstanding. + */ + protected Transferable getTransferable() + throws InvalidDnDOperationException + { + // FIXME: Implement this + if (dtcp != null) + return dtcp.getTransferable(); + return null; + } + + protected Transferable createTransferableProxy(Transferable t, boolean local) + { + return new TransferableProxy(t, local); + } +} // class DropTargetContext diff --git a/libjava/classpath/java/awt/dnd/DropTargetDragEvent.java b/libjava/classpath/java/awt/dnd/DropTargetDragEvent.java new file mode 100644 index 000000000..21c9e2b35 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DropTargetDragEvent.java @@ -0,0 +1,152 @@ +/* DropTargetDragEvent.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.dnd; + +import java.awt.Point; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.util.List; + +/** + * @since 1.2 + */ +public class DropTargetDragEvent extends DropTargetEvent +{ + /** + * Compatible with 1.2+ + */ + private static final long serialVersionUID = -8422265619058953682L; + + private final int dropAction; + private final int srcActions; + private final Point location; + + /** + * Initializes a <code>DropTargetDragEvent</code>. + * + * @exception IllegalArgumentException If dropAction is not one of DnDConstants, + * srcActions is not a bitwise mask of DnDConstants, or dtc is null. + * @exception NullPointerException If location is null. + */ + public DropTargetDragEvent (DropTargetContext context, Point location, + int dropAction, int srcActions) + { + super (context); + + if (location == null) + throw new NullPointerException (); + + if (context == null) + throw new IllegalArgumentException (); + + if (dropAction != DnDConstants.ACTION_NONE + && dropAction != DnDConstants.ACTION_COPY + && dropAction != DnDConstants.ACTION_MOVE + && dropAction != DnDConstants.ACTION_COPY_OR_MOVE + && dropAction != DnDConstants.ACTION_LINK + && dropAction != DnDConstants.ACTION_REFERENCE) + throw new IllegalArgumentException (); + + int srcActionsMask = DnDConstants.ACTION_NONE + | DnDConstants.ACTION_COPY + | DnDConstants.ACTION_MOVE + | DnDConstants.ACTION_COPY_OR_MOVE + | DnDConstants.ACTION_LINK + | DnDConstants.ACTION_REFERENCE; + + if (~(srcActions ^ srcActionsMask) != 0) + throw new IllegalArgumentException (); + + this.dropAction = dropAction; + this.srcActions = srcActions; + this.location = location; + } + + public void acceptDrag (int dragOperation) + { + context.acceptDrag (dragOperation); + } + + public DataFlavor[] getCurrentDataFlavors () + { + return context.getCurrentDataFlavors (); + } + + public List<DataFlavor> getCurrentDataFlavorsAsList () + { + return context.getCurrentDataFlavorsAsList (); + } + + public int getDropAction() + { + return dropAction & ((DropTargetContext) source).getTargetActions(); + } + + public Point getLocation () + { + return location; + } + + public int getSourceActions () + { + return srcActions; + } + + public boolean isDataFlavorSupported (DataFlavor df) + { + return context.isDataFlavorSupported (df); + } + + public void rejectDrag () + { + context.rejectDrag (); + } + + /** + * TODO + * + * @return + * + * @since 1.5 + */ + public Transferable getTransferable() + { + return context.getTransferable(); + } +} // class DropTargetDragEvent diff --git a/libjava/classpath/java/awt/dnd/DropTargetDropEvent.java b/libjava/classpath/java/awt/dnd/DropTargetDropEvent.java new file mode 100644 index 000000000..333f8c6cc --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DropTargetDropEvent.java @@ -0,0 +1,170 @@ +/* DropTargetDropEvent.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.dnd; + +import java.awt.Point; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.util.List; + +/** + * @since 1.2 + */ +public class DropTargetDropEvent extends DropTargetEvent +{ + /** + * Compatible with JDK 1.2+ + */ + private static final long serialVersionUID = -1721911170440459322L; + + private final int dropAction; + private final int actions; + private final Point location; + private final boolean isLocalTx; + + /** + * Initializes a <code>DropTargetDropEvent</code>. By default this constructor + * assumes that the target is not int same JVM. + * + * @exception IllegalArgumentException If dropAction is not one of DnDConstants, + * actions is not a bitwise mask of DnDConstants, or dtc is null. + * @exception NullPointerException If location is null. + */ + public DropTargetDropEvent(DropTargetContext dtc, Point location, + int dropAction, int actions) + { + this(dtc, location, dropAction, actions, false); + } + + /** + * Initializes a <code>DropTargetDropEvent</code>. + * + * @exception IllegalArgumentException If dropAction is not one of DnDConstants, + * actions is not a bitwise mask of DnDConstants, or dtc is null. + * @exception NullPointerException If location is null. + */ + public DropTargetDropEvent(DropTargetContext dtc, Point location, + int dropAction, int actions, boolean isLocalTx) + { + super(dtc); + + if (location == null) + throw new NullPointerException(); + + if (dtc == null) + throw new IllegalArgumentException(); + + if (dropAction != DnDConstants.ACTION_NONE + && dropAction != DnDConstants.ACTION_COPY + && dropAction != DnDConstants.ACTION_MOVE + && dropAction != DnDConstants.ACTION_COPY_OR_MOVE + && dropAction != DnDConstants.ACTION_LINK + && dropAction != DnDConstants.ACTION_REFERENCE) + throw new IllegalArgumentException(); + + int actionsMask = DnDConstants.ACTION_NONE + | DnDConstants.ACTION_COPY + | DnDConstants.ACTION_MOVE + | DnDConstants.ACTION_COPY_OR_MOVE + | DnDConstants.ACTION_LINK + | DnDConstants.ACTION_REFERENCE; + + if (~(actions ^ actionsMask) != 0) + throw new IllegalArgumentException(); + + this.dropAction = dropAction; + this.actions = actions; + this.location = location; + this.isLocalTx = isLocalTx; + } + + public Point getLocation() + { + return location; + } + + public DataFlavor[] getCurrentDataFlavors() + { + return context.getCurrentDataFlavors(); + } + + public List<DataFlavor> getCurrentDataFlavorsAsList() + { + return context.getCurrentDataFlavorsAsList(); + } + + public boolean isDataFlavorSupported(DataFlavor flavor) + { + return context.isDataFlavorSupported(flavor); + } + + public int getSourceActions() + { + return actions; + } + + public int getDropAction() + { + return dropAction; + } + + public Transferable getTransferable() + { + return context.getTransferable (); + } + + public void acceptDrop(int dropAction) + { + context.acceptDrop(dropAction); + } + + public void rejectDrop() + { + context.rejectDrop(); + } + + public void dropComplete(boolean success) + { + context.dropComplete(success); + } + + public boolean isLocalTransfer() + { + return isLocalTx; + } +} // class DropTargetDropEvent diff --git a/libjava/classpath/java/awt/dnd/DropTargetEvent.java b/libjava/classpath/java/awt/dnd/DropTargetEvent.java new file mode 100644 index 000000000..fc599a9e2 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DropTargetEvent.java @@ -0,0 +1,62 @@ +/* DropTarget.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.dnd; + +import java.util.EventObject; + +public class DropTargetEvent extends EventObject +{ + + /** + * Serialization identifier for Sun 1.5 compatability + */ + private static final long serialVersionUID = 2821229066521922993L; + + protected DropTargetContext context; + + public DropTargetEvent (DropTargetContext context) + { + super (context); + this.context = context; + } + + public DropTargetContext getDropTargetContext () + { + return context; + } +} diff --git a/libjava/classpath/java/awt/dnd/DropTargetListener.java b/libjava/classpath/java/awt/dnd/DropTargetListener.java new file mode 100644 index 000000000..ceb839bac --- /dev/null +++ b/libjava/classpath/java/awt/dnd/DropTargetListener.java @@ -0,0 +1,89 @@ +/* DropTargetListener.java -- listen to events during the drop + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.dnd; + +import java.util.EventListener; + +/** + * @author Michael Koch (konqueror@gmx.de) + * @since 1.2 + * @status updated to 1.4 + */ +public interface DropTargetListener extends EventListener +{ + /** + * Called when the cursor hotspot enters a drop site which will accept the + * drag. + * + * @param e the drag source drag event + */ + void dragEnter (DropTargetDragEvent e); + + /** + * Called when the cursor hotspot moves inside of a drop site which will + * accept the drag. + * + * @param e the drag source drag event + */ + void dragOver (DropTargetDragEvent e); + + /** + * Called when the user modifies the drop gesture. This is often the case + * when additional mouse or key events are received during the drag. + * + * @param e the drag source drag event + */ + void dropActionChanged (DropTargetDragEvent e); + + /** + * Called when the cursor hotspot moves outside of a drop site which will + * accept the drag. This could also happen if the drop site is no longer + * active, or no longer accepts the drag. + * + * @param e the drag source drag event + */ + void dragExit (DropTargetEvent e); + + /** + * Called when the drag operation has terminated with a drop. + * + * @param e the drag source drag event + */ + void drop (DropTargetDropEvent e); +} // interface DropTargetListener diff --git a/libjava/classpath/java/awt/dnd/InvalidDnDOperationException.java b/libjava/classpath/java/awt/dnd/InvalidDnDOperationException.java new file mode 100644 index 000000000..4a75610bf --- /dev/null +++ b/libjava/classpath/java/awt/dnd/InvalidDnDOperationException.java @@ -0,0 +1,74 @@ +/* InvalidDnDOperationException.java -- thrown when drag-and-drop fails + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.dnd; + +/** + * Thrown when a method in the java.awt.dnd package is unable to perform a + * requested operation, usually because the underlying DnD system is in the + * wrong state. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ +public class InvalidDnDOperationException extends IllegalStateException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -6062568741193956678L; + + /** + * Create an exception without a message. + */ + public InvalidDnDOperationException() + { + super(); + } + + /** + * Create an exception with a message. + * + * @param s the message + */ + public InvalidDnDOperationException(String s) + { + super(s); + } +} // class InvalidDnDOperationException diff --git a/libjava/classpath/java/awt/dnd/MouseDragGestureRecognizer.java b/libjava/classpath/java/awt/dnd/MouseDragGestureRecognizer.java new file mode 100644 index 000000000..08a2ac085 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/MouseDragGestureRecognizer.java @@ -0,0 +1,131 @@ +/* MouseDragGestureRecognizer.java -- + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.dnd; + +import java.awt.Component; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; + +/** + * @author Michael Koch (konqueror@gmx.de) + */ +public abstract class MouseDragGestureRecognizer + extends DragGestureRecognizer + implements MouseListener, MouseMotionListener +{ + /** + * Creates a <code>MouseDragGestureRecognizer</code> object. + */ + protected MouseDragGestureRecognizer (DragSource ds, Component c, int act, + DragGestureListener dgl) + { + super (ds, c, act, dgl); + } + + /** + * Creates a <code>MouseDragGestureRecognizer</code> object. + */ + protected MouseDragGestureRecognizer (DragSource ds, Component c, int act) + { + super (ds, c, act); + } + + /** + * Creates a <code>MouseDragGestureRecognizer</code> object. + */ + protected MouseDragGestureRecognizer (DragSource ds, Component c) + { + super (ds, c); + } + + /** + * Creates a <code>MouseDragGestureRecognizer</code> object. + */ + protected MouseDragGestureRecognizer (DragSource ds) + { + super (ds); + } + + protected void registerListeners () + { + component.addMouseListener (this); + component.addMouseMotionListener (this); + } + + protected void unregisterListeners () + { + component.removeMouseListener (this); + component.removeMouseMotionListener (this); + } + + public void mouseClicked (MouseEvent e) + { + // Do nothing in here by default. + } + + public void mousePressed (MouseEvent e) + { + // Do nothing in here by default. + } + + public void mouseReleased (MouseEvent e) + { + // Do nothing in here by default. + } + + public void mouseEntered (MouseEvent e) + { + // Do nothing in here by default. + } + + public void mouseExited (MouseEvent e) + { + // Do nothing in here by default. + } + + public void mouseDragged (MouseEvent e) + { + // Do nothing in here by default. + } + + public void mouseMoved (MouseEvent e) + { + // Do nothing in here by default. + } +} // class MouseDragGestureRecognizer diff --git a/libjava/classpath/java/awt/dnd/package.html b/libjava/classpath/java/awt/dnd/package.html new file mode 100644 index 000000000..d1ae5215c --- /dev/null +++ b/libjava/classpath/java/awt/dnd/package.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in java.awt.dnd package. + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - java.awt.dnd</title></head> + +<body> +<p>Events and listeners for drag and drop sources and targets.</p> + +</body> +</html> diff --git a/libjava/classpath/java/awt/dnd/peer/DragSourceContextPeer.java b/libjava/classpath/java/awt/dnd/peer/DragSourceContextPeer.java new file mode 100644 index 000000000..8c134b623 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/peer/DragSourceContextPeer.java @@ -0,0 +1,57 @@ +/* DragSourceContextPeer.java -- interface for drag-and-drop peers + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.dnd.peer; + +import java.awt.Cursor; +import java.awt.Image; +import java.awt.Point; +import java.awt.dnd.DragSourceContext; +import java.awt.dnd.InvalidDnDOperationException; + +/** + * STUBBED + */ +public interface DragSourceContextPeer +{ + void startDrag(DragSourceContext context, Cursor c, Image i, Point p) + throws InvalidDnDOperationException; + Cursor getCursor(); + void setCursor(Cursor c) throws InvalidDnDOperationException; + void transferablesFlavorsChanged(); +} // interface DragSourceContextPeer diff --git a/libjava/classpath/java/awt/dnd/peer/DropTargetContextPeer.java b/libjava/classpath/java/awt/dnd/peer/DropTargetContextPeer.java new file mode 100644 index 000000000..2f4da5ff3 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/peer/DropTargetContextPeer.java @@ -0,0 +1,68 @@ +/* DropTargetContextPeer.java -- interface for drag-and-drop peers + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.dnd.peer; + +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DropTarget; +import java.awt.dnd.InvalidDnDOperationException; + + +/** + * Used to control state of recipient protocol from the + * <code>DropTargetListener</code>. Occurs when a <code>Component</code> + * with an associated <code>DropTarget</code> and visible geometry is first + * intersected by a logical cursor. + * + * @author Michael Koch (konqueror@gmx.de) + */ +public interface DropTargetContextPeer +{ + void setTargetActions(int actions); + int getTargetActions(); + DropTarget getDropTarget(); + DataFlavor[] getTransferDataFlavors(); + Transferable getTransferable() throws InvalidDnDOperationException; + boolean isTransferableJVMLocal(); + void acceptDrag(int dragAction); + void rejectDrag(); + void acceptDrop(int dropAction); + void rejectDrop(); + void dropComplete(boolean success); +} diff --git a/libjava/classpath/java/awt/dnd/peer/DropTargetPeer.java b/libjava/classpath/java/awt/dnd/peer/DropTargetPeer.java new file mode 100644 index 000000000..ec17cbe4b --- /dev/null +++ b/libjava/classpath/java/awt/dnd/peer/DropTargetPeer.java @@ -0,0 +1,48 @@ +/* DropTargetPeer.java -- interface for drag-and-drop peers + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.dnd.peer; + +import java.awt.dnd.DropTarget; + +/** + */ +public interface DropTargetPeer +{ + void addDropTarget (DropTarget target); + void removeDropTarget (DropTarget target); +} // interface DropTargetContextPeer diff --git a/libjava/classpath/java/awt/dnd/peer/package.html b/libjava/classpath/java/awt/dnd/peer/package.html new file mode 100644 index 000000000..52ec19cb4 --- /dev/null +++ b/libjava/classpath/java/awt/dnd/peer/package.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in java.awt.dnd.peer package. + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - java.awt.dnd.peer</title></head> + +<body> +<p>Interfaces for using native interface components.</p> + +</body> +</html> diff --git a/libjava/classpath/java/awt/doc-files/capjoin.png b/libjava/classpath/java/awt/doc-files/capjoin.png Binary files differnew file mode 100644 index 000000000..555dca901 --- /dev/null +++ b/libjava/classpath/java/awt/doc-files/capjoin.png diff --git a/libjava/classpath/java/awt/event/AWTEventListener.java b/libjava/classpath/java/awt/event/AWTEventListener.java new file mode 100644 index 000000000..3f30df46e --- /dev/null +++ b/libjava/classpath/java/awt/event/AWTEventListener.java @@ -0,0 +1,65 @@ +/* AWTEventListener.java -- listen for all events in the AWT system + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.awt.AWTEvent; +import java.awt.Toolkit; +import java.util.EventListener; + +/** + * This listener is for classes that need to listen to all events in the AWT + * system. In general, this should not be used except for classes like + * javax.accessibility or by event recorders. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see AWTEvent + * @see Toolkit#addAWTEventListener(AWTEventListener, long) + * @see Toolkit#removeAWTEventListener(AWTEventListener) + * @since 1.2 + * @status updated to 1.4 + */ +public interface AWTEventListener extends EventListener +{ + /** + * This method is called when any event in the AWT system is dispatched. + * + * @param event the AWTEvent that was dispatched + */ + void eventDispatched(AWTEvent event); +} // interface AWTEventListener diff --git a/libjava/classpath/java/awt/event/AWTEventListenerProxy.java b/libjava/classpath/java/awt/event/AWTEventListenerProxy.java new file mode 100644 index 000000000..55a4bfe37 --- /dev/null +++ b/libjava/classpath/java/awt/event/AWTEventListenerProxy.java @@ -0,0 +1,95 @@ +/* AWTEventListenerProxy.java -- wrapper/filter for AWTEventListener + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.awt.AWTEvent; +import java.awt.Toolkit; +import java.util.EventListenerProxy; + +/** + * This class allows adding an AWTEventListener which only pays attention to + * a specific event mask. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see Toolkit + * @see EventListenerProxy + * @since 1.4 + * @status updated to 1.4 + */ +public class AWTEventListenerProxy extends EventListenerProxy + implements AWTEventListener +{ + /** The event mask. */ + private final long mask; + + /** + * Construct an AWT Event Listener which only listens to events in the given + * mask, passing the work on to the real listener. + * + * @param eventMask the mask of events to listen to + * @param listener the wrapped listener + */ + public AWTEventListenerProxy(long eventMask, AWTEventListener listener) + { + super(listener); + mask = eventMask; + } + + /** + * Forwards events on to the delegate. + * + * @param event the to forward to the delagate listener + * + * @throws NullPointerException if the delegate this was created with is null + */ + public void eventDispatched(AWTEvent event) + { + ((AWTEventListener) getListener()).eventDispatched(event); + } + + /** + * This returns the event mask associated with this listener. + * + * @return the event mask + */ + public long getEventMask() + { + return mask; + } +} // class AWTEventListenerProxy diff --git a/libjava/classpath/java/awt/event/ActionEvent.java b/libjava/classpath/java/awt/event/ActionEvent.java new file mode 100644 index 000000000..776ab04be --- /dev/null +++ b/libjava/classpath/java/awt/event/ActionEvent.java @@ -0,0 +1,228 @@ +/* ActionEvent.java -- an action has been triggered + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import gnu.java.lang.CPStringBuilder; + +import java.awt.AWTEvent; +import java.awt.EventQueue; + +/** + * This event is generated when an action on a component (such as a + * button press) occurs. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ActionListener + * @since 1.1 + * @status updated to 1.4 + */ +public class ActionEvent extends AWTEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -7671078796273832149L; + + /** Bit mask indicating the shift key was pressed. */ + public static final int SHIFT_MASK = InputEvent.SHIFT_MASK; + + /** Bit mask indicating the control key was pressed. */ + public static final int CTRL_MASK = InputEvent.CTRL_MASK; + + /** Bit mask indicating the that meta key was pressed. */ + public static final int META_MASK = InputEvent.META_MASK; + + /** Bit mask indicating that the alt key was pressed. */ + public static final int ALT_MASK = InputEvent.ALT_MASK; + + /** The first id number in the range of action id's. */ + public static final int ACTION_FIRST = 1001; + + /** The last id number in the range of action id's. */ + public static final int ACTION_LAST = 1001; + + /** An event id indicating that an action has occurred. */ + public static final int ACTION_PERFORMED = 1001; + + /** + * A nonlocalized string that gives more specific details of the event cause. + * + * @see #getActionCommand() + * @serial the command for this event + */ + private final String actionCommand; + + /** + * The bitmask of the modifiers that were pressed during the action. + * + * @see #getModifiers() + * @serial modifiers for this event + */ + private final int modifiers; + + /** + * The timestamp of this event; usually the same as the underlying input + * event. + * + * @see #getWhen() + * @serial the timestamp of the event + * @since 1.4 + */ + private final long when; + + /** + * Initializes a new instance of <code>ActionEvent</code> with the + * specified source, id, and command. Note that an invalid id leads to + * unspecified results. + * + * @param source the event source + * @param id the event id + * @param command the command string for this action + * @throws IllegalArgumentException if source is null + */ + public ActionEvent(Object source, int id, String command) + { + this(source, id, command, EventQueue.getMostRecentEventTime(), 0); + } + + /** + * Initializes a new instance of <code>ActionEvent</code> with the + * specified source, id, command, and modifiers. Note that an invalid id + * leads to unspecified results. + * + * @param source the event source + * @param id the event id + * @param command the command string for this action + * @param modifiers the bitwise or of modifier keys down during the action + * @throws IllegalArgumentException if source is null + */ + public ActionEvent(Object source, int id, String command, int modifiers) + { + this(source, id, command, EventQueue.getMostRecentEventTime(), modifiers); + } + + /** + * Initializes a new instance of <code>ActionEvent</code> with the + * specified source, id, command, and modifiers, and timestamp. Note that + * an invalid id leads to unspecified results. + * + * @param source the event source + * @param id the event id + * @param command the command string for this action + * @param when the timestamp of the event + * @param modifiers the bitwise or of modifier keys down during the action + * @throws IllegalArgumentException if source is null + * @since 1.4 + */ + public ActionEvent(Object source, int id, String command, long when, + int modifiers) + { + super(source, id); + actionCommand = command; + this.when = when; + this.modifiers = modifiers; + } + + /** + * Returns the command string associated with this action. + * + * @return the command string associated with this action + */ + public String getActionCommand() + { + return actionCommand; + } + + /** + * Gets the timestamp of when this action took place. Usually, this + * corresponds to the timestamp of the underlying InputEvent. + * + * @return the timestamp of this action + * @since 1.4 + */ + public long getWhen() + { + return when; + } + + /** + * Returns the keys held down during the action. This value will be a + * combination of the bit mask constants defined in this class, or 0 if no + * modifiers were pressed. + * + * @return the modifier bits + */ + public int getModifiers() + { + return modifiers; + } + + /** + * Returns a string that identifies the action event. This is in the format + * <code>"ACTION_PERFORMED,cmd=" + getActionCommand() + ",when=" + getWhen() + * + ",modifiers=" + <modifier string></code>, where the modifier + * string is in the order "Meta", "Ctrl", "Alt", "Shift", "Alt Graph", and + * "Button1", separated by '+', according to the bits set in getModifiers(). + * + * @return a string identifying the event + */ + public String paramString() + { + CPStringBuilder s = new CPStringBuilder(id == ACTION_PERFORMED + ? "ACTION_PERFORMED,cmd=" + : "unknown type,cmd="); + s.append(actionCommand).append(",when=").append(when).append(",modifiers"); + int len = s.length(); + s.setLength(len + 1); + if ((modifiers & META_MASK) != 0) + s.append("+Meta"); + if ((modifiers & CTRL_MASK) != 0) + s.append("+Ctrl"); + if ((modifiers & ALT_MASK) != 0) + s.append("+Alt"); + if ((modifiers & SHIFT_MASK) != 0) + s.append("+Shift"); + if ((modifiers & InputEvent.ALT_GRAPH_MASK) != 0) + s.append("+Alt Graph"); + if ((modifiers & InputEvent.BUTTON1_MASK) != 0) + s.append("+Button1"); + s.setCharAt(len, '='); + return s.toString(); + } +} // class ActionEvent diff --git a/libjava/classpath/java/awt/event/ActionListener.java b/libjava/classpath/java/awt/event/ActionListener.java new file mode 100644 index 000000000..4c302cca3 --- /dev/null +++ b/libjava/classpath/java/awt/event/ActionListener.java @@ -0,0 +1,59 @@ +/* ActionListener.java -- listens for action events + Copyright (C) 1999, 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that listen for action events. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ActionEvent + * @since 1.1 + * @status updated to 1.4 + */ +public interface ActionListener extends EventListener +{ + /** + * This method is invoked when an action occurs. + * + * @param event the <code>ActionEvent</code> that occurred + */ + void actionPerformed(ActionEvent event); +} diff --git a/libjava/classpath/java/awt/event/AdjustmentEvent.java b/libjava/classpath/java/awt/event/AdjustmentEvent.java new file mode 100644 index 000000000..867c577d3 --- /dev/null +++ b/libjava/classpath/java/awt/event/AdjustmentEvent.java @@ -0,0 +1,222 @@ +/* AdjustmentEvent.java -- an adjustable value was changed + Copyright (C) 1999, 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.awt.AWTEvent; +import java.awt.Adjustable; + +/** + * This class represents an event that is generated when an adjustable + * value is changed. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see Adjustable + * @see AdjustmentListener + * @since 1.1 + * @status updated to 1.4 + */ +public class AdjustmentEvent extends AWTEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 5700290645205279921L; + + /** This is the first id in the range of ids used by adjustment events. */ + public static final int ADJUSTMENT_FIRST = 601; + + /** This is the last id in the range of ids used by adjustment events. */ + public static final int ADJUSTMENT_LAST = 601; + + /** This is the id indicating an adjustment value changed. */ + public static final int ADJUSTMENT_VALUE_CHANGED = 601; + + /** Adjustment type for unit increments. */ + public static final int UNIT_INCREMENT = 1; + + /** Adjustment type for unit decrements. */ + public static final int UNIT_DECREMENT = 2; + + /** Adjustment type for block decrements. */ + public static final int BLOCK_DECREMENT = 3; + + /** Adjustment type for block increments. */ + public static final int BLOCK_INCREMENT = 4; + + /** Adjustment type for tracking adjustments. */ + public static final int TRACK = 5; + + /** + * The adjustable object that caused the event. + * + * @see #getAdjustable() + * @serial the cause + */ + private final Adjustable adjustable; + + /** + * The type of adjustment, one of {@link #UNIT_INCREMENT}, + * {@link #UNIT_DECREMENT}, {@link #BLOCK_INCREMENT}, + * {@link #BLOCK_DECREMENT}, or {@link #TRACK}. + * + * @see #getAdjustmentType() + * @serial the adjustment type + */ + private final int adjustmentType; + + /** + * The new value of the adjustable; it should be in the range of the + * adjustable cause. + * + * @see #getValue() + * @serial the adjustment value + */ + private final int value; + + /** + * True if this is in a series of multiple adjustment events. + * + * @see #getValueIsAdjusting() + * @serial true if this is not the last adjustment + * @since 1.4 + */ + private final boolean isAdjusting; + + /** + * Initializes an instance of <code>AdjustmentEvent</code> with the + * specified source, id, type, and value. Note that an invalid id leads to + * unspecified results. + * + * @param source the source of the event + * @param id the event id + * @param type the event type, one of the constants of this class + * @param value the value of the adjustment + * @throws IllegalArgumentException if source is null + */ + public AdjustmentEvent(Adjustable source, int id, int type, int value) + { + this(source, id, type, value, false); + } + + /** + * Initializes an instance of <code>AdjustmentEvent</code> with the + * specified source, id, type, and value. Note that an invalid id leads to + * unspecified results. + * + * @param source the source of the event + * @param id the event id + * @param type the event type, one of the constants of this class + * @param value the value of the adjustment + * @param isAdjusting if this event is in a chain of adjustments + * @throws IllegalArgumentException if source is null + * @since 1.4 + */ + public AdjustmentEvent(Adjustable source, int id, int type, int value, + boolean isAdjusting) + { + super(source, id); + this.adjustmentType = type; + this.value = value; + adjustable = source; + this.isAdjusting = isAdjusting; + } + + /** + * This method returns the source of the event as an <code>Adjustable</code>. + * + * @return the <code>Adjustable</code> source of the event + */ + public Adjustable getAdjustable() + { + return adjustable; + } + + /** + * Returns the new value of the adjustable object. + * + * @return the value of the event + */ + public int getValue() + { + return value; + } + + /** + * Returns the type of the event, which will be one of + * {@link #UNIT_INCREMENT}, {@link #UNIT_DECREMENT}, + * {@link #BLOCK_INCREMENT}, {@link #BLOCK_DECREMENT}, or {@link #TRACK}. + * + * @return the type of the event + */ + public int getAdjustmentType() + { + return adjustmentType; + } + + /** + * Test if this event is part of a sequence of multiple adjustements. + * + * @return true if this is not the last adjustment + * @since 1.4 + */ + public boolean getValueIsAdjusting() + { + return isAdjusting; + } + + /** + * Returns a string that describes the event. This is in the format + * <code>"ADJUSTMENT_VALUE_CHANGED,adjType=" + <type> + ",value=" + * + getValue() + ",isAdjusting=" + getValueIsAdjusting()</code>, where + * type is the name of the constant returned by getAdjustmentType(). + * + * @return a string that describes the event + */ + public String paramString() + { + return (id == ADJUSTMENT_VALUE_CHANGED + ? "ADJUSTMENT_VALUE_CHANGED,adjType=" : "unknown type,adjType=") + + (adjustmentType == UNIT_INCREMENT ? "UNIT_INCREMENT,value=" + : adjustmentType == UNIT_DECREMENT ? "UNIT_DECREMENT,value=" + : adjustmentType == BLOCK_INCREMENT ? "BLOCK_INCREMENT,value=" + : adjustmentType == BLOCK_DECREMENT ? "BLOCK_DECREMENT,value=" + : adjustmentType == TRACK ? "TRACK,value=" : "unknown type,value=") + + value + ",isAdjusting=" + isAdjusting; + } +} // class AdjustmentEvent diff --git a/libjava/classpath/java/awt/event/AdjustmentListener.java b/libjava/classpath/java/awt/event/AdjustmentListener.java new file mode 100644 index 000000000..1eb2e3bcf --- /dev/null +++ b/libjava/classpath/java/awt/event/AdjustmentListener.java @@ -0,0 +1,58 @@ +/* AdjustmentListener.java -- listen for adjustment events + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.util.EventListener; + +/** + * Interface for classes that listen for adjustment events. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.1 + * @status updated to 1.4 + */ +public interface AdjustmentListener extends EventListener +{ + /** + * This method is called when an adjustable value changes. + * + * @param event the <code>AdjustmentEvent</code> that occurred + */ + void adjustmentValueChanged(AdjustmentEvent event); +} // interface AdjustmentListener diff --git a/libjava/classpath/java/awt/event/ComponentAdapter.java b/libjava/classpath/java/awt/event/ComponentAdapter.java new file mode 100644 index 000000000..cb1c0dae9 --- /dev/null +++ b/libjava/classpath/java/awt/event/ComponentAdapter.java @@ -0,0 +1,97 @@ +/* ComponentAdapter.java -- convenience class for writing component listeners + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +/** + * This class implements <code>ComponentListener</code> and implements + * all methods with empty bodies. This allows a listener interested in + * implementing only a subset of the <code>ComponentListener</code> + * interface to extend this class and override only the desired methods. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ComponentEvent + * @see ComponentListener + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class ComponentAdapter implements ComponentListener +{ + /** + * Do nothing default constructor for subclasses. + */ + public ComponentAdapter() + { + } + + /** + * Implements this method from the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void componentResized(ComponentEvent event) + { + } + + /** + * Implements this method from the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void componentMoved(ComponentEvent event) + { + } + + /** + * Implements this method from the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void componentShown(ComponentEvent event) + { + } + + /** + * Implements this method from the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void componentHidden(ComponentEvent event) + { + } +} // class ComponentAdapter diff --git a/libjava/classpath/java/awt/event/ComponentEvent.java b/libjava/classpath/java/awt/event/ComponentEvent.java new file mode 100644 index 000000000..3fd86853b --- /dev/null +++ b/libjava/classpath/java/awt/event/ComponentEvent.java @@ -0,0 +1,142 @@ +/* ComponentEvent.java -- notification of events for components + Copyright (C) 1999, 2002, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import gnu.java.lang.CPStringBuilder; + +import java.awt.AWTEvent; +import java.awt.Component; + +/** + * This class is for events generated when a component is moved, resized, + * hidden, or shown. These events normally do not need to be handled by the + * application, since the AWT system automatically takes care of them. This + * is also the superclass for other events on components, but + * ComponentListeners ignore such subclasses. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ComponentAdapter + * @see ComponentListener + * @since 1.1 + * @status updated to 1.4 + */ +public class ComponentEvent extends AWTEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 8101406823902992965L; + + /** This is the first id in the range of ids used by this class. */ + public static final int COMPONENT_FIRST = 100; + + /** This is the last id in the range of ids used by this class. */ + public static final int COMPONENT_LAST = 103; + + /** This id indicates that a component was moved. */ + public static final int COMPONENT_MOVED = 100; + + /** This id indicates that a component was resized. */ + public static final int COMPONENT_RESIZED = 101; + + /** This id indicates that a component was shown. */ + public static final int COMPONENT_SHOWN = 102; + + /** This id indicates that a component was hidden. */ + public static final int COMPONENT_HIDDEN = 103; + + /** + * Initializes a new instance of <code>ComponentEvent</code> with the + * specified source and id. Note that an invalid id leads to unspecified + * results. + * + * @param source the source of the event + * @param id the event id + * @throws IllegalArgumentException if source is null + */ + public ComponentEvent(Component source, int id) + { + super(source, id); + } + + /** + * This method returns the event source as a <code>Component</code>. If the + * source has subsequently been modified to a non-Component, this returns + * null. + * + * @return the event source as a <code>Component</code>, or null + */ + public Component getComponent() + { + return source instanceof Component ? (Component) source : null; + } + + /** + * This method returns a string identifying this event. This is the field + * name of the id type, and for COMPONENT_MOVED or COMPONENT_RESIZED, the + * new bounding box of the component. + * + * @return a string identifying this event + */ + public String paramString() + { + CPStringBuilder s = new CPStringBuilder(); + + // Unlike Sun, we don't throw NullPointerException or ClassCastException + // when source was illegally changed. + if (id == COMPONENT_MOVED) + s.append("COMPONENT_MOVED "); + else if (id == COMPONENT_RESIZED) + s.append("COMPONENT_RESIZED "); + else if (id == COMPONENT_SHOWN) + s.append("COMPONENT_SHOWN "); + else if (id == COMPONENT_HIDDEN) + s.append("COMPONENT_HIDDEN "); + else + return "unknown type"; + + s.append("(").append(getComponent().getX()).append(",") + .append(getComponent().getY()).append(" ") + .append(getComponent().getWidth()).append("x") + .append(getComponent().getHeight()).append(")"); + + return s.toString(); + } + +} // class ComponentEvent diff --git a/libjava/classpath/java/awt/event/ComponentListener.java b/libjava/classpath/java/awt/event/ComponentListener.java new file mode 100644 index 000000000..b43faaed7 --- /dev/null +++ b/libjava/classpath/java/awt/event/ComponentListener.java @@ -0,0 +1,84 @@ +/* ComponentListener.java -- receive all events for a component + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that receive all events from a component. + * Normally it is not necessary to process these events since the AWT + * handles them internally, taking all appropriate actions. To watch a subset + * of these events, use a ComponentAdapter. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ComponentAdapter + * @see ComponentEvent + * @since 1.1 + * @status updated to 1.4 + */ +public interface ComponentListener extends EventListener +{ + /** + * This method is called when the component is resized. + * + * @param event the <code>ComponentEvent</code> indicating the resize + */ + void componentResized(ComponentEvent event); + + /** + * This method is called when the component is moved. + * + * @param event the <code>ComponentEvent</code> indicating the move + */ + void componentMoved(ComponentEvent event); + + /** + * This method is called when the component is made visible. + * + * @param event the <code>ComponentEvent</code> indicating the visibility + */ + void componentShown(ComponentEvent event); + + /** + * This method is called when the component is hidden. + * + * @param event the <code>ComponentEvent</code> indicating the visibility + */ + void componentHidden(ComponentEvent event); +} // interface ComponentListener diff --git a/libjava/classpath/java/awt/event/ContainerAdapter.java b/libjava/classpath/java/awt/event/ContainerAdapter.java new file mode 100644 index 000000000..c847adfa2 --- /dev/null +++ b/libjava/classpath/java/awt/event/ContainerAdapter.java @@ -0,0 +1,79 @@ +/* ContainerAdapter.java -- convenience class for writing container listeners + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +/** + * This class implements <code>ContainerListener</code> and implements + * all methods with empty bodies. This allows a listener interested in + * implementing only a subset of the <code>ContainerListener</code> + * interface to extend this class and override only the desired methods. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ContainerEvent + * @see ContainerListener + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class ContainerAdapter implements ContainerListener +{ + /** + * Do nothing default constructor for subclasses. + */ + public ContainerAdapter() + { + } + + /** + * Implements this method from the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void componentAdded(ContainerEvent event) + { + } + + /** + * Implements this method from the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void componentRemoved(ContainerEvent event) + { + } +} // class ContainerAdapter diff --git a/libjava/classpath/java/awt/event/ContainerEvent.java b/libjava/classpath/java/awt/event/ContainerEvent.java new file mode 100644 index 000000000..3c401fe1a --- /dev/null +++ b/libjava/classpath/java/awt/event/ContainerEvent.java @@ -0,0 +1,135 @@ +/* ContainerEvent.java -- components added/removed from a container + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.awt.Component; +import java.awt.Container; + +/** + * This event is generated when a component is added or removed from a + * container. Applications do not ordinarily need to handle these events + * since the AWT system handles them internally. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ContainerAdapter + * @see ContainerListener + * @since 1.1 + * @status updated to 1.4 + */ +public class ContainerEvent extends ComponentEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -4114942250539772041L; + + /** This is the first id in the id range used by this class. */ + public static final int CONTAINER_FIRST = 300; + + /** This is the last id in the id range used by this class. */ + public static final int CONTAINER_LAST = 301; + + /** This id indicates a component was added to the container. */ + public static final int COMPONENT_ADDED = 300; + + /** This id indicates a component was removed from the container. */ + public static final int COMPONENT_REMOVED = 301; + + /** + * The non-null child component that was added or removed. + * + * @serial the child component that changed + */ + private final Component child; + + /** + * Initializes a new instance of <code>ContainerEvent</code> with the + * specified source and id. Additionally, the affected child component + * is also passed as a parameter. Note that an invalid id leads to + * unspecified results. + * + * @param source the source container of the event + * @param id the event id + * @param child the child component affected by this event + * @throws IllegalArgumentException if source is null + */ + public ContainerEvent(Component source, int id, Component child) + { + super(source, id); + this.child = child; + } + + /** + * Returns the source of this event as a <code>Container</code>. + * + * @return the source of the event + * @throws ClassCastException if the source is changed to a non-Container + */ + public Container getContainer() + { + return (Container) source; + } + + /** + * This method returns the child object that was added or removed from + * the container. + * + * @return the child object added or removed + */ + public Component getChild() + { + return child; + } + + /** + * This method returns a string identifying this event. It is formatted as: + * <code>(getID() == COMPONENT_ADDED ? "COMPONENT_ADDED" + * : "COMPONENT_REMOVED") + ",child=" + getChild().getName()</code>. + * + * @return a string identifying this event + */ + public String paramString() + { + // Unlike Sun, we don't throw NullPointerException if child is illegally + // null. + return (id == COMPONENT_ADDED ? "COMPONENT_ADDED,child=" + : id == COMPONENT_REMOVED ? "COMPONENT_REMOVED,child=" + : "unknown type,child=") + (child == null ? "" : child.getName()); + } +} // class ContainerEvent diff --git a/libjava/classpath/java/awt/event/ContainerListener.java b/libjava/classpath/java/awt/event/ContainerListener.java new file mode 100644 index 000000000..b37d43408 --- /dev/null +++ b/libjava/classpath/java/awt/event/ContainerListener.java @@ -0,0 +1,70 @@ +/* ContainerListener.java -- listen for container events + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that wish to listen for all events from + * container objects. This is normally not necessary since the AWT system + * listens for and processes these events. To watch a subset of these events, + * use a ContainerAdapter. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ContainerAdapter + * @see ContainerEvent + * @since 1.1 + * @status updated to 1.4 + */ +public interface ContainerListener extends EventListener +{ + /** + * This method is called when a component is added to the container. + * + * @param event the <code>ContainerEvent</code> indicating component addition + */ + void componentAdded(ContainerEvent event); + + /** + * This method is called when a component is removed from the container. + * + * @param event the <code>ContainerEvent</code> indicating component removal + */ + void componentRemoved(ContainerEvent event); +} // interface ContainerListener diff --git a/libjava/classpath/java/awt/event/FocusAdapter.java b/libjava/classpath/java/awt/event/FocusAdapter.java new file mode 100644 index 000000000..fb0532a3a --- /dev/null +++ b/libjava/classpath/java/awt/event/FocusAdapter.java @@ -0,0 +1,79 @@ +/* FocusAdapter.java -- convenience class for writing focus listeners + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +/** + * This class implements <code>FocusListener</code> and implements all + * methods with empty bodies. This allows a listener interested in + * implementing only a subset of the <code>FocusListener</code> interface to + * extend this class and override only the desired methods. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see FocusEvent + * @see FocusListener + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class FocusAdapter implements FocusListener +{ + /** + * Do nothing default constructor for subclasses. + */ + public FocusAdapter() + { + } + + /** + * Implements this method from the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void focusGained(FocusEvent event) + { + } + + /** + * Implements this method from the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void focusLost(FocusEvent event) + { + } +} // class FocusAdapter diff --git a/libjava/classpath/java/awt/event/FocusEvent.java b/libjava/classpath/java/awt/event/FocusEvent.java new file mode 100644 index 000000000..a44284aea --- /dev/null +++ b/libjava/classpath/java/awt/event/FocusEvent.java @@ -0,0 +1,181 @@ +/* FocusEvent.java -- generated for a focus change + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.awt.Component; + +/** + * This class represents an event generated when a focus change occurs for a + * component. There are both temporary changes, such as when focus is stolen + * during a sroll then returned, and permanent changes, such as when the user + * TABs through focusable components. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see FocusAdapter + * @see FocusListener + * @since 1.1 + * @status updated to 1.4 + */ +public class FocusEvent extends ComponentEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 523753786457416396L; + + /** This is the first id in the range of ids used by this class. */ + public static final int FOCUS_FIRST = 1004; + + /** This is the last id in the range of ids used by this class. */ + public static final int FOCUS_LAST = 1005; + + /** This is the event id for a focus gained event. */ + public static final int FOCUS_GAINED = 1004; + + /** This is the event id for a focus lost event. */ + public static final int FOCUS_LOST = 1005; + + /** + * Indicates whether or not the focus change is temporary. + * + * @see #isTemporary() + * @serial true if the focus change is temporary + */ + private final boolean temporary; + + /** + * The other component which is giving up or stealing focus from this + * component, if known. + * + * @see #getOppositeComponent() + * @serial the component with the opposite focus event, or null + * @since 1.4 + */ + private final Component opposite; + + /** + * Initializes a new instance of <code>FocusEvent</code> with the + * specified source, id, temporary status, and opposite counterpart. Note + * that an invalid id leads to unspecified results. + * + * @param source the component that is gaining or losing focus + * @param id the event id + * @param temporary true if the focus change is temporary + * @param opposite the component receiving the opposite focus event, or null + * @throws IllegalArgumentException if source is null + */ + public FocusEvent(Component source, int id, boolean temporary, + Component opposite) + { + super(source, id); + this.temporary = temporary; + this.opposite = opposite; + } + + /** + * Initializes a new instance of <code>FocusEvent</code> with the + * specified source, id, and temporary status. Note that an invalid id + * leads to unspecified results. + * + * @param source the component that is gaining or losing focus + * @param id the event id + * @param temporary true if the focus change is temporary + * @throws IllegalArgumentException if source is null + */ + public FocusEvent(Component source, int id, boolean temporary) + { + this(source, id, temporary, null); + } + + /** + * Initializes a new instance of <code>FocusEvent</code> with the + * specified source and id. Note that an invalid id leads to unspecified + * results. + * + * @param source the component that is gaining or losing focus + * @param id the event id + * @throws IllegalArgumentException if source is null + */ + public FocusEvent(Component source, int id) + { + this(source, id, false, null); + } + + /** + * This method tests whether or not the focus change is temporary or + * permanent. + * + * @return true if the focus change is temporary + */ + public boolean isTemporary() + { + return temporary; + } + + /** + * Returns the component which received the opposite focus event. If this + * component gained focus, the opposite lost focus; likewise if this + * component is giving up focus, the opposite is gaining it. If this + * information is unknown, perhaps because the opposite is a native + * application, this returns null. + * + * @return the component with the focus opposite, or null + * @since 1.4 + */ + public Component getOppositeComponent() + { + return opposite; + } + + /** + * Returns a string identifying this event. This is formatted as: + * <code>(getID() == FOCUS_GAINED ? "FOCUS_GAINED" : "FOCUS_LOST") + * + (isTemporary() ? ",temporary," : ",permanent,") + "opposite=" + * + getOppositeComponent()</code>. + * + * @return a string identifying this event + */ + public String paramString() + { + return (id == FOCUS_GAINED ? "FOCUS_GAINED" + : id == FOCUS_LOST ? "FOCUS_LOST" : "unknown type") + + (temporary ? ",temporary,opposite=" : ",permanent,opposite=") + + opposite; + } +} // class FocusEvent diff --git a/libjava/classpath/java/awt/event/FocusListener.java b/libjava/classpath/java/awt/event/FocusListener.java new file mode 100644 index 000000000..1f7201825 --- /dev/null +++ b/libjava/classpath/java/awt/event/FocusListener.java @@ -0,0 +1,69 @@ +/* FocusListener.java -- listen for focus changes + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that wish to be notified of changes of + * keyboard focus for a component. To watch a subset of these events, use a + * FocusAdapter. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see FocusAdapter + * @see FocusEvent + * @since 1.1 + * @status updated to 1.4 + */ +public interface FocusListener extends EventListener +{ + /** + * This method is called when a component gains the keyboard focus. + * + * @param event the <code>FocusEvent</code> indicating that focus was gained + */ + void focusGained(FocusEvent event); + + /** + * This method is invoked when a component loses the keyboard focus. + * + * @param event the <code>FocusEvent</code> indicating that focus was lost + */ + void focusLost(FocusEvent event); +} // interface FocusListener diff --git a/libjava/classpath/java/awt/event/HierarchyBoundsAdapter.java b/libjava/classpath/java/awt/event/HierarchyBoundsAdapter.java new file mode 100644 index 000000000..340cf01ed --- /dev/null +++ b/libjava/classpath/java/awt/event/HierarchyBoundsAdapter.java @@ -0,0 +1,78 @@ +/* HierarchyBoundsAdapter.java -- convenience class for writing listeners + Copyright (C) 2000, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.event; + +/** + * This class implements <code>HierarchyBoundsListener</code> and implements + * all methods with empty bodies. This allows a listener interested in + * implementing only a subset of the <code>HierarchyBoundsListener</code> + * interface to extend this class and override only the desired methods. + * + * @author Bryce McKinlay + * @see HierarchyBoundsListener + * @see HierarchyEvent + * @since 1.3 + * @status updated to 1.4 + */ +public abstract class HierarchyBoundsAdapter implements HierarchyBoundsListener +{ + /** + * Do nothing default constructor for subclasses. + */ + public HierarchyBoundsAdapter() + { + } + + /** + * Implements this method from the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void ancestorMoved(HierarchyEvent event) + { + } + + /** + * Implements this method from the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void ancestorResized(HierarchyEvent event) + { + } +} diff --git a/libjava/classpath/java/awt/event/HierarchyBoundsListener.java b/libjava/classpath/java/awt/event/HierarchyBoundsListener.java new file mode 100644 index 000000000..689623744 --- /dev/null +++ b/libjava/classpath/java/awt/event/HierarchyBoundsListener.java @@ -0,0 +1,70 @@ +/* HierarchyBoundsListener.java -- listens to bounds changes of parents + Copyright (C) 2000, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.util.EventListener; + +/** + * This listens for changes in an ancestors size or location. Normally it is + * not necessary to process these events since the AWT handles them + * internally, taking all appropriate actions. To watch a subset of these + * events, use a HierarchyBoundsAdapter. + * + * @author Bryce McKinlay + * @see HierarchyBoundsAdapter + * @see HierarchyEvent + * @since 1.3 + * @status updated to 1.4 + */ +public interface HierarchyBoundsListener extends EventListener +{ + /** + * Called when an ancestor component of the source is moved. + * + * @param e the event describing the ancestor's motion + */ + void ancestorMoved(HierarchyEvent e); + + /** + * Called when an ancestor component is resized. + * + * @param e the event describing the ancestor's resizing + */ + void ancestorResized(HierarchyEvent e); +} // interface HierarchyBoundsListener diff --git a/libjava/classpath/java/awt/event/HierarchyEvent.java b/libjava/classpath/java/awt/event/HierarchyEvent.java new file mode 100644 index 000000000..3237978f9 --- /dev/null +++ b/libjava/classpath/java/awt/event/HierarchyEvent.java @@ -0,0 +1,255 @@ +/* HierarchyEvent.java -- generated for a change in hierarchy + Copyright (C) 2000, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import gnu.java.lang.CPStringBuilder; + +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.Container; + +/** + * This class represents an event generated for an ancestor component which + * may affect this component. These events normally do not need to be handled + * by the application, since the AWT system automatically takes care of them. + * + * <p>There are two types of hierarchy events. The first type is handled by + * HierarchyListener, and includes addition or removal of an ancestor, or + * an ancestor changing its on-screen status (visible and/or displayble). The + * second type is handled by HierarchyBoundsListener, and includes resizing + * or moving of an ancestor. + * + * @author Bryce McKinlay + * @see HierarchyListener + * @see HierarchyBoundsAdapter + * @see HierarchyBoundsListener + * @since 1.3 + * @status updated to 1.4 + */ +public class HierarchyEvent extends AWTEvent +{ + /** + * Compatible with JDK 1.3+. + */ + private static final long serialVersionUID = -5337576970038043990L; + + /** This is the first id in the range of ids used by this class. */ + public static final int HIERARCHY_FIRST = 1400; + + /** This id indicates that the hierarchy tree changed. */ + public static final int HIERARCHY_CHANGED = 1400; + + /** This id indicates that an ancestor was moved. */ + public static final int ANCESTOR_MOVED = 1401; + + /** This id indicates that an ancestor was resized. */ + public static final int ANCESTOR_RESIZED = 1402; + + /** This is the last id in the range of ids used by this class. */ + public static final int HIERARCHY_LAST = 1402; + + /** This indicates that the HIERARCHY_CHANGED is a changed parent. */ + public static final int PARENT_CHANGED = 1; + + /** + * This indicates that the HIERARCHY_CHANGED is caused by a change in + * displayability. + * + * @see Component#isDisplayable() + * @see Component#addNotify() + * @see Component#removeNotify() + */ + public static final int DISPLAYABILITY_CHANGED = 2; + + /** + * This indicates that the HIERARCHY_CHANGED is a changed visibility. + * + * @see Component#isShowing() + * @see Component#addNotify() + * @see Component#removeNotify() + * @see Component#show() + * @see Component#hide() + */ + public static final int SHOWING_CHANGED = 4; + + /** + * The component at the top of the changed hierarchy. + * + * @serial the top component changed + */ + private final Component changed; + + /** + * The parent of this component, either before or after the change depending + * on the type of change. + * + * @serial the parent component changed + */ + private final Container changedParent; + + /** + * The bitmask of HIERARCHY_CHANGED event types. + * + * @serial the change flags + */ + private final long changeFlags; + + /** + * Initializes a new instance of <code>HierarchyEvent</code> with the + * specified parameters. Note that an invalid id leads to unspecified + * results. + * + * @param source the component whose hierarchy changed + * @param id the event id + * @param changed the top component in the tree of changed hierarchy + * @param changedParent the updated parent of this object + * @throws IllegalArgumentException if source is null + */ + public HierarchyEvent(Component source, int id, Component changed, + Container changedParent) + { + this(source, id, changed, changedParent, 0); + } + + /** + * Initializes a new instance of <code>HierarchyEvent</code> with the + * specified parameters. Note that an invalid id leads to unspecified + * results. + * + * @param source the component whose hierarchy changed + * @param id the event id + * @param changed the top component in the tree of changed hierarchy + * @param changedParent the updated parent of this object + * @param changeFlags the bitmask of specific HIERARCHY_CHANGED events + * @throws IllegalArgumentException if source is null + */ + public HierarchyEvent(Component source, int id, Component changed, + Container changedParent, long changeFlags) + { + super(source, id); + this.changed = changed; + this.changedParent = changedParent; + this.changeFlags = changeFlags; + } + + /** + * This method returns the event source as a <code>Component</code>. If the + * source has subsequently been modified to a non-Component, this returns + * null. + * + * @return the event source as a <code>Component</code>, or null + */ + public Component getComponent() + { + return source instanceof Component ? (Component) source : null; + } + + /** + * Returns the component at the top of the hierarchy which changed. + * + * @return the top changed component + */ + public Component getChanged() + { + return changed; + } + + /** + * Returns the parent of the component listed in <code>getChanged()</code>. + * If the cause of this event was <code>Container.add</code>, this is the + * new parent; if the cause was <code>Container.remove</code>, this is the + * old parent; otherwise it is the unchanged parent. + * + * @return the parent container of the changed component + */ + public Container getChangedParent() + { + return changedParent; + } + + /** + * If this is a HIERARCHY_CHANGED event, this returns a bitmask of the + * types of changes that took place. + * + * @return the bitwise or of hierarchy change types, or 0 + * @see #PARENT_CHANGED + * @see #DISPLAYABILITY_CHANGED + * @see #SHOWING_CHANGED + */ + public long getChangeFlags() + { + return changeFlags; + } + + /** + * This method returns a string identifying this event. This is the field + * name of the id type, followed by a parenthesized listing of the changed + * component and its parent container. In addition, if the type is + * HIERARCHY_CHANGED, the flags preceed the changed component, in the + * order PARENT_CHANGED, DISPLAYABILITY_CHANGED, and SHOWING_CHANGED. + * + * @return a string identifying this event + */ + public String paramString() + { + CPStringBuilder r = new CPStringBuilder(); + switch (id) + { + case HIERARCHY_CHANGED: + r.append("HIERARCHY_CHANGED ("); + if ((changeFlags & PARENT_CHANGED) != 0) + r.append("PARENT_CHANGED,"); + if ((changeFlags & DISPLAYABILITY_CHANGED) != 0) + r.append("DISPLAYABILITY_CHANGED,"); + if ((changeFlags & SHOWING_CHANGED) != 0) + r.append("SHOWING_CHANGED,"); + break; + case ANCESTOR_MOVED: + r.append("ANCESTOR_MOVED ("); + break; + case ANCESTOR_RESIZED: + r.append("ANCESTOR_RESIZED ("); + break; + default: + return "unknown type"; + } + r.append(changed).append(',').append(changedParent).append(')'); + return r.toString(); + } +} // class HierarchyEvent diff --git a/libjava/classpath/java/awt/event/HierarchyListener.java b/libjava/classpath/java/awt/event/HierarchyListener.java new file mode 100644 index 000000000..f90414b86 --- /dev/null +++ b/libjava/classpath/java/awt/event/HierarchyListener.java @@ -0,0 +1,62 @@ +/* HierarchyListener.java -- listens to changes in the component hierarchy + Copyright (C) 2000, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.util.EventListener; + +/** + * This listens for changes in the hierarchy tree of components. Normally it is + * not necessary to process these events since the AWT handles them + * internally, taking all appropriate actions. + * + * @author Bryce McKinlay + * @see HierarchyEvent + * @since 1.3 + * @status updated to 1.4 + */ +public interface HierarchyListener extends EventListener +{ + /** + * Called when the hierarchy of this component changes. Use + * <code>getChangeFlags()</code> on the event to see what exactly changed. + * + * @param e the event describing the change + */ + void hierarchyChanged(HierarchyEvent e); +} // interface HierarchyListener diff --git a/libjava/classpath/java/awt/event/InputEvent.java b/libjava/classpath/java/awt/event/InputEvent.java new file mode 100644 index 000000000..241630ca3 --- /dev/null +++ b/libjava/classpath/java/awt/event/InputEvent.java @@ -0,0 +1,399 @@ +/* InputEvent.java -- common superclass of component input events + Copyright (C) 1999, 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import gnu.java.awt.EventModifier; +import gnu.java.lang.CPStringBuilder; + +import java.awt.Component; + +/** + * This is the common superclass for all component input classes. These are + * passed to listeners before the component, so that listeners can consume + * the event before it does its default behavior. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see KeyEvent + * @see KeyAdapter + * @see MouseEvent + * @see MouseAdapter + * @see MouseMotionAdapter + * @see MouseWheelEvent + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class InputEvent extends ComponentEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -2482525981698309786L; + + /** + * This is the bit mask which indicates the shift key is down. It is + * recommended that SHIFT_DOWN_MASK be used instead. + * + * @see #SHIFT_DOWN_MASK + */ + public static final int SHIFT_MASK = 1; + + /** + * This is the bit mask which indicates the control key is down. It is + * recommended that CTRL_DOWN_MASK be used instead. + * + * @see #CTRL_DOWN_MASK + */ + public static final int CTRL_MASK = 2; + + /** + * This is the bit mask which indicates the meta key is down. It is + * recommended that META_DOWN_MASK be used instead. + * + * @see #META_DOWN_MASK + */ + public static final int META_MASK = 4; + + /** + * This is the bit mask which indicates the alt key is down. It is + * recommended that ALT_DOWN_MASK be used instead. + * + * @see #ALT_DOWN_MASK + */ + public static final int ALT_MASK = 8; + + /** + * This is the bit mask which indicates the alt-graph modifier is in effect. + * It is recommended that ALT_GRAPH_DOWN_MASK be used instead. + * + * @see #ALT_GRAPH_DOWN_MASK + */ + public static final int ALT_GRAPH_MASK = 0x20; + + /** + * This bit mask indicates mouse button one is down. It is recommended that + * BUTTON1_DOWN_MASK be used instead. + * + * @see #BUTTON1_DOWN_MASK + */ + public static final int BUTTON1_MASK = 0x10; + + /** + * This bit mask indicates mouse button two is down. It is recommended that + * BUTTON2_DOWN_MASK be used instead. + * + * @see #BUTTON2_DOWN_MASK + */ + public static final int BUTTON2_MASK = 8; + + /** + * This bit mask indicates mouse button three is down. It is recommended + * that BUTTON3_DOWN_MASK be used instead. + * + * @see #BUTTON3_DOWN_MASK + */ + public static final int BUTTON3_MASK = 4; + + /** + * The SHIFT key extended modifier. + * + * @since 1.4 + */ + public static final int SHIFT_DOWN_MASK = 0x0040; + + /** + * The CTRL key extended modifier. + * + * @since 1.4 + */ + public static final int CTRL_DOWN_MASK = 0x0080; + + /** + * The META key extended modifier. + * + * @since 1.4 + */ + public static final int META_DOWN_MASK = 0x0100; + + /** + * The ALT key extended modifier. + * + * @since 1.4 + */ + public static final int ALT_DOWN_MASK = 0x0200; + + /** + * The mouse button1 key extended modifier. + * + * @since 1.4 + */ + public static final int BUTTON1_DOWN_MASK = 0x0400; + + /** + * The mouse button2 extended modifier. + * + * @since 1.4 + */ + public static final int BUTTON2_DOWN_MASK = 0x0800; + + /** + * The mouse button3 extended modifier. + * + * @since 1.4 + */ + public static final int BUTTON3_DOWN_MASK = 0x1000; + + /** + * The ALT_GRAPH key extended modifier. + * + * @since 1.4 + */ + public static final int ALT_GRAPH_DOWN_MASK = 0x2000; + + /** The mask to convert new to old, package visible for use in subclasses. */ + static final int CONVERT_MASK + = EventModifier.NEW_MASK & ~(BUTTON2_DOWN_MASK | BUTTON3_DOWN_MASK); + + /** + * The timestamp when this event occurred. + * + * @see #getWhen() + * @serial the timestamp + */ + private final long when; + + /** + * The old-style modifiers in effect for this event. Package visible + * for use by subclasses. The old style (bitmask 0x3f) should not be + * mixed with the new style (bitmasks 0xffffffc0). + * + * @see #getModifiers() + * @see MouseEvent + * @serial the modifier state, stored in the old style + */ + int modifiers; + + /** + * The new-style modifiers in effect for this event. Package visible + * for use by subclasses. The old style (bitmask 0x3f) should not be + * mixed with the new style (bitmasks 0xffffffc0). + * + * @see #getModifiersEx() + * @see MouseEvent + * @serial the modifier state, stored in the new style + */ + int modifiersEx; + + /** + * Initializes a new instance of <code>InputEvent</code> with the specified + * source, id, timestamp, and modifiers. Note that an invalid id leads to + * unspecified results. + * + * @param source the source of the event + * @param id the event id + * @param when the timestamp when the event occurred + * @param modifiers the modifiers in effect for this event, old or new style + * @throws IllegalArgumentException if source is null + */ + InputEvent(Component source, int id, long when, int modifiers) + { + super(source, id); + this.when = when; + this.modifiers = modifiers & EventModifier.OLD_MASK; + this.modifiersEx = modifiers & EventModifier.NEW_MASK; + } + + /** + * This method tests whether or not the shift key was down during the event. + * + * @return true if the shift key is down + */ + public boolean isShiftDown() + { + return ((modifiers & SHIFT_MASK) != 0) + || ((modifiersEx & SHIFT_DOWN_MASK) != 0); + } + + /** + * This method tests whether or not the control key was down during the + * event. + * + * @return true if the control key is down + */ + public boolean isControlDown() + { + return ((modifiers & CTRL_MASK) != 0) + || ((modifiersEx & CTRL_DOWN_MASK) != 0); + } + + /** + * This method tests whether or not the meta key was down during the event. + * + * @return true if the meta key is down + */ + public boolean isMetaDown() + { + return ((modifiers & META_MASK) != 0) + || ((modifiersEx & META_DOWN_MASK) != 0); + } + + /** + * This method tests whether or not the alt key was down during the event. + * + * @return true if the alt key is down + */ + public boolean isAltDown() + { + return ((modifiers & ALT_MASK) != 0) + || ((modifiersEx & ALT_DOWN_MASK) != 0); + } + + /** + * This method tests whether or not the alt-graph modifier was in effect + * during the event. + * + * @return true if the alt-graph modifier is down + */ + public boolean isAltGraphDown() + { + return ((modifiers & ALT_GRAPH_MASK) != 0) + || ((modifiersEx & ALT_GRAPH_DOWN_MASK) != 0); + } + + /** + * This method returns the timestamp when this event occurred. + * + * @return the timestamp when this event occurred + */ + public long getWhen() + { + return when; + } + + /** + * This method returns the old-style modifiers in effect for this event. + * Note that this is ambiguous between button2 and alt, and between + * button3 and meta. Also, code which generated these modifiers tends to + * only list the modifier that just changed, even if others were down at + * the time. Consider using getModifiersEx instead. This will be a union + * of the bit masks defined in this class that are applicable to the event. + * + * @return the modifiers in effect for this event + * @see #getModifiersEx() + */ + public int getModifiers() + { + return modifiers; + } + + /** + * Returns the extended modifiers (new-style) for this event. This represents + * the state of all modal keys and mouse buttons at the time of the event, + * and does not suffer from the problems mentioned in getModifiers. + * + * <p>For an example of checking multiple modifiers, this code will return + * true only if SHIFT and BUTTON1 were pressed and CTRL was not: + * <pre> + * int onmask = InputEvent.SHIFT_DOWN_MASK | InputEvent.BUTTON1_DOWN_MASK; + * int offmask = InputEvent.CTRL_DOWN_MASK; + * return (event.getModifiersEx() & (onmask | offmask)) == onmask; + * </pre> + * + * @return the bitwise or of all modifiers pressed during the event + * @since 1.4 + */ + public int getModifiersEx() + { + return modifiersEx; + } + + /** + * Consumes this event. A consumed event is not processed further by the AWT + * system. + */ + public void consume() + { + consumed = true; + } + + /** + * This method tests whether or not this event has been consumed. + * + * @return true if this event has been consumed + */ + public boolean isConsumed() + { + return consumed; + } + + /** + * Convert the extended modifier bitmask into a String, such as "Shift" or + * "Ctrl+Button1". + * + * XXX Sun claims this can be localized via the awt.properties file - how + * do we implement that? + * + * @param modifiers the modifiers + * @return a string representation of the modifiers in this bitmask + * @since 1.4 + */ + public static String getModifiersExText(int modifiers) + { + modifiers &= EventModifier.NEW_MASK; + if (modifiers == 0) + return ""; + CPStringBuilder s = new CPStringBuilder(); + if ((modifiers & META_DOWN_MASK) != 0) + s.append("Meta+"); + if ((modifiers & CTRL_DOWN_MASK) != 0) + s.append("Ctrl+"); + if ((modifiers & ALT_DOWN_MASK) != 0) + s.append("Alt+"); + if ((modifiers & SHIFT_DOWN_MASK) != 0) + s.append("Shift+"); + if ((modifiers & ALT_GRAPH_DOWN_MASK) != 0) + s.append("Alt Graph+"); + if ((modifiers & BUTTON1_DOWN_MASK) != 0) + s.append("Button1+"); + if ((modifiers & BUTTON2_DOWN_MASK) != 0) + s.append("Button2+"); + if ((modifiers & BUTTON3_DOWN_MASK) != 0) + s.append("Button3+"); + return s.substring(0, s.length() - 1); + } +} // class InputEvent diff --git a/libjava/classpath/java/awt/event/InputMethodEvent.java b/libjava/classpath/java/awt/event/InputMethodEvent.java new file mode 100644 index 000000000..1542bcc9f --- /dev/null +++ b/libjava/classpath/java/awt/event/InputMethodEvent.java @@ -0,0 +1,305 @@ +/* InputMethodEvent.java -- events from a text input method + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import gnu.java.lang.CPStringBuilder; + +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.EventQueue; +import java.awt.font.TextHitInfo; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.text.AttributedCharacterIterator; + +/** + * This class is for event generated by change in a text input method. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see InputMethodListener + * @since 1.2 + * @status updated to 1.4 + */ +public class InputMethodEvent extends AWTEvent +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 4727190874778922661L; + + /** This is the first id in the range of event ids used by this class. */ + public static final int INPUT_METHOD_FIRST = 1100; + + /** This event id indicates that the text in the input method has changed. */ + public static final int INPUT_METHOD_TEXT_CHANGED = 1100; + + /** This event id indicates that the input method curor point has changed. */ + public static final int CARET_POSITION_CHANGED = 1101; + + /** This is the last id in the range of event ids used by this class. */ + public static final int INPUT_METHOD_LAST = 1101; + + /** + * The timestamp when this event was created. + * + * @serial the timestamp + * @since 1.4 + */ + private long when; + + /** The input method text. */ + private final transient AttributedCharacterIterator text; + + /** The number of committed characters in the text. */ + private final transient int committedCharacterCount; + + /** The caret. */ + private final transient TextHitInfo caret; + + /** The most important position to be visible. */ + private final transient TextHitInfo visiblePosition; + + /** + * Initializes a new instance of <code>InputMethodEvent</code> with the + * specified source, id, timestamp, text, char count, caret, and visible + * position. + * + * @param source the source that generated the event + * @param id the event id + * @param when the timestamp of the event + * @param text the input text + * @param committedCharacterCount the number of committed characters + * @param caret the caret position + * @param visiblePosition the position most important to make visible + * @throws IllegalArgumentException if source is null, id is invalid, id is + * CARET_POSITION_CHANGED and text is non-null, or if + * committedCharacterCount is out of range + * @since 1.4 + */ + public InputMethodEvent(Component source, int id, long when, + AttributedCharacterIterator text, + int committedCharacterCount, TextHitInfo caret, + TextHitInfo visiblePosition) + { + super(source, id); + this.when = when; + this.text = text; + this.committedCharacterCount = committedCharacterCount; + this.caret = caret; + this.visiblePosition = visiblePosition; + if (id < INPUT_METHOD_FIRST || id > INPUT_METHOD_LAST + || (id == CARET_POSITION_CHANGED && text != null) + || committedCharacterCount < 0 + || (committedCharacterCount + > (text == null ? 0 : text.getEndIndex() - text.getBeginIndex()))) + throw new IllegalArgumentException(); + } + + /** + * Initializes a new instance of <code>InputMethodEvent</code> with the + * specified source, id, text, char count, caret, and visible position. + * + * @param source the source that generated the event + * @param id the event id + * @param text the input text + * @param committedCharacterCount the number of committed characters + * @param caret the caret position + * @param visiblePosition the position most important to make visible + * @throws IllegalArgumentException if source is null, id is invalid, id is + * CARET_POSITION_CHANGED and text is non-null, or if + * committedCharacterCount is out of range + * @since 1.4 + */ + public InputMethodEvent(Component source, int id, + AttributedCharacterIterator text, + int committedCharacterCount, TextHitInfo caret, + TextHitInfo visiblePosition) + { + this(source, id, EventQueue.getMostRecentEventTime(), text, + committedCharacterCount, caret, visiblePosition); + } + + /** + * Initializes a new instance of <code>InputMethodEvent</code> with the + * specified source, id, caret, and visible position, and with a null + * text and char count. + * + * @param source the source that generated the event + * @param id the event id + * @param caret the caret position + * @param visiblePosition the position most important to make visible + * @throws IllegalArgumentException if source is null or id is invalid + * @since 1.4 + */ + public InputMethodEvent(Component source, int id, TextHitInfo caret, + TextHitInfo visiblePosition) + { + this(source, id, EventQueue.getMostRecentEventTime(), null, 0, caret, + visiblePosition); + } + + /** + * This method returns the input method text. This can be <code>null</code>, + * and will always be null for <code>CARET_POSITION_CHANGED</code> events. + * Characters from 0 to <code>getCommittedCharacterCount()-1</code> have + * been committed, the remaining characters are composed text. + * + * @return the input method text, or null + */ + public AttributedCharacterIterator getText() + { + return text; + } + + /** + * Returns the number of committed characters in the input method text. + * + * @return the number of committed characters in the input method text + */ + public int getCommittedCharacterCount() + { + return committedCharacterCount; + } + + /** + * Returns the caret position. The caret offset is relative to the composed + * text of the most recent <code>INPUT_METHOD_TEXT_CHANGED</code> event. + * + * @return the caret position, or null + */ + public TextHitInfo getCaret() + { + return caret; + } + + /** + * Returns the position that is most important to be visible, or null if + * such a hint is not necessary. The caret offset is relative to the composed + * text of the most recent <code>INPUT_METHOD_TEXT_CHANGED</code> event. + * + * @return the position that is most important to be visible + */ + public TextHitInfo getVisiblePosition() + { + return visiblePosition; + } + + /** + * This method consumes the event. A consumed event is not processed + * in the default manner by the component that generated it. + */ + public void consume() + { + consumed = true; + } + + /** + * This method tests whether or not this event has been consumed. + * + * @return true if the event has been consumed + */ + public boolean isConsumed() + { + return consumed; + } + + /** + * Return the timestamp of this event. + * + * @return the timestamp + * @since 1.4 + */ + public long getWhen() + { + return when; + } + + /** + * This method returns a string identifying the event. This contains the + * event ID, the committed and composed characters separated by '+', the + * number of committed characters, the caret, and the visible position. + * + * @return a string identifying the event + */ + public String paramString() + { + CPStringBuilder s + = new CPStringBuilder(80 + (text == null ? 0 + : text.getEndIndex() - text.getBeginIndex())); + s.append(id == INPUT_METHOD_TEXT_CHANGED ? "INPUT_METHOD_TEXT_CHANGED, " + : "CARET_POSITION_CHANGED, "); + if (text == null) + s.append("no text, 0 characters committed, caret: "); + else + { + s.append('"'); + int i = text.getBeginIndex(); + int j = committedCharacterCount; + while (--j >= 0) + s.append(text.setIndex(i++)); + s.append("\" + \""); + j = text.getEndIndex() - i; + while (--j >= 0) + s.append(text.setIndex(i++)); + s.append("\", ").append(committedCharacterCount) + .append(" characters committed, caret: "); + } + s.append(caret == null ? (Object) "no caret" : caret).append(", ") + .append(visiblePosition == null ? (Object) "no visible position" + : visiblePosition); + return s.toString(); + } + + /** + * Reads in the object from a serial stream, updating when to + * {@link EventQueue#getMostRecentEventTime()} if necessary. + * + * @param s the stream to read from + * @throws IOException if deserialization fails + * @throws ClassNotFoundException if deserialization fails + * @serialData default, except for updating when + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + if (when == 0) + when = EventQueue.getMostRecentEventTime(); + } +} // class InputMethodEvent diff --git a/libjava/classpath/java/awt/event/InputMethodListener.java b/libjava/classpath/java/awt/event/InputMethodListener.java new file mode 100644 index 000000000..e2f6a4e67 --- /dev/null +++ b/libjava/classpath/java/awt/event/InputMethodListener.java @@ -0,0 +1,70 @@ +/* InputMethodListener.java -- listen for input method events + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.awt.im.InputMethodRequests; +import java.util.EventListener; + +/** + * This interface is for classes that wish to receive events from an input + * method. For a text component to use input methods, it must also install + * an InputMethodRequests handler. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see InputMethodEvent + * @see InputMethodRequests + * @since 1.2 + * @status updated to 1.4 + */ +public interface InputMethodListener extends EventListener +{ + /** + * This method is called when the text is changed. + * + * @param event the <code>InputMethodEvent</code> indicating the text change + */ + void inputMethodTextChanged(InputMethodEvent event); + + /** + * This method is called when the cursor position within the text is changed. + * + * @param event the <code>InputMethodEvent</code> indicating the change + */ + void caretPositionChanged(InputMethodEvent event); +} // interface InputMethodListener diff --git a/libjava/classpath/java/awt/event/InvocationEvent.java b/libjava/classpath/java/awt/event/InvocationEvent.java new file mode 100644 index 000000000..afa09de13 --- /dev/null +++ b/libjava/classpath/java/awt/event/InvocationEvent.java @@ -0,0 +1,258 @@ +/* InvocationEvent.java -- call a runnable when dispatched + Copyright (C) 1999, 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.awt.AWTEvent; +import java.awt.ActiveEvent; +import java.awt.EventQueue; + +/** + * This event executes {@link Runnable#run()} of a target object when it is + * dispatched. This class is used by calls to <code>invokeLater</code> and + * <code>invokeAndWait</code>, so client code can use this fact to avoid + * writing special-casing AWTEventListener objects. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ActiveEvent + * @see EventQueue#invokeLater(Runnable) + * @see EventQueue#invokeAndWait(Runnable) + * @see AWTEventListener + * @since 1.2 + * @status updated to 1.4 + */ +public class InvocationEvent extends AWTEvent implements ActiveEvent +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 436056344909459450L; + + /** This is the first id in the range of event ids used by this class. */ + public static final int INVOCATION_FIRST = 1200; + + /** This is the default id for this event type. */ + public static final int INVOCATION_DEFAULT = 1200; + + /** This is the last id in the range of event ids used by this class. */ + public static final int INVOCATION_LAST = 1200; + + /** + * This is the <code>Runnable</code> object to call when dispatched. + * + * @serial the runnable to execute + */ + protected Runnable runnable; + + /** + * This is the object to call <code>notifyAll()</code> on when + * the call to <code>run()</code> returns, or <code>null</code> if no + * object is to be notified. + * + * @serial the object to notify + */ + protected Object notifier; + + /** + * This variable is set to <code>true</code> if exceptions are caught + * and stored in a variable during the call to <code>run()</code>, otherwise + * exceptions are ignored and propagate up. + * + * @serial true to catch exceptions + */ + protected boolean catchExceptions; + + /** + * This is the caught exception thrown in the <code>run()</code> method. It + * is null if exceptions are ignored, the run method hasn't completed, or + * there were no exceptions. + * + * @serial the caught exception, if any + */ + private Exception exception; + + /** + * This is the caught Throwable thrown in the <code>run()</code> method. + * It is null if throwables are ignored, the run method hasn't completed, + * or there were no throwables thrown. + */ + private Throwable throwable; + + /** + * The timestamp when this event was created. + * + * @see #getWhen() + * @serial the timestamp + * @since 1.4 + */ + private final long when = EventQueue.getMostRecentEventTime(); + + /** + * Initializes a new instance of <code>InvocationEvent</code> with the + * specified source and runnable. + * + * @param source the source of the event + * @param runnable the <code>Runnable</code> object to invoke + * @throws IllegalArgumentException if source is null + */ + public InvocationEvent(Object source, Runnable runnable) + { + this(source, INVOCATION_DEFAULT, runnable, null, false); + } + + /** + * Initializes a new instance of <code>InvocationEvent</code> with the + * specified source, runnable, and notifier. It will also catch exceptions + * if specified. If notifier is non-null, this will call notifyAll() on + * the object when the runnable is complete. If catchExceptions is true, + * this traps any exception in the runnable, otherwise it lets the exception + * propagate up the Event Dispatch thread. + * + * @param source the source of the event + * @param runnable the <code>Runnable</code> object to invoke + * @param notifier the object to notify, or null + * @param catchExceptions true to catch exceptions from the runnable + */ + public InvocationEvent(Object source, Runnable runnable, Object notifier, + boolean catchExceptions) + { + this(source, INVOCATION_DEFAULT, runnable, notifier, catchExceptions); + } + + /** + * Initializes a new instance of <code>InvocationEvent</code> with the + * specified source, runnable, and notifier. It will also catch exceptions + * if specified. If notifier is non-null, this will call notifyAll() on + * the object when the runnable is complete. If catchExceptions is true, + * this traps any exception in the runnable, otherwise it lets the exception + * propagate up the Event Dispatch thread. Note that an invalid id leads to + * unspecified results. + * + * @param source the source of the event + * @param id the event id + * @param runnable the <code>Runnable</code> object to invoke + * @param notifier the object to notify, or null + * @param catchExceptions true to catch exceptions from the runnable + */ + protected InvocationEvent(Object source, int id, Runnable runnable, + Object notifier, boolean catchExceptions) + { + super(source, id); + this.runnable = runnable; + this.notifier = notifier; + this.catchExceptions = catchExceptions; + } + + /** + * This method calls the <code>run()</code> method of the runnable, traps + * exceptions if instructed to do so, and calls <code>notifyAll()</code> + * on any notifier if all worked successfully. + */ + public void dispatch() + { + if (catchExceptions) + try + { + runnable.run(); + } + catch (Throwable t) + { + throwable = t; + if (t instanceof Exception) + exception = (Exception)t; + } + else + runnable.run(); + + Object o = notifier; + if (o != null) + synchronized(o) + { + o.notifyAll(); + } + } + + /** + * This method returns the exception that occurred during the execution of + * the runnable, or <code>null</code> if not exception was thrown or + * exceptions were not caught. + * + * @return the exception thrown by the runnable + */ + public Exception getException() + { + return exception; + } + + /** + * Returns a throwable caught while executing the Runnable's run() method. + * Null if none was thrown or if this InvocationEvent doesn't catch + * throwables. + * @return the caught Throwable + * @since 1.5 + */ + public Throwable getThrowable() + { + return throwable; + } + + /** + * Gets the timestamp of when this event was created. + * + * @return the timestamp of this event + * @since 1.4 + */ + public long getWhen() + { + return when; + } + + /** + * This method returns a string identifying this event. This is formatted as: + * <code>"INVOCATION_DEFAULT,runnable=" + runnable + ",notifier=" + notifier + * + ",catchExceptions=" + catchExceptions + ",when=" + getWhen()</code>. + * + * @return a string identifying this event + */ + public String paramString() + { + return (id == INVOCATION_DEFAULT ? "INVOCATION_DEFAULT,runnable=" + : "unknown type,runnable=") + runnable + ",notifier=" + notifier + + ",catchExceptions=" + catchExceptions + ",when=" + when; + } +} // class InvocationEvent diff --git a/libjava/classpath/java/awt/event/ItemEvent.java b/libjava/classpath/java/awt/event/ItemEvent.java new file mode 100644 index 000000000..467815b16 --- /dev/null +++ b/libjava/classpath/java/awt/event/ItemEvent.java @@ -0,0 +1,155 @@ +/* ItemEvent.java -- event for item state changes + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.awt.AWTEvent; +import java.awt.ItemSelectable; + +/** + * This event is generated when a selection item changes state. This is an + * abstraction that distills a large number of individual mouse or keyboard + * events into a simpler "item selected" and "item deselected" events. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ItemSelectable + * @see ItemListener + * @since 1.1 + * @status updated to 1.4 + */ +public class ItemEvent extends AWTEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -608708132447206933L; + + /** This is the first id in the event id range used by this class. */ + public static final int ITEM_FIRST = 701; + + /** This is the last id in the event id range used by this class. */ + public static final int ITEM_LAST = 701; + + /** This event id indicates a state change occurred. */ + public static final int ITEM_STATE_CHANGED = 701; + + /** This type indicates that the item was selected. */ + public static final int SELECTED = 1; + + /** This type indicates that the item was deselected. */ + public static final int DESELECTED = 2; + + /** + * The item affected by this event. + * + * @serial the item of the selection + */ + private final Object item; + + /** + * The state change direction, one of {@link #SELECTED} or + * {@link #DESELECTED}. + * + * @serial the selection state + */ + private final int stateChange; + + /** + * Initializes a new instance of <code>ItemEvent</code> with the specified + * source, id, and state change constant. Note that an invalid id leads to + * unspecified results. + * + * @param source the source of the event + * @param id the event id + * @param item the item affected by the state change + * @param stateChange one of {@link #SELECTED} or {@link #DESELECTED} + */ + public ItemEvent(ItemSelectable source, int id, Object item, int stateChange) + { + super(source, id); + this.item = item; + this.stateChange = stateChange; + } + + /** + * This method returns the event source as an <code>ItemSelectable</code>. + * + * @return the event source as an <code>ItemSelected</code> + * @throws ClassCastException if source is changed to a non-ItemSelectable + */ + public ItemSelectable getItemSelectable() + { + return (ItemSelectable) source; + } + + /** + * Returns the item affected by this state change. + * + * @return the item affected by this state change + */ + public Object getItem() + { + return item; + } + + /** + * Returns the type of state change, either {@link #SELECTED} or + * {@link #DESELECTED}. + * + * @return the type of state change + */ + public int getStateChange() + { + return stateChange; + } + + /** + * Returns a string identifying this event. This is in the format: + * <code>"ITEM_STATE_CHANGED,item=" + item + ",stateChange=" + * + (getStateChange() == DESELECTED ? "DESELECTED" : "SELECTED")</code>. + * + * @return a string identifying this event + */ + public String paramString() + { + return (id == ITEM_STATE_CHANGED ? "ITEM_STATE_CHANGED,item=" + : "unknown type,item=") + item + ",stateChange=" + + (stateChange == SELECTED ? "SELECTED" + : stateChange == DESELECTED ? "DESELECTED" : "unknown type"); + } +} // class ItemEvent diff --git a/libjava/classpath/java/awt/event/ItemListener.java b/libjava/classpath/java/awt/event/ItemListener.java new file mode 100644 index 000000000..fa5f3aad3 --- /dev/null +++ b/libjava/classpath/java/awt/event/ItemListener.java @@ -0,0 +1,62 @@ +/* ItemListener.java -- listen for item events + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.awt.ItemSelectable; +import java.util.EventListener; + +/** + * This interface is for classes that wish to receive events when an + * item's selection state changes. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ItemSelectable + * @see ItemEvent + * @since 1.1 + * @status updated to 1.4 + */ +public interface ItemListener extends EventListener +{ + /** + * This method is called when an item's state is changed. + * + * @param event the <code>ItemEvent</code> indicating the change + */ + void itemStateChanged(ItemEvent event); +} // interface ItemListener diff --git a/libjava/classpath/java/awt/event/KeyAdapter.java b/libjava/classpath/java/awt/event/KeyAdapter.java new file mode 100644 index 000000000..c01d61ff3 --- /dev/null +++ b/libjava/classpath/java/awt/event/KeyAdapter.java @@ -0,0 +1,88 @@ +/* KeyAdapter.java -- convenience class for writing key listeners + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +/** + * This class implements <code>KeyListener</code> and implements all methods + * with empty bodies. This allows a listener interested in implementing only + * a subset of the <code>KeyListener</code> interface to extend this class + * and override only the desired methods. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see KeyEvent + * @see KeyListener + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class KeyAdapter implements KeyListener +{ + /** + * Do nothing default constructor for subclasses. + */ + public KeyAdapter() + { + } + + /** + * Implements this method in the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void keyTyped(KeyEvent event) + { + } + + /** + * Implements this method in the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void keyPressed(KeyEvent event) + { + } + + /** + * Implements this method in the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void keyReleased(KeyEvent event) + { + } +} // class KeyAdapter diff --git a/libjava/classpath/java/awt/event/KeyEvent.java b/libjava/classpath/java/awt/event/KeyEvent.java new file mode 100644 index 000000000..a2b1dc94c --- /dev/null +++ b/libjava/classpath/java/awt/event/KeyEvent.java @@ -0,0 +1,1762 @@ +/* KeyEvent.java -- event for key presses + Copyright (C) 1999, 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import gnu.java.awt.EventModifier; +import gnu.java.lang.CPStringBuilder; + +import java.awt.Component; +import java.io.IOException; +import java.io.ObjectInputStream; + +/** + * This event is generated when a key is pressed or released. There are two + * categories of key events: + * + * <p><em>"Key typed" events</em> are higher-level, and have already + * compensated for modifiers and keyboard layout to generate a single Unicode + * character. It may take several key press events to generate one key typed. + * The <code>getKeyCode</code> method will return <code>VK_UNDEFINED</code>, + * and <code>getKeyChar</code> will return a valid Unicode character or + * <code>CHAR_UNDEFINED</code>. + * + * <p><em>"Key pressed" and "key released" events</em> are lower-level, and + * are platform and keyboard dependent. They correspond to the actaul motion + * on a keyboard, and return a virtual key code which labels the key that was + * pressed. The <code>getKeyCode</code> method will return one of the + * <code>VK_*</code> constants (except VK_UNDEFINED), and the + * <code>getKeyChar</code> method is undefined. + * + * <p>Some keys do not generate key typed events, such as the F1 or HELP keys. + * Not all keyboards can generate all virtual keys, and no attempt is made to + * simulate the ones that can't be typed. Virtual keys correspond to the + * keyboard layout, so for example, VK_Q in English is VK_A in French. Also, + * there are some additional virtual keys to ease handling of actions, such + * as VK_ALL_CANDIDATES in place of ALT+VK_CONVERT. Do not rely on the value + * of the VK_* constants, except for VK_ENTER, VK_BACK_SPACE, and VK_TAB. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see KeyAdapter + * @see KeyListener + * @since 1.1 + * @status updated to 1.4 + */ +public class KeyEvent extends InputEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -2352130953028126954L; + + /** This is the first id in the range of event ids used by this class. */ + public static final int KEY_FIRST = 400; + + /** This is the last id in the range of event ids used by this class. */ + public static final int KEY_LAST = 402; + + /** + * This event id indicates a key was typed, which is a key press followed + * by a key release to generate an actual Unicode character. It may take + * several key presses to generate one key typed event, and some action + * keys have no corresponding key typed. + */ + public static final int KEY_TYPED = 400; + + /** This event id indicates a key was pressed. */ + public static final int KEY_PRESSED = 401; + + /** This event it indicates a key was released. */ + public static final int KEY_RELEASED = 402; + + /** The virtual key Enter, which will always map to '\n'. */ + public static final int VK_ENTER = '\n'; + + /** The virtual key Backspace, which will always map to '\b'. */ + public static final int VK_BACK_SPACE = '\b'; + + /** The virtual key Tab, which will always map to '\t'. */ + public static final int VK_TAB = '\t'; + + /** The virtual key Cancel. */ + public static final int VK_CANCEL = 3; + + /** The virtual key VK_CLEAR. */ + public static final int VK_CLEAR = 12; + + /** The virtual key VK_SHIFT. */ + public static final int VK_SHIFT = 16; + + /** The virtual key VK_CONTROL. */ + public static final int VK_CONTROL = 17; + + /** The virtual key VK_ALT. */ + public static final int VK_ALT = 18; + + /** The virtual key VK_PAUSE. */ + public static final int VK_PAUSE = 19; + + /** The virtual key VK_CAPS_LOCK. */ + public static final int VK_CAPS_LOCK = 20; + + /** The virtual key VK_ESCAPE. */ + public static final int VK_ESCAPE = 27; + + /** The virtual key VK_SPACE. */ + public static final int VK_SPACE = ' '; + + /** The virtual key VK_PAGE_UP. */ + public static final int VK_PAGE_UP = 33; + + /** The virtual key VK_PAGE_DOWN. */ + public static final int VK_PAGE_DOWN = 34; + + /** The virtual key VK_END. */ + public static final int VK_END = 35; + + /** The virtual key VK_HOME. */ + public static final int VK_HOME = 36; + + /** + * The virtual key for the non-numpad VK_LEFT. + * + * @see #VK_KP_LEFT + */ + public static final int VK_LEFT = 37; + + /** + * The virtual key for the non-numpad VK_UP. + * + * @see #VK_KP_UP + */ + public static final int VK_UP = 38; + + /** + * The virtual key for the non-numpad VK_RIGHT. + * + * @see #VK_KP_RIGHT + */ + public static final int VK_RIGHT = 39; + + /** + * The virtual key for the non-numpad VK_DOWN. + * + * @see #VK_KP_DOWN + */ + public static final int VK_DOWN = 40; + + /** The virtual key VK_COMMA. */ + public static final int VK_COMMA = ','; + + /** + * The virtual key VK_MINUS. + * + * @since 1.2 + */ + public static final int VK_MINUS = '-'; + + /** The virtual key VK_PERIOD. */ + public static final int VK_PERIOD = '.'; + + /** The virtual key VK_SLASH. */ + public static final int VK_SLASH = '/'; + + /** The virtual key VK_0. */ + public static final int VK_0 = '0'; + + /** The virtual key VK_1. */ + public static final int VK_1 = '1'; + + /** The virtual key VK_2. */ + public static final int VK_2 = '2'; + + /** The virtual key VK_3. */ + public static final int VK_3 = '3'; + + /** The virtual key VK_4. */ + public static final int VK_4 = '4'; + + /** The virtual key VK_5. */ + public static final int VK_5 = '5'; + + /** The virtual key VK_6. */ + public static final int VK_6 = '6'; + + /** The virtual key VK_7. */ + public static final int VK_7 = '7'; + + /** The virtual key VK_8. */ + public static final int VK_8 = '8'; + + /** The virtual key VK_9. */ + public static final int VK_9 = '9'; + + /** The virtual key VK_SEMICOLON. */ + public static final int VK_SEMICOLON = ';'; + + /** The virtual key VK_EQUALS. */ + public static final int VK_EQUALS = '='; + + /** The virtual key VK_A. */ + public static final int VK_A = 'A'; + + /** The virtual key VK_B. */ + public static final int VK_B = 'B'; + + /** The virtual key VK_C. */ + public static final int VK_C = 'C'; + + /** The virtual key VK_D. */ + public static final int VK_D = 'D'; + + /** The virtual key VK_E. */ + public static final int VK_E = 'E'; + + /** The virtual key VK_F. */ + public static final int VK_F = 'F'; + + /** The virtual key VK_G. */ + public static final int VK_G = 'G'; + + /** The virtual key VK_H. */ + public static final int VK_H = 'H'; + + /** The virtual key VK_I. */ + public static final int VK_I = 'I'; + + /** The virtual key VK_J. */ + public static final int VK_J = 'J'; + + /** The virtual key VK_K. */ + public static final int VK_K = 'K'; + + /** The virtual key VK_L. */ + public static final int VK_L = 'L'; + + /** The virtual key VK_M. */ + public static final int VK_M = 'M'; + + /** The virtual key VK_N. */ + public static final int VK_N = 'N'; + + /** The virtual key VK_O. */ + public static final int VK_O = 'O'; + + /** The virtual key VK_P. */ + public static final int VK_P = 'P'; + + /** The virtual key VK_Q. */ + public static final int VK_Q = 'Q'; + + /** The virtual key VK_R. */ + public static final int VK_R = 'R'; + + /** The virtual key VK_S. */ + public static final int VK_S = 'S'; + + /** The virtual key VK_T. */ + public static final int VK_T = 'T'; + + /** The virtual key VK_U. */ + public static final int VK_U = 'U'; + + /** The virtual key VK_V. */ + public static final int VK_V = 'V'; + + /** The virtual key VK_W. */ + public static final int VK_W = 'W'; + + /** The virtual key VK_X. */ + public static final int VK_X = 'X'; + + /** The virtual key VK_Y. */ + public static final int VK_Y = 'Y'; + + /** The virtual key VK_Z. */ + public static final int VK_Z = 'Z'; + + /** The virtual key VK_OPEN_BRACKET. */ + public static final int VK_OPEN_BRACKET = '['; + + /** The virtual key VK_BACK_SLASH. */ + public static final int VK_BACK_SLASH = '\\'; + + /** The virtual key VK_CLOSE_BRACKET. */ + public static final int VK_CLOSE_BRACKET = ']'; + + /** The virtual key VK_NUMPAD0. */ + public static final int VK_NUMPAD0 = 96; + + /** The virtual key VK_NUMPAD1. */ + public static final int VK_NUMPAD1 = 97; + + /** The virtual key VK_NUMPAD2. */ + public static final int VK_NUMPAD2 = 98; + + /** The virtual key VK_NUMPAD3. */ + public static final int VK_NUMPAD3 = 99; + + /** The virtual key VK_NUMPAD4. */ + public static final int VK_NUMPAD4 = 100; + + /** The virtual key VK_NUMPAD5. */ + public static final int VK_NUMPAD5 = 101; + + /** The virtual key VK_NUMPAD6. */ + public static final int VK_NUMPAD6 = 102; + + /** The virtual key VK_NUMPAD7. */ + public static final int VK_NUMPAD7 = 103; + + /** The virtual key VK_NUMPAD8. */ + public static final int VK_NUMPAD8 = 104; + + /** The virtual key VK_NUMPAD9. */ + public static final int VK_NUMPAD9 = 105; + + /** The virtual key VK_MULTIPLY. */ + public static final int VK_MULTIPLY = 106; + + /** The virtual key VK_ADD. */ + public static final int VK_ADD = 107; + + /** + * The virtual key VK_SEPARATOR, handily mispelled for those who can't + * figure it out. + * + * @deprecated use {@link #VK_SEPARATOR} + */ + public static final int VK_SEPARATER = 108; + + /** + * The virtual key VK_SEPARATOR. + * + * @since 1.4 + */ + public static final int VK_SEPARATOR = 108; + + /** The virtual key VK_SUBTRACT. */ + public static final int VK_SUBTRACT = 109; + + /** The virtual key VK_DECIMAL. */ + public static final int VK_DECIMAL = 110; + + /** The virtual key VK_DIVIDE. */ + public static final int VK_DIVIDE = 111; + + /** The virtual key VK_DELETE. */ + public static final int VK_DELETE = 127; + + /** The virtual key VK_NUM_LOCK. */ + public static final int VK_NUM_LOCK = 144; + + /** The virtual key VK_SCROLL_LOCK. */ + public static final int VK_SCROLL_LOCK = 145; + + /** The virtual key VK_F1. */ + public static final int VK_F1 = 112; + + /** The virtual key VK_F2. */ + public static final int VK_F2 = 113; + + /** The virtual key VK_F3. */ + public static final int VK_F3 = 114; + + /** The virtual key VK_F4. */ + public static final int VK_F4 = 115; + + /** The virtual key VK_F5. */ + public static final int VK_F5 = 116; + + /** The virtual key VK_F6. */ + public static final int VK_F6 = 117; + + /** The virtual key VK_F7. */ + public static final int VK_F7 = 118; + + /** The virtual key VK_F8. */ + public static final int VK_F8 = 119; + + /** The virtual key VK_F9. */ + public static final int VK_F9 = 120; + + /** The virtual key VK_F10. */ + public static final int VK_F10 = 121; + + /** The virtual key VK_F11. */ + public static final int VK_F11 = 122; + + /** The virtual key VK_F12. */ + public static final int VK_F12 = 123; + + /** + * The virtual key VK_F13. + * + * @since 1.2 + */ + public static final int VK_F13 = 61440; + + /** + * The virtual key VK_F14. + * + * @since 1.2 + */ + public static final int VK_F14 = 61441; + + /** + * The virtual key VK_F15. + * + * @since 1.2 + */ + public static final int VK_F15 = 61442; + + /** + * The virtual key VK_F16. + * + * @since 1.2 + */ + public static final int VK_F16 = 61443; + + /** + * The virtual key VK_F17. + * + * @since 1.2 + */ + public static final int VK_F17 = 61444; + + /** + * The virtual key VK_F18. + * + * @since 1.2 + */ + public static final int VK_F18 = 61445; + + /** + * The virtual key VK_F19. + * + * @since 1.2 + */ + public static final int VK_F19 = 61446; + + /** + * The virtual key VK_F20. + * + * @since 1.2 + */ + public static final int VK_F20 = 61447; + + /** + * The virtual key VK_F21. + * + * @since 1.2 + */ + public static final int VK_F21 = 61448; + + /** + * The virtual key VK_F22. + * + * @since 1.2 + */ + public static final int VK_F22 = 61449; + + /** + * The virtual key VK_F23. + * + * @since 1.2 + */ + public static final int VK_F23 = 61450; + + /** + * The virtual key VK_F24. + * + * @since 1.2 + */ + public static final int VK_F24 = 61451; + + /** The virtual key VK_PRINTSCREEN. */ + public static final int VK_PRINTSCREEN = 154; + + /** The virtual key VK_INSERT. */ + public static final int VK_INSERT = 155; + + /** The virtual key VK_HELP. */ + public static final int VK_HELP = 156; + + /** The virtual key VK_META. */ + public static final int VK_META = 157; + + /** The virtual key VK_BACK_QUOTE. */ + public static final int VK_BACK_QUOTE = 192; + + /** The virtual key VK_QUOTE. */ + public static final int VK_QUOTE = 222; + + /** + * The virtual key for the numpad VK_KP_UP. + * + * @see #VK_UP + * @since 1.2 + */ + public static final int VK_KP_UP = 224; + + /** + * The virtual key for the numpad VK_KP_DOWN. + * + * @see #VK_DOWN + * @since 1.2 + */ + public static final int VK_KP_DOWN = 225; + + /** + * The virtual key for the numpad VK_KP_LEFT. + * + * @see #VK_LEFT + * @since 1.2 + */ + public static final int VK_KP_LEFT = 226; + + /** + * The virtual key for the numpad VK_KP_RIGHT. + * + * @see #VK_RIGHT + * @since 1.2 + */ + public static final int VK_KP_RIGHT = 227; + + /** + * The virtual key VK_DEAD_GRAVE. + * + * @since 1.2 + */ + public static final int VK_DEAD_GRAVE = 128; + + /** + * The virtual key VK_DEAD_ACUTE. + * + * @since 1.2 + */ + public static final int VK_DEAD_ACUTE = 129; + + /** + * The virtual key VK_DEAD_CIRCUMFLEX. + * + * @since 1.2 + */ + public static final int VK_DEAD_CIRCUMFLEX = 130; + + /** + * The virtual key VK_DEAD_TILDE. + * + * @since 1.2 + */ + public static final int VK_DEAD_TILDE = 131; + + /** + * The virtual key VK_DEAD_MACRON. + * + * @since 1.2 + */ + public static final int VK_DEAD_MACRON = 132; + + /** + * The virtual key VK_DEAD_BREVE. + * + * @since 1.2 + */ + public static final int VK_DEAD_BREVE = 133; + + /** + * The virtual key VK_DEAD_ABOVEDOT. + * + * @since 1.2 + */ + public static final int VK_DEAD_ABOVEDOT = 134; + + /** + * The virtual key VK_DEAD_DIAERESIS. + * + * @since 1.2 + */ + public static final int VK_DEAD_DIAERESIS = 135; + + /** + * The virtual key VK_DEAD_ABOVERING. + * + * @since 1.2 + */ + public static final int VK_DEAD_ABOVERING = 136; + + /** + * The virtual key VK_DEAD_DOUBLEACUTE. + * + * @since 1.2 + */ + public static final int VK_DEAD_DOUBLEACUTE = 137; + + /** + * The virtual key VK_DEAD_CARON. + * + * @since 1.2 + */ + public static final int VK_DEAD_CARON = 138; + + /** + * The virtual key VK_DEAD_CEDILLA. + * + * @since 1.2 + */ + public static final int VK_DEAD_CEDILLA = 139; + + /** + * The virtual key VK_DEAD_OGONEK. + * + * @since 1.2 + */ + public static final int VK_DEAD_OGONEK = 140; + + /** + * The virtual key VK_DEAD_IOTA. + * + * @since 1.2 + */ + public static final int VK_DEAD_IOTA = 141; + + /** + * The virtual key VK_DEAD_VOICED_SOUND. + * + * @since 1.2 + */ + public static final int VK_DEAD_VOICED_SOUND = 142; + + /** + * The virtual key VK_DEAD_SEMIVOICED_SOUND. + * + * @since 1.2 + */ + public static final int VK_DEAD_SEMIVOICED_SOUND = 143; + + /** + * The virtual key VK_AMPERSAND. + * + * @since 1.2 + */ + public static final int VK_AMPERSAND = 150; + + /** + * The virtual key VK_ASTERISK. + * + * @since 1.2 + */ + public static final int VK_ASTERISK = 151; + + /** + * The virtual key VK_QUOTEDBL. + * + * @since 1.2 + */ + public static final int VK_QUOTEDBL = 152; + + /** + * The virtual key VK_LESS. + * + * @since 1.2 + */ + public static final int VK_LESS = 153; + + /** + * The virtual key VK_GREATER. + * + * @since 1.2 + */ + public static final int VK_GREATER = 160; + + /** + * The virtual key VK_BRACELEFT. + * + * @since 1.2 + */ + public static final int VK_BRACELEFT = 161; + + /** + * The virtual key VK_BRACERIGHT. + * + * @since 1.2 + */ + public static final int VK_BRACERIGHT = 162; + + /** + * The virtual key VK_AT. + * + * @since 1.2 + */ + public static final int VK_AT = 512; + + /** + * The virtual key VK_COLON. + * + * @since 1.2 + */ + public static final int VK_COLON = 513; + + /** + * The virtual key VK_CIRCUMFLEX. + * + * @since 1.2 + */ + public static final int VK_CIRCUMFLEX = 514; + + /** + * The virtual key VK_DOLLAR. + * + * @since 1.2 + */ + public static final int VK_DOLLAR = 515; + + /** + * The virtual key VK_EURO_SIGN. + * + * @since 1.2 + */ + public static final int VK_EURO_SIGN = 516; + + /** + * The virtual key VK_EXCLAMATION_MARK. + * + * @since 1.2 + */ + public static final int VK_EXCLAMATION_MARK = 517; + + /** + * The virtual key VK_INVERTED_EXCLAMATION_MARK. + * + * @since 1.2 + */ + public static final int VK_INVERTED_EXCLAMATION_MARK = 518; + + /** + * The virtual key VK_LEFT_PARENTHESIS. + * + * @since 1.2 + */ + public static final int VK_LEFT_PARENTHESIS = 519; + + /** + * The virtual key VK_NUMBER_SIGN. + * + * @since 1.2 + */ + public static final int VK_NUMBER_SIGN = 520; + + /** + * The virtual key VK_PLUS. + * + * @since 1.2 + */ + public static final int VK_PLUS = 521; + + /** + * The virtual key VK_RIGHT_PARENTHESIS. + * + * @since 1.2 + */ + public static final int VK_RIGHT_PARENTHESIS = 522; + + /** + * The virtual key VK_UNDERSCORE. + * + * @since 1.2 + */ + public static final int VK_UNDERSCORE = 523; + + /** The virtual key VK_FINAL. */ + public static final int VK_FINAL = 24; + + /** The virtual key VK_CONVERT. */ + public static final int VK_CONVERT = 28; + + /** The virtual key VK_NONCONVERT. */ + public static final int VK_NONCONVERT = 29; + + /** The virtual key VK_ACCEPT. */ + public static final int VK_ACCEPT = 30; + + /** The virtual key VK_MODECHANGE. */ + public static final int VK_MODECHANGE = 31; + + /** The virtual key VK_KANA. */ + public static final int VK_KANA = 21; + + /** The virtual key VK_KANJI. */ + public static final int VK_KANJI = 25; + + /** + * The virtual key VK_ALPHANUMERIC. + * + * @since 1.2 + */ + public static final int VK_ALPHANUMERIC = 240; + + /** + * The virtual key VK_KATAKANA. + * + * @since 1.2 + */ + public static final int VK_KATAKANA = 241; + + /** + * The virtual key VK_HIRAGANA. + * + * @since 1.2 + */ + public static final int VK_HIRAGANA = 242; + + /** + * The virtual key VK_FULL_WIDTH. + * + * @since 1.2 + */ + public static final int VK_FULL_WIDTH = 243; + + /** + * The virtual key VK_HALF_WIDTH. + * + * @since 1.2 + */ + public static final int VK_HALF_WIDTH = 244; + + /** + * The virtual key VK_ROMAN_CHARACTERS. + * + * @since 1.2 + */ + public static final int VK_ROMAN_CHARACTERS = 245; + + /** + * The virtual key VK_ALL_CANDIDATES. + * + * @since 1.2 + */ + public static final int VK_ALL_CANDIDATES = 256; + + /** + * The virtual key VK_PREVIOUS_CANDIDATE. + * + * @since 1.2 + */ + public static final int VK_PREVIOUS_CANDIDATE = 257; + + /** + * The virtual key VK_CODE_INPUT. + * + * @since 1.2 + */ + public static final int VK_CODE_INPUT = 258; + + /** + * The virtual key VK_JAPANESE_KATAKANA. + * + * @since 1.2 + */ + public static final int VK_JAPANESE_KATAKANA = 259; + + /** + * The virtual key VK_JAPANESE_HIRAGANA. + * + * @since 1.2 + */ + public static final int VK_JAPANESE_HIRAGANA = 260; + + /** + * The virtual key VK_JAPANESE_ROMAN. + * + * @since 1.2 + */ + public static final int VK_JAPANESE_ROMAN = 261; + + /** + * The virtual key VK_KANA_LOCK. + * + * @since 1.3 + */ + public static final int VK_KANA_LOCK = 262; + + /** + * The virtual key VK_INPUT_METHOD_ON_OFF. + * + * @since 1.3 + */ + public static final int VK_INPUT_METHOD_ON_OFF = 263; + + /** + * The virtual key VK_CUT. + * + * @since 1.2 + */ + public static final int VK_CUT = 65489; + + /** + * The virtual key VK_COPY. + * + * @since 1.2 + */ + public static final int VK_COPY = 65485; + + /** + * The virtual key VK_PASTE. + * + * @since 1.2 + */ + public static final int VK_PASTE = 65487; + + /** + * The virtual key VK_UNDO. + * + * @since 1.2 + */ + public static final int VK_UNDO = 65483; + + /** + * The virtual key VK_AGAIN. + * + * @since 1.2 + */ + public static final int VK_AGAIN = 65481; + + /** + * The virtual key VK_FIND. + * + * @since 1.2 + */ + public static final int VK_FIND = 65488; + + /** + * The virtual key VK_PROPS. + * + * @since 1.2 + */ + public static final int VK_PROPS = 65482; + + /** + * The virtual key VK_STOP. + * + * @since 1.2 + */ + public static final int VK_STOP = 65480; + + /** + * The virtual key VK_COMPOSE. + * + * @since 1.2 + */ + public static final int VK_COMPOSE = 65312; + + /** + * The virtual key VK_ALT_GRAPH. + * + * @since 1.2 + */ + public static final int VK_ALT_GRAPH = 65406; + + /** + * The 'begin' key VK_BEGIN + * + * @since 1.5 + */ + public static final int VK_BEGIN = 65368; + + /** + * The context-menu key VK_CONTEXT_MENU + * + * @since 1.5 + */ + public static final int VK_CONTEXT_MENU = 525; + + /** + * The 'Windows' key VK_WINDOWS + * + * @since 1.5 + */ + public static final int VK_WINDOWS = 524; + + /** + * The virtual key VK_UNDEFINED. This is used for key typed events, which + * do not have a virtual key. + */ + public static final int VK_UNDEFINED = 0; + + /** + * The only char with no valid Unicode interpretation. This is used for + * key pressed and key released events which do not have a valid keyChar. + */ + public static final char CHAR_UNDEFINED = '\uffff'; + + /** + * Indicates unknown or irrelavent key location. This is also used for + * key typed events, which do not need a location. + * + * @since 1.4 + */ + public static final int KEY_LOCATION_UNKNOWN = 0; + + /** + * Indicates a standard key location, with no left/right variants and not + * on the numeric pad. + * + * @since 1.4 + */ + public static final int KEY_LOCATION_STANDARD = 1; + + /** + * Indicates the key is on the left side of the keyboard, such as the left + * shift. + * + * @since 1.4 + */ + public static final int KEY_LOCATION_LEFT = 2; + + /** + * Indicates the key is on the right side of the keyboard, such as the right + * shift. + * + * @since 1.4 + */ + public static final int KEY_LOCATION_RIGHT = 3; + + /** + * Indicates the key is on the numeric pad, such as the numpad 0. + * + * @since 1.4 + */ + public static final int KEY_LOCATION_NUMPAD = 4; + + /** + * The code assigned to the physical keyboard location (as adjusted by the + * keyboard layout). Use the symbolic VK_* names instead of numbers. + * + * @see #getKeyCode() + * @serial the VK_ code for this key + */ + private int keyCode; + + /** + * The Unicode character produced by the key type event. This has no meaning + * for key pressed and key released events. + * + * @see #getKeyChar() + * @serial the Unicode value for this key + */ + private char keyChar; + + /** + * The keyboard location of the key. One of {@link #KEY_LOCATION_UNKNOWN}, + * {@link #KEY_LOCATION_STANDARD}, {@link #KEY_LOCATION_LEFT}, + * {@link #KEY_LOCATION_RIGHT}, or {@link #KEY_LOCATION_NUMPAD}. + * + * @see #getKeyLocation() + * @serial the key location + * @since 1.4 + */ + private final int keyLocation; + + /** + * Stores the state of the native event dispatching system, to correctly + * dispatch in Component#dispatchEventImpl when a proxy is active. + * + * XXX Does this matter in Classpath? + * + * @serial whether the proxy is active + */ + private boolean isProxyActive; + + + /** + * Initializes a new instance of <code>KeyEvent</code> with the specified + * information. Note that an invalid id leads to unspecified results. + * + * @param source the component that generated this event + * @param id the event id + * @param when the timestamp when the even occurred + * @param modifiers the modifier keys during the event, in old or new style + * @param keyCode the integer constant for the virtual key type + * @param keyChar the Unicode value of the key + * @param keyLocation the location of the key + * @throws IllegalArgumentException if source is null, if keyLocation is + * invalid, or if (id == KEY_TYPED && (keyCode != VK_UNDEFINED + * || keyChar == CHAR_UNDEFINED)) + */ + public KeyEvent(Component source, int id, long when, int modifiers, + int keyCode, char keyChar, int keyLocation) + { + super(source, id, when, modifiers); + this.keyCode = keyCode; + this.keyChar = keyChar; + this.keyLocation = keyLocation; + if ((id == KEY_TYPED && (keyCode != VK_UNDEFINED + || keyChar == CHAR_UNDEFINED)) + || keyLocation < KEY_LOCATION_UNKNOWN + || keyLocation > KEY_LOCATION_NUMPAD) + throw new IllegalArgumentException(); + } + + /** + * Initializes a new instance of <code>KeyEvent</code> with the specified + * information. Note that an invalid id leads to unspecified results. + * + * @param source the component that generated this event + * @param id the event id + * @param when the timestamp when the even occurred + * @param modifiers the modifier keys during the event, in old or new style + * @param keyCode the integer constant for the virtual key type + * @param keyChar the Unicode value of the key + * @throws IllegalArgumentException if source is null, or if + * (id == KEY_TYPED && (keyCode != VK_UNDEFINED + * || keyChar == CHAR_UNDEFINED)) + */ + public KeyEvent(Component source, int id, long when, int modifiers, + int keyCode, char keyChar) + { + this(source, id, when, modifiers, keyCode, keyChar, KEY_LOCATION_UNKNOWN); + } + + /** + * Initializes a new instance of <code>KeyEvent</code> with the specified + * information. Note that an invalid id leads to unspecified results. + * + * @param source the component that generated this event + * @param id the event id + * @param when the timestamp when the even occurred + * @param modifiers the modifier keys during the event, in old or new style + * @param keyCode the integer constant for the virtual key type + * @throws IllegalArgumentException if source is null, or if + * id == KEY_TYPED but keyCode != VK_UNDEFINED + * + * @deprecated + */ + public KeyEvent(Component source, int id, long when, int modifiers, + int keyCode) + { + this(source, id, when, modifiers, keyCode, '\0', KEY_LOCATION_UNKNOWN); + } + + /** + * Returns the key code for the event key. This will be one of the + * <code>VK_*</code> constants defined in this class. If the event type is + * KEY_TYPED, the result will be VK_UNDEFINED. + * + * @return the key code for this event + */ + public int getKeyCode() + { + return keyCode; + } + + /** + * Sets the key code for this event. This must be one of the + * <code>VK_*</code> constants defined in this class. + * + * @param keyCode the new key code for this event + */ + public void setKeyCode(int keyCode) + { + this.keyCode = keyCode; + } + + /** + * Returns the Unicode value for the event key. This will be + * <code>CHAR_UNDEFINED</code> if there is no Unicode equivalent for + * this key, usually when this is a KEY_PRESSED or KEY_RELEASED event. + * + * @return the Unicode character for this event + */ + public char getKeyChar() + { + return keyChar; + } + + /** + * Sets the Unicode character for this event to the specified value. + * + * @param keyChar the new Unicode character for this event + */ + public void setKeyChar(char keyChar) + { + this.keyChar = keyChar; + } + + /** + * Sets the modifier keys to the specified value. This should be a union + * of the bit mask constants from <code>InputEvent</code>. The use of this + * method is not recommended, particularly for KEY_TYPED events, which do + * not check if the modifiers were changed. + * + * @param modifiers the new modifier value, in either old or new style + * @see InputEvent + * + * @deprecated + */ + public void setModifiers(int modifiers) + { + this.modifiers = EventModifier.extend(modifiers); + } + + /** + * Returns the keyboard location of the key that generated this event. This + * provides a way to distinguish between keys like left and right shift + * which share a common key code. The result will be one of + * {@link #KEY_LOCATION_UNKNOWN}, {@link #KEY_LOCATION_STANDARD}, + * {@link #KEY_LOCATION_LEFT}, {@link #KEY_LOCATION_RIGHT}, or + * {@link #KEY_LOCATION_NUMPAD}. + * + * @return the key location + * @since 1.4 + */ + public int getKeyLocation() + { + return keyLocation; + } + + /** + * Returns the text name of key code, such as "HOME", "F1", or "A". + * + * XXX Sun claims this can be localized via the awt.properties file - how + * do we implement that? + * + * @return the text name of the key code + */ + public static String getKeyText(int keyCode) + { + switch (keyCode) + { + case VK_CANCEL: + return "Cancel"; + case VK_BACK_SPACE: + return "Backspace"; + case VK_TAB: + return "Tab"; + case VK_ENTER: + return "Enter"; + case VK_CLEAR: + return "Clear"; + case VK_SHIFT: + return "Shift"; + case VK_CONTROL: + return "Ctrl"; + case VK_ALT: + return "Alt"; + case VK_PAUSE: + return "Pause"; + case VK_CAPS_LOCK: + return "Caps Lock"; + case VK_KANA: + return "Kana"; + case VK_FINAL: + return "Final"; + case VK_KANJI: + return "Kanji"; + case VK_ESCAPE: + return "Escape"; + case VK_CONVERT: + return "Convert"; + case VK_NONCONVERT: + return "No Convert"; + case VK_ACCEPT: + return "Accept"; + case VK_MODECHANGE: + return "Mode Change"; + case VK_SPACE: + return "Space"; + case VK_PAGE_UP: + return "Page Up"; + case VK_PAGE_DOWN: + return "Page Down"; + case VK_END: + return "End"; + case VK_HOME: + return "Home"; + case VK_LEFT: + case VK_KP_LEFT: + return "Left"; + case VK_UP: + case VK_KP_UP: + return "Up"; + case VK_RIGHT: + case VK_KP_RIGHT: + return "Right"; + case VK_DOWN: + case VK_KP_DOWN: + return "Down"; + case VK_MINUS: + return "Minus"; + case VK_MULTIPLY: + return "NumPad *"; + case VK_ADD: + return "NumPad +"; + case VK_SEPARATOR: + return "NumPad ,"; + case VK_SUBTRACT: + return "NumPad -"; + case VK_DECIMAL: + return "NumPad ."; + case VK_DIVIDE: + return "NumPad /"; + case VK_DELETE: + return "Delete"; + case VK_DEAD_GRAVE: + return "Dead Grave"; + case VK_DEAD_ACUTE: + return "Dead Acute"; + case VK_DEAD_CIRCUMFLEX: + return "Dead Circumflex"; + case VK_DEAD_TILDE: + return "Dead Tilde"; + case VK_DEAD_MACRON: + return "Dead Macron"; + case VK_DEAD_BREVE: + return "Dead Breve"; + case VK_DEAD_ABOVEDOT: + return "Dead Above Dot"; + case VK_DEAD_DIAERESIS: + return "Dead Diaeresis"; + case VK_DEAD_ABOVERING: + return "Dead Above Ring"; + case VK_DEAD_DOUBLEACUTE: + return "Dead Double Acute"; + case VK_DEAD_CARON: + return "Dead Caron"; + case VK_DEAD_CEDILLA: + return "Dead Cedilla"; + case VK_DEAD_OGONEK: + return "Dead Ogonek"; + case VK_DEAD_IOTA: + return "Dead Iota"; + case VK_DEAD_VOICED_SOUND: + return "Dead Voiced Sound"; + case VK_DEAD_SEMIVOICED_SOUND: + return "Dead Semivoiced Sound"; + case VK_NUM_LOCK: + return "Num Lock"; + case VK_SCROLL_LOCK: + return "Scroll Lock"; + case VK_AMPERSAND: + return "Ampersand"; + case VK_ASTERISK: + return "Asterisk"; + case VK_QUOTEDBL: + return "Double Quote"; + case VK_LESS: + return "Less"; + case VK_PRINTSCREEN: + return "Print Screen"; + case VK_INSERT: + return "Insert"; + case VK_HELP: + return "Help"; + case VK_META: + return "Meta"; + case VK_GREATER: + return "Greater"; + case VK_BRACELEFT: + return "Left Brace"; + case VK_BRACERIGHT: + return "Right Brace"; + case VK_BACK_QUOTE: + return "Back Quote"; + case VK_QUOTE: + return "Quote"; + case VK_ALPHANUMERIC: + return "Alphanumeric"; + case VK_KATAKANA: + return "Katakana"; + case VK_HIRAGANA: + return "Hiragana"; + case VK_FULL_WIDTH: + return "Full-Width"; + case VK_HALF_WIDTH: + return "Half-Width"; + case VK_ROMAN_CHARACTERS: + return "Roman Characters"; + case VK_ALL_CANDIDATES: + return "All Candidates"; + case VK_PREVIOUS_CANDIDATE: + return "Previous Candidate"; + case VK_CODE_INPUT: + return "Code Input"; + case VK_JAPANESE_KATAKANA: + return "Japanese Katakana"; + case VK_JAPANESE_HIRAGANA: + return "Japanese Hiragana"; + case VK_JAPANESE_ROMAN: + return "Japanese Roman"; + case VK_KANA_LOCK: + return "Kana Lock"; + case VK_INPUT_METHOD_ON_OFF: + return "Input Method On/Off"; + case VK_AT: + return "At"; + case VK_COLON: + return "Colon"; + case VK_CIRCUMFLEX: + return "Circumflex"; + case VK_DOLLAR: + return "Dollar"; + case VK_EURO_SIGN: + return "Euro"; + case VK_EXCLAMATION_MARK: + return "Exclamation Mark"; + case VK_INVERTED_EXCLAMATION_MARK: + return "Inverted Exclamation Mark"; + case VK_LEFT_PARENTHESIS: + return "Left Parenthesis"; + case VK_NUMBER_SIGN: + return "Number Sign"; + case VK_PLUS: + return "Plus"; + case VK_RIGHT_PARENTHESIS: + return "Right Parenthesis"; + case VK_UNDERSCORE: + return "Underscore"; + case VK_COMPOSE: + return "Compose"; + case VK_ALT_GRAPH: + return "Alt Graph"; + case VK_STOP: + return "Stop"; + case VK_AGAIN: + return "Again"; + case VK_PROPS: + return "Props"; + case VK_UNDO: + return "Undo"; + case VK_COPY: + return "Copy"; + case VK_PASTE: + return "Paste"; + case VK_FIND: + return "Find"; + case VK_CUT: + return "Cut"; + case VK_COMMA: + case VK_PERIOD: + case VK_SLASH: + case VK_0: + case VK_1: + case VK_2: + case VK_3: + case VK_4: + case VK_5: + case VK_6: + case VK_7: + case VK_8: + case VK_9: + case VK_SEMICOLON: + case VK_EQUALS: + case VK_A: + case VK_B: + case VK_C: + case VK_D: + case VK_E: + case VK_F: + case VK_G: + case VK_H: + case VK_I: + case VK_J: + case VK_K: + case VK_L: + case VK_M: + case VK_N: + case VK_O: + case VK_P: + case VK_Q: + case VK_R: + case VK_S: + case VK_T: + case VK_U: + case VK_V: + case VK_W: + case VK_X: + case VK_Y: + case VK_Z: + case VK_OPEN_BRACKET: + case VK_BACK_SLASH: + case VK_CLOSE_BRACKET: + return "" + (char) keyCode; + case VK_NUMPAD0: + case VK_NUMPAD1: + case VK_NUMPAD2: + case VK_NUMPAD3: + case VK_NUMPAD4: + case VK_NUMPAD5: + case VK_NUMPAD6: + case VK_NUMPAD7: + case VK_NUMPAD8: + case VK_NUMPAD9: + return "NumPad-" + (keyCode - VK_NUMPAD0); + case VK_F1: + case VK_F2: + case VK_F3: + case VK_F4: + case VK_F5: + case VK_F6: + case VK_F7: + case VK_F8: + case VK_F9: + case VK_F10: + case VK_F11: + case VK_F12: + return "F" + (keyCode - (VK_F1 - 1)); + case VK_F13: + case VK_F14: + case VK_F15: + case VK_F16: + case VK_F17: + case VK_F18: + case VK_F19: + case VK_F20: + case VK_F21: + case VK_F22: + case VK_F23: + case VK_F24: + return "F" + (keyCode - (VK_F13 - 13)); + default: + // This is funky on negative numbers, but that's Sun's fault. + return "Unknown keyCode: 0x" + (keyCode < 0 ? "-" : "") + + Integer.toHexString(Math.abs(keyCode)); + } + } + + /** + * Returns a string describing the modifiers, such as "Shift" or + * "Ctrl+Button1". + * + * XXX Sun claims this can be localized via the awt.properties file - how + * do we implement that? + * + * @param modifiers the old-style modifiers to convert to text + * @return a string representation of the modifiers in this bitmask + */ + public static String getKeyModifiersText(int modifiers) + { + return getModifiersExText(EventModifier.extend(modifiers + & EventModifier.OLD_MASK)); + } + + /** + * Tests whether or not this key is an action key. An action key typically + * does not fire a KEY_TYPED event, and is not a modifier. + * + * @return true if this is an action key + */ + public boolean isActionKey() + { + switch (keyCode) + { + case VK_PAUSE: + case VK_CAPS_LOCK: + case VK_KANA: + case VK_FINAL: + case VK_KANJI: + case VK_CONVERT: + case VK_NONCONVERT: + case VK_ACCEPT: + case VK_MODECHANGE: + case VK_PAGE_UP: + case VK_PAGE_DOWN: + case VK_END: + case VK_HOME: + case VK_LEFT: + case VK_UP: + case VK_RIGHT: + case VK_DOWN: + case VK_F1: + case VK_F2: + case VK_F3: + case VK_F4: + case VK_F5: + case VK_F6: + case VK_F7: + case VK_F8: + case VK_F9: + case VK_F10: + case VK_F11: + case VK_F12: + case VK_NUM_LOCK: + case VK_SCROLL_LOCK: + case VK_PRINTSCREEN: + case VK_INSERT: + case VK_HELP: + case VK_KP_UP: + case VK_KP_DOWN: + case VK_KP_LEFT: + case VK_KP_RIGHT: + case VK_ALPHANUMERIC: + case VK_KATAKANA: + case VK_HIRAGANA: + case VK_FULL_WIDTH: + case VK_HALF_WIDTH: + case VK_ROMAN_CHARACTERS: + case VK_ALL_CANDIDATES: + case VK_PREVIOUS_CANDIDATE: + case VK_CODE_INPUT: + case VK_JAPANESE_KATAKANA: + case VK_JAPANESE_HIRAGANA: + case VK_JAPANESE_ROMAN: + case VK_KANA_LOCK: + case VK_INPUT_METHOD_ON_OFF: + case VK_F13: + case VK_F14: + case VK_F15: + case VK_F16: + case VK_F17: + case VK_F18: + case VK_F19: + case VK_F20: + case VK_F21: + case VK_F22: + case VK_F23: + case VK_F24: + case VK_STOP: + case VK_AGAIN: + case VK_PROPS: + case VK_UNDO: + case VK_COPY: + case VK_PASTE: + case VK_FIND: + case VK_CUT: + return true; + default: + return false; + } + } + + /** + * Returns a string identifying the event. This is formatted as the + * field name of the id type, followed by the keyCode, then the + * keyChar, modifiers (if any), extModifiers (if any), and + * keyLocation. + * + * @return a string identifying the event + */ + public String paramString() + { + CPStringBuilder s = new CPStringBuilder(); + + switch (id) + { + case KEY_PRESSED: + s.append("KEY_PRESSED"); + break; + case KEY_RELEASED: + s.append("KEY_RELEASED"); + break; + case KEY_TYPED: + s.append("KEY_TYPED"); + break; + default: + s.append("unknown type"); + } + + s.append(",keyCode=").append(keyCode); + + s.append(",keyText=").append(getKeyText(keyCode)); + + s.append(",keyChar="); + if (isActionKey() + || keyCode == VK_SHIFT + || keyCode == VK_CONTROL + || keyCode == VK_ALT) + s.append("Undefined keyChar"); + else + { + /* This output string must be selected by examining keyChar + * rather than keyCode, because key code information is not + * included in KEY_TYPED events. + */ + if (keyChar == VK_BACK_SPACE + || keyChar == VK_TAB + || keyChar == VK_ENTER + || keyChar == VK_ESCAPE + || keyChar == VK_DELETE) + s.append(getKeyText(keyChar)); + else + s.append("'").append(keyChar).append("'"); + } + + if ((modifiers & CONVERT_MASK) != 0) + s.append(",modifiers=").append(getModifiersExText(modifiers + & CONVERT_MASK)); + if (modifiers != 0) + s.append(",extModifiers=").append(getModifiersExText(modifiers)); + + s.append(",keyLocation=KEY_LOCATION_"); + switch (keyLocation) + { + case KEY_LOCATION_UNKNOWN: + s.append("UNKNOWN"); + break; + case KEY_LOCATION_STANDARD: + s.append("STANDARD"); + break; + case KEY_LOCATION_LEFT: + s.append("LEFT"); + break; + case KEY_LOCATION_RIGHT: + s.append("RIGHT"); + break; + case KEY_LOCATION_NUMPAD: + s.append("NUMPAD"); + } + + return s.toString(); + } + + /** + * Reads in the object from a serial stream. + * + * @param s the stream to read from + * @throws IOException if deserialization fails + * @throws ClassNotFoundException if deserialization fails + * @serialData default, except that the modifiers are converted to new style + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + modifiersEx = EventModifier.extend(modifiers) & EventModifier.NEW_MASK; + } +} // class KeyEvent diff --git a/libjava/classpath/java/awt/event/KeyListener.java b/libjava/classpath/java/awt/event/KeyListener.java new file mode 100644 index 000000000..5c0a640f6 --- /dev/null +++ b/libjava/classpath/java/awt/event/KeyListener.java @@ -0,0 +1,77 @@ +/* KeyListener.java -- listen for keyboard presses + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that wish to receive keyboard events. To + * watch a subset of these events, use a KeyAdapter. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see KeyAdapter + * @see KeyEvent + * @since 1.1 + * @status updated to 1.4 + */ +public interface KeyListener extends EventListener +{ + /** + * This method is called when a key is typed. A key is considered typed + * when it and all modifiers have been pressed and released, mapping to + * a single virtual key. + * + * @param event the <code>KeyEvent</code> indicating that a key was typed + */ + void keyTyped(KeyEvent event); + + /** + * This method is called when a key is pressed. + * + * @param event the <code>KeyEvent</code> indicating the key press + */ + void keyPressed(KeyEvent event); + + /** + * This method is called when a key is released. + * + * @param event the <code>KeyEvent</code> indicating the key release + */ + void keyReleased(KeyEvent event); +} // interface KeyListener diff --git a/libjava/classpath/java/awt/event/MouseAdapter.java b/libjava/classpath/java/awt/event/MouseAdapter.java new file mode 100644 index 000000000..9f40c285a --- /dev/null +++ b/libjava/classpath/java/awt/event/MouseAdapter.java @@ -0,0 +1,106 @@ +/* MouseAdapter.java -- convenience class for writing mouse listeners + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +/** + * This class implements <code>MouseListener</code> and implements all methods + * with empty bodies. This allows a listener interested in implementing only + * a subset of the <code>MouseListener</code> interface to extend this class + * and override only the desired methods. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see MouseEvent + * @see MouseListener + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class MouseAdapter implements MouseListener +{ + /** + * Do nothing default constructor for subclasses. + */ + public MouseAdapter() + { + } + + /** + * Implements this method in the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void mouseClicked(MouseEvent event) + { + } + + /** + * Implements this method in the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void mousePressed(MouseEvent event) + { + } + + /** + * Implements this method in the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void mouseReleased(MouseEvent event) + { + } + + /** + * Implements this method in the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void mouseEntered(MouseEvent event) + { + } + + /** + * Implements this method in the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void mouseExited(MouseEvent event) + { + } +} // class MouseAdapter diff --git a/libjava/classpath/java/awt/event/MouseEvent.java b/libjava/classpath/java/awt/event/MouseEvent.java new file mode 100644 index 000000000..64142ecc6 --- /dev/null +++ b/libjava/classpath/java/awt/event/MouseEvent.java @@ -0,0 +1,502 @@ +/* MouseEvent.java -- a mouse event + Copyright (C) 1999, 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import gnu.java.awt.EventModifier; +import gnu.java.lang.CPStringBuilder; + +import java.awt.Component; +import java.awt.Point; +import java.awt.PopupMenu; +import java.io.IOException; +import java.io.ObjectInputStream; + +/** + * This event is generated for a mouse event. There are three main categories + * of mouse events: Regular events include pressing, releasing, and clicking + * buttons, as well as moving over the boundary of the unobscured portion of + * a component. Motion events include movement and dragging. Wheel events are + * covered separately by the subclass MouseWheelEvent. + * + * <p>A mouse event is tied to the unobstructed visible component that the + * mouse cursor was over at the time of the action. The button that was + * most recently pressed is the only one that shows up in + * <code>getModifiers</code>, and is returned by <code>getButton</code>, + * while all buttons that are down show up in <code>getModifiersEx</code>. + * + * <p>Drag events may be cut short if native drag-and-drop operations steal + * the event. Likewise, if a mouse drag exceeds the bounds of a window or + * virtual device, some platforms may clip the path to fit in the bounds of + * the component. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see MouseAdapter + * @see MouseListener + * @see MouseMotionAdapter + * @see MouseMotionListener + * @see MouseWheelListener + * @since 1.1 + * @status updated to 1.4 + */ +public class MouseEvent extends InputEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -991214153494842848L; + + /** This is the first id in the range of event ids used by this class. */ + public static final int MOUSE_FIRST = 500; + + /** This is the last id in the range of event ids used by this class. */ + public static final int MOUSE_LAST = 507; + + /** This event id indicates that the mouse was clicked. */ + public static final int MOUSE_CLICKED = 500; + + /** This event id indicates that the mouse was pressed. */ + public static final int MOUSE_PRESSED = 501; + + /** This event id indicates that the mouse was released. */ + public static final int MOUSE_RELEASED = 502; + + /** This event id indicates that the mouse was moved. */ + public static final int MOUSE_MOVED = 503; + + /** This event id indicates that the mouse entered a component. */ + public static final int MOUSE_ENTERED = 504; + + /** This event id indicates that the mouse exited a component. */ + public static final int MOUSE_EXITED = 505; + + /** + * This indicates that no button changed state. + * + * @see #getButton() + * @since 1.4 + */ + public static final int NOBUTTON = 0; + + /** + * This indicates that button 1 changed state. + * + * @see #getButton() + * @since 1.4 + */ + public static final int BUTTON1 = 1; + + /** + * This indicates that button 2 changed state. + * + * @see #getButton() + * @since 1.4 + */ + public static final int BUTTON2 = 2; + + /** + * This indicates that button 3 changed state. + * + * @see #getButton() + * @since 1.4 + */ + public static final int BUTTON3 = 3; + + /** This event id indicates that the mouse was dragged over a component. */ + public static final int MOUSE_DRAGGED = 506; + + /** + * This event id indicates that the mouse wheel was rotated. + * + * @since 1.4 + */ + public static final int MOUSE_WHEEL = 507; + + /** + * The X coordinate of the mouse cursor at the time of the event. + * + * @see #getX() + * @serial the x coordinate + */ + private int x; + + /** + * The Y coordinate of the mouse cursor at the time of the event. + * + * @see #getY() + * @serial the y coordinate + */ + private int y; + + /** + * The screen position of that mouse event, X coordinate. + */ + private int absX; + + /** + * The screen position of that mouse event, Y coordinate. + */ + private int absY; + + /** + * The number of clicks that took place. For MOUSE_CLICKED, MOUSE_PRESSED, + * and MOUSE_RELEASED, this will be at least 1; otherwise it is 0. + * + * see #getClickCount() + * @serial the number of clicks + */ + private final int clickCount; + + /** + * Indicates which mouse button changed state. Can only be one of + * {@link #NOBUTTON}, {@link #BUTTON1}, {@link #BUTTON2}, or + * {@link #BUTTON3}. + * + * @see #getButton() + * @since 1.4 + */ + private int button; + + /** + * Whether or not this event should trigger a popup menu. + * + * @see PopupMenu + * @see #isPopupTrigger() + * @serial true if this is a popup trigger + */ + private final boolean popupTrigger; + + /** + * Initializes a new instance of <code>MouseEvent</code> with the specified + * information. Note that an invalid id leads to unspecified results. + * + * @param source the source of the event + * @param id the event id + * @param when the timestamp of when the event occurred + * @param modifiers the modifier keys during the event, in old or new style + * @param x the X coordinate of the mouse point + * @param y the Y coordinate of the mouse point + * @param clickCount the number of mouse clicks for this event + * @param popupTrigger true if this event triggers a popup menu + * @param button the most recent mouse button to change state + * @throws IllegalArgumentException if source is null or button is invalid + * @since 1.4 + */ + public MouseEvent(Component source, int id, long when, int modifiers, + int x, int y, int clickCount, boolean popupTrigger, + int button) + { + this(source, id, when, modifiers, x, y, 0, 0, clickCount, popupTrigger, + button); + } + + /** + * Initializes a new instance of <code>MouseEvent</code> with the specified + * information. Note that an invalid id leads to unspecified results. + * + * @param source the source of the event + * @param id the event id + * @param when the timestamp of when the event occurred + * @param modifiers the modifier keys during the event, in old or new style + * @param x the X coordinate of the mouse point + * @param y the Y coordinate of the mouse point + * @param clickCount the number of mouse clicks for this event + * @param popupTrigger true if this event triggers a popup menu + * @throws IllegalArgumentException if source is null + */ + public MouseEvent(Component source, int id, long when, int modifiers, + int x, int y, int clickCount, boolean popupTrigger) + { + this(source, id, when, modifiers, x, y, clickCount, popupTrigger, + NOBUTTON); + } + + /** + * Creates a new MouseEvent. This is like the other constructors and adds + * specific absolute coordinates. + * + * @param source the source of the event + * @param id the event id + * @param when the timestamp of when the event occurred + * @param modifiers the modifier keys during the event, in old or new style + * @param x the X coordinate of the mouse point + * @param y the Y coordinate of the mouse point + * @param absX the absolute X screen coordinate of this event + * @param absY the absolute Y screen coordinate of this event + * @param clickCount the number of mouse clicks for this event + * @param popupTrigger true if this event triggers a popup menu + * @param button the most recent mouse button to change state + * + * @throws IllegalArgumentException if source is null or button is invalid + * + * @since 1.6 + */ + public MouseEvent(Component source, int id, long when, int modifiers, + int x, int y, int absX, int absY, int clickCount, + boolean popupTrigger, int button) + { + super(source, id, when, modifiers); + + this.x = x; + this.y = y; + this.clickCount = clickCount; + this.popupTrigger = popupTrigger; + this.button = button; + if (button < NOBUTTON || button > BUTTON3) + throw new IllegalArgumentException(); + if ((modifiers & EventModifier.OLD_MASK) != 0) + { + if ((modifiers & BUTTON1_MASK) != 0) + this.button = BUTTON1; + else if ((modifiers & BUTTON2_MASK) != 0) + this.button = BUTTON2; + else if ((modifiers & BUTTON3_MASK) != 0) + this.button = BUTTON3; + } + // clear the mouse button modifier masks if this is a button + // release event. + if (id == MOUSE_RELEASED) + this.modifiersEx &= ~(BUTTON1_DOWN_MASK + | BUTTON2_DOWN_MASK + | BUTTON3_DOWN_MASK); + + this.absX = absX; + this.absY = absY; + } + + /** + * This method returns the X coordinate of the mouse position. This is + * relative to the source component. + * + * @return the x coordinate + */ + public int getX() + { + return x; + } + + /** + * This method returns the Y coordinate of the mouse position. This is + * relative to the source component. + * + * @return the y coordinate + */ + public int getY() + { + return y; + } + + /** + * @since 1.6 + */ + public Point getLocationOnScreen() + { + return new Point(absX, absY); + } + + /** + * @since 1.6 + */ + public int getXOnScreen() + { + return absX; + } + + /** + * @since 1.6 + */ + public int getYOnScreen() + { + return absY; + } + + /** + * This method returns a <code>Point</code> for the x,y position of + * the mouse pointer. This is relative to the source component. + * + * @return a <code>Point</code> for the event position + */ + public Point getPoint() + { + return new Point(x, y); + } + + /** + * Translates the event coordinates by the specified x and y offsets. + * + * @param dx the value to add to the X coordinate of this event + * @param dy the value to add to the Y coordiante of this event + */ + public void translatePoint(int dx, int dy) + { + x += dx; + y += dy; + } + + /** + * This method returns the number of mouse clicks associated with this + * event. + * + * @return the number of mouse clicks for this event + */ + public int getClickCount() + { + return clickCount; + } + + /** + * Returns which button, if any, was the most recent to change state. This + * will be one of {@link #NOBUTTON}, {@link #BUTTON1}, {@link #BUTTON2}, or + * {@link #BUTTON3}. + * + * @return the button that changed state + * @since 1.4 + */ + public int getButton() + { + return button; + } + + /** + * This method tests whether or not the event is a popup menu trigger. This + * should be checked in both MousePressed and MouseReleased to be + * cross-platform compatible, as different systems have different popup + * triggers. + * + * @return true if the event is a popup menu trigger + */ + public boolean isPopupTrigger() + { + return popupTrigger; + } + + /** + * Returns a string describing the modifiers, such as "Shift" or + * "Ctrl+Button1". + * + * XXX Sun claims this can be localized via the awt.properties file - how + * do we implement that? + * + * @param modifiers the old-style modifiers to convert to text + * @return a string representation of the modifiers in this bitmask + */ + public static String getMouseModifiersText(int modifiers) + { + modifiers &= EventModifier.OLD_MASK; + if ((modifiers & BUTTON2_MASK) != 0) + modifiers |= BUTTON2_DOWN_MASK; + if ((modifiers & BUTTON3_MASK) != 0) + modifiers |= BUTTON3_DOWN_MASK; + return getModifiersExText(EventModifier.extend(modifiers)); + } + + /** + * Returns a string identifying this event. This is formatted as the field + * name of the id type, followed by the (x,y) point, the most recent button + * changed, modifiers (if any), extModifiers (if any), and clickCount. + * + * @return a string identifying this event + */ + public String paramString() + { + CPStringBuilder s = new CPStringBuilder(); + switch (id) + { + case MOUSE_CLICKED: + s.append("MOUSE_CLICKED,("); + break; + case MOUSE_PRESSED: + s.append("MOUSE_PRESSED,("); + break; + case MOUSE_RELEASED: + s.append("MOUSE_RELEASED,("); + break; + case MOUSE_MOVED: + s.append("MOUSE_MOVED,("); + break; + case MOUSE_ENTERED: + s.append("MOUSE_ENTERED,("); + break; + case MOUSE_EXITED: + s.append("MOUSE_EXITED,("); + break; + case MOUSE_DRAGGED: + s.append("MOUSE_DRAGGED,("); + break; + case MOUSE_WHEEL: + s.append("MOUSE_WHEEL,("); + break; + default: + s.append("unknown type,("); + } + s.append(x).append(',').append(y).append("),button=").append(button); + // FIXME: need a mauve test for this method + if (modifiersEx != 0) + s.append(",extModifiers=").append(getModifiersExText(modifiersEx)); + + s.append(",clickCount=").append(clickCount); + s.append(",consumed=").append(consumed); + + return s.toString(); + } + + /** + * Reads in the object from a serial stream. + * + * @param s the stream to read from + * @throws IOException if deserialization fails + * @throws ClassNotFoundException if deserialization fails + * @serialData default, except that the modifiers are converted to new style + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + if ((modifiers & EventModifier.OLD_MASK) != 0) + { + if ((modifiers & BUTTON1_MASK) != 0) + button = BUTTON1; + else if ((modifiers & BUTTON2_MASK) != 0) + button = BUTTON2; + else if ((modifiers & BUTTON3_MASK) != 0) + button = BUTTON3; + modifiersEx = EventModifier.extend(modifiers) & EventModifier.NEW_MASK; + } + } +} // class MouseEvent diff --git a/libjava/classpath/java/awt/event/MouseListener.java b/libjava/classpath/java/awt/event/MouseListener.java new file mode 100644 index 000000000..735ca6b5a --- /dev/null +++ b/libjava/classpath/java/awt/event/MouseListener.java @@ -0,0 +1,94 @@ +/* MouseListener.java -- listen for mouse clicks and crossing component edges + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that wish to receive mouse events other than + * simple motion events. This includes clicks (but not mouse wheel events), + * and crossing component boundaries without change in button status. To + * track moves and drags, use MouseMotionListener, and to track wheel events, + * use MouseWheelListener. To watch a subset of these events, use a + * MouseAdapter. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see MouseAdapter + * @see MouseEvent + * @since 1.1 + * @status updated to 1.4 + */ +public interface MouseListener extends EventListener +{ + /** + * This method is called when the mouse is clicked (pressed and released + * in short succession) on a component. + * + * @param event the <code>MouseEvent</code> indicating the click + */ + void mouseClicked(MouseEvent event); + + /** + * This method is called when the mouse is pressed over a component. + * + * @param event the <code>MouseEvent</code> for the press + */ + void mousePressed(MouseEvent event); + + /** + * This method is called when the mouse is released over a component. + * + * @param event the <code>MouseEvent</code> for the release + */ + void mouseReleased(MouseEvent event); + + /** + * This method is called when the mouse enters a component. + * + * @param event the <code>MouseEvent</code> for the entry + */ + void mouseEntered(MouseEvent event); + + /** + * This method is called when the mouse exits a component. + * + * @param event the <code>MouseEvent</code> for the exit + */ + void mouseExited(MouseEvent event); +} // interface MouseListener diff --git a/libjava/classpath/java/awt/event/MouseMotionAdapter.java b/libjava/classpath/java/awt/event/MouseMotionAdapter.java new file mode 100644 index 000000000..8a295f66c --- /dev/null +++ b/libjava/classpath/java/awt/event/MouseMotionAdapter.java @@ -0,0 +1,79 @@ +/* MouseMotionAdapter.java -- convenience class for mouse motion listeners + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +/** + * This class implements <code>MouseMotionListener</code> and implements all + * methods with empty bodies. This allows a listener interested in + * implementing only a subset of the <code>MouseMotionListener</code> + * interface to extend this class and override only the desired methods. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see MouseEvent + * @see MouseMotionListener + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class MouseMotionAdapter implements MouseMotionListener +{ + /** + * Do nothing default constructor for subclasses. + */ + public MouseMotionAdapter() + { + } + + /** + * Implement this method in the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void mouseDragged(MouseEvent event) + { + } + + /** + * Implement this method in the interface with an empty body. + * + * @param event the event, ignored in this implementation + */ + public void mouseMoved(MouseEvent event) + { + } +} // class MouseMotionAdapter diff --git a/libjava/classpath/java/awt/event/MouseMotionListener.java b/libjava/classpath/java/awt/event/MouseMotionListener.java new file mode 100644 index 000000000..ba2c5698b --- /dev/null +++ b/libjava/classpath/java/awt/event/MouseMotionListener.java @@ -0,0 +1,72 @@ +/* MouseMotionListener.java -- listen to mouse motion events + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that wish to be notified of mouse movements. + * This includes moves and drags, but not crossing component boundaries. To + * track other mouse events, use MouseListener or MouseWheelListener. To + * watch a subset of these events, use a MouseMotionAdapter. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see MouseMotionAdapter + * @see MouseEvent + * @since 1.1 + * @status updated to 1.4 + */ +public interface MouseMotionListener extends EventListener +{ + /** + * This method is called when the mouse is moved over a component + * while a button has been pressed. + * + * @param event the <code>MouseEvent</code> indicating the motion + */ + void mouseDragged(MouseEvent event); + + /** + * This method is called when the mouse is moved over a component + * while no button is pressed. + * + * @param event the <code>MouseEvent</code> indicating the motion + */ + void mouseMoved(MouseEvent event); +} // interface MouseMotionListener diff --git a/libjava/classpath/java/awt/event/MouseWheelEvent.java b/libjava/classpath/java/awt/event/MouseWheelEvent.java new file mode 100644 index 000000000..1ca946582 --- /dev/null +++ b/libjava/classpath/java/awt/event/MouseWheelEvent.java @@ -0,0 +1,232 @@ +/* MouseWheelEvent.java -- a mouse wheel event + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.awt.Adjustable; +import java.awt.Component; +import java.awt.Rectangle; +import java.awt.ScrollPane; + +import javax.swing.JScrollPane; +import javax.swing.Scrollable; + +/** + * This event is generated for a mouse wheel rotation. The wheel (the middle + * mouse button on most modern mice) can be rotated towards or away from the + * user, and is often used for scrolling. + * + * <p>Because of the special use for scrolling components, MouseWheelEvents + * often affect a different component than the one located at the point of + * the event. If the component under the mouse cursor does not accept wheel + * events, the event is passed to the first ancestor container which does. This + * is often a ScrollPane, which knows how to scroll. If an AWT component is + * built from a native widget that knows how to use mouse wheel events, that + * component will consume the event. + * + * <p>The two most common scroll types are "units" (lines at a time) or + * "blocks" (pages at a time). The initial setting is taken from the platform, + * although the user can adjust the setting at any time. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see MouseWheelListener + * @see ScrollPane + * @see ScrollPane#setWheelScrollingEnabled(boolean) + * @see JScrollPane + * @see JScrollPane#setWheelScrollingEnabled(boolean) + * @since 1.4 + * @status updated to 1.4 + */ +public class MouseWheelEvent extends MouseEvent +{ + /** + * Compatible with JDK 1.4+. + */ + private static final long serialVersionUID = 6459879390515399677L; + + /** + * Indicates scrolling by units (lines). + * + * @see #getScrollType() + */ + public static final int WHEEL_UNIT_SCROLL = 0; + + /** + * Indicates scrolling by blocks (pages). + * + * @see #getScrollType() + */ + public static final int WHEEL_BLOCK_SCROLL = 1; + + /** + * Indicates what scroll type should take place. This should be limited + * to {@link #WHEEL_UNIT_SCROLL} and {@link #WHEEL_BLOCK_SCROLL}. + * + * @serial the scroll type + */ + private final int scrollType; + + /** + * Indicates the scroll amount. This is only meaningful if scrollType is + * WHEEL_UNIT_SCROLL. + * + * @serial the number of lines to scroll + */ + private final int scrollAmount; + + /** + * Indicates how far the mouse wheel was rotated. + * + * @serial the rotation amount + */ + private final int wheelRotation; + + /** + * Initializes a new instance of <code>MouseWheelEvent</code> with the + * specified information. Note that an invalid id leads to unspecified + * results. + * + * @param source the source of the event + * @param id the event id + * @param when the timestamp of when the event occurred + * @param modifiers any modifier bits for this event + * @param x the X coordinate of the mouse point + * @param y the Y coordinate of the mouse point + * @param clickCount the number of mouse clicks for this event + * @param popupTrigger true if this event triggers a popup menu + * @param scrollType one of {@link #WHEEL_UNIT_SCROLL}, + * {@link #WHEEL_BLOCK_SCROLL} + * @param scrollAmount the number of units to scroll, ignored for block type + * @param wheelRotation the number of rotation "clicks" + * @throws IllegalArgumentException if source is null + * @see MouseEvent#MouseEvent(Component, int, long, int, int, int, int, + * boolean) + */ + public MouseWheelEvent(Component source, int id, long when, int modifiers, + int x, int y, int clickCount, boolean popupTrigger, + int scrollType, int scrollAmount, int wheelRotation) + { + super(source, id, when, modifiers, x, y, clickCount, popupTrigger); + this.scrollType = scrollType; + this.scrollAmount = scrollAmount; + this.wheelRotation = wheelRotation; + } + + /** + * This method returns the scrolling pattern this event requests. Legal + * values are {@link #WHEEL_UNIT_SCROLL} and {@link #WHEEL_BLOCK_SCROLL}. + * + * @return the scroll type + * @see Adjustable#getUnitIncrement() + * @see Adjustable#getBlockIncrement() + * @see Scrollable#getScrollableUnitIncrement(Rectangle, int, int) + * @see Scrollable#getScrollableBlockIncrement(Rectangle, int, int) + */ + public int getScrollType() + { + return scrollType; + } + + /** + * Returns the number of units to scroll in response to this event. This + * only makes sense when the scroll type is WHEEL_UNIT_SCROLL. + * + * @return the number of scroll units, if defined + * @see #getScrollType() + */ + public int getScrollAmount() + { + return scrollAmount; + } + + /** + * Gets the number of "clicks" the wheel was rotated. Negative values move + * up (away) from the user, positive values move down (towards) the user. + * + * @return the number of rotation clicks + */ + public int getWheelRotation() + { + return wheelRotation; + } + + /** + * This is a convenience method which aids in a common listener for scrolling + * a scrollpane (although this is already built into ScrollPane and + * JScrollPane). This method only makes sense when getScrollType() returns + * WHEEL_UNIT_SCROLL. + * + * <p>This accounts for direction of scroll and amount of wheel movement, as + * interpreted by the platform settings. + * + * @return the number of units to scroll + * @see #getScrollType() + * @see #getScrollAmount() + * @see MouseWheelListener + * @see Adjustable + * @see Adjustable#getUnitIncrement() + * @see Scrollable + * @see Scrollable#getScrollableUnitIncrement(Rectangle, int, int) + * @see ScrollPane + * @see ScrollPane#setWheelScrollingEnabled(boolean) + * @see JScrollPane + * @see JScrollPane#setWheelScrollingEnabled(boolean) + */ + public int getUnitsToScroll() + { + return wheelRotation * scrollAmount; + } + + /** + * Returns a string identifying this event. For mouse wheel events, this + * is <code>super.paramString() + ",scrollType=WHEEL_" + + * (getScrollType() == WHEEL_UNIT_SCROLL ? "UNIT" : "BLOCK") + * + "_SCROLL,scrollAmount=" + getScrollAmount() + ",wheelRotation=" + * + getWheelRotation()</code>. + * + * @return a string identifying this event + */ + public String paramString() + { + return super.paramString() + ",scrollType=" + + (scrollType == WHEEL_UNIT_SCROLL ? "WHEEL_UNIT_SCROLL" + : scrollType == WHEEL_BLOCK_SCROLL ? "WHEEL_BLOCK_SCROLL" + : "unknown scroll type") + + ",scrollAmount=" + scrollAmount + ",wheelRotation=" + wheelRotation; + } +} // class MouseWheelEvent diff --git a/libjava/classpath/java/awt/event/MouseWheelListener.java b/libjava/classpath/java/awt/event/MouseWheelListener.java new file mode 100644 index 000000000..1125582e1 --- /dev/null +++ b/libjava/classpath/java/awt/event/MouseWheelListener.java @@ -0,0 +1,60 @@ +/* MouseWheelListener.java -- listen for mouse wheel events + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that wish to receive mouse wheel events. For + * other events, use MouseListener or MouseMotionListener. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see MouseWheelEvent + * @since 1.4 + * @status updated to 1.4 + */ +public interface MouseWheelListener extends EventListener +{ + /** + * This method is called when the mouse wheel is rotated. + * + * @param event the <code>MouseWheelEvent</code> indicating the rotation + */ + void mouseWheelMoved(MouseWheelEvent event); +} // interface MouseWheelListener diff --git a/libjava/classpath/java/awt/event/PaintEvent.java b/libjava/classpath/java/awt/event/PaintEvent.java new file mode 100644 index 000000000..bb89c3722 --- /dev/null +++ b/libjava/classpath/java/awt/event/PaintEvent.java @@ -0,0 +1,127 @@ +/* PaintEvent.java -- an area of the screen needs to be repainted + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.awt.Component; +import java.awt.Rectangle; + +/** + * This event is generated when an area of the screen needs to be painted. + * This event is not meant for users, but exists to allow proper serialization + * behavior in the EventQueue with user-accessible events. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @since 1.1 + * @status updated to 1.4 + */ +public class PaintEvent extends ComponentEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 1267492026433337593L; + + /** This is the first id in the range of event ids used by this class. */ + public static final int PAINT_FIRST = 800; + + /** This is the last id in the range of event ids used by this class. */ + public static final int PAINT_LAST = 801; + + /** This id is for paint event types. */ + public static final int PAINT = 800; + + /** This id is for update event types. */ + public static final int UPDATE = 801; + + /** + * This is the rectange to be painted or updated. + * + * @see #getUpdateRect() + * @see #setUpdateRect(Rectangle) + * @serial the non-null rectangle to be painted + */ + private Rectangle updateRect; + + /** + * Initializes a new instance of <code>PaintEvent</code> with the specified + * source, id, and update region. Note that an invalid id leads to + * unspecified results. + * + * @param source the event source + * @param id the event id + * @param updateRect the rectangle to repaint + * @throws IllegalArgumentException if source is null + */ + public PaintEvent(Component source, int id, Rectangle updateRect) + { + super(source, id); + this.updateRect = updateRect; + } + + /** + * Returns the rectange to be updated for this event. + * + * @return the rectangle to update + */ + public Rectangle getUpdateRect() + { + return updateRect; + } + + /** + * Sets the rectangle to be updated for this event. + * + * @param updateRect the new update rectangle for this event + */ + public void setUpdateRect(Rectangle updateRect) + { + this.updateRect = updateRect; + } + + /** + * Returns a string identifying this event. + * + * @return a string identifying this event + */ + public String paramString() + { + return (id == PAINT ? "PAINT,updateRect=" : id == UPDATE + ? "UPDATE,updateRect=" : "unknown type,updateRect=") + updateRect; + } +} // class PaintEvent diff --git a/libjava/classpath/java/awt/event/TextEvent.java b/libjava/classpath/java/awt/event/TextEvent.java new file mode 100644 index 000000000..0288abbb7 --- /dev/null +++ b/libjava/classpath/java/awt/event/TextEvent.java @@ -0,0 +1,93 @@ +/* TextEvent.java -- event for text changes + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.awt.AWTEvent; +import java.awt.TextComponent; + +/** + * This event is generated when a text box changes contents. This is an + * abstraction that distills a large number of individual mouse or keyboard + * events into a simpler "text changed" event. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see TextComponent + * @see TextListener + * @since 1.1 + * @status updated to 1.4 + */ +public class TextEvent extends AWTEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 6269902291250941179L; + + /** This is the first id in the range of event ids used by this class. */ + public static final int TEXT_FIRST = 900; + + /** This is the last id in the range of event ids used by this class. */ + public static final int TEXT_LAST = 900; + + /** This event id indicates that the text of an object has changed. */ + public static final int TEXT_VALUE_CHANGED = 900; + + /** + * Initializes a new instance of <code>TextEvent</code> with the specified + * source and id. Note that an invalid id leads to unspecified results. + * + * @param source the (TextComponent) object that generated this event + * @param id the event id + * @throws IllegalArgumentException if source is null + */ + public TextEvent(Object source, int id) + { + super(source, id); + } + + /** + * Returns a string identifying this event. This is "TEXT_VALUE_CHANGED". + * + * @return a string identifying this event + */ + public String paramString() + { + return id == TEXT_VALUE_CHANGED ? "TEXT_VALUE_CHANGED" : "unknown type"; + } +} // class TextEvent diff --git a/libjava/classpath/java/awt/event/TextListener.java b/libjava/classpath/java/awt/event/TextListener.java new file mode 100644 index 000000000..bcdd7fa7a --- /dev/null +++ b/libjava/classpath/java/awt/event/TextListener.java @@ -0,0 +1,60 @@ +/* TextListener.java -- listen for text changes + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that wish to be notified when text changes + * in a component. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see TextEvent + * @since 1.1 + * @status updated to 1.4 + */ +public interface TextListener extends EventListener +{ + /** + * This method is called when the text being monitored changes. + * + * @param event the <code>TextEvent</code> indicating the change + */ + void textValueChanged(TextEvent event); +} // interface TextListener diff --git a/libjava/classpath/java/awt/event/WindowAdapter.java b/libjava/classpath/java/awt/event/WindowAdapter.java new file mode 100644 index 000000000..708de588c --- /dev/null +++ b/libjava/classpath/java/awt/event/WindowAdapter.java @@ -0,0 +1,156 @@ +/* WindowAdapter.java -- convenience class for writing window listeners + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +/** + * This class implements <code>WindowListener</code>, + * <code>WindowStateListener</code>, and <code>WindowFocusListener</code>, and + * implements all methods with empty bodies. This allows a listener + * interested in listening to only a subset of any <code>WindowEvent</code> + * actions to extend this class and override only the desired methods. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see ComponentEvent + * @see ComponentListener + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class WindowAdapter + implements WindowListener, WindowStateListener, WindowFocusListener +{ + /** + * Do nothing default constructor for subclasses. + */ + public WindowAdapter() + { + } + + /** + * Implements this method from the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void windowOpened(WindowEvent event) + { + } + + /** + * Implements this method from the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void windowClosing(WindowEvent event) + { + } + + /** + * Implements this method from the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void windowClosed(WindowEvent event) + { + } + + /** + * Implements this method from the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void windowIconified(WindowEvent event) + { + } + + /** + * Implements this method from the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void windowDeiconified(WindowEvent event) + { + } + + /** + * Implements this method from the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void windowActivated(WindowEvent event) + { + } + + /** + * Implements this method from the interface with an empty method body. + * + * @param event the event, ignored in this implementation + */ + public void windowDeactivated(WindowEvent event) + { + } + + /** + * Implements this method from the interface with an empty method body. + * + * @param event the event, ignored in this implementation + * @since 1.4 + */ + public void windowStateChanged(WindowEvent event) + { + } + + /** + * Implements this method from the interface with an empty method body. + * + * @param event the event, ignored in this implementation + * @since 1.4 + */ + public void windowGainedFocus(WindowEvent event) + { + } + + /** + * Implements this method from the interface with an empty method body. + * + * @param event the event, ignored in this implementation + * @since 1.4 + */ + public void windowLostFocus(WindowEvent event) + { + } +} // class WindowAdapter diff --git a/libjava/classpath/java/awt/event/WindowEvent.java b/libjava/classpath/java/awt/event/WindowEvent.java new file mode 100644 index 000000000..b52fefcdc --- /dev/null +++ b/libjava/classpath/java/awt/event/WindowEvent.java @@ -0,0 +1,314 @@ +/* WindowEvent.java -- window change event + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import gnu.java.lang.CPStringBuilder; + +import java.awt.Frame; +import java.awt.Window; + +/** + * This event is generated when there is a change in a window. This includes + * creation, closing, iconification, activation, and focus changes. There + * are three listeners, for three types of events: WindowListeners deal with + * the lifecycle of a window, WindowStateListeners deal with window state + * like maximization, and WindowFocusListeners deal with focus switching to + * or from a window. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see WindowAdapter + * @see WindowListener + * @see WindowFocusListener + * @see WindowStateListener + * @since 1.1 + * @status updated to 1.4 + */ +public class WindowEvent extends ComponentEvent +{ + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = -1567959133147912127L; + + /** This is the first id in the range of event ids used by this class. */ + public static final int WINDOW_FIRST = 200; + + /** This is the id for a window that is opened. */ + public static final int WINDOW_OPENED = 200; + + /** This is the id for a window that is about to close. */ + public static final int WINDOW_CLOSING = 201; + + /** This is the id for a window that finished closing. */ + public static final int WINDOW_CLOSED = 202; + + /** This is the id for a window that is iconified. */ + public static final int WINDOW_ICONIFIED = 203; + + /** This is the id for a window that is de-iconified. */ + public static final int WINDOW_DEICONIFIED = 204; + + /** This is the id for a window that is activated. */ + public static final int WINDOW_ACTIVATED = 205; + + /** This is the id for a window that is de-activated. */ + public static final int WINDOW_DEACTIVATED = 206; + + /** + * This is the id for a window becoming the focused window. + * + * @since 1.4 + */ + public static final int WINDOW_GAINED_FOCUS = 207; + + /** + * This is the id for a window losing all focus. + * + * @since 1.4 + */ + public static final int WINDOW_LOST_FOCUS = 208; + + /** + * This is the id for a window state change, such as maximization. + * + * @since 1.4 + */ + public static final int WINDOW_STATE_CHANGED = 209; + + /** This is the last id in the range of event ids used by this class. */ + public static final int WINDOW_LAST = 209; + + /** + * The other Window involved in a focus or activation change. For + * WINDOW_ACTIVATED and WINDOW_GAINED_FOCUS events, this is the window that + * lost focus; for WINDOW_DEACTIVATED and WINDOW_LOST_FOCUS, this is the + * window that stole focus; and for other events (or when native + * implementation does not have the data available), this is null. + * + * @see #getOppositeWindow() + * @serial the opposite window, or null + * @since 1.4 + */ + private final Window opposite; + + /** + * The former state of the window. + * + * @serial bitmask of the old window state + * @since 1.4 + */ + private final int oldState; + + /** + * The present state of the window. + * + * @serial bitmask of the new window state + * @since 1.4 + */ + private final int newState; + + /** + * Initializes a new instance of <code>WindowEvent</code> with the specified + * parameters. Note that an invalid id leads to unspecified results. + * + * @param source the window that generated this event + * @param id the event id + * @param opposite the window that received the opposite event, or null + * @param oldState the previous state of this window + * @param newState the new state of this window + * @throws IllegalArgumentException if source is null + * @since 1.4 + */ + public WindowEvent(Window source, int id, Window opposite, + int oldState, int newState) + { + super(source, id); + this.opposite = opposite; + this.oldState = oldState; + this.newState = newState; + } + + /** + * Initializes a new instance of <code>WindowEvent</code> with the specified + * parameters. Note that an invalid id leads to unspecified results. + * + * @param source the window that generated this event + * @param id the event id + * @param opposite the window that received the opposite event, or null + * @throws IllegalArgumentException if source is null + * @since 1.4 + */ + public WindowEvent(Window source, int id, Window opposite) + { + this(source, id, opposite, 0, 0); + } + + /** + * Initializes a new instance of <code>WindowEvent</code> with the specified + * parameters. Note that an invalid id leads to unspecified results. + * + * @param source the window that generated this event + * @param id the event id + * @param oldState the previous state of this window + * @param newState the new state of this window + * @throws IllegalArgumentException if source is null + * @since 1.4 + */ + public WindowEvent(Window source, int id, int oldState, int newState) + { + this(source, id, null, oldState, newState); + } + + /** + * Initializes a new instance of <code>WindowEvent</code> with the specified + * parameters. Note that an invalid id leads to unspecified results. + * + * @param source the window that generated this event + * @param id the event id + * @throws IllegalArgumentException if source is null + */ + public WindowEvent(Window source, int id) + { + this(source, id, null, 0, 0); + } + + /** + * Returns the event source as a <code>Window</code>. If the source has + * subsequently been modified to a non-Window, this returns null. + * + * @return the event source as a <code>Window</code> + */ + public Window getWindow() + { + return source instanceof Window ? (Window) source : null; + } + + /** + * Returns the opposite window if this window was involved in an activation + * or focus change. For WINDOW_ACTIVATED and WINDOW_GAINED_FOCUS events, + * this is the window that lost focus; for WINDOW_DEACTIVATED and + * WINDOW_LOST_FOCUS, this is the window that stole focus; and for other + * events (or when native implementation does not have the data available), + * this is null. + * + * @return the opposite window, or null + * @since 1.4 + */ + public Window getOppositeWindow() + { + return opposite; + } + + /** + * Returns the state of this window before the event. This is the bitwise + * or of fields in Frame: NORMAL, ICONIFIED, MAXIMIZED_HORIZ, MAXIMIZED_VERT, + * and MAXIMIZED_BOTH. + * + * @return the former state + * @see Frame#getExtendedState() + * @since 1.4 + */ + public int getOldState() + { + return oldState; + } + + /** + * Returns the state of this window after the event. This is the bitwise + * or of fields in Frame: NORMAL, ICONIFIED, MAXIMIZED_HORIZ, MAXIMIZED_VERT, + * and MAXIMIZED_BOTH. + * + * @return the updated state + * @see Frame#getExtendedState() + * @since 1.4 + */ + public int getNewState() + { + return newState; + } + + /** + * Returns a string that identifies this event. This is formatted as the + * field name of the id, followed by the opposite window, old state, and + * new state. + * + * @return a string that identifies this event + */ + public String paramString() + { + CPStringBuilder s = new CPStringBuilder(); + switch (id) + { + case WINDOW_OPENED: + s.append("WINDOW_OPENED,opposite="); + break; + case WINDOW_CLOSING: + s.append("WINDOW_CLOSING,opposite="); + break; + case WINDOW_CLOSED: + s.append("WINDOW_CLOSED,opposite="); + break; + case WINDOW_ICONIFIED: + s.append("WINDOW_ICONIFIED,opposite="); + break; + case WINDOW_DEICONIFIED: + s.append("WINDOW_DEICONIFIED,opposite="); + break; + case WINDOW_ACTIVATED: + s.append("WINDOW_ACTIVATED,opposite="); + break; + case WINDOW_DEACTIVATED: + s.append("WINDOW_DEACTIVATED,opposite="); + break; + case WINDOW_GAINED_FOCUS: + s.append("WINDOW_GAINED_FOCUS,opposite="); + break; + case WINDOW_LOST_FOCUS: + s.append("WINDOW_LOST_FOCUS,opposite="); + break; + case WINDOW_STATE_CHANGED: + s.append("WINDOW_STATE_CHANGED,opposite="); + break; + default: + s.append("unknown type,opposite="); + } + return s.append(opposite).append(",oldState=").append(oldState) + .append(",newState=").append(newState).toString(); + } +} // class WindowEvent diff --git a/libjava/classpath/java/awt/event/WindowFocusListener.java b/libjava/classpath/java/awt/event/WindowFocusListener.java new file mode 100644 index 000000000..738425353 --- /dev/null +++ b/libjava/classpath/java/awt/event/WindowFocusListener.java @@ -0,0 +1,68 @@ +/* WindowFocusListener.java -- listens for window focus events + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that wish to monitor events for window + * focus changes. To watch a subset of these events, use a WindowAdapter. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see WindowAdapter + * @see WindowEvent + * @since 1.4 + * @status updated to 1.4 + */ +public interface WindowFocusListener extends EventListener +{ + /** + * This method is called when a window gains focus. + * + * @param event the <code>WindowEvent</code> indicating the focus change + */ + void windowGainedFocus(WindowEvent event); + + /** + * This method is called when a window loses focus. + * + * @param event the <code>WindowEvent</code> indicating the focus change + */ + void windowLostFocus(WindowEvent event); +} // interface WindowFocusListener diff --git a/libjava/classpath/java/awt/event/WindowListener.java b/libjava/classpath/java/awt/event/WindowListener.java new file mode 100644 index 000000000..52213eb3d --- /dev/null +++ b/libjava/classpath/java/awt/event/WindowListener.java @@ -0,0 +1,109 @@ +/* WindowListener.java -- listens for window events + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.awt.Frame; +import java.awt.Image; +import java.util.EventListener; + +/** + * This interface is for classes that wish to monitor events for window + * changes. To watch a subset of these events, use a WindowAdapter. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @see WindowAdapter + * @see WindowEvent + * @since 1.1 + * @status updated to 1.4 + */ +public interface WindowListener extends EventListener +{ + /** + * This method is called when the window is made visible. + * + * @param event the <code>WindowEvent</code> indicating the change + */ + void windowOpened(WindowEvent event); + + /** + * This method is called when the user calls the system menu close + * function, giving the program a chance to cancel the close. + * + * @param event the <code>WindowEvent</code> indicating the close attempt + */ + void windowClosing(WindowEvent event); + + /** + * This method is called when the window is closed. + * + * @param event the <code>WindowEvent</code> indicating the dispose + */ + void windowClosed(WindowEvent event); + + /** + * This method is called when the window is iconified. + * + * @param event the <code>WindowEvent</code> indicating the iconification + * @see Frame#setIconImage(Image) + */ + void windowIconified(WindowEvent event); + + /** + * This method is called when the window is deiconified. + * + * @param event the <code>WindowEvent</code> indicating the deiconification + */ + void windowDeiconified(WindowEvent event); + + /** + * This method is called when a window is activated. Only Frames and Dialogs + * can be active, and the active window always contains the component with + * focus. + * + * @param event the <code>WindowEvent</code> indicating the activation + */ + void windowActivated(WindowEvent event); + + /** + * This method is called when the window is deactivated. + * + * @param event the <code>WindowEvent</code> indicating the deactivation + */ + void windowDeactivated(WindowEvent event); +} // interface WindowListener diff --git a/libjava/classpath/java/awt/event/WindowStateListener.java b/libjava/classpath/java/awt/event/WindowStateListener.java new file mode 100644 index 000000000..9bc6174fd --- /dev/null +++ b/libjava/classpath/java/awt/event/WindowStateListener.java @@ -0,0 +1,62 @@ +/* WindowStateListener.java -- listens for window state changes + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.event; + +import java.util.EventListener; + +/** + * This interface is for classes that wish to monitor events for window + * state changes. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see WindowAdapter + * @see WindowEvent + * @since 1.4 + * @status updated to 1.4 + */ +public interface WindowStateListener extends EventListener +{ + /** + * This method is called when the window state is changed, because of + * iconification or maximization. + * + * @param event the <code>WindowEvent</code> indicating the change + */ + void windowStateChanged(WindowEvent event); +} // interface WindowStateListener diff --git a/libjava/classpath/java/awt/event/package.html b/libjava/classpath/java/awt/event/package.html new file mode 100644 index 000000000..77662a3fb --- /dev/null +++ b/libjava/classpath/java/awt/event/package.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in java.awt.event package. + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - java.awt.event</title></head> + +<body> +<p>Listeners and adapters for different kinds of AWT events.</p> + +</body> +</html> diff --git a/libjava/classpath/java/awt/font/FontRenderContext.java b/libjava/classpath/java/awt/font/FontRenderContext.java new file mode 100644 index 000000000..8d530ec5f --- /dev/null +++ b/libjava/classpath/java/awt/font/FontRenderContext.java @@ -0,0 +1,137 @@ +/* FontRenderContext.java + Copyright (C) 2002, 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.font; + +import java.awt.geom.AffineTransform; + +/** + * @author Michael Koch + */ +public class FontRenderContext +{ + private AffineTransform affineTransform; + private boolean isAntiAliased; + private boolean usesFractionalMetrics; + + /** + * Construct a new <code>FontRenderContext</code>. + */ + protected FontRenderContext() + { + // Do nothing here. + } + + /** + * Construct a new <code>FontRenderContext</code>. + */ + public FontRenderContext (AffineTransform tx, boolean isAntiAliased, + boolean usesFractionalMetrics) + { + if (tx != null + && !tx.isIdentity ()) + { + this.affineTransform = new AffineTransform (tx); + } + + this.isAntiAliased = isAntiAliased; + this.usesFractionalMetrics = usesFractionalMetrics; + } + + public boolean equals (Object obj) + { + if (! (obj instanceof FontRenderContext)) + return false; + + return equals ((FontRenderContext) obj); + } + + public boolean equals (FontRenderContext rhs) + { + if (rhs == null) + return false; + + if (affineTransform == null && rhs.affineTransform != null + || affineTransform != null && rhs.affineTransform == null) + return false; + + return ((affineTransform == rhs.affineTransform + || affineTransform.equals (rhs.getTransform ())) + && isAntiAliased == rhs.isAntiAliased () + && usesFractionalMetrics == rhs.usesFractionalMetrics ()); + } + + + /** + * Retrieves the affine transform for scaling typographical points + * to raster pixels. + * + * @return a clone of the transform object. + */ + public AffineTransform getTransform () + { + if (affineTransform == null) + return new AffineTransform (); + else + return new AffineTransform (affineTransform); + } + + + /** + * Returns the hash code of the font render context. + */ + public int hashCode () + { + int code = ( isAntiAliased ? 1 : 0 ) + ( usesFractionalMetrics ? 2 : 0 ); + + if( affineTransform != null && !affineTransform.isIdentity() ) + code ^= affineTransform.hashCode(); + + return code; + } + + public boolean isAntiAliased () + { + return isAntiAliased; + } + + public boolean usesFractionalMetrics () + { + return usesFractionalMetrics; + } +} diff --git a/libjava/classpath/java/awt/font/GlyphJustificationInfo.java b/libjava/classpath/java/awt/font/GlyphJustificationInfo.java new file mode 100644 index 000000000..cfa64f05e --- /dev/null +++ b/libjava/classpath/java/awt/font/GlyphJustificationInfo.java @@ -0,0 +1,77 @@ +/* GlyphJustificationInfo.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.font; + +/** + * @author Michael Koch + */ +public final class GlyphJustificationInfo +{ + public static final int PRIORITY_KASHIDA = 0; + public static final int PRIORITY_WHITESPACE = 1; + public static final int PRIORITY_INTERCHAR = 2; + public static final int PRIORITY_NONE = 3; + + public final float weight; + public final int growPriority; + public final boolean growAbsorb; + public final float growLeftLimit; + public final float growRightLimit; + public final int shrinkPriority; + public final boolean shrinkAbsorb; + public final float shrinkLeftLimit; + public final float shrinkRightLimit; + + public GlyphJustificationInfo (float weight, boolean growAbsorb, + int growPriority, float growLeftLimit, + float growRightLimit, boolean shrinkAbsorb, + int shrinkPriority, float shrinkLeftLimit, + float shrinkRightLimit) + { + this.weight = weight; + this.growAbsorb = growAbsorb; + this.growPriority = growPriority; + this.growLeftLimit = growLeftLimit; + this.growRightLimit = growRightLimit; + this.shrinkAbsorb = shrinkAbsorb; + this.shrinkPriority = shrinkPriority; + this.shrinkLeftLimit = shrinkLeftLimit; + this.shrinkRightLimit = shrinkRightLimit; + } +} diff --git a/libjava/classpath/java/awt/font/GlyphMetrics.java b/libjava/classpath/java/awt/font/GlyphMetrics.java new file mode 100644 index 000000000..b41b7f45b --- /dev/null +++ b/libjava/classpath/java/awt/font/GlyphMetrics.java @@ -0,0 +1,138 @@ +/* GlyphMetrics.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.font; + +import java.awt.geom.Rectangle2D; + +/** + * @author Michael Koch + */ +public final class GlyphMetrics +{ + public static final byte COMBINING = 2; + public static final byte COMPONENT = 3; + public static final byte LIGATURE = 1; + public static final byte STANDARD = 0; + public static final byte WHITESPACE = 4; + + private boolean horizontal; + private float advanceX; + private float advanceY; + private Rectangle2D bounds; + private byte glyphType; + + public GlyphMetrics (boolean horizontal, float advanceX, float advanceY, + Rectangle2D bounds, byte glyphType) + { + this.horizontal = horizontal; + this.advanceX = advanceX; + this.advanceY = advanceY; + this.bounds = bounds; + this.glyphType = glyphType; + } + + public GlyphMetrics (float advance, Rectangle2D bounds, byte glyphType) + { + this (true, advance, advance, bounds, glyphType); + } + + public float getAdvance () + { + return horizontal ? advanceX : advanceY; + } + + public float getAdvanceX () + { + return advanceX; + } + + public float getAdvanceY () + { + return advanceY; + } + + public Rectangle2D getBounds2D () + { + return bounds; + } + + public float getLSB() + { + if (horizontal) + return (float) bounds.getX(); + return (float) bounds.getY(); + } + + public float getRSB() + { + if (horizontal) + return (float) (advanceX - (bounds.getX() + bounds.getWidth())); + return (float) (advanceY - (bounds.getY() + bounds.getHeight())); + } + + public int getType () + { + return glyphType; + } + + public boolean isCombining () + { + return (glyphType == COMBINING); + } + + public boolean isComponent () + { + return (glyphType == COMPONENT); + } + + public boolean isLigature() + { + return (glyphType == LIGATURE); + } + + public boolean isStandard() + { + return (glyphType == STANDARD); + } + + public boolean isWhitespace() + { + return (glyphType == WHITESPACE); + } +} diff --git a/libjava/classpath/java/awt/font/GlyphVector.java b/libjava/classpath/java/awt/font/GlyphVector.java new file mode 100644 index 000000000..4a87f4c62 --- /dev/null +++ b/libjava/classpath/java/awt/font/GlyphVector.java @@ -0,0 +1,174 @@ +/* GlyphVector.java + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.font; + +import java.awt.Font; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * @author Lillian Angel (langel at redhat dot com) + * @author Michael Koch + */ +public abstract class GlyphVector implements Cloneable +{ + public static final int FLAG_COMPLEX_GLYPHS = 8; + public static final int FLAG_HAS_POSITION_ADJUSTMENTS = 2; + public static final int FLAG_HAS_TRANSFORMS = 1; + public static final int FLAG_MASK = 15; + public static final int FLAG_RUN_RTL = 4; + + /** + * Constructs a <code>GlyphVector</code> object. + */ + public GlyphVector () + { + } + + public abstract boolean equals (GlyphVector set); + + public abstract Font getFont (); + + public abstract FontRenderContext getFontRenderContext (); + + public int getGlyphCharIndex (int glyphIndex) + { + return glyphIndex; + } + + public int[] getGlyphCharIndices(int beginGlyphIndex, int numEntries, + int[] codeReturn) + { + if (codeReturn == null) + codeReturn = new int[numEntries]; + + int i = 0; + int j = beginGlyphIndex; + while (j < numEntries) + codeReturn[i++] = getGlyphCharIndex(j++); + + return codeReturn; + } + + public abstract int getGlyphCode (int glyphIndex); + + public abstract int[] getGlyphCodes (int beginGlyphIndex, int numEntries, + int[] codeReturn); + + public abstract GlyphJustificationInfo getGlyphJustificationInfo + (int glyphIndex); + + public abstract Shape getGlyphLogicalBounds (int glyphIndex); + + public abstract GlyphMetrics getGlyphMetrics (int glyphIndex); + + public abstract Shape getGlyphOutline (int glyphIndex); + + public Shape getGlyphOutline(int glyphIndex, float x, float y) + { + Shape s = getGlyphOutline(glyphIndex); + + // This is the only way to translate the origin of a shape + AffineTransform at = AffineTransform.getTranslateInstance(x, y); + return at.createTransformedShape(s); + } + + public Rectangle getGlyphPixelBounds(int index, FontRenderContext renderFRC, + float x, float y) + { + Rectangle bounds = new Rectangle(); + Rectangle2D rect = getGlyphVisualBounds(index).getBounds2D(); + + bounds.x = (int) (rect.getX() + x); + bounds.y = (int) (rect.getY() + y); + bounds.width = (int) rect.getMaxX() - bounds.x; + bounds.height = (int) rect.getMaxY() - bounds.y; + + return bounds; + } + + public abstract Point2D getGlyphPosition (int glyphIndex); + + public abstract float[] getGlyphPositions (int beginGlyphIndex, + int numEntries, + float[] positionReturn); + + public abstract AffineTransform getGlyphTransform (int glyphIndex); + + public abstract Shape getGlyphVisualBounds (int glyphIndex); + + public int getLayoutFlags() + { + return 0; + } + + public abstract Rectangle2D getLogicalBounds (); + + public abstract int getNumGlyphs (); + + public abstract Shape getOutline (); + + public abstract Shape getOutline (float x, float y); + + public Rectangle getPixelBounds (FontRenderContext renderFRC, + float x, float y) + { + Rectangle bounds = new Rectangle(); + Rectangle2D rect = getVisualBounds(); + + bounds.x = (int) (rect.getX() + x); + bounds.y = (int) (rect.getY() + y); + bounds.width = (int) rect.getMaxX() - bounds.x; + bounds.height = (int) rect.getMaxY() - bounds.y; + + return bounds; + } + + public abstract Rectangle2D getVisualBounds (); + + public abstract void performDefaultLayout (); + + public abstract void setGlyphPosition (int glyphIndex, Point2D newPos); + + public abstract void setGlyphTransform (int glyphIndex, + AffineTransform newTX); +} diff --git a/libjava/classpath/java/awt/font/GraphicAttribute.java b/libjava/classpath/java/awt/font/GraphicAttribute.java new file mode 100644 index 000000000..edf0c204d --- /dev/null +++ b/libjava/classpath/java/awt/font/GraphicAttribute.java @@ -0,0 +1,137 @@ +/* GraphicAttribute.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.font; + +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; + +/** + * This class represents a graphic embedded in text. + * + * @author Michael Koch + * @author Lillian Angel (langel at redhat dot com) + */ +public abstract class GraphicAttribute +{ + public static final int BOTTOM_ALIGNMENT = - 2; + public static final int CENTER_BASELINE = 1; + public static final int HANGING_BASELINE = 2; + public static final int ROMAN_BASELINE = 0; + public static final int TOP_ALIGNMENT = - 1; + + private int alignment; + + /** + * Constructor. + * + * @param alignment - the alignment to use for the graphic + */ + protected GraphicAttribute(int alignment) + { + if (alignment < BOTTOM_ALIGNMENT || alignment > HANGING_BASELINE) + throw new IllegalArgumentException("Invalid alignment"); + this.alignment = alignment; + } + + /** + * Draws the graphic. + * + * @param graphics - the graphics configuration to use + * @param x - the x location + * @param y - the y location + */ + public abstract void draw(Graphics2D graphics, float x, float y); + + /** + * Gets the distance from the origin of its graphic to the right side of the + * bounds of its graphic. + * + * @return the advance + */ + public abstract float getAdvance(); + + /** + * Gets the positive distance from the origin of its graphic to the top of + * bounds. + * + * @return the ascent + */ + public abstract float getAscent(); + + /** + * Gets the distance from the origin of its graphic to the bottom of the bounds. + * + * @return the descent + */ + public abstract float getDescent(); + + /** + * Gets the alignment. + * + * @return the alignment + */ + public final int getAlignment() + { + return alignment; + } + + /** + * Returns a Rectangle2D that encloses the rendered area. + * Default bounds is the rectangle (0, -ascent, advance, ascent+descent). + * + * @return the bounds of the rendered area + */ + public Rectangle2D getBounds() + { + float asc = getAscent(); + return new Rectangle2D.Float(0, - asc, getAdvance(), asc + getDescent()); + } + + /** + * Returns the justification information for this object. + * + * @return the justification information + */ + public GlyphJustificationInfo getJustificationInfo() + { + float adv = getAdvance(); + return new GlyphJustificationInfo(adv, false, 2, adv / 3, adv / 3, false, + 1, 0, 0); + } +} diff --git a/libjava/classpath/java/awt/font/ImageGraphicAttribute.java b/libjava/classpath/java/awt/font/ImageGraphicAttribute.java new file mode 100644 index 000000000..63fff4101 --- /dev/null +++ b/libjava/classpath/java/awt/font/ImageGraphicAttribute.java @@ -0,0 +1,187 @@ +/* ImageGraphicAttribute.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.font; + +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.geom.Rectangle2D; + +/** + * This is an implementation of GraphicAttribute which draws images in a + * TextLayout. + * + * @author Lillian Angel + * @author Michael Koch + */ +public final class ImageGraphicAttribute + extends GraphicAttribute +{ + private Image image; + private float originX; + private float originY; + + /** + * Constucts an instance from the specified Image. The origin is at (0, 0). + * + * @param image - image to construct from. + * @param alignment - the alignment + */ + public ImageGraphicAttribute(Image image, int alignment) + { + this(image, alignment, 0, 0); + } + + /** + * Constucts an instance from the specified Image. The origin is at (originX, + * originY). + * + * @param image - image to construct from + * @param alignment - the alignment + * @param originX - x point of origin + * @param originY - y point of origin + */ + public ImageGraphicAttribute(Image image, int alignment, float originX, + float originY) + { + super(alignment); + this.image = image; + this.originX = originX; + this.originY = originY; + } + + /** + * Draws the image at the specified location, relative to the + * origin. + * + * @param g - the graphics to use to render the image + * @param x - the x location + * @param y - the y location + */ + public void draw(Graphics2D g, float x, float y) + { + g.drawImage(image, (int) (x - originX), (int) (y - originY), null); + } + + /** + * Compares this to the specified Object + * + * @param obj - the object to compare + * @return true if the obj and this are equivalent + */ + public boolean equals(Object obj) + { + if (! (obj instanceof ImageGraphicAttribute)) + return false; + + return equals((ImageGraphicAttribute) obj); + } + + /** + * Compares this to the ImageGraphicAttribute given, by + * comparing all fields and values. + * + * @param rhs - the ImageGraphicAttribute to compare + * @return true if the object given is equivalent to this + */ + public boolean equals(ImageGraphicAttribute rhs) + { + return ((this == rhs) || ((this.getAscent() == rhs.getAscent()) + && (this.getAdvance() == rhs.getAdvance()) + && (this.getAlignment() == rhs.getAlignment()) + && (this.getBounds().equals(rhs.getBounds())) + && (this.getDescent() == rhs.getDescent()) + && (this.hashCode() == rhs.hashCode()) + && (this.image.equals(rhs.image)) + && (this.originX == rhs.originX) + && (this.originY == rhs.originY))); + } + + /** + * Returns distance from the origin to the right edge of the image of this. + * + * @return the advance + */ + public float getAdvance() + { + return Math.max(0, image.getWidth(null) - originX); + } + + /** + * Returns the the distance from the top of the image to the origin of this. + * + * @return the ascent. + */ + public float getAscent() + { + return Math.max(0, originY); + } + + /** + * Gets the bounds of the object rendered, relative to the position. + * + * @return the bounds of the object rendered, relative to the position. + */ + public Rectangle2D getBounds() + { + // This is equivalent to what Sun's JDK returns. + // I am not entirely sure why the origin is negative. + return new Rectangle2D.Float(- originX, - originY, image.getWidth(null), + image.getHeight(null)); + } + + /** + * Returns the distance from the origin to the bottom of the image. + * + * @return the descent + */ + public float getDescent() + { + return Math.max(0, image.getHeight(null) - originY); + } + + /** + * Gets the hash code for this image. + * + * @return the hash code + */ + public int hashCode() + { + return image.hashCode(); + } +} diff --git a/libjava/classpath/java/awt/font/LineBreakMeasurer.java b/libjava/classpath/java/awt/font/LineBreakMeasurer.java new file mode 100644 index 000000000..d11f20d1f --- /dev/null +++ b/libjava/classpath/java/awt/font/LineBreakMeasurer.java @@ -0,0 +1,148 @@ +/* LineBreakMeasurer.java + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.font; + +import java.text.AttributedCharacterIterator; +import java.text.BreakIterator; + +public final class LineBreakMeasurer +{ + private AttributedCharacterIterator text; + private int position; + private TextMeasurer tm; + private int numChars; + + public LineBreakMeasurer(AttributedCharacterIterator text, + BreakIterator breakIter, FontRenderContext frc) + { + this( text, frc ); + } + + public LineBreakMeasurer(AttributedCharacterIterator text, + FontRenderContext frc) + { + this.text = text; + position = 0; + numChars = text.getEndIndex(); + tm = new TextMeasurer( text, frc ); + } + + public void deleteChar(AttributedCharacterIterator newParagraph, + int deletePos) + { + tm.deleteChar( newParagraph, deletePos ); + position = 0; + } + + public void insertChar(AttributedCharacterIterator newParagraph, + int insertPos) + { + tm.insertChar( newParagraph, insertPos ); + position = 0; + } + + public TextLayout nextLayout(float wrappingWidth) + { + return nextLayout( wrappingWidth, numChars, false ); + } + + public TextLayout nextLayout(float wrappingWidth, int offsetLimit, + boolean requireNextWord) + { + int next = nextOffset( wrappingWidth, offsetLimit, requireNextWord ); + TextLayout tl = tm.getLayout( position, next ); + position = next; + return tl; + } + + public int nextOffset(float wrappingWidth) + { + return nextOffset( wrappingWidth, numChars, false ); + } + + public int nextOffset(float wrappingWidth, int offsetLimit, + boolean requireNextWord) + { + int guessOffset = tm.getLineBreakIndex(position, wrappingWidth); + if( offsetLimit > numChars ) + offsetLimit = numChars; + + if( guessOffset > offsetLimit ) + { + text.setIndex( offsetLimit ); + return offsetLimit; + } + + text.setIndex( guessOffset ); + + // If we're on a breaking character, return directly + if( Character.isWhitespace( text.current() ) ) + return guessOffset; + + // Otherwise jump forward or backward to the last such char. + if( !requireNextWord ) + while( !Character.isWhitespace( text.previous() ) && + guessOffset > position ) + guessOffset--; + else + while( !Character.isWhitespace( text.next() ) && + guessOffset < offsetLimit ) + guessOffset++; + + if( guessOffset > offsetLimit ) + { + text.setIndex( offsetLimit ); + return offsetLimit; + } + + text.setIndex( guessOffset ); + + return guessOffset; + } + + public void setPosition(int newPosition) + { + position = newPosition; + } + + public int getPosition() + { + return position; + } +} diff --git a/libjava/classpath/java/awt/font/LineMetrics.java b/libjava/classpath/java/awt/font/LineMetrics.java new file mode 100644 index 000000000..d43fd98bb --- /dev/null +++ b/libjava/classpath/java/awt/font/LineMetrics.java @@ -0,0 +1,67 @@ +/* LineMetrics.java -- Information about about a line display characteristics + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.font; + +/** + * @author Michael Koch + */ +public abstract class LineMetrics +{ + public abstract float getAscent(); + + public abstract int getBaselineIndex(); + + public abstract float[] getBaselineOffsets(); + + public abstract float getDescent(); + + public abstract float getHeight(); + + public abstract float getLeading(); + + public abstract int getNumChars(); + + public abstract float getStrikethroughOffset(); + + public abstract float getStrikethroughThickness(); + + public abstract float getUnderlineOffset(); + + public abstract float getUnderlineThickness(); +} diff --git a/libjava/classpath/java/awt/font/MultipleMaster.java b/libjava/classpath/java/awt/font/MultipleMaster.java new file mode 100644 index 000000000..1be44bd75 --- /dev/null +++ b/libjava/classpath/java/awt/font/MultipleMaster.java @@ -0,0 +1,61 @@ +/* MultipleMaster.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.font; + +import java.awt.Font; + +/** + * @author Michael Koch + */ +public interface MultipleMaster +{ + Font deriveMMFont (float[] axes); + + Font deriveMMFont (float[] glyphWidths, float avgStemWidth, + float typicalCapHeight, float typicalXHeight, + float italicAngle); + + float[] getDesignAxisDefaults(); + + String[] getDesignAxisNames(); + + float[] getDesignAxisRanges(); + + int getNumDesignAxes(); +} diff --git a/libjava/classpath/java/awt/font/NumericShaper.java b/libjava/classpath/java/awt/font/NumericShaper.java new file mode 100644 index 000000000..add1c6a44 --- /dev/null +++ b/libjava/classpath/java/awt/font/NumericShaper.java @@ -0,0 +1,425 @@ +/* NumericShaper.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.font; + +import java.io.Serializable; +import java.lang.Character.UnicodeBlock; + +/** + * This class handles numeric shaping. A shaper can either be contextual + * or not. A non-contextual shaper will always translate ASCII digits + * in its input into the target Unicode range. A contextual shaper will + * change the target Unicode range depending on the characters it has + * previously processed. + * + * @author Michael Koch + * @author Tom Tromey + * + * @since 1.4 + * @specnote This class does not handle LIMBU or OSMANYA. + * @specnote The JDK does not seem to properly handle ranges without a + * digit zero, such as TAMIL. This implementation does. + */ +public final class NumericShaper implements Serializable +{ + private static final long serialVersionUID = -8022764705923730308L; + + /** Convenience constant representing all the valid Unicode ranges. */ + public static final int ALL_RANGES = 524287; + + /** + * Constant representing the Unicode ARABIC range. Shaping done + * using this range will translate to the arabic decimal characters. + * Use EASTERN_ARABIC if you want to shape to the eastern arabic + * (also known as the extended arabic) decimal characters. + */ + public static final int ARABIC = 2; + + /** Constant representing the Unicode BENGALI range. */ + public static final int BENGALI = 16; + + /** Constant representing the Unicode DEVANAGARI range. */ + public static final int DEVANAGARI = 8; + + /** + * Constant representing the Unicode extended arabic range. + * In Unicode there are two different sets of arabic digits; + * this selects the extended or eastern set. + */ + public static final int EASTERN_ARABIC = 4; + + /** + * Constant representing the Unicode ETHIOPIC range. Note that + * there is no digit zero in this range; an ASCII digit zero + * is left unchanged when shaping to this range. + */ + public static final int ETHIOPIC = 65536; + + /** + * Constant representing the Unicode EUROPEAN range. For + * contextual shaping purposes, characters in the various + * extended Latin character blocks are recognized as EUROPEAN. + */ + public static final int EUROPEAN = 1; + + /** Constant representing the Unicode GUJARATI range. */ + public static final int GUJARATI = 64; + + /** Constant representing the Unicode GURMUKHI range. */ + public static final int GURMUKHI = 32; + + /** Constant representing the Unicode KANNADA range. */ + public static final int KANNADA = 1024; + + /** Constant representing the Unicode KHMER range. */ + public static final int KHMER = 131072; + + /** Constant representing the Unicode LAO range. */ + public static final int LAO = 8192; + + /** Constant representing the Unicode MALAYALAM range. */ + public static final int MALAYALAM = 2048; + + /** Constant representing the Unicode MONGOLIAN range. */ + public static final int MONGOLIAN = 262144; + + /** Constant representing the Unicode MYANMAR range. */ + public static final int MYANMAR = 32768; + + /** Constant representing the Unicode ORIYA range. */ + public static final int ORIYA = 128; + + /** + * Constant representing the Unicode TAMIL range. Note that + * there is no digit zero in this range; an ASCII digit zero + * is left unchanged when shaping to this range. + */ + public static final int TAMIL = 256; + + /** Constant representing the Unicode TELUGU range. */ + public static final int TELUGU = 512; + + /** Constant representing the Unicode THAI range. */ + public static final int THAI = 4096; + + /** Constant representing the Unicode TIBETAN range. */ + public static final int TIBETAN = 16384; + + /** + * This table holds the zero digits for each language. This is hard-coded + * because the values will not change and the table layout is tied to the + * other constants in this class in any case. In the two places where a + * language does not have a zero digit, the character immediately preceeding + * the one digit is used instead. These languages are special-cased in + * the shaping code. + */ + private static final char[] zeroDigits = + { + '0', // EUROPEAN + '\u0660', // ARABIC + '\u06f0', // EASTERN_ARABIC + '\u0966', // DEVANAGARI + '\u09e6', // BENGALI + '\u0a66', // GURMUKHI + '\u0ae6', // GUJARATI + '\u0b66', // ORIYA + '\u0be6', // TAMIL - special case as there is no digit zero + '\u0c66', // TELUGU + '\u0ce6', // KANNADA + '\u0d66', // MALAYALAM + '\u0e50', // THAI + '\u0ed0', // LAO + '\u0f20', // TIBETAN + '\u1040', // MYANMAR + '\u1368', // ETHIOPIC - special case as there is no digit zero + '\u17e0', // KHMER + '\u1810' // MONGOLIAN + }; + + /** + * The default initial context for this shaper, specified as + * an integer from 0 to 18. + */ + private int key; + + /** + * The target ranges handled by this shaper. If the shaper + * is not contextual, the high bit of this field will be set. + * @specnote This was discovered by reading the serialization spec + */ + private int mask; + + /** + * Create a new numeric shaper. The key given is a constant from + * this class, the constructor turns it into its internal form. + * @param key the key to use, as one of the manifest constants + * @param mask a mask of languages to shape for + */ + private NumericShaper (int key, int mask) + { + // This internal form is a bit goofy, but it is specified by + // the serialization spec. + this.key = Integer.numberOfTrailingZeros(key); + this.mask = mask; + } + + /** + * Return an integer representing all the languages for which this + * shaper will shape. The result is taken by "or"ing together + * the constants representing the various languages. + */ + public int getRanges () + { + return mask & ALL_RANGES; + } + + /** + * Return true if this shaper is contextual, false if it is not. + */ + public boolean isContextual () + { + return mask > 0; + } + + /** + * Shape the text in the given array. The starting context will + * be the context passed to the shaper at creation time. + * @param text the text to shape + * @param start the index of the starting character of the array + * @param count the number of characters in the array + */ + public void shape (char[] text, int start, int count) + { + shape (text, start, count, 1 << key); + } + + /** + * Given a unicode block object, return corresponding language constant. + * If the block is not recognized, returns zero. Note that as there + * is no separate ARABIC block in Character, this case must + * be specially handled by the caller; EASTERN_ARABIC is preferred when + * both are specified. + * @param b the unicode block to classify + * @return the language constant, or zero if not recognized + */ + private int classify(UnicodeBlock b) + { + if (b == null) + return 0; + // ARABIC is handled by the caller; from testing we know + // that EASTERN_ARABIC takes precedence. + if (b == UnicodeBlock.ARABIC) + return EASTERN_ARABIC; + if (b == UnicodeBlock.BENGALI) + return BENGALI; + if (b == UnicodeBlock.DEVANAGARI) + return DEVANAGARI; + if (b == UnicodeBlock.ETHIOPIC) + return ETHIOPIC; + if (b == UnicodeBlock.BASIC_LATIN + || b == UnicodeBlock.LATIN_1_SUPPLEMENT + || b == UnicodeBlock.LATIN_EXTENDED_A + || b == UnicodeBlock.LATIN_EXTENDED_ADDITIONAL + || b == UnicodeBlock.LATIN_EXTENDED_B) + return EUROPEAN; + if (b == UnicodeBlock.GUJARATI) + return GUJARATI; + if (b == UnicodeBlock.GURMUKHI) + return GURMUKHI; + if (b == UnicodeBlock.KANNADA) + return KANNADA; + if (b == UnicodeBlock.KHMER) + return KHMER; + if (b == UnicodeBlock.LAO) + return LAO; + if (b == UnicodeBlock.MALAYALAM) + return MALAYALAM; + if (b == UnicodeBlock.MONGOLIAN) + return MONGOLIAN; + if (b == UnicodeBlock.MYANMAR) + return MYANMAR; + if (b == UnicodeBlock.ORIYA) + return ORIYA; + if (b == UnicodeBlock.TAMIL) + return TAMIL; + if (b == UnicodeBlock.TELUGU) + return TELUGU; + if (b == UnicodeBlock.THAI) + return THAI; + if (b == UnicodeBlock.TIBETAN) + return TIBETAN; + return 0; + } + + /** + * Shape the given text, using the indicated initial context. + * If this shaper is not a contextual shaper, then the given context + * will be ignored. + * @param text the text to shape + * @param start the index of the first character of the text to shape + * @param count the number of characters to shape in the text + * @param context the initial context + * @throws IllegalArgumentException if the initial context is invalid + */ + public void shape (char[] text, int start, int count, int context) + { + int currentContext; + if (isContextual()) + { + if (Integer.bitCount(context) != 1 || (context & ~ALL_RANGES) != 0) + throw new IllegalArgumentException("invalid context argument"); + // If the indicated context is not one we are handling, reset it. + if ((context & mask) == 0) + currentContext = -1; + else + currentContext = Integer.numberOfTrailingZeros(context); + } + else + currentContext = key; + + for (int i = 0; i < count; ++i) + { + char c = text[start + i]; + if (c >= '0' && c <= '9') + { + if (currentContext >= 0) + { + // Shape into the current context. + if (c == '0' + && ((1 << currentContext) == TAMIL + || (1 << currentContext) == ETHIOPIC)) + { + // No digit 0 in this context; do nothing. + } + else + text[start + i] + = (char) (zeroDigits[currentContext] + c - '0'); + } + } + else if (isContextual()) + { + // if c is in a group, set currentContext; else reset it. + int group = classify(UnicodeBlock.of(c)); + // Specially handle ARABIC. + if (group == EASTERN_ARABIC && (mask & EASTERN_ARABIC) == 0 + && (mask & ARABIC) != 0) + group = ARABIC; + if ((mask & group) != 0) + { + // The character was classified as being in a group + // we recognize, and it was selected by the shaper. + // So, change the context. + currentContext = Integer.numberOfTrailingZeros(group); + } + } + } + } + + public boolean equals (Object obj) + { + if (! (obj instanceof NumericShaper)) + return false; + NumericShaper tmp = (NumericShaper) obj; + return key == tmp.key && mask == tmp.mask; + } + + public int hashCode () + { + return key ^ mask; + } + + public String toString () + { + // For debugging only. + return "key=" + key + "; mask=" + mask; + } + + /** + * Return a non-contextual shaper which can shape to a single range. + * All ASCII digits in the input text are translated to this language. + * @param singleRange the target language + * @return a non-contextual shaper for this language + * @throws IllegalArgumentException if the argument does not name a + * single language, as specified by the constants declared in this class + */ + public static NumericShaper getShaper (int singleRange) + { + if (Integer.bitCount(singleRange) != 1) + throw new IllegalArgumentException("more than one bit set in argument"); + if ((singleRange & ~ALL_RANGES) != 0) + throw new IllegalArgumentException("argument out of range"); + return new NumericShaper(singleRange, Integer.MIN_VALUE | singleRange); + } + + /** + * Return a contextual shaper which can shape to any of the indicated + * languages. The default initial context for this shaper is EUROPEAN. + * @param ranges the ranges to shape to + * @return a contextual shaper which will target any of these ranges + * @throws IllegalArgumentException if the argument specifies an + * unrecognized range + */ + public static NumericShaper getContextualShaper (int ranges) + { + if ((ranges & ~ALL_RANGES) != 0) + throw new IllegalArgumentException("argument out of range"); + return new NumericShaper(EUROPEAN, ranges); + } + + /** + * Return a contextual shaper which can shape to any of the indicated + * languages. The default initial context for this shaper is given as + * an argument. + * @param ranges the ranges to shape to + * @param defaultContext the default initial context + * @return a contextual shaper which will target any of these ranges + * @throws IllegalArgumentException if the ranges argument specifies an + * unrecognized range, or if the defaultContext argument does not specify + * a single valid range + */ + public static NumericShaper getContextualShaper (int ranges, + int defaultContext) + { + if (Integer.bitCount(defaultContext) != 1) + throw new IllegalArgumentException("more than one bit set in context"); + if ((ranges & ~ALL_RANGES) != 0 || (defaultContext & ~ALL_RANGES) != 0) + throw new IllegalArgumentException("argument out of range"); + return new NumericShaper(defaultContext, ranges); + } +} diff --git a/libjava/classpath/java/awt/font/OpenType.java b/libjava/classpath/java/awt/font/OpenType.java new file mode 100644 index 000000000..e992d0700 --- /dev/null +++ b/libjava/classpath/java/awt/font/OpenType.java @@ -0,0 +1,111 @@ +/* OpenType.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.font; + +/** + * @author Michael Koch + */ +public interface OpenType +{ + int TAG_ACNT = 1633906292; + int TAG_AVAR = 1635148146; + int TAG_BASE = 1111577413; + int TAG_BDAT = 1650745716; + int TAG_BLOC = 1651273571; + int TAG_BSLN = 1651731566; + int TAG_CFF = 1128678944; + int TAG_CMAP = 1668112752; + int TAG_CVAR = 1668702578; + int TAG_CVT = 1668707360; + int TAG_DSIG = 1146308935; + int TAG_EBDT = 1161970772; + int TAG_EBLC = 1161972803; + int TAG_EBSC = 1161974595; + int TAG_FDSC = 1717859171; + int TAG_FEAT = 1717920116; + int TAG_FMTX = 1718449272; + int TAG_FPGM = 1718642541; + int TAG_FVAR = 1719034226; + int TAG_GASP = 1734439792; + int TAG_GDEF = 1195656518; + int TAG_GLYF = 1735162214; + int TAG_GPOS = 1196445523; + int TAG_GSUB = 1196643650; + int TAG_GVAR = 1735811442; + int TAG_HDMX = 1751412088; + int TAG_HEAD = 1751474532; + int TAG_HHEA = 1751672161; + int TAG_HMTX = 1752003704; + int TAG_JSTF = 1246975046; + int TAG_JUST = 1786082164; + int TAG_KERN = 1801810542; + int TAG_LCAR = 1818452338; + int TAG_LOCA = 1819239265; + int TAG_LTSH = 1280594760; + int TAG_MAXP = 1835104368; + int TAG_MMFX = 1296909912; + int TAG_MMSD = 1296913220; + int TAG_MORT = 1836020340; + int TAG_NAME = 1851878757; + int TAG_OPBD = 1836020340; + int TAG_OS2 = 1330851634; + int TAG_PCLT = 1346587732; + int TAG_POST = 1886352244; + int TAG_PREP = 1886545264; + int TAG_PROP = 1886547824; + int TAG_TRAK = 1953653099; + int TAG_TYP1 = 1954115633; + int TAG_VDMX = 1447316824; + int TAG_VHEA = 1986553185; + int TAG_VMTX = 1986884728; + + byte[] getFontTable (int sfntTag); + + byte[] getFontTable (int sfntTag, int offset, int count); + + byte[] getFontTable (String strSfntTag); + + byte[] getFontTable (String strSfntTag, int offset, int count); + + int getFontTableSize (int sfntTag); + + int getFontTableSize (String strSfntTag); + + int getVersion (); +} diff --git a/libjava/classpath/java/awt/font/ShapeGraphicAttribute.java b/libjava/classpath/java/awt/font/ShapeGraphicAttribute.java new file mode 100644 index 000000000..8d6891632 --- /dev/null +++ b/libjava/classpath/java/awt/font/ShapeGraphicAttribute.java @@ -0,0 +1,185 @@ +/* ShapeGraphicAttribute.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.font; + +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.Rectangle2D; + +/** + * This is an implementation of GraphicAttribute that draws shapes in a TextLayout. + * + * @author Lillian Angel (langel at redhat dot com) + */ +public final class ShapeGraphicAttribute extends GraphicAttribute +{ + /** True if the shape should be filled. */ + public static final boolean FILL = false; + + /** True if the shape should be stroked with a 1-pixel wide stroke. */ + public static final boolean STROKE = true; + + private Shape shape; + private boolean stroke; + private Rectangle2D bounds; + + /** + * Constructor. + * + * @param shape - the Shape to render. The Shape is rendered with its origin. + * @param alignment - the alignment + * @param stroke - true if the Shape should be stroked; false if the Shape + * should be filled. + */ + public ShapeGraphicAttribute(Shape shape, int alignment, boolean stroke) + { + super(alignment); + this.shape = shape; + this.stroke = stroke; + this.bounds = shape.getBounds2D(); + } + + /** + * Draws the graphic at the given location. + * + * @param graphics - the graphics to use. + * @param x - the x location to draw at. + * @param y - the y location to draw at. + */ + public void draw(Graphics2D graphics, float x, float y) + { + graphics.translate(x, y); + if (stroke == STROKE) + graphics.draw(shape); + else + graphics.fill(shape); + graphics.translate(- x, - y); + } + + /** + * Compares this ShapeGraphicAttribute to obj. + * + * @param obj - the object to compare. + */ + public boolean equals(Object obj) + { + if (! (obj instanceof ShapeGraphicAttribute)) + return false; + + return equals((ShapeGraphicAttribute) obj); + } + + /** + * Compares this ShapeGraphicAttribute to rhs. + * + * @param rhs - the ShapeGraphicAttribute to compare. + */ + public boolean equals(ShapeGraphicAttribute rhs) + { + return (this == rhs || (this.shape.equals(rhs.shape) + && getAlignment() == rhs.getAlignment() + && stroke == rhs.stroke + && getAdvance() == rhs.getAdvance() + && getAscent() == rhs.getAscent() + && getBounds().equals(rhs.getBounds()) + && getDescent() == rhs.getDescent() + && hashCode() == rhs.hashCode())); + } + + /** + * Gets the distance from the origin of its Shape to the right side of the + * bounds of its Shape. + * + * @return the advance + */ + public float getAdvance() + { + return Math.max(0, (float) bounds.getMaxX()); + } + + /** + * Gets the positive distance from the origin of its Shape to the top of + * bounds. + * + * @return the ascent + */ + public float getAscent() + { + return Math.max(0, -(float) bounds.getMinY()); + } + + /** + * Gets the distance from the origin of its Shape to the bottom of the bounds. + * + * @return the descent + */ + public float getDescent() + { + return Math.max(0, (float) bounds.getMaxY()); + } + + /** + * Returns a Rectangle2D that encloses all of the bits drawn by this shape. + * + * @return the bounds of the shape. + */ + public Rectangle2D getBounds() + { + Rectangle2D.Float bounds = new Rectangle2D.Float(); + bounds.setRect(this.bounds); + + if (stroke == STROKE) + { + bounds.width++; + bounds.height++; + } + + return bounds; + } + + /** + * Gets the hash code. + * + * @return the hash code. + */ + public int hashCode() + { + return shape.hashCode(); + } +} diff --git a/libjava/classpath/java/awt/font/TextAttribute.java b/libjava/classpath/java/awt/font/TextAttribute.java new file mode 100644 index 000000000..bfade21bb --- /dev/null +++ b/libjava/classpath/java/awt/font/TextAttribute.java @@ -0,0 +1,309 @@ +/* TextAttribute.java -- + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.font; + +import java.io.InvalidObjectException; +import java.text.AttributedCharacterIterator; + +/** + * Attributes (and associated values) that can be used to define an + * {@link java.text.AttributedString}. + */ +public final class TextAttribute extends AttributedCharacterIterator.Attribute +{ + private static final long serialVersionUID = 7744112784117861702L; + + /** A key for the background paint attribute. */ + public static final TextAttribute BACKGROUND = + new TextAttribute("background"); + + /** A key for the BIDI_EMBEDDING attribute. */ + public static final TextAttribute BIDI_EMBEDDING = + new TextAttribute("bidi_embedding"); + + /** A key for the CHAR_REPLACEMENT attribute. */ + public static final TextAttribute CHAR_REPLACEMENT = + new TextAttribute("char_replacement"); + + /** A key for the FAMILY attribute. */ + public static final TextAttribute FAMILY = new TextAttribute("family"); + + /** A key for the font attribute. */ + public static final TextAttribute FONT = new TextAttribute("font"); + + /** A key for the foreground paint attribute. */ + public static final TextAttribute FOREGROUND = + new TextAttribute("foreground"); + + /** A key for the INPUT_METHOD_HIGHLIGHT attribute. */ + public static final TextAttribute INPUT_METHOD_HIGHLIGHT = + new TextAttribute("input method highlight"); + + /** A key for the INPUT_METHOD_UNDERLINE attribute. */ + public static final TextAttribute INPUT_METHOD_UNDERLINE = + new TextAttribute("input method underline"); + + /** A key for the text justification attribute. */ + public static final TextAttribute JUSTIFICATION = + new TextAttribute("justification"); + + /** + * A value that can be used with the {@link #JUSTIFICATION} attribute to + * indicate full justification of the text. + */ + public static final Float JUSTIFICATION_FULL = new Float(1.0); + + /** + * A value that can be used with the {@link #JUSTIFICATION} attribute to + * indicate no justification of the text. + */ + public static final Float JUSTIFICATION_NONE = new Float(0.0); + + /** A key for the NUMERIC_SHAPING attribute. */ + public static final TextAttribute NUMERIC_SHAPING = + new TextAttribute("numeric_shaping"); + + /** A key for the POSTURE attribute. */ + public static final TextAttribute POSTURE = new TextAttribute("posture"); + + /** A value that can be used with the {@link #POSTURE} attribute. */ + public static final Float POSTURE_OBLIQUE = new Float(0.2); + + /** A value that can be used with the {@link #POSTURE} attribute. */ + public static final Float POSTURE_REGULAR = new Float(0.0); + + /** A key for the RUN_DIRECTION attribute. */ + public static final TextAttribute RUN_DIRECTION = + new TextAttribute("run_direction"); + + /** A value that can be used with the {@link #RUN_DIRECTION} attribute. */ + public static final Boolean RUN_DIRECTION_LTR = Boolean.FALSE; + + /** A value that can be used with the {@link #RUN_DIRECTION} attribute. */ + public static final Boolean RUN_DIRECTION_RTL = Boolean.TRUE; + + /** A key for the text size attribute. */ + public static final TextAttribute SIZE = new TextAttribute("size"); + + /** A key for the STRIKETHROUGH attribute. */ + public static final TextAttribute STRIKETHROUGH = + new TextAttribute("strikethrough"); + + /** A value that can be used with the {@link #STRIKETHROUGH} attribute. */ + public static final Boolean STRIKETHROUGH_ON = Boolean.TRUE; + + /** A key for the SUPERSCRIPT attribute. */ + public static final TextAttribute SUPERSCRIPT = + new TextAttribute("superscript"); + + /** A value that can be used with the {@link #SUPERSCRIPT} attribute. */ + public static final Integer SUPERSCRIPT_SUB = new Integer(-1); + + /** A value that can be used with the {@link #SUPERSCRIPT} attribute. */ + public static final Integer SUPERSCRIPT_SUPER = new Integer(1); + + /** A key for the SWAP_COLORS attribute. */ + public static final TextAttribute SWAP_COLORS = + new TextAttribute("swap_colors"); + + /** A value that can be used with the {@link #SWAP_COLORS} attribute. */ + public static final Boolean SWAP_COLORS_ON = Boolean.TRUE; + + /** A key for the TRANFORM attribute. */ + public static final TextAttribute TRANSFORM = new TextAttribute("transform"); + + /** A key for the UNDERLINE attribute. */ + public static final TextAttribute UNDERLINE = new TextAttribute("underline"); + + /** A value that can be used with the {@link #UNDERLINE} attribute. */ + public static final Integer UNDERLINE_LOW_DASHED = new Integer(5); + + /** A value that can be used with the {@link #UNDERLINE} attribute. */ + public static final Integer UNDERLINE_LOW_DOTTED = new Integer(3); + + /** A value that can be used with the {@link #UNDERLINE} attribute. */ + public static final Integer UNDERLINE_LOW_GRAY = new Integer(4); + + /** A value that can be used with the {@link #UNDERLINE} attribute. */ + public static final Integer UNDERLINE_LOW_ONE_PIXEL = new Integer(1); + + /** A value that can be used with the {@link #UNDERLINE} attribute. */ + public static final Integer UNDERLINE_LOW_TWO_PIXEL = new Integer(2); + + /** A value that can be used with the {@link #UNDERLINE} attribute. */ + public static final Integer UNDERLINE_ON = new Integer(0); + + /** A key for the WEIGHT attribute. */ + public static final TextAttribute WEIGHT = new TextAttribute("weight"); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_BOLD = new Float(2.0); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_DEMIBOLD = new Float(1.75); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_DEMILIGHT = new Float(0.875); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_EXTRA_LIGHT = new Float(0.5); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_EXTRABOLD = new Float(2.5); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_HEAVY = new Float(2.25); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_LIGHT = new Float(0.75); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_MEDIUM = new Float(1.5); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_REGULAR = new Float(1.0); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_SEMIBOLD = new Float(1.25); + + /** A value that can be used with the {@link #WEIGHT} attribute. */ + public static final Float WEIGHT_ULTRABOLD = new Float(2.75); + + /** A key for the WIDTH attribute. */ + public static final TextAttribute WIDTH = new TextAttribute("width"); + + /** A value that can be used with the {@link #WIDTH} attribute. */ + public static final Float WIDTH_CONDENSED = new Float(0.75); + + /** A value that can be used with the {@link #WIDTH} attribute. */ + public static final Float WIDTH_EXTENDED = new Float(1.5); + + /** A value that can be used with the {@link #WIDTH} attribute. */ + public static final Float WIDTH_REGULAR = new Float(1.0); + + /** A value that can be used with the {@link #WIDTH} attribute. */ + public static final Float WIDTH_SEMI_CONDENSED = new Float(0.875); + + /** A value that can be used with the {@link #WIDTH} attribute. */ + public static final Float WIDTH_SEMI_EXTENDED = new Float(1.25); + + /** + * Creates a new attribute. + * + * @param name the name. + */ + protected TextAttribute(String name) + { + super(name); + } + + /** + * After deserialization, this method ensures that only one instance of + * each attribute is used. + * + * @return The (single) attribute instance. + * + * @throws InvalidObjectException if the attribute is not recognised. + */ + protected Object readResolve() + throws InvalidObjectException + { + if (this.getName().equals("background")) + return BACKGROUND; + + if (this.getName().equals("bidi_embedding")) + return BIDI_EMBEDDING; + + if (this.getName().equals("char_replacement")) + return CHAR_REPLACEMENT; + + if (this.getName().equals("family")) + return FAMILY; + + if (this.getName().equals("font")) + return FONT; + + if (this.getName().equals("foreground")) + return FOREGROUND; + + if (this.getName().equals("input method highlight")) + return INPUT_METHOD_HIGHLIGHT; + + if (this.getName().equals("input method underline")) + return INPUT_METHOD_UNDERLINE; + + if (this.getName().equals("justification")) + return JUSTIFICATION; + + if (this.getName().equals("numeric_shaping")) + return NUMERIC_SHAPING; + + if (this.getName().equals("posture")) + return POSTURE; + + if (this.getName().equals("run_direction")) + return RUN_DIRECTION; + + if (this.getName().equals("size")) + return SIZE; + + if (this.getName().equals("strikethrough")) + return STRIKETHROUGH; + + if (this.getName().equals("superscript")) + return SUPERSCRIPT; + + if (this.getName().equals("swap_colors")) + return SWAP_COLORS; + + if (this.getName().equals("transform")) + return TRANSFORM; + + if (this.getName().equals("underline")) + return UNDERLINE; + + if (this.getName().equals("weight")) + return WEIGHT; + + if (this.getName().equals("width")) + return WIDTH; + + throw new InvalidObjectException("Can't resolve Attribute: " + getName()); + } +} diff --git a/libjava/classpath/java/awt/font/TextHitInfo.java b/libjava/classpath/java/awt/font/TextHitInfo.java new file mode 100644 index 000000000..17479b09e --- /dev/null +++ b/libjava/classpath/java/awt/font/TextHitInfo.java @@ -0,0 +1,128 @@ +/* TextHitInfo.java -- + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.font; + +/** + * @author John Leuner (jewel@debian.org) + */ +public final class TextHitInfo +{ + private int charIndex; + private boolean leadingEdge; + + TextHitInfo (int charIndex, boolean leadingEdge) + { + this.charIndex = charIndex; + this.leadingEdge = leadingEdge; + } + + public int getCharIndex() + { + return charIndex; + } + + public boolean isLeadingEdge() + { + return leadingEdge; + } + + public int getInsertionIndex() + { + return (leadingEdge ? charIndex : charIndex + 1); + } + + public int hashCode() + { + return charIndex; + } + + public boolean equals(Object obj) + { + if(obj instanceof TextHitInfo) + return this.equals((TextHitInfo) obj); + + return false; + } + + public boolean equals(TextHitInfo hitInfo) + { + if (hitInfo == null) + return false; + + return (charIndex == hitInfo.getCharIndex ()) + && (leadingEdge == hitInfo.isLeadingEdge ()); + } + + public static TextHitInfo leading(int charIndex) + { + return new TextHitInfo (charIndex, true); + } + + public static TextHitInfo trailing(int charIndex) + { + return new TextHitInfo (charIndex, false); + } + + public static TextHitInfo beforeOffset(int offset) + { + return new TextHitInfo ((offset - 1), false); + } + + public static TextHitInfo afterOffset(int offset) + { + return new TextHitInfo (offset, true); + } + + public TextHitInfo getOtherHit() + { + return (leadingEdge ? trailing (charIndex - 1) : leading (charIndex + 1)); + } + + public TextHitInfo getOffsetHit(int offset) + { + return new TextHitInfo (charIndex + offset, leadingEdge); + } + + public String toString() + { + return "TextHitInfo[" + + charIndex + + (leadingEdge ? "L" : "T" ) + + "]"; + } +} diff --git a/libjava/classpath/java/awt/font/TextLayout.java b/libjava/classpath/java/awt/font/TextLayout.java new file mode 100644 index 000000000..c4f174245 --- /dev/null +++ b/libjava/classpath/java/awt/font/TextLayout.java @@ -0,0 +1,1420 @@ +/* TextLayout.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.font; + +import gnu.java.lang.CPStringBuilder; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Line2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.text.CharacterIterator; +import java.text.AttributedCharacterIterator; +import java.text.Bidi; +import java.util.ArrayList; +import java.util.Map; + +/** + * @author Sven de Marothy + */ +public final class TextLayout implements Cloneable +{ + /** + * Holds the layout data that belongs to one run of characters. + */ + private class Run + { + /** + * The actual glyph vector. + */ + GlyphVector glyphVector; + + /** + * The font for this text run. + */ + Font font; + + /** + * The start of the run. + */ + int runStart; + + /** + * The end of the run. + */ + int runEnd; + + /** + * The layout location of the beginning of the run. + */ + float location; + + /** + * Initializes the Run instance. + * + * @param gv the glyph vector + * @param start the start index of the run + * @param end the end index of the run + */ + Run(GlyphVector gv, Font f, int start, int end) + { + glyphVector = gv; + font = f; + runStart = start; + runEnd = end; + } + + /** + * Returns <code>true</code> when this run is left to right, + * <code>false</code> otherwise. + * + * @return <code>true</code> when this run is left to right, + * <code>false</code> otherwise + */ + boolean isLeftToRight() + { + return (glyphVector.getLayoutFlags() & GlyphVector.FLAG_RUN_RTL) == 0; + } + } + + /** + * The laid out character runs. + */ + private Run[] runs; + + private FontRenderContext frc; + private char[] string; + private int offset; + private int length; + private Rectangle2D boundsCache; + private LineMetrics lm; + + /** + * The total advance of this text layout. This is cache for maximum + * performance. + */ + private float totalAdvance = -1F; + + /** + * The cached natural bounds. + */ + private Rectangle2D naturalBounds; + + /** + * Character indices. + * Fixt index is the glyphvector, second index is the (first) glyph. + */ + private int[][] charIndices; + + /** + * Base directionality, determined from the first char. + */ + private boolean leftToRight; + + /** + * Whether this layout contains whitespace or not. + */ + private boolean hasWhitespace = false; + + /** + * The {@link Bidi} object that is used for reordering and by + * {@link #getCharacterLevel(int)}. + */ + private Bidi bidi; + + /** + * Mpas the logical position of each individual character in the original + * string to its visual position. + */ + private int[] logicalToVisual; + + /** + * Maps visual positions of a character to its logical position + * in the original string. + */ + private int[] visualToLogical; + + /** + * The cached hashCode. + */ + private int hash; + + /** + * The default caret policy. + */ + public static final TextLayout.CaretPolicy DEFAULT_CARET_POLICY = + new CaretPolicy(); + + /** + * Constructs a TextLayout. + */ + public TextLayout (String str, Font font, FontRenderContext frc) + { + this.frc = frc; + string = str.toCharArray(); + offset = 0; + length = this.string.length; + lm = font.getLineMetrics(this.string, offset, length, frc); + + // Get base direction and whitespace info + getStringProperties(); + + if (Bidi.requiresBidi(string, offset, offset + length)) + { + bidi = new Bidi(str, leftToRight ? Bidi.DIRECTION_LEFT_TO_RIGHT + : Bidi.DIRECTION_RIGHT_TO_LEFT ); + int rc = bidi.getRunCount(); + byte[] table = new byte[ rc ]; + for(int i = 0; i < table.length; i++) + table[i] = (byte)bidi.getRunLevel(i); + + runs = new Run[rc]; + for(int i = 0; i < rc; i++) + { + int start = bidi.getRunStart(i); + int end = bidi.getRunLimit(i); + if(start != end) // no empty runs. + { + GlyphVector gv = font.layoutGlyphVector(frc, + string, start, end, + ((table[i] & 1) == 0) ? Font.LAYOUT_LEFT_TO_RIGHT + : Font.LAYOUT_RIGHT_TO_LEFT ); + runs[i] = new Run(gv, font, start, end); + } + } + Bidi.reorderVisually( table, 0, runs, 0, runs.length ); + // Clean up null runs. + ArrayList cleaned = new ArrayList(rc); + for (int i = 0; i < rc; i++) + { + if (runs[i] != null) + cleaned.add(runs[i]); + } + runs = new Run[cleaned.size()]; + runs = (Run[]) cleaned.toArray(runs); + } + else + { + GlyphVector gv = font.layoutGlyphVector( frc, string, offset, length, + leftToRight ? Font.LAYOUT_LEFT_TO_RIGHT + : Font.LAYOUT_RIGHT_TO_LEFT ); + Run run = new Run(gv, font, 0, length); + runs = new Run[]{ run }; + } + setCharIndices(); + setupMappings(); + layoutRuns(); + } + + public TextLayout (String string, + Map<? extends AttributedCharacterIterator.Attribute, ?> attributes, + FontRenderContext frc) + { + this( string, new Font( attributes ), frc ); + } + + public TextLayout (AttributedCharacterIterator text, FontRenderContext frc) + { + // FIXME: Very rudimentary. + this(getText(text), getFont(text), frc); + } + + /** + * Package-private constructor to make a textlayout from an existing one. + * This is used by TextMeasurer for returning sub-layouts, and it + * saves a lot of time in not having to relayout the text. + */ + TextLayout(TextLayout t, int startIndex, int endIndex) + { + frc = t.frc; + boundsCache = null; + lm = t.lm; + leftToRight = t.leftToRight; + + if( endIndex > t.getCharacterCount() ) + endIndex = t.getCharacterCount(); + string = t.string; + offset = startIndex + offset; + length = endIndex - startIndex; + + int startingRun = t.charIndices[startIndex][0]; + int nRuns = 1 + t.charIndices[endIndex - 1][0] - startingRun; + + runs = new Run[nRuns]; + for( int i = 0; i < nRuns; i++ ) + { + Run run = t.runs[i + startingRun]; + GlyphVector gv = run.glyphVector; + Font font = run.font; + // Copy only the relevant parts of the first and last runs. + int beginGlyphIndex = (i > 0) ? 0 : t.charIndices[startIndex][1]; + int numEntries = ( i < nRuns - 1) ? gv.getNumGlyphs() : + 1 + t.charIndices[endIndex - 1][1] - beginGlyphIndex; + + int[] codes = gv.getGlyphCodes(beginGlyphIndex, numEntries, null); + gv = font.createGlyphVector(frc, codes); + runs[i] = new Run(gv, font, run.runStart - startIndex, + run.runEnd - startIndex); + } + runs[nRuns - 1].runEnd = endIndex - 1; + + setCharIndices(); + setupMappings(); + determineWhiteSpace(); + layoutRuns(); + } + + private void setCharIndices() + { + charIndices = new int[ getCharacterCount() ][2]; + int i = 0; + int currentChar = 0; + for(int run = 0; run < runs.length; run++) + { + currentChar = -1; + Run current = runs[run]; + GlyphVector gv = current.glyphVector; + for( int gi = 0; gi < gv.getNumGlyphs(); gi++) + { + if( gv.getGlyphCharIndex( gi ) != currentChar ) + { + charIndices[ i ][0] = run; + charIndices[ i ][1] = gi; + currentChar = gv.getGlyphCharIndex( gi ); + i++; + } + } + } + } + + /** + * Initializes the logicalToVisual and visualToLogial maps. + */ + private void setupMappings() + { + int numChars = getCharacterCount(); + logicalToVisual = new int[numChars]; + visualToLogical = new int[numChars]; + int lIndex = 0; + int vIndex = 0; + // We scan the runs in visual order and set the mappings accordingly. + for (int i = 0; i < runs.length; i++) + { + Run run = runs[i]; + if (run.isLeftToRight()) + { + for (lIndex = run.runStart; lIndex < run.runEnd; lIndex++) + { + logicalToVisual[lIndex] = vIndex; + visualToLogical[vIndex] = lIndex; + vIndex++; + } + } + else + { + for (lIndex = run.runEnd - 1; lIndex >= run.runStart; lIndex--) + { + logicalToVisual[lIndex] = vIndex; + visualToLogical[vIndex] = lIndex; + vIndex++; + } + } + } + } + + private static String getText(AttributedCharacterIterator iter) + { + CPStringBuilder sb = new CPStringBuilder(); + int idx = iter.getIndex(); + for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) + sb.append(c); + iter.setIndex( idx ); + return sb.toString(); + } + + private static Font getFont(AttributedCharacterIterator iter) + { + Font f = (Font)iter.getAttribute(TextAttribute.FONT); + if( f == null ) + { + int size; + Float i = (Float)iter.getAttribute(TextAttribute.SIZE); + if( i != null ) + size = (int)i.floatValue(); + else + size = 14; + f = new Font("Dialog", Font.PLAIN, size ); + } + return f; + } + + /** + * Scan the character run for the first strongly directional character, + * which in turn defines the base directionality of the whole layout. + */ + private void getStringProperties() + { + boolean gotDirection = false; + int i = offset; + int endOffs = offset + length; + leftToRight = true; + while( i < endOffs && !gotDirection ) + switch( Character.getDirectionality(string[i++]) ) + { + case Character.DIRECTIONALITY_LEFT_TO_RIGHT: + case Character.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING: + case Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE: + gotDirection = true; + break; + + case Character.DIRECTIONALITY_RIGHT_TO_LEFT: + case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC: + case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING: + case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE: + leftToRight = false; + gotDirection = true; + break; + } + determineWhiteSpace(); + } + + private void determineWhiteSpace() + { + // Determine if there's whitespace in the thing. + // Ignore trailing chars. + int i = offset + length - 1; + hasWhitespace = false; + while( i >= offset && Character.isWhitespace( string[i] ) ) + i--; + // Check the remaining chars + while( i >= offset ) + if( Character.isWhitespace( string[i--] ) ) + hasWhitespace = true; + } + + protected Object clone () + { + return new TextLayout( this, 0, length); + } + + public void draw (Graphics2D g2, float x, float y) + { + for(int i = 0; i < runs.length; i++) + { + Run run = runs[i]; + GlyphVector gv = run.glyphVector; + g2.drawGlyphVector(gv, x, y); + Rectangle2D r = gv.getLogicalBounds(); + x += r.getWidth(); + } + } + + public boolean equals (Object obj) + { + if( !( obj instanceof TextLayout) ) + return false; + + return equals( (TextLayout) obj ); + } + + public boolean equals (TextLayout tl) + { + if( runs.length != tl.runs.length ) + return false; + // Compare all glyph vectors. + for( int i = 0; i < runs.length; i++ ) + if( !runs[i].equals( tl.runs[i] ) ) + return false; + return true; + } + + public float getAdvance () + { + if (totalAdvance == -1F) + { + totalAdvance = 0f; + for(int i = 0; i < runs.length; i++) + { + Run run = runs[i]; + GlyphVector gv = run.glyphVector; + totalAdvance += gv.getLogicalBounds().getWidth(); + } + } + return totalAdvance; + } + + public float getAscent () + { + return lm.getAscent(); + } + + public byte getBaseline () + { + return (byte)lm.getBaselineIndex(); + } + + public float[] getBaselineOffsets () + { + return lm.getBaselineOffsets(); + } + + public Shape getBlackBoxBounds (int firstEndpoint, int secondEndpoint) + { + if( secondEndpoint - firstEndpoint <= 0 ) + return new Rectangle2D.Float(); // Hmm? + + if( firstEndpoint < 0 || secondEndpoint > getCharacterCount()) + return new Rectangle2D.Float(); + + GeneralPath gp = new GeneralPath(); + + int ri = charIndices[ firstEndpoint ][0]; + int gi = charIndices[ firstEndpoint ][1]; + + double advance = 0; + + for( int i = 0; i < ri; i++ ) + { + Run run = runs[i]; + GlyphVector gv = run.glyphVector; + advance += gv.getLogicalBounds().getWidth(); + } + + for( int i = ri; i <= charIndices[ secondEndpoint - 1 ][0]; i++ ) + { + Run run = runs[i]; + GlyphVector gv = run.glyphVector; + int dg; + if( i == charIndices[ secondEndpoint - 1 ][0] ) + dg = charIndices[ secondEndpoint - 1][1]; + else + dg = gv.getNumGlyphs() - 1; + + for( int j = 0; j <= dg; j++ ) + { + Rectangle2D r2 = (gv.getGlyphVisualBounds( j )). + getBounds2D(); + Point2D p = gv.getGlyphPosition( j ); + r2.setRect( advance + r2.getX(), r2.getY(), + r2.getWidth(), r2.getHeight() ); + gp.append(r2, false); + } + + advance += gv.getLogicalBounds().getWidth(); + } + return gp; + } + + public Rectangle2D getBounds() + { + if( boundsCache == null ) + boundsCache = getOutline(new AffineTransform()).getBounds(); + return boundsCache; + } + + public float[] getCaretInfo (TextHitInfo hit) + { + return getCaretInfo(hit, getNaturalBounds()); + } + + public float[] getCaretInfo (TextHitInfo hit, Rectangle2D bounds) + { + float[] info = new float[2]; + int index = hit.getCharIndex(); + boolean leading = hit.isLeadingEdge(); + // For the boundary cases we return the boundary runs. + Run run; + + if (index >= length) + { + info[0] = getAdvance(); + info[1] = 0; + } + else + { + if (index < 0) + { + run = runs[0]; + index = 0; + leading = true; + } + else + run = findRunAtIndex(index); + + int glyphIndex = index - run.runStart; + Shape glyphBounds = run.glyphVector.getGlyphLogicalBounds(glyphIndex); + Rectangle2D glyphRect = glyphBounds.getBounds2D(); + if (isVertical()) + { + if (leading) + info[0] = (float) glyphRect.getMinY(); + else + info[0] = (float) glyphRect.getMaxY(); + } + else + { + if (leading) + info[0] = (float) glyphRect.getMinX(); + else + info[0] = (float) glyphRect.getMaxX(); + } + info[0] += run.location; + info[1] = run.font.getItalicAngle(); + } + return info; + } + + public Shape getCaretShape(TextHitInfo hit) + { + return getCaretShape(hit, getBounds()); + } + + public Shape getCaretShape(TextHitInfo hit, Rectangle2D bounds) + { + // TODO: Handle vertical shapes somehow. + float[] info = getCaretInfo(hit); + float x1 = info[0]; + float y1 = (float) bounds.getMinY(); + float x2 = info[0]; + float y2 = (float) bounds.getMaxY(); + if (info[1] != 0) + { + // Shift x1 and x2 according to the slope. + x1 -= y1 * info[1]; + x2 -= y2 * info[1]; + } + GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 2); + path.moveTo(x1, y1); + path.lineTo(x2, y2); + return path; + } + + public Shape[] getCaretShapes(int offset) + { + return getCaretShapes(offset, getNaturalBounds()); + } + + public Shape[] getCaretShapes(int offset, Rectangle2D bounds) + { + return getCaretShapes(offset, bounds, DEFAULT_CARET_POLICY); + } + + public Shape[] getCaretShapes(int offset, Rectangle2D bounds, + CaretPolicy policy) + { + // The RI returns a 2-size array even when there's only one + // shape in it. + Shape[] carets = new Shape[2]; + TextHitInfo hit1 = TextHitInfo.afterOffset(offset); + int caretHit1 = hitToCaret(hit1); + TextHitInfo hit2 = hit1.getOtherHit(); + int caretHit2 = hitToCaret(hit2); + if (caretHit1 == caretHit2) + { + carets[0] = getCaretShape(hit1); + carets[1] = null; // The RI returns null in this seldom case. + } + else + { + Shape caret1 = getCaretShape(hit1); + Shape caret2 = getCaretShape(hit2); + TextHitInfo strong = policy.getStrongCaret(hit1, hit2, this); + if (strong == hit1) + { + carets[0] = caret1; + carets[1] = caret2; + } + else + { + carets[0] = caret2; + carets[1] = caret1; + } + } + return carets; + } + + public int getCharacterCount () + { + return length; + } + + public byte getCharacterLevel (int index) + { + byte level; + if( bidi == null ) + level = 0; + else + level = (byte) bidi.getLevelAt(index); + return level; + } + + public float getDescent () + { + return lm.getDescent(); + } + + public TextLayout getJustifiedLayout (float justificationWidth) + { + TextLayout newLayout = (TextLayout)clone(); + + if( hasWhitespace ) + newLayout.handleJustify( justificationWidth ); + + return newLayout; + } + + public float getLeading () + { + return lm.getLeading(); + } + + public Shape getLogicalHighlightShape (int firstEndpoint, int secondEndpoint) + { + return getLogicalHighlightShape( firstEndpoint, secondEndpoint, + getBounds() ); + } + + public Shape getLogicalHighlightShape (int firstEndpoint, int secondEndpoint, + Rectangle2D bounds) + { + if( secondEndpoint - firstEndpoint <= 0 ) + return new Rectangle2D.Float(); // Hmm? + + if( firstEndpoint < 0 || secondEndpoint > getCharacterCount()) + return new Rectangle2D.Float(); + + Rectangle2D r = null; + int ri = charIndices[ firstEndpoint ][0]; + int gi = charIndices[ firstEndpoint ][1]; + + double advance = 0; + + for( int i = 0; i < ri; i++ ) + advance += runs[i].glyphVector.getLogicalBounds().getWidth(); + + for( int i = ri; i <= charIndices[ secondEndpoint - 1 ][0]; i++ ) + { + Run run = runs[i]; + GlyphVector gv = run.glyphVector; + int dg; // last index in this run to use. + if( i == charIndices[ secondEndpoint - 1 ][0] ) + dg = charIndices[ secondEndpoint - 1][1]; + else + dg = gv.getNumGlyphs() - 1; + + for(; gi <= dg; gi++ ) + { + Rectangle2D r2 = (gv.getGlyphLogicalBounds( gi )). + getBounds2D(); + if( r == null ) + r = r2; + else + r = r.createUnion(r2); + } + gi = 0; // reset glyph index into run for next run. + + advance += gv.getLogicalBounds().getWidth(); + } + + return r; + } + + public int[] getLogicalRangesForVisualSelection (TextHitInfo firstEndpoint, + TextHitInfo secondEndpoint) + { + // Check parameters. + checkHitInfo(firstEndpoint); + checkHitInfo(secondEndpoint); + + // Convert to visual and order correctly. + int start = hitToCaret(firstEndpoint); + int end = hitToCaret(secondEndpoint); + if (start > end) + { + // Swap start and end so that end >= start. + int temp = start; + start = end; + end = temp; + } + + // Now walk through the visual indices and mark the included pieces. + boolean[] include = new boolean[length]; + for (int i = start; i < end; i++) + { + include[visualToLogical[i]] = true; + } + + // Count included runs. + int numRuns = 0; + boolean in = false; + for (int i = 0; i < length; i++) + { + if (include[i] != in) // At each run in/out point we toggle the in var. + { + in = ! in; + if (in) // At each run start we count up. + numRuns++; + } + } + + // Put together the ranges array. + int[] ranges = new int[numRuns * 2]; + int index = 0; + in = false; + for (int i = 0; i < length; i++) + { + if (include[i] != in) + { + ranges[index] = i; + index++; + in = ! in; + } + } + // If the last run ends at the very end, include that last bit too. + if (in) + ranges[index] = length; + + return ranges; + } + + public TextHitInfo getNextLeftHit(int offset) + { + return getNextLeftHit(offset, DEFAULT_CARET_POLICY); + } + + public TextHitInfo getNextLeftHit(int offset, CaretPolicy policy) + { + if (policy == null) + throw new IllegalArgumentException("Null policy not allowed"); + if (offset < 0 || offset > length) + throw new IllegalArgumentException("Offset out of bounds"); + + TextHitInfo hit1 = TextHitInfo.afterOffset(offset); + TextHitInfo hit2 = hit1.getOtherHit(); + + TextHitInfo strong = policy.getStrongCaret(hit1, hit2, this); + TextHitInfo next = getNextLeftHit(strong); + TextHitInfo ret = null; + if (next != null) + { + TextHitInfo next2 = getVisualOtherHit(next); + ret = policy.getStrongCaret(next2, next, this); + } + return ret; + } + + public TextHitInfo getNextLeftHit (TextHitInfo hit) + { + checkHitInfo(hit); + int index = hitToCaret(hit); + TextHitInfo next = null; + if (index != 0) + { + index--; + next = caretToHit(index); + } + return next; + } + + public TextHitInfo getNextRightHit(int offset) + { + return getNextRightHit(offset, DEFAULT_CARET_POLICY); + } + + public TextHitInfo getNextRightHit(int offset, CaretPolicy policy) + { + if (policy == null) + throw new IllegalArgumentException("Null policy not allowed"); + if (offset < 0 || offset > length) + throw new IllegalArgumentException("Offset out of bounds"); + + TextHitInfo hit1 = TextHitInfo.afterOffset(offset); + TextHitInfo hit2 = hit1.getOtherHit(); + + TextHitInfo next = getNextRightHit(policy.getStrongCaret(hit1, hit2, this)); + TextHitInfo ret = null; + if (next != null) + { + TextHitInfo next2 = getVisualOtherHit(next); + ret = policy.getStrongCaret(next2, next, this); + } + return ret; + } + + public TextHitInfo getNextRightHit(TextHitInfo hit) + { + checkHitInfo(hit); + int index = hitToCaret(hit); + TextHitInfo next = null; + if (index < length) + { + index++; + next = caretToHit(index); + } + return next; + } + + public Shape getOutline (AffineTransform tx) + { + float x = 0f; + GeneralPath gp = new GeneralPath(); + for(int i = 0; i < runs.length; i++) + { + GlyphVector gv = runs[i].glyphVector; + gp.append( gv.getOutline( x, 0f ), false ); + Rectangle2D r = gv.getLogicalBounds(); + x += r.getWidth(); + } + if( tx != null ) + gp.transform( tx ); + return gp; + } + + public float getVisibleAdvance () + { + float totalAdvance = 0f; + + if( runs.length <= 0 ) + return 0f; + + // No trailing whitespace + if( !Character.isWhitespace( string[offset + length - 1]) ) + return getAdvance(); + + // Get length of all runs up to the last + for(int i = 0; i < runs.length - 1; i++) + totalAdvance += runs[i].glyphVector.getLogicalBounds().getWidth(); + + int lastRun = runs[runs.length - 1].runStart; + int j = length - 1; + while( j >= lastRun && Character.isWhitespace( string[j] ) ) j--; + + if( j < lastRun ) + return totalAdvance; // entire last run is whitespace + + int lastNonWSChar = j - lastRun; + j = 0; + while( runs[ runs.length - 1 ].glyphVector.getGlyphCharIndex( j ) + <= lastNonWSChar ) + { + totalAdvance += runs[ runs.length - 1 ].glyphVector + .getGlyphLogicalBounds( j ) + .getBounds2D().getWidth(); + j ++; + } + + return totalAdvance; + } + + public Shape getVisualHighlightShape (TextHitInfo firstEndpoint, + TextHitInfo secondEndpoint) + { + return getVisualHighlightShape( firstEndpoint, secondEndpoint, + getBounds() ); + } + + public Shape getVisualHighlightShape (TextHitInfo firstEndpoint, + TextHitInfo secondEndpoint, + Rectangle2D bounds) + { + GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); + Shape caret1 = getCaretShape(firstEndpoint, bounds); + path.append(caret1, false); + Shape caret2 = getCaretShape(secondEndpoint, bounds); + path.append(caret2, false); + // Append left (top) bounds to selection if necessary. + int c1 = hitToCaret(firstEndpoint); + int c2 = hitToCaret(secondEndpoint); + if (c1 == 0 || c2 == 0) + { + path.append(left(bounds), false); + } + // Append right (bottom) bounds if necessary. + if (c1 == length || c2 == length) + { + path.append(right(bounds), false); + } + return path.getBounds2D(); + } + + /** + * Returns the shape that makes up the left (top) edge of this text layout. + * + * @param b the bounds + * + * @return the shape that makes up the left (top) edge of this text layout + */ + private Shape left(Rectangle2D b) + { + GeneralPath left = new GeneralPath(GeneralPath.WIND_EVEN_ODD); + left.append(getCaretShape(TextHitInfo.beforeOffset(0)), false); + if (isVertical()) + { + float y = (float) b.getMinY(); + left.append(new Line2D.Float((float) b.getMinX(), y, + (float) b.getMaxX(), y), false); + } + else + { + float x = (float) b.getMinX(); + left.append(new Line2D.Float(x, (float) b.getMinY(), + x, (float) b.getMaxY()), false); + } + return left.getBounds2D(); + } + + /** + * Returns the shape that makes up the right (bottom) edge of this text + * layout. + * + * @param b the bounds + * + * @return the shape that makes up the right (bottom) edge of this text + * layout + */ + private Shape right(Rectangle2D b) + { + GeneralPath right = new GeneralPath(GeneralPath.WIND_EVEN_ODD); + right.append(getCaretShape(TextHitInfo.afterOffset(length)), false); + if (isVertical()) + { + float y = (float) b.getMaxY(); + right.append(new Line2D.Float((float) b.getMinX(), y, + (float) b.getMaxX(), y), false); + } + else + { + float x = (float) b.getMaxX(); + right.append(new Line2D.Float(x, (float) b.getMinY(), + x, (float) b.getMaxY()), false); + } + return right.getBounds2D(); + } + + public TextHitInfo getVisualOtherHit (TextHitInfo hit) + { + checkHitInfo(hit); + int hitIndex = hit.getCharIndex(); + + int index; + boolean leading; + if (hitIndex == -1 || hitIndex == length) + { + // Boundary case. + int visual; + if (isLeftToRight() == (hitIndex == -1)) + visual = 0; + else + visual = length - 1; + index = visualToLogical[visual]; + if (isLeftToRight() == (hitIndex == -1)) + leading = isCharacterLTR(index); // LTR. + else + leading = ! isCharacterLTR(index); // RTL. + } + else + { + // Normal case. + int visual = logicalToVisual[hitIndex]; + boolean b; + if (isCharacterLTR(hitIndex) == hit.isLeadingEdge()) + { + visual--; + b = false; + } + else + { + visual++; + b = true; + } + if (visual >= 0 && visual < length) + { + index = visualToLogical[visual]; + leading = b == isLeftToRight(); + } + else + { + index = b == isLeftToRight() ? length : -1; + leading = index == length; + } + } + return leading ? TextHitInfo.leading(index) : TextHitInfo.trailing(index); + } + + /** + * This is a protected method of a <code>final</code> class, meaning + * it exists only to taunt you. + */ + protected void handleJustify (float justificationWidth) + { + // We assume that the text has non-trailing whitespace. + // First get the change in width to insert into the whitespaces. + double deltaW = justificationWidth - getVisibleAdvance(); + int nglyphs = 0; // # of whitespace chars + + // determine last non-whitespace char. + int lastNWS = offset + length - 1; + while( Character.isWhitespace( string[lastNWS] ) ) lastNWS--; + + // locations of the glyphs. + int[] wsglyphs = new int[length * 10]; + for(int run = 0; run < runs.length; run++ ) + { + Run current = runs[run]; + for(int i = 0; i < current.glyphVector.getNumGlyphs(); i++ ) + { + int cindex = current.runStart + + current.glyphVector.getGlyphCharIndex( i ); + if( Character.isWhitespace( string[cindex] ) ) + // && cindex < lastNWS ) + { + wsglyphs[ nglyphs * 2 ] = run; + wsglyphs[ nglyphs * 2 + 1] = i; + nglyphs++; + } + } + } + deltaW = deltaW / nglyphs; // Change in width per whitespace glyph + double w = 0; + int cws = 0; + // Shift all characters + for(int run = 0; run < runs.length; run++ ) + { + Run current = runs[run]; + for(int i = 0; i < current.glyphVector.getNumGlyphs(); i++ ) + { + if( wsglyphs[ cws * 2 ] == run && wsglyphs[ cws * 2 + 1 ] == i ) + { + cws++; // update 'current whitespace' + w += deltaW; // increment the shift + } + Point2D p = current.glyphVector.getGlyphPosition( i ); + p.setLocation( p.getX() + w, p.getY() ); + current.glyphVector.setGlyphPosition( i, p ); + } + } + } + + public TextHitInfo hitTestChar (float x, float y) + { + return hitTestChar(x, y, getNaturalBounds()); + } + + /** + * Finds the character hit at the specified point. This 'clips' this + * text layout against the specified <code>bounds</code> rectangle. That + * means that in the case where a point is outside these bounds, this method + * returns the leading edge of the first character or the trailing edge of + * the last character. + * + * @param x the X location to test + * @param y the Y location to test + * @param bounds the bounds to test against + * + * @return the character hit at the specified point + */ + public TextHitInfo hitTestChar (float x, float y, Rectangle2D bounds) + { + // Check bounds. + if (isVertical()) + { + if (y < bounds.getMinY()) + return TextHitInfo.leading(0); + else if (y > bounds.getMaxY()) + return TextHitInfo.trailing(getCharacterCount() - 1); + } + else + { + if (x < bounds.getMinX()) + return TextHitInfo.leading(0); + else if (x > bounds.getMaxX()) + return TextHitInfo.trailing(getCharacterCount() - 1); + } + + TextHitInfo hitInfo = null; + if (isVertical()) + { + // Search for the run at the location. + // TODO: Perform binary search for maximum efficiency. However, we + // need the run location laid out statically to do that. + int numRuns = runs.length; + Run hitRun = null; + for (int i = 0; i < numRuns && hitRun == null; i++) + { + Run run = runs[i]; + Rectangle2D lBounds = run.glyphVector.getLogicalBounds(); + if (lBounds.getMinY() + run.location <= y + && lBounds.getMaxY() + run.location >= y) + hitRun = run; + } + // Now we have (hopefully) found a run that hits. Now find the + // right character. + if (hitRun != null) + { + GlyphVector gv = hitRun.glyphVector; + for (int i = hitRun.runStart; + i < hitRun.runEnd && hitInfo == null; i++) + { + int gi = i - hitRun.runStart; + Rectangle2D lBounds = gv.getGlyphLogicalBounds(gi) + .getBounds2D(); + if (lBounds.getMinY() + hitRun.location <= y + && lBounds.getMaxY() + hitRun.location >= y) + { + // Found hit. Now check if we are leading or trailing. + boolean leading = true; + if (lBounds.getCenterY() + hitRun.location <= y) + leading = false; + hitInfo = leading ? TextHitInfo.leading(i) + : TextHitInfo.trailing(i); + } + } + } + } + else + { + // Search for the run at the location. + // TODO: Perform binary search for maximum efficiency. However, we + // need the run location laid out statically to do that. + int numRuns = runs.length; + Run hitRun = null; + for (int i = 0; i < numRuns && hitRun == null; i++) + { + Run run = runs[i]; + Rectangle2D lBounds = run.glyphVector.getLogicalBounds(); + if (lBounds.getMinX() + run.location <= x + && lBounds.getMaxX() + run.location >= x) + hitRun = run; + } + // Now we have (hopefully) found a run that hits. Now find the + // right character. + if (hitRun != null) + { + GlyphVector gv = hitRun.glyphVector; + for (int i = hitRun.runStart; + i < hitRun.runEnd && hitInfo == null; i++) + { + int gi = i - hitRun.runStart; + Rectangle2D lBounds = gv.getGlyphLogicalBounds(gi) + .getBounds2D(); + if (lBounds.getMinX() + hitRun.location <= x + && lBounds.getMaxX() + hitRun.location >= x) + { + // Found hit. Now check if we are leading or trailing. + boolean leading = true; + if (lBounds.getCenterX() + hitRun.location <= x) + leading = false; + hitInfo = leading ? TextHitInfo.leading(i) + : TextHitInfo.trailing(i); + } + } + } + } + return hitInfo; + } + + public boolean isLeftToRight () + { + return leftToRight; + } + + public boolean isVertical () + { + return false; // FIXME: How do you create a vertical layout? + } + + public int hashCode () + { + // This is implemented in sync to equals(). + if (hash == 0 && runs.length > 0) + { + hash = runs.length; + for (int i = 0; i < runs.length; i++) + hash ^= runs[i].glyphVector.hashCode(); + } + return hash; + } + + public String toString () + { + return "TextLayout [string:"+ new String(string, offset, length) + +" Rendercontext:"+ + frc+"]"; + } + + /** + * Returns the natural bounds of that text layout. This is made up + * of the ascent plus descent and the text advance. + * + * @return the natural bounds of that text layout + */ + private Rectangle2D getNaturalBounds() + { + if (naturalBounds == null) + naturalBounds = new Rectangle2D.Float(0.0F, -getAscent(), getAdvance(), + getAscent() + getDescent()); + return naturalBounds; + } + + private void checkHitInfo(TextHitInfo hit) + { + if (hit == null) + throw new IllegalArgumentException("Null hit info not allowed"); + int index = hit.getInsertionIndex(); + if (index < 0 || index > length) + throw new IllegalArgumentException("Hit index out of range"); + } + + private int hitToCaret(TextHitInfo hit) + { + int index = hit.getCharIndex(); + int ret; + if (index < 0) + ret = isLeftToRight() ? 0 : length; + else if (index >= length) + ret = isLeftToRight() ? length : 0; + else + { + ret = logicalToVisual[index]; + if (hit.isLeadingEdge() != isCharacterLTR(index)) + ret++; + } + return ret; + } + + private TextHitInfo caretToHit(int index) + { + TextHitInfo hit; + if (index == 0 || index == length) + { + if ((index == length) == isLeftToRight()) + hit = TextHitInfo.leading(length); + else + hit = TextHitInfo.trailing(-1); + } + else + { + int logical = visualToLogical[index]; + boolean leading = isCharacterLTR(logical); // LTR. + hit = leading ? TextHitInfo.leading(logical) + : TextHitInfo.trailing(logical); + } + return hit; + } + + private boolean isCharacterLTR(int index) + { + byte level = getCharacterLevel(index); + return (level & 1) == 0; + } + + /** + * Finds the run that holds the specified (logical) character index. This + * returns <code>null</code> when the index is not inside the range. + * + * @param index the index of the character to find + * + * @return the run that holds the specified character + */ + private Run findRunAtIndex(int index) + { + Run found = null; + // TODO: Can we do better than linear searching here? + for (int i = 0; i < runs.length && found == null; i++) + { + Run run = runs[i]; + if (run.runStart <= index && run.runEnd > index) + found = run; + } + return found; + } + + /** + * Computes the layout locations for each run. + */ + private void layoutRuns() + { + float loc = 0.0F; + float lastWidth = 0.0F; + for (int i = 0; i < runs.length; i++) + { + runs[i].location = loc; + Rectangle2D bounds = runs[i].glyphVector.getLogicalBounds(); + loc += isVertical() ? bounds.getHeight() : bounds.getWidth(); + } + } + + /** + * Inner class describing a caret policy + */ + public static class CaretPolicy + { + public CaretPolicy() + { + } + + public TextHitInfo getStrongCaret(TextHitInfo hit1, + TextHitInfo hit2, + TextLayout layout) + { + byte l1 = layout.getCharacterLevel(hit1.getCharIndex()); + byte l2 = layout.getCharacterLevel(hit2.getCharIndex()); + TextHitInfo strong; + if (l1 == l2) + { + if (hit2.isLeadingEdge() && ! hit1.isLeadingEdge()) + strong = hit2; + else + strong = hit1; + } + else + { + if (l1 < l2) + strong = hit1; + else + strong = hit2; + } + return strong; + } + } +} diff --git a/libjava/classpath/java/awt/font/TextMeasurer.java b/libjava/classpath/java/awt/font/TextMeasurer.java new file mode 100644 index 000000000..e443e8bc7 --- /dev/null +++ b/libjava/classpath/java/awt/font/TextMeasurer.java @@ -0,0 +1,190 @@ +/* TextMeasurer.java + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.font; + +import java.text.AttributedCharacterIterator; +import java.awt.Shape; + +/** + * TextMeasurer is a small utility class for measuring the length of laid-out + * text objects. + * + * @author Sven de Marothy + * @since 1.3 + */ +public final class TextMeasurer implements Cloneable +{ + private AttributedCharacterIterator text; + private FontRenderContext frc; + private TextLayout totalLayout; + private int numChars; + + /** + * Creates a TextMeasurer from a given text in the form of an + * <code>AttributedCharacterIterator</code> and a + * <code>FontRenderContext</code>. + */ + public TextMeasurer (AttributedCharacterIterator text, FontRenderContext frc) + { + this.text = text; + this.frc = frc; + totalLayout = new TextLayout( text, frc ); + numChars = totalLayout.getCharacterCount(); + } + + /** + * Clones the TextMeasurer object + */ + protected Object clone () + { + return new TextMeasurer( text, frc ); + } + + /** + * Update the text if a character is deleted at the position deletePos + * @param newParagraph - the updated paragraph. + * @param deletePos - the deletion position + */ + public void deleteChar (AttributedCharacterIterator newParagraph, + int deletePos) + { + totalLayout = new TextLayout(newParagraph, frc); + if( deletePos < 0 || deletePos > totalLayout.getCharacterCount() ) + throw new NullPointerException("Invalid deletePos:"+deletePos); + numChars = totalLayout.getCharacterCount(); + text = newParagraph; + } + + /** + * Update the text if a character is inserted at the position insertPos + * @param newParagraph - the updated paragraph. + * @param insertPos - the insertion position + */ + public void insertChar (AttributedCharacterIterator newParagraph, + int insertPos) + { + totalLayout = new TextLayout(newParagraph, frc); + if( insertPos < 0 || insertPos > totalLayout.getCharacterCount() ) + throw new NullPointerException("Invalid insertPos:"+insertPos); + numChars = totalLayout.getCharacterCount(); + text = newParagraph; + } + + /*** + * Returns the total advance between two positions in the paragraph. + * Characters from start to limit-1 (inclusive) are included in this count. + * + * @param start - the starting character index. + * @param limit - the limiting index. + */ + public float getAdvanceBetween (int start, int limit) + { + Shape s = totalLayout.getLogicalHighlightShape( start, limit ); + return (float)s.getBounds2D().getWidth(); + } + + /** + * Returns a <code>TextLayout</code> object corresponding to the characters + * from text to limit. + * @param start - the starting character index. + * @param limit - the limiting index. + */ + public TextLayout getLayout (int start, int limit) + { + if( start >= limit ) + throw new IllegalArgumentException("Start position must be < limit."); + return new TextLayout( totalLayout, start, limit ); + } + + /** + * Returns the line-break index from a given starting index and a maximum + * advance. The index returned is the first character outside the given + * advance (or the limit of the string, if all remaining characters fit.) + * + * @param start - the starting index. + * @param maxAdvance - the maximum advance allowed. + * @return the index of the first character beyond maxAdvance, or the + * index of the last character + 1. + */ + public int getLineBreakIndex (int start, float maxAdvance) + { + if( start < 0 ) + throw new IllegalArgumentException("Start parameter must be > 0."); + + double remainingLength = getAdvanceBetween( start, numChars ); + + int guessOffset = (int)( ( (double)maxAdvance / (double)remainingLength) + * ( (double)numChars - (double)start ) ); + guessOffset += start; + if( guessOffset > numChars ) + guessOffset = numChars; + + double guessLength = getAdvanceBetween( start, guessOffset ); + boolean makeSmaller = ( guessLength > maxAdvance ); + int inc = makeSmaller ? -1 : 1; + boolean keepGoing = true; + + do + { + guessOffset = guessOffset + inc; + if( guessOffset <= start || guessOffset > numChars ) + { + keepGoing = false; + } + else + { + guessLength = getAdvanceBetween( start, guessOffset ); + if( makeSmaller && ( guessLength <= maxAdvance) ) + keepGoing = false; + if( !makeSmaller && ( guessLength >= maxAdvance) ) + keepGoing = false; + } + } + while( keepGoing ); + + // Return first index that doesn't fit. + if( !makeSmaller ) + guessOffset--; + + if( guessOffset > numChars ) + return numChars; + + return guessOffset; + } +} diff --git a/libjava/classpath/java/awt/font/TransformAttribute.java b/libjava/classpath/java/awt/font/TransformAttribute.java new file mode 100644 index 000000000..56d15bb0b --- /dev/null +++ b/libjava/classpath/java/awt/font/TransformAttribute.java @@ -0,0 +1,100 @@ +/* TransformAttribute.java -- + Copyright (C) 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.font; + +import java.awt.geom.AffineTransform; +import java.io.Serializable; + +/** + * This class provides a mechanism for using an {@link AffineTransform} as + * an <i>immutable</i> attribute (for example, in the + * {@link java.text.AttributedString} class). Any transform passed to + * this class is copied before being stored, and any transform handed out + * by this class is a copy of the stored transform. In this way, it is + * not possible to modify the stored transform. + * + * @author Michael Koch + */ +public final class TransformAttribute implements Serializable +{ + private static final long serialVersionUID = 3356247357827709530L; + + private AffineTransform affineTransform; + + /** + * Creates a new attribute that contains a copy of the given transform. + * + * @param transform the transform (<code>null</code> not permitted). + * + * @throws IllegalArgumentException if <code>transform</code> is + * <code>null</code>. + */ + public TransformAttribute (AffineTransform transform) + { + if (transform == null) + { + throw new IllegalArgumentException("Null 'transform' not permitted."); + } + this.affineTransform = new AffineTransform (transform); + } + + /** + * Returns a copy of the transform contained by this attribute. + * + * @return A copy of the transform. + */ + public AffineTransform getTransform () + { + return (AffineTransform) affineTransform.clone(); + } + + /** + * Returns <code>true</code> if the transform contained by this attribute is + * an identity transform, and <code>false</code> otherwise. + * + * @return <code>true</code> if the transform contained by this attribute is + * an identity transform, and <code>false</code> otherwise. + * + * @since 1.4 + */ + public boolean isIdentity () + { + return (affineTransform == null ? false : affineTransform.isIdentity ()); + } +} diff --git a/libjava/classpath/java/awt/font/package.html b/libjava/classpath/java/awt/font/package.html new file mode 100644 index 000000000..8c3c61a40 --- /dev/null +++ b/libjava/classpath/java/awt/font/package.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in java.awt.font package. + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - java.awt.font</title></head> + +<body> +<p>Representations of different kind of characters and fonts.</p> + +</body> +</html> diff --git a/libjava/classpath/java/awt/geom/AffineTransform.java b/libjava/classpath/java/awt/geom/AffineTransform.java new file mode 100644 index 000000000..42590efce --- /dev/null +++ b/libjava/classpath/java/awt/geom/AffineTransform.java @@ -0,0 +1,1489 @@ +/* AffineTransform.java -- transform coordinates between two 2-D spaces + Copyright (C) 2000, 2001, 2002, 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.geom; + +import java.awt.Shape; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; + +/** + * This class represents an affine transformation between two coordinate + * spaces in 2 dimensions. Such a transform preserves the "straightness" + * and "parallelness" of lines. The transform is built from a sequence of + * translations, scales, flips, rotations, and shears. + * + * <p>The transformation can be represented using matrix math on a 3x3 array. + * Given (x,y), the transformation (x',y') can be found by: + * <pre> + * [ x'] [ m00 m01 m02 ] [ x ] [ m00*x + m01*y + m02 ] + * [ y'] = [ m10 m11 m12 ] [ y ] = [ m10*x + m11*y + m12 ] + * [ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ] + * </pre> + * The bottom row of the matrix is constant, so a transform can be uniquely + * represented (as in {@link #toString()}) by + * "[[m00, m01, m02], [m10, m11, m12]]". + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status partially updated to 1.4, still has some problems + */ +public class AffineTransform implements Cloneable, Serializable +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 1330973210523860834L; + + /** + * The transformation is the identity (x' = x, y' = y). All other transforms + * have either a combination of the appropriate transform flag bits for + * their type, or the type GENERAL_TRANSFORM. + * + * @see #TYPE_TRANSLATION + * @see #TYPE_UNIFORM_SCALE + * @see #TYPE_GENERAL_SCALE + * @see #TYPE_FLIP + * @see #TYPE_QUADRANT_ROTATION + * @see #TYPE_GENERAL_ROTATION + * @see #TYPE_GENERAL_TRANSFORM + * @see #getType() + */ + public static final int TYPE_IDENTITY = 0; + + /** + * The transformation includes a translation - shifting in the x or y + * direction without changing length or angles. + * + * @see #TYPE_IDENTITY + * @see #TYPE_UNIFORM_SCALE + * @see #TYPE_GENERAL_SCALE + * @see #TYPE_FLIP + * @see #TYPE_QUADRANT_ROTATION + * @see #TYPE_GENERAL_ROTATION + * @see #TYPE_GENERAL_TRANSFORM + * @see #getType() + */ + public static final int TYPE_TRANSLATION = 1; + + /** + * The transformation includes a uniform scale - length is scaled in both + * the x and y directions by the same amount, without affecting angles. + * This is mutually exclusive with TYPE_GENERAL_SCALE. + * + * @see #TYPE_IDENTITY + * @see #TYPE_TRANSLATION + * @see #TYPE_GENERAL_SCALE + * @see #TYPE_FLIP + * @see #TYPE_QUADRANT_ROTATION + * @see #TYPE_GENERAL_ROTATION + * @see #TYPE_GENERAL_TRANSFORM + * @see #TYPE_MASK_SCALE + * @see #getType() + */ + public static final int TYPE_UNIFORM_SCALE = 2; + + /** + * The transformation includes a general scale - length is scaled in either + * or both the x and y directions, but by different amounts; without + * affecting angles. This is mutually exclusive with TYPE_UNIFORM_SCALE. + * + * @see #TYPE_IDENTITY + * @see #TYPE_TRANSLATION + * @see #TYPE_UNIFORM_SCALE + * @see #TYPE_FLIP + * @see #TYPE_QUADRANT_ROTATION + * @see #TYPE_GENERAL_ROTATION + * @see #TYPE_GENERAL_TRANSFORM + * @see #TYPE_MASK_SCALE + * @see #getType() + */ + public static final int TYPE_GENERAL_SCALE = 4; + + /** + * This constant checks if either variety of scale transform is performed. + * + * @see #TYPE_UNIFORM_SCALE + * @see #TYPE_GENERAL_SCALE + */ + public static final int TYPE_MASK_SCALE = 6; + + /** + * The transformation includes a flip about an axis, swapping between + * right-handed and left-handed coordinate systems. In a right-handed + * system, the positive x-axis rotates counter-clockwise to the positive + * y-axis; in a left-handed system it rotates clockwise. + * + * @see #TYPE_IDENTITY + * @see #TYPE_TRANSLATION + * @see #TYPE_UNIFORM_SCALE + * @see #TYPE_GENERAL_SCALE + * @see #TYPE_QUADRANT_ROTATION + * @see #TYPE_GENERAL_ROTATION + * @see #TYPE_GENERAL_TRANSFORM + * @see #getType() + */ + public static final int TYPE_FLIP = 64; + + /** + * The transformation includes a rotation of a multiple of 90 degrees (PI/2 + * radians). Angles are rotated, but length is preserved. This is mutually + * exclusive with TYPE_GENERAL_ROTATION. + * + * @see #TYPE_IDENTITY + * @see #TYPE_TRANSLATION + * @see #TYPE_UNIFORM_SCALE + * @see #TYPE_GENERAL_SCALE + * @see #TYPE_FLIP + * @see #TYPE_GENERAL_ROTATION + * @see #TYPE_GENERAL_TRANSFORM + * @see #TYPE_MASK_ROTATION + * @see #getType() + */ + public static final int TYPE_QUADRANT_ROTATION = 8; + + /** + * The transformation includes a rotation by an arbitrary angle. Angles are + * rotated, but length is preserved. This is mutually exclusive with + * TYPE_QUADRANT_ROTATION. + * + * @see #TYPE_IDENTITY + * @see #TYPE_TRANSLATION + * @see #TYPE_UNIFORM_SCALE + * @see #TYPE_GENERAL_SCALE + * @see #TYPE_FLIP + * @see #TYPE_QUADRANT_ROTATION + * @see #TYPE_GENERAL_TRANSFORM + * @see #TYPE_MASK_ROTATION + * @see #getType() + */ + public static final int TYPE_GENERAL_ROTATION = 16; + + /** + * This constant checks if either variety of rotation is performed. + * + * @see #TYPE_QUADRANT_ROTATION + * @see #TYPE_GENERAL_ROTATION + */ + public static final int TYPE_MASK_ROTATION = 24; + + /** + * The transformation is an arbitrary conversion of coordinates which + * could not be decomposed into the other TYPEs. + * + * @see #TYPE_IDENTITY + * @see #TYPE_TRANSLATION + * @see #TYPE_UNIFORM_SCALE + * @see #TYPE_GENERAL_SCALE + * @see #TYPE_FLIP + * @see #TYPE_QUADRANT_ROTATION + * @see #TYPE_GENERAL_ROTATION + * @see #getType() + */ + public static final int TYPE_GENERAL_TRANSFORM = 32; + + /** + * The X coordinate scaling element of the transform matrix. + * + * @serial matrix[0,0] + */ + private double m00; + + /** + * The Y coordinate shearing element of the transform matrix. + * + * @serial matrix[1,0] + */ + private double m10; + + /** + * The X coordinate shearing element of the transform matrix. + * + * @serial matrix[0,1] + */ + private double m01; + + /** + * The Y coordinate scaling element of the transform matrix. + * + * @serial matrix[1,1] + */ + private double m11; + + /** + * The X coordinate translation element of the transform matrix. + * + * @serial matrix[0,2] + */ + private double m02; + + /** + * The Y coordinate translation element of the transform matrix. + * + * @serial matrix[1,2] + */ + private double m12; + + /** The type of this transform. */ + private transient int type; + + /** + * Construct a new identity transform: + * <pre> + * [ 1 0 0 ] + * [ 0 1 0 ] + * [ 0 0 1 ] + * </pre> + */ + public AffineTransform() + { + m00 = m11 = 1; + } + + /** + * Create a new transform which copies the given one. + * + * @param tx the transform to copy + * @throws NullPointerException if tx is null + */ + public AffineTransform(AffineTransform tx) + { + setTransform(tx); + } + + /** + * Construct a transform with the given matrix entries: + * <pre> + * [ m00 m01 m02 ] + * [ m10 m11 m12 ] + * [ 0 0 1 ] + * </pre> + * + * @param m00 the x scaling component + * @param m10 the y shearing component + * @param m01 the x shearing component + * @param m11 the y scaling component + * @param m02 the x translation component + * @param m12 the y translation component + */ + public AffineTransform(float m00, float m10, + float m01, float m11, + float m02, float m12) + { + this.m00 = m00; + this.m10 = m10; + this.m01 = m01; + this.m11 = m11; + this.m02 = m02; + this.m12 = m12; + updateType(); + } + + /** + * Construct a transform from a sequence of float entries. The array must + * have at least 4 entries, which has a translation factor of 0; or 6 + * entries, for specifying all parameters: + * <pre> + * [ f[0] f[2] (f[4]) ] + * [ f[1] f[3] (f[5]) ] + * [ 0 0 1 ] + * </pre> + * + * @param f the matrix to copy from, with at least 4 (6) entries + * @throws NullPointerException if f is null + * @throws ArrayIndexOutOfBoundsException if f is too small + */ + public AffineTransform(float[] f) + { + m00 = f[0]; + m10 = f[1]; + m01 = f[2]; + m11 = f[3]; + if (f.length >= 6) + { + m02 = f[4]; + m12 = f[5]; + } + updateType(); + } + + /** + * Construct a transform with the given matrix entries: + * <pre> + * [ m00 m01 m02 ] + * [ m10 m11 m12 ] + * [ 0 0 1 ] + * </pre> + * + * @param m00 the x scaling component + * @param m10 the y shearing component + * @param m01 the x shearing component + * @param m11 the y scaling component + * @param m02 the x translation component + * @param m12 the y translation component + */ + public AffineTransform(double m00, double m10, double m01, + double m11, double m02, double m12) + { + this.m00 = m00; + this.m10 = m10; + this.m01 = m01; + this.m11 = m11; + this.m02 = m02; + this.m12 = m12; + updateType(); + } + + /** + * Construct a transform from a sequence of double entries. The array must + * have at least 4 entries, which has a translation factor of 0; or 6 + * entries, for specifying all parameters: + * <pre> + * [ d[0] d[2] (d[4]) ] + * [ d[1] d[3] (d[5]) ] + * [ 0 0 1 ] + * </pre> + * + * @param d the matrix to copy from, with at least 4 (6) entries + * @throws NullPointerException if d is null + * @throws ArrayIndexOutOfBoundsException if d is too small + */ + public AffineTransform(double[] d) + { + m00 = d[0]; + m10 = d[1]; + m01 = d[2]; + m11 = d[3]; + if (d.length >= 6) + { + m02 = d[4]; + m12 = d[5]; + } + updateType(); + } + + /** + * Returns a translation transform: + * <pre> + * [ 1 0 tx ] + * [ 0 1 ty ] + * [ 0 0 1 ] + * </pre> + * + * @param tx the x translation distance + * @param ty the y translation distance + * @return the translating transform + */ + public static AffineTransform getTranslateInstance(double tx, double ty) + { + AffineTransform t = new AffineTransform(); + t.m02 = tx; + t.m12 = ty; + t.type = (tx == 0 && ty == 0) ? TYPE_UNIFORM_SCALE : TYPE_TRANSLATION; + return t; + } + + /** + * Returns a rotation transform. A positive angle (in radians) rotates + * the positive x-axis to the positive y-axis: + * <pre> + * [ cos(theta) -sin(theta) 0 ] + * [ sin(theta) cos(theta) 0 ] + * [ 0 0 1 ] + * </pre> + * + * @param theta the rotation angle + * @return the rotating transform + */ + public static AffineTransform getRotateInstance(double theta) + { + AffineTransform t = new AffineTransform(); + t.setToRotation(theta); + return t; + } + + /** + * Returns a rotation transform about a point. A positive angle (in radians) + * rotates the positive x-axis to the positive y-axis. This is the same + * as calling: + * <pre> + * AffineTransform tx = new AffineTransform(); + * tx.setToTranslation(x, y); + * tx.rotate(theta); + * tx.translate(-x, -y); + * </pre> + * + * <p>The resulting matrix is: + * <pre> + * [ cos(theta) -sin(theta) x-x*cos+y*sin ] + * [ sin(theta) cos(theta) y-x*sin-y*cos ] + * [ 0 0 1 ] + * </pre> + * + * @param theta the rotation angle + * @param x the x coordinate of the pivot point + * @param y the y coordinate of the pivot point + * @return the rotating transform + */ + public static AffineTransform getRotateInstance(double theta, + double x, double y) + { + AffineTransform t = new AffineTransform(); + t.setToTranslation(x, y); + t.rotate(theta); + t.translate(-x, -y); + return t; + } + + /** + * Returns a scaling transform: + * <pre> + * [ sx 0 0 ] + * [ 0 sy 0 ] + * [ 0 0 1 ] + * </pre> + * + * @param sx the x scaling factor + * @param sy the y scaling factor + * @return the scaling transform + */ + public static AffineTransform getScaleInstance(double sx, double sy) + { + AffineTransform t = new AffineTransform(); + t.setToScale(sx, sy); + return t; + } + + /** + * Returns a shearing transform (points are shifted in the x direction based + * on a factor of their y coordinate, and in the y direction as a factor of + * their x coordinate): + * <pre> + * [ 1 shx 0 ] + * [ shy 1 0 ] + * [ 0 0 1 ] + * </pre> + * + * @param shx the x shearing factor + * @param shy the y shearing factor + * @return the shearing transform + */ + public static AffineTransform getShearInstance(double shx, double shy) + { + AffineTransform t = new AffineTransform(); + t.setToShear(shx, shy); + return t; + } + + /** + * Returns the type of this transform. The result is always valid, although + * it may not be the simplest interpretation (in other words, there are + * sequences of transforms which reduce to something simpler, which this + * does not always detect). The result is either TYPE_GENERAL_TRANSFORM, + * or a bit-wise combination of TYPE_TRANSLATION, the mutually exclusive + * TYPE_*_ROTATIONs, and the mutually exclusive TYPE_*_SCALEs. + * + * @return The type. + * + * @see #TYPE_IDENTITY + * @see #TYPE_TRANSLATION + * @see #TYPE_UNIFORM_SCALE + * @see #TYPE_GENERAL_SCALE + * @see #TYPE_QUADRANT_ROTATION + * @see #TYPE_GENERAL_ROTATION + * @see #TYPE_GENERAL_TRANSFORM + */ + public int getType() + { + return type; + } + + /** + * Return the determinant of this transform matrix. If the determinant is + * non-zero, the transform is invertible; otherwise operations which require + * an inverse throw a NoninvertibleTransformException. A result very near + * zero, due to rounding errors, may indicate that inversion results do not + * carry enough precision to be meaningful. + * + * <p>If this is a uniform scale transformation, the determinant also + * represents the squared value of the scale. Otherwise, it carries little + * additional meaning. The determinant is calculated as: + * <pre> + * | m00 m01 m02 | + * | m10 m11 m12 | = m00 * m11 - m01 * m10 + * | 0 0 1 | + * </pre> + * + * @return the determinant + * @see #createInverse() + */ + public double getDeterminant() + { + return m00 * m11 - m01 * m10; + } + + /** + * Return the matrix of values used in this transform. If the matrix has + * fewer than 6 entries, only the scale and shear factors are returned; + * otherwise the translation factors are copied as well. The resulting + * values are: + * <pre> + * [ d[0] d[2] (d[4]) ] + * [ d[1] d[3] (d[5]) ] + * [ 0 0 1 ] + * </pre> + * + * @param d the matrix to store the results into; with 4 (6) entries + * @throws NullPointerException if d is null + * @throws ArrayIndexOutOfBoundsException if d is too small + */ + public void getMatrix(double[] d) + { + d[0] = m00; + d[1] = m10; + d[2] = m01; + d[3] = m11; + if (d.length >= 6) + { + d[4] = m02; + d[5] = m12; + } + } + + /** + * Returns the X coordinate scaling factor of the matrix. + * + * @return m00 + * @see #getMatrix(double[]) + */ + public double getScaleX() + { + return m00; + } + + /** + * Returns the Y coordinate scaling factor of the matrix. + * + * @return m11 + * @see #getMatrix(double[]) + */ + public double getScaleY() + { + return m11; + } + + /** + * Returns the X coordinate shearing factor of the matrix. + * + * @return m01 + * @see #getMatrix(double[]) + */ + public double getShearX() + { + return m01; + } + + /** + * Returns the Y coordinate shearing factor of the matrix. + * + * @return m10 + * @see #getMatrix(double[]) + */ + public double getShearY() + { + return m10; + } + + /** + * Returns the X coordinate translation factor of the matrix. + * + * @return m02 + * @see #getMatrix(double[]) + */ + public double getTranslateX() + { + return m02; + } + + /** + * Returns the Y coordinate translation factor of the matrix. + * + * @return m12 + * @see #getMatrix(double[]) + */ + public double getTranslateY() + { + return m12; + } + + /** + * Concatenate a translation onto this transform. This is equivalent, but + * more efficient than + * <code>concatenate(AffineTransform.getTranslateInstance(tx, ty))</code>. + * + * @param tx the x translation distance + * @param ty the y translation distance + * @see #getTranslateInstance(double, double) + * @see #concatenate(AffineTransform) + */ + public void translate(double tx, double ty) + { + m02 += tx * m00 + ty * m01; + m12 += tx * m10 + ty * m11; + updateType(); + } + + /** + * Concatenate a rotation onto this transform. This is equivalent, but + * more efficient than + * <code>concatenate(AffineTransform.getRotateInstance(theta))</code>. + * + * @param theta the rotation angle + * @see #getRotateInstance(double) + * @see #concatenate(AffineTransform) + */ + public void rotate(double theta) + { + double c = Math.cos(theta); + double s = Math.sin(theta); + double n00 = m00 * c + m01 * s; + double n01 = m00 * -s + m01 * c; + double n10 = m10 * c + m11 * s; + double n11 = m10 * -s + m11 * c; + m00 = n00; + m01 = n01; + m10 = n10; + m11 = n11; + updateType(); + } + + /** + * Concatenate a rotation about a point onto this transform. This is + * equivalent, but more efficient than + * <code>concatenate(AffineTransform.getRotateInstance(theta, x, y))</code>. + * + * @param theta the rotation angle + * @param x the x coordinate of the pivot point + * @param y the y coordinate of the pivot point + * @see #getRotateInstance(double, double, double) + * @see #concatenate(AffineTransform) + */ + public void rotate(double theta, double x, double y) + { + translate(x, y); + rotate(theta); + translate(-x, -y); + } + + /** + * Concatenate a scale onto this transform. This is equivalent, but more + * efficient than + * <code>concatenate(AffineTransform.getScaleInstance(sx, sy))</code>. + * + * @param sx the x scaling factor + * @param sy the y scaling factor + * @see #getScaleInstance(double, double) + * @see #concatenate(AffineTransform) + */ + public void scale(double sx, double sy) + { + m00 *= sx; + m01 *= sy; + m10 *= sx; + m11 *= sy; + updateType(); + } + + /** + * Concatenate a shearing onto this transform. This is equivalent, but more + * efficient than + * <code>concatenate(AffineTransform.getShearInstance(sx, sy))</code>. + * + * @param shx the x shearing factor + * @param shy the y shearing factor + * @see #getShearInstance(double, double) + * @see #concatenate(AffineTransform) + */ + public void shear(double shx, double shy) + { + double n00 = m00 + (shy * m01); + double n01 = m01 + (shx * m00); + double n10 = m10 + (shy * m11); + double n11 = m11 + (shx * m10); + m00 = n00; + m01 = n01; + m10 = n10; + m11 = n11; + updateType(); + } + + /** + * Reset this transform to the identity (no transformation): + * <pre> + * [ 1 0 0 ] + * [ 0 1 0 ] + * [ 0 0 1 ] + * </pre> + */ + public void setToIdentity() + { + m00 = m11 = 1; + m01 = m02 = m10 = m12 = 0; + type = TYPE_IDENTITY; + } + + /** + * Set this transform to a translation: + * <pre> + * [ 1 0 tx ] + * [ 0 1 ty ] + * [ 0 0 1 ] + * </pre> + * + * @param tx the x translation distance + * @param ty the y translation distance + */ + public void setToTranslation(double tx, double ty) + { + m00 = m11 = 1; + m01 = m10 = 0; + m02 = tx; + m12 = ty; + type = (tx == 0 && ty == 0) ? TYPE_UNIFORM_SCALE : TYPE_TRANSLATION; + } + + /** + * Set this transform to a rotation. A positive angle (in radians) rotates + * the positive x-axis to the positive y-axis: + * <pre> + * [ cos(theta) -sin(theta) 0 ] + * [ sin(theta) cos(theta) 0 ] + * [ 0 0 1 ] + * </pre> + * + * @param theta the rotation angle + */ + public void setToRotation(double theta) + { + double c = Math.cos(theta); + double s = Math.sin(theta); + m00 = c; + m01 = -s; + m02 = 0; + m10 = s; + m11 = c; + m12 = 0; + type = (c == 1 ? TYPE_IDENTITY + : c == 0 || c == -1 ? TYPE_QUADRANT_ROTATION + : TYPE_GENERAL_ROTATION); + } + + /** + * Set this transform to a rotation about a point. A positive angle (in + * radians) rotates the positive x-axis to the positive y-axis. This is the + * same as calling: + * <pre> + * tx.setToTranslation(x, y); + * tx.rotate(theta); + * tx.translate(-x, -y); + * </pre> + * + * <p>The resulting matrix is: + * <pre> + * [ cos(theta) -sin(theta) x-x*cos+y*sin ] + * [ sin(theta) cos(theta) y-x*sin-y*cos ] + * [ 0 0 1 ] + * </pre> + * + * @param theta the rotation angle + * @param x the x coordinate of the pivot point + * @param y the y coordinate of the pivot point + */ + public void setToRotation(double theta, double x, double y) + { + double c = Math.cos(theta); + double s = Math.sin(theta); + m00 = c; + m01 = -s; + m02 = x - x * c + y * s; + m10 = s; + m11 = c; + m12 = y - x * s - y * c; + updateType(); + } + + /** + * Set this transform to a scale: + * <pre> + * [ sx 0 0 ] + * [ 0 sy 0 ] + * [ 0 0 1 ] + * </pre> + * + * @param sx the x scaling factor + * @param sy the y scaling factor + */ + public void setToScale(double sx, double sy) + { + m00 = sx; + m01 = m02 = m10 = m12 = 0; + m11 = sy; + type = (sx != sy ? TYPE_GENERAL_SCALE + : sx == 1 ? TYPE_IDENTITY : TYPE_UNIFORM_SCALE); + } + + /** + * Set this transform to a shear (points are shifted in the x direction based + * on a factor of their y coordinate, and in the y direction as a factor of + * their x coordinate): + * <pre> + * [ 1 shx 0 ] + * [ shy 1 0 ] + * [ 0 0 1 ] + * </pre> + * + * @param shx the x shearing factor + * @param shy the y shearing factor + */ + public void setToShear(double shx, double shy) + { + m00 = m11 = 1; + m01 = shx; + m10 = shy; + m02 = m12 = 0; + updateType(); + } + + /** + * Set this transform to a copy of the given one. + * + * @param tx the transform to copy + * @throws NullPointerException if tx is null + */ + public void setTransform(AffineTransform tx) + { + m00 = tx.m00; + m01 = tx.m01; + m02 = tx.m02; + m10 = tx.m10; + m11 = tx.m11; + m12 = tx.m12; + type = tx.type; + } + + /** + * Set this transform to the given values: + * <pre> + * [ m00 m01 m02 ] + * [ m10 m11 m12 ] + * [ 0 0 1 ] + * </pre> + * + * @param m00 the x scaling component + * @param m10 the y shearing component + * @param m01 the x shearing component + * @param m11 the y scaling component + * @param m02 the x translation component + * @param m12 the y translation component + */ + public void setTransform(double m00, double m10, double m01, + double m11, double m02, double m12) + { + this.m00 = m00; + this.m10 = m10; + this.m01 = m01; + this.m11 = m11; + this.m02 = m02; + this.m12 = m12; + updateType(); + } + + /** + * Set this transform to the result of performing the original version of + * this followed by tx. This is commonly used when chaining transformations + * from one space to another. In matrix form: + * <pre> + * [ this ] = [ this ] x [ tx ] + * </pre> + * + * @param tx the transform to concatenate + * @throws NullPointerException if tx is null + * @see #preConcatenate(AffineTransform) + */ + public void concatenate(AffineTransform tx) + { + double n00 = m00 * tx.m00 + m01 * tx.m10; + double n01 = m00 * tx.m01 + m01 * tx.m11; + double n02 = m00 * tx.m02 + m01 * tx.m12 + m02; + double n10 = m10 * tx.m00 + m11 * tx.m10; + double n11 = m10 * tx.m01 + m11 * tx.m11; + double n12 = m10 * tx.m02 + m11 * tx.m12 + m12; + m00 = n00; + m01 = n01; + m02 = n02; + m10 = n10; + m11 = n11; + m12 = n12; + updateType(); + } + + /** + * Set this transform to the result of performing tx followed by the + * original version of this. This is less common than normal concatenation, + * but can still be used to chain transformations from one space to another. + * In matrix form: + * <pre> + * [ this ] = [ tx ] x [ this ] + * </pre> + * + * @param tx the transform to concatenate + * @throws NullPointerException if tx is null + * @see #concatenate(AffineTransform) + */ + public void preConcatenate(AffineTransform tx) + { + double n00 = tx.m00 * m00 + tx.m01 * m10; + double n01 = tx.m00 * m01 + tx.m01 * m11; + double n02 = tx.m00 * m02 + tx.m01 * m12 + tx.m02; + double n10 = tx.m10 * m00 + tx.m11 * m10; + double n11 = tx.m10 * m01 + tx.m11 * m11; + double n12 = tx.m10 * m02 + tx.m11 * m12 + tx.m12; + m00 = n00; + m01 = n01; + m02 = n02; + m10 = n10; + m11 = n11; + m12 = n12; + updateType(); + } + + /** + * Returns a transform, which if concatenated to this one, will result in + * the identity transform. This is useful for undoing transformations, but + * is only possible if the original transform has an inverse (ie. does not + * map multiple points to the same line or point). A transform exists only + * if getDeterminant() has a non-zero value. + * + * The inverse is calculated as: + * + * <pre> + * + * Let A be the matrix for which we want to find the inverse: + * + * A = [ m00 m01 m02 ] + * [ m10 m11 m12 ] + * [ 0 0 1 ] + * + * + * 1 + * inverse (A) = --- x adjoint(A) + * det + * + * + * + * = 1 [ m11 -m01 m01*m12-m02*m11 ] + * --- x [ -m10 m00 -m00*m12+m10*m02 ] + * det [ 0 0 m00*m11-m10*m01 ] + * + * + * + * = [ m11/det -m01/det m01*m12-m02*m11/det ] + * [ -m10/det m00/det -m00*m12+m10*m02/det ] + * [ 0 0 1 ] + * + * + * </pre> + * + * + * + * @return a new inverse transform + * @throws NoninvertibleTransformException if inversion is not possible + * @see #getDeterminant() + */ + public AffineTransform createInverse() + throws NoninvertibleTransformException + { + double det = getDeterminant(); + if (det == 0) + throw new NoninvertibleTransformException("can't invert transform"); + + double im00 = m11 / det; + double im10 = -m10 / det; + double im01 = -m01 / det; + double im11 = m00 / det; + double im02 = (m01 * m12 - m02 * m11) / det; + double im12 = (-m00 * m12 + m10 * m02) / det; + + return new AffineTransform (im00, im10, im01, im11, im02, im12); + } + + /** + * Perform this transformation on the given source point, and store the + * result in the destination (creating it if necessary). It is safe for + * src and dst to be the same. + * + * @param src the source point + * @param dst the destination, or null + * @return the transformation of src, in dst if it was non-null + * @throws NullPointerException if src is null + */ + public Point2D transform(Point2D src, Point2D dst) + { + if (dst == null) + dst = new Point2D.Double(); + double x = src.getX(); + double y = src.getY(); + double nx = m00 * x + m01 * y + m02; + double ny = m10 * x + m11 * y + m12; + dst.setLocation(nx, ny); + return dst; + } + + /** + * Perform this transformation on an array of points, storing the results + * in another (possibly same) array. This will not create a destination + * array, but will create points for the null entries of the destination. + * The transformation is done sequentially. While having a single source + * and destination point be the same is safe, you should be aware that + * duplicate references to the same point in the source, and having the + * source overlap the destination, may result in your source points changing + * from a previous transform before it is their turn to be evaluated. + * + * @param src the array of source points + * @param srcOff the starting offset into src + * @param dst the array of destination points (may have null entries) + * @param dstOff the starting offset into dst + * @param num the number of points to transform + * @throws NullPointerException if src or dst is null, or src has null + * entries + * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded + * @throws ArrayStoreException if new points are incompatible with dst + */ + public void transform(Point2D[] src, int srcOff, + Point2D[] dst, int dstOff, int num) + { + while (--num >= 0) + dst[dstOff] = transform(src[srcOff++], dst[dstOff++]); + } + + /** + * Perform this transformation on an array of points, in (x,y) pairs, + * storing the results in another (possibly same) array. This will not + * create a destination array. All sources are copied before the + * transformation, so that no result will overwrite a point that has not yet + * been evaluated. + * + * @param srcPts the array of source points + * @param srcOff the starting offset into src + * @param dstPts the array of destination points + * @param dstOff the starting offset into dst + * @param num the number of points to transform + * @throws NullPointerException if src or dst is null + * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded + */ + public void transform(float[] srcPts, int srcOff, + float[] dstPts, int dstOff, int num) + { + if (srcPts == dstPts && dstOff > srcOff + && num > 1 && srcOff + 2 * num > dstOff) + { + float[] f = new float[2 * num]; + System.arraycopy(srcPts, srcOff, f, 0, 2 * num); + srcPts = f; + } + while (--num >= 0) + { + float x = srcPts[srcOff++]; + float y = srcPts[srcOff++]; + dstPts[dstOff++] = (float) (m00 * x + m01 * y + m02); + dstPts[dstOff++] = (float) (m10 * x + m11 * y + m12); + } + } + + /** + * Perform this transformation on an array of points, in (x,y) pairs, + * storing the results in another (possibly same) array. This will not + * create a destination array. All sources are copied before the + * transformation, so that no result will overwrite a point that has not yet + * been evaluated. + * + * @param srcPts the array of source points + * @param srcOff the starting offset into src + * @param dstPts the array of destination points + * @param dstOff the starting offset into dst + * @param num the number of points to transform + * @throws NullPointerException if src or dst is null + * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded + */ + public void transform(double[] srcPts, int srcOff, + double[] dstPts, int dstOff, int num) + { + if (srcPts == dstPts && dstOff > srcOff + && num > 1 && srcOff + 2 * num > dstOff) + { + double[] d = new double[2 * num]; + System.arraycopy(srcPts, srcOff, d, 0, 2 * num); + srcPts = d; + } + while (--num >= 0) + { + double x = srcPts[srcOff++]; + double y = srcPts[srcOff++]; + dstPts[dstOff++] = m00 * x + m01 * y + m02; + dstPts[dstOff++] = m10 * x + m11 * y + m12; + } + } + + /** + * Perform this transformation on an array of points, in (x,y) pairs, + * storing the results in another array. This will not create a destination + * array. + * + * @param srcPts the array of source points + * @param srcOff the starting offset into src + * @param dstPts the array of destination points + * @param dstOff the starting offset into dst + * @param num the number of points to transform + * @throws NullPointerException if src or dst is null + * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded + */ + public void transform(float[] srcPts, int srcOff, + double[] dstPts, int dstOff, int num) + { + while (--num >= 0) + { + float x = srcPts[srcOff++]; + float y = srcPts[srcOff++]; + dstPts[dstOff++] = m00 * x + m01 * y + m02; + dstPts[dstOff++] = m10 * x + m11 * y + m12; + } + } + + /** + * Perform this transformation on an array of points, in (x,y) pairs, + * storing the results in another array. This will not create a destination + * array. + * + * @param srcPts the array of source points + * @param srcOff the starting offset into src + * @param dstPts the array of destination points + * @param dstOff the starting offset into dst + * @param num the number of points to transform + * @throws NullPointerException if src or dst is null + * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded + */ + public void transform(double[] srcPts, int srcOff, + float[] dstPts, int dstOff, int num) + { + while (--num >= 0) + { + double x = srcPts[srcOff++]; + double y = srcPts[srcOff++]; + dstPts[dstOff++] = (float) (m00 * x + m01 * y + m02); + dstPts[dstOff++] = (float) (m10 * x + m11 * y + m12); + } + } + + /** + * Perform the inverse of this transformation on the given source point, + * and store the result in the destination (creating it if necessary). It + * is safe for src and dst to be the same. + * + * @param src the source point + * @param dst the destination, or null + * @return the inverse transformation of src, in dst if it was non-null + * @throws NullPointerException if src is null + * @throws NoninvertibleTransformException if the inverse does not exist + * @see #getDeterminant() + */ + public Point2D inverseTransform(Point2D src, Point2D dst) + throws NoninvertibleTransformException + { + return createInverse().transform(src, dst); + } + + /** + * Perform the inverse of this transformation on an array of points, in + * (x,y) pairs, storing the results in another (possibly same) array. This + * will not create a destination array. All sources are copied before the + * transformation, so that no result will overwrite a point that has not yet + * been evaluated. + * + * @param srcPts the array of source points + * @param srcOff the starting offset into src + * @param dstPts the array of destination points + * @param dstOff the starting offset into dst + * @param num the number of points to transform + * @throws NullPointerException if src or dst is null + * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded + * @throws NoninvertibleTransformException if the inverse does not exist + * @see #getDeterminant() + */ + public void inverseTransform(double[] srcPts, int srcOff, + double[] dstPts, int dstOff, int num) + throws NoninvertibleTransformException + { + createInverse().transform(srcPts, srcOff, dstPts, dstOff, num); + } + + /** + * Perform this transformation, less any translation, on the given source + * point, and store the result in the destination (creating it if + * necessary). It is safe for src and dst to be the same. The reduced + * transform is equivalent to: + * <pre> + * [ x' ] = [ m00 m01 ] [ x ] = [ m00 * x + m01 * y ] + * [ y' ] [ m10 m11 ] [ y ] = [ m10 * x + m11 * y ] + * </pre> + * + * @param src the source point + * @param dst the destination, or null + * @return the delta transformation of src, in dst if it was non-null + * @throws NullPointerException if src is null + */ + public Point2D deltaTransform(Point2D src, Point2D dst) + { + if (dst == null) + dst = new Point2D.Double(); + double x = src.getX(); + double y = src.getY(); + double nx = m00 * x + m01 * y; + double ny = m10 * x + m11 * y; + dst.setLocation(nx, ny); + return dst; + } + + /** + * Perform this transformation, less any translation, on an array of points, + * in (x,y) pairs, storing the results in another (possibly same) array. + * This will not create a destination array. All sources are copied before + * the transformation, so that no result will overwrite a point that has + * not yet been evaluated. The reduced transform is equivalent to: + * <pre> + * [ x' ] = [ m00 m01 ] [ x ] = [ m00 * x + m01 * y ] + * [ y' ] [ m10 m11 ] [ y ] = [ m10 * x + m11 * y ] + * </pre> + * + * @param srcPts the array of source points + * @param srcOff the starting offset into src + * @param dstPts the array of destination points + * @param dstOff the starting offset into dst + * @param num the number of points to transform + * @throws NullPointerException if src or dst is null + * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded + */ + public void deltaTransform(double[] srcPts, int srcOff, + double[] dstPts, int dstOff, + int num) + { + if (srcPts == dstPts && dstOff > srcOff + && num > 1 && srcOff + 2 * num > dstOff) + { + double[] d = new double[2 * num]; + System.arraycopy(srcPts, srcOff, d, 0, 2 * num); + srcPts = d; + } + while (--num >= 0) + { + double x = srcPts[srcOff++]; + double y = srcPts[srcOff++]; + dstPts[dstOff++] = m00 * x + m01 * y; + dstPts[dstOff++] = m10 * x + m11 * y; + } + } + + /** + * Return a new Shape, based on the given one, where the path of the shape + * has been transformed by this transform. Notice that this uses GeneralPath, + * which only stores points in float precision. + * + * @param src the shape source to transform + * @return the shape, transformed by this, <code>null</code> if src is + * <code>null</code>. + * @see GeneralPath#transform(AffineTransform) + */ + public Shape createTransformedShape(Shape src) + { + if(src == null) + return null; + GeneralPath p = new GeneralPath(src); + p.transform(this); + return p; + } + + /** + * Returns a string representation of the transform, in the format: + * <code>"AffineTransform[[" + m00 + ", " + m01 + ", " + m02 + "], [" + * + m10 + ", " + m11 + ", " + m12 + "]]"</code>. + * + * @return the string representation + */ + public String toString() + { + return "AffineTransform[[" + m00 + ", " + m01 + ", " + m02 + "], [" + + m10 + ", " + m11 + ", " + m12 + "]]"; + } + + /** + * Tests if this transformation is the identity: + * <pre> + * [ 1 0 0 ] + * [ 0 1 0 ] + * [ 0 0 1 ] + * </pre> + * + * @return true if this is the identity transform + */ + public boolean isIdentity() + { + // Rather than rely on type, check explicitly. + return (m00 == 1 && m01 == 0 && m02 == 0 + && m10 == 0 && m11 == 1 && m12 == 0); + } + + /** + * Create a new transform of the same run-time type, with the same + * transforming properties as this one. + * + * @return the clone + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } + + /** + * Return the hashcode for this transformation. The formula is not + * documented, but appears to be the same as: + * <pre> + * long l = Double.doubleToLongBits(getScaleX()); + * l = l * 31 + Double.doubleToLongBits(getShearX()); + * l = l * 31 + Double.doubleToLongBits(getTranslateX()); + * l = l * 31 + Double.doubleToLongBits(getShearY()); + * l = l * 31 + Double.doubleToLongBits(getScaleY()); + * l = l * 31 + Double.doubleToLongBits(getTranslateY()); + * return (int) ((l >> 32) ^ l); + * </pre> + * + * @return the hashcode + */ + public int hashCode() + { + long l = Double.doubleToLongBits(m00); + l = l * 31 + Double.doubleToLongBits(m01); + l = l * 31 + Double.doubleToLongBits(m02); + l = l * 31 + Double.doubleToLongBits(m10); + l = l * 31 + Double.doubleToLongBits(m11); + l = l * 31 + Double.doubleToLongBits(m12); + return (int) ((l >> 32) ^ l); + } + + /** + * Compares two transforms for equality. This returns true if they have the + * same matrix values. + * + * @param obj the transform to compare + * @return true if it is equal + */ + public boolean equals(Object obj) + { + if (! (obj instanceof AffineTransform)) + return false; + AffineTransform t = (AffineTransform) obj; + return (m00 == t.m00 && m01 == t.m01 && m02 == t.m02 + && m10 == t.m10 && m11 == t.m11 && m12 == t.m12); + } + + /** + * Helper to decode the type from the matrix. This is not guaranteed + * to find the optimal type, but at least it will be valid. + */ + private void updateType() + { + double det = getDeterminant(); + if (det == 0) + { + type = TYPE_GENERAL_TRANSFORM; + return; + } + // Scale (includes rotation by PI) or translation. + if (m01 == 0 && m10 == 0) + { + if (m00 == m11) + type = m00 == 1 ? TYPE_IDENTITY : TYPE_UNIFORM_SCALE; + else + type = TYPE_GENERAL_SCALE; + if (m02 != 0 || m12 != 0) + type |= TYPE_TRANSLATION; + } + // Rotation. + else if (m00 == m11 && m01 == -m10) + { + type = m00 == 0 ? TYPE_QUADRANT_ROTATION : TYPE_GENERAL_ROTATION; + if (det != 1) + type |= TYPE_UNIFORM_SCALE; + if (m02 != 0 || m12 != 0) + type |= TYPE_TRANSLATION; + } + else + type = TYPE_GENERAL_TRANSFORM; + } + + /** + * Reads a transform from an object stream. + * + * @param s the stream to read from + * @throws ClassNotFoundException if there is a problem deserializing + * @throws IOException if there is a problem deserializing + */ + private void readObject(ObjectInputStream s) + throws ClassNotFoundException, IOException + { + s.defaultReadObject(); + updateType(); + } +} // class AffineTransform diff --git a/libjava/classpath/java/awt/geom/Arc2D.java b/libjava/classpath/java/awt/geom/Arc2D.java new file mode 100644 index 000000000..928c5cfc8 --- /dev/null +++ b/libjava/classpath/java/awt/geom/Arc2D.java @@ -0,0 +1,1413 @@ +/* Arc2D.java -- represents an arc in 2-D space + Copyright (C) 2002, 2003, 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.geom; + +import java.util.NoSuchElementException; + + +/** + * This class represents all arcs (segments of an ellipse in 2-D space). The + * arcs are defined by starting angle and extent (arc length) in degrees, as + * opposed to radians (like the rest of Java), and can be open, chorded, or + * wedge shaped. The angles are skewed according to the ellipse, so that 45 + * degrees always points to the upper right corner (positive x, negative y) + * of the bounding rectangle. A positive extent draws a counterclockwise arc, + * and while the angle can be any value, the path iterator only traverses the + * first 360 degrees. Storage is up to the subclasses. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @author Sven de Marothy (sven@physto.se) + * @since 1.2 + */ +public abstract class Arc2D extends RectangularShape +{ + /** + * An open arc, with no segment connecting the endpoints. This type of + * arc still contains the same points as a chorded version. + */ + public static final int OPEN = 0; + + /** + * A closed arc with a single segment connecting the endpoints (a chord). + */ + public static final int CHORD = 1; + + /** + * A closed arc with two segments, one from each endpoint, meeting at the + * center of the ellipse. + */ + public static final int PIE = 2; + + /** The closure type of this arc. This is package-private to avoid an + * accessor method. */ + int type; + + /** + * Create a new arc, with the specified closure type. + * + * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE}. + * @throws IllegalArgumentException if type is invalid + */ + protected Arc2D(int type) + { + if (type < OPEN || type > PIE) + throw new IllegalArgumentException(); + this.type = type; + } + + /** + * Get the starting angle of the arc in degrees. + * + * @return the starting angle + * @see #setAngleStart(double) + */ + public abstract double getAngleStart(); + + /** + * Get the extent angle of the arc in degrees. + * + * @return the extent angle + * @see #setAngleExtent(double) + */ + public abstract double getAngleExtent(); + + /** + * Return the closure type of the arc. + * + * @return the closure type + * @see #OPEN + * @see #CHORD + * @see #PIE + * @see #setArcType(int) + */ + public int getArcType() + { + return type; + } + + /** + * Returns the starting point of the arc. + * + * @return the start point + */ + public Point2D getStartPoint() + { + double angle = Math.toRadians(getAngleStart()); + double rx = getWidth() / 2; + double ry = getHeight() / 2; + double x = getX() + rx + rx * Math.cos(angle); + double y = getY() + ry - ry * Math.sin(angle); + return new Point2D.Double(x, y); + } + + /** + * Returns the ending point of the arc. + * + * @return the end point + */ + public Point2D getEndPoint() + { + double angle = Math.toRadians(getAngleStart() + getAngleExtent()); + double rx = getWidth() / 2; + double ry = getHeight() / 2; + double x = getX() + rx + rx * Math.cos(angle); + double y = getY() + ry - ry * Math.sin(angle); + return new Point2D.Double(x, y); + } + + /** + * Set the parameters of the arc. The angles are in degrees, and a positive + * extent sweeps counterclockwise (from the positive x-axis to the negative + * y-axis). + * + * @param x the new x coordinate of the upper left of the bounding box + * @param y the new y coordinate of the upper left of the bounding box + * @param w the new width of the bounding box + * @param h the new height of the bounding box + * @param start the start angle, in degrees + * @param extent the arc extent, in degrees + * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + */ + public abstract void setArc(double x, double y, double w, double h, + double start, double extent, int type); + + /** + * Set the parameters of the arc. The angles are in degrees, and a positive + * extent sweeps counterclockwise (from the positive x-axis to the negative + * y-axis). + * + * @param p the upper left point of the bounding box + * @param d the dimensions of the bounding box + * @param start the start angle, in degrees + * @param extent the arc extent, in degrees + * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + * @throws NullPointerException if p or d is null + */ + public void setArc(Point2D p, Dimension2D d, double start, double extent, + int type) + { + setArc(p.getX(), p.getY(), d.getWidth(), d.getHeight(), start, extent, type); + } + + /** + * Set the parameters of the arc. The angles are in degrees, and a positive + * extent sweeps counterclockwise (from the positive x-axis to the negative + * y-axis). + * + * @param r the new bounding box + * @param start the start angle, in degrees + * @param extent the arc extent, in degrees + * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + * @throws NullPointerException if r is null + */ + public void setArc(Rectangle2D r, double start, double extent, int type) + { + setArc(r.getX(), r.getY(), r.getWidth(), r.getHeight(), start, extent, type); + } + + /** + * Set the parameters of the arc from the given one. + * + * @param a the arc to copy + * @throws NullPointerException if a is null + */ + public void setArc(Arc2D a) + { + setArc(a.getX(), a.getY(), a.getWidth(), a.getHeight(), a.getAngleStart(), + a.getAngleExtent(), a.getArcType()); + } + + /** + * Set the parameters of the arc. The angles are in degrees, and a positive + * extent sweeps counterclockwise (from the positive x-axis to the negative + * y-axis). This controls the center point and radius, so the arc will be + * circular. + * + * @param x the x coordinate of the center of the circle + * @param y the y coordinate of the center of the circle + * @param r the radius of the circle + * @param start the start angle, in degrees + * @param extent the arc extent, in degrees + * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + */ + public void setArcByCenter(double x, double y, double r, double start, + double extent, int type) + { + setArc(x - r, y - r, r + r, r + r, start, extent, type); + } + + /** + * Sets the parameters of the arc by finding the tangents of two lines, and + * using the specified radius. The arc will be circular, will begin on the + * tangent point of the line extending from p1 to p2, and will end on the + * tangent point of the line extending from p2 to p3. + * + * XXX What happens if the points are colinear, or the radius negative? + * + * @param p1 the first point + * @param p2 the tangent line intersection point + * @param p3 the third point + * @param r the radius of the arc + * @throws NullPointerException if any point is null + */ + public void setArcByTangent(Point2D p1, Point2D p2, Point2D p3, double r) + { + if ((p2.getX() - p1.getX()) * (p3.getY() - p1.getY()) + - (p3.getX() - p1.getX()) * (p2.getY() - p1.getY()) > 0) + { + Point2D p = p3; + p3 = p1; + p1 = p; + } + + // normalized tangent vectors + double dx1 = (p1.getX() - p2.getX()) / p1.distance(p2); + double dy1 = (p1.getY() - p2.getY()) / p1.distance(p2); + double dx2 = (p2.getX() - p3.getX()) / p3.distance(p2); + double dy2 = (p2.getY() - p3.getY()) / p3.distance(p2); + double theta1 = Math.atan2(dx1, dy1); + double theta2 = Math.atan2(dx2, dy2); + + double dx = r * Math.cos(theta2) - r * Math.cos(theta1); + double dy = -r * Math.sin(theta2) + r * Math.sin(theta1); + + if (theta1 < 0) + theta1 += 2 * Math.PI; + if (theta2 < 0) + theta2 += 2 * Math.PI; + if (theta2 < theta1) + theta2 += 2 * Math.PI; + + // Vectors of the lines, not normalized, note we change + // the direction of line 2. + dx1 = p1.getX() - p2.getX(); + dy1 = p1.getY() - p2.getY(); + dx2 = p3.getX() - p2.getX(); + dy2 = p3.getY() - p2.getY(); + + // Calculate the tangent point to the second line + double t2 = -(dx1 * dy - dy1 * dx) / (dx2 * dy1 - dx1 * dy2); + double x2 = t2 * (p3.getX() - p2.getX()) + p2.getX(); + double y2 = t2 * (p3.getY() - p2.getY()) + p2.getY(); + + // calculate the center point + double x = x2 - r * Math.cos(theta2); + double y = y2 + r * Math.sin(theta2); + + setArc(x - r, y - r, 2 * r, 2 * r, Math.toDegrees(theta1), + Math.toDegrees(theta2 - theta1), getArcType()); + } + + /** + * Set the start, in degrees. + * + * @param start the new start angle + * @see #getAngleStart() + */ + public abstract void setAngleStart(double start); + + /** + * Set the extent, in degrees. + * + * @param extent the new extent angle + * @see #getAngleExtent() + */ + public abstract void setAngleExtent(double extent); + + /** + * Sets the starting angle to the angle of the given point relative to + * the center of the arc. The extent remains constant; in other words, + * this rotates the arc. + * + * @param p the new start point + * @throws NullPointerException if p is null + * @see #getStartPoint() + * @see #getAngleStart() + */ + public void setAngleStart(Point2D p) + { + // Normalize. + double x = p.getX() - (getX() + getWidth() / 2); + double y = p.getY() - (getY() + getHeight() / 2); + setAngleStart(Math.toDegrees(Math.atan2(-y, x))); + } + + /** + * Sets the starting and extent angles to those of the given points + * relative to the center of the arc. The arc will be non-empty, and will + * extend counterclockwise. + * + * @param x1 the first x coordinate + * @param y1 the first y coordinate + * @param x2 the second x coordinate + * @param y2 the second y coordinate + * @see #setAngleStart(Point2D) + */ + public void setAngles(double x1, double y1, double x2, double y2) + { + // Normalize the points. + double mx = getX(); + double my = getY(); + double mw = getWidth(); + double mh = getHeight(); + x1 = x1 - (mx + mw / 2); + y1 = y1 - (my + mh / 2); + x2 = x2 - (mx + mw / 2); + y2 = y2 - (my + mh / 2); + double start = Math.toDegrees(Math.atan2(-y1, x1)); + double extent = Math.toDegrees(Math.atan2(-y2, x2)) - start; + if (extent < 0) + extent += 360; + setAngleStart(start); + setAngleExtent(extent); + } + + /** + * Sets the starting and extent angles to those of the given points + * relative to the center of the arc. The arc will be non-empty, and will + * extend counterclockwise. + * + * @param p1 the first point + * @param p2 the second point + * @throws NullPointerException if either point is null + * @see #setAngleStart(Point2D) + */ + public void setAngles(Point2D p1, Point2D p2) + { + setAngles(p1.getX(), p1.getY(), p2.getX(), p2.getY()); + } + + /** + * Set the closure type of this arc. + * + * @param type one of {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + * @see #getArcType() + */ + public void setArcType(int type) + { + if (type < OPEN || type > PIE) + throw new IllegalArgumentException(); + this.type = type; + } + + /** + * Sets the location and bounds of the ellipse of which this arc is a part. + * + * @param x the new x coordinate + * @param y the new y coordinate + * @param w the new width + * @param h the new height + * @see #getFrame() + */ + public void setFrame(double x, double y, double w, double h) + { + setArc(x, y, w, h, getAngleStart(), getAngleExtent(), type); + } + + /** + * Gets the bounds of the arc. This is much tighter than + * <code>getBounds</code>, as it takes into consideration the start and + * end angles, and the center point of a pie wedge, rather than just the + * overall ellipse. + * + * @return the bounds of the arc + * @see #getBounds() + */ + public Rectangle2D getBounds2D() + { + double extent = getAngleExtent(); + if (Math.abs(extent) >= 360) + return makeBounds(getX(), getY(), getWidth(), getHeight()); + + // Find the minimal bounding box. This determined by its extrema, + // which are the center, the endpoints of the arc, and any local + // maximum contained by the arc. + double rX = getWidth() / 2; + double rY = getHeight() / 2; + double centerX = getX() + rX; + double centerY = getY() + rY; + + Point2D p1 = getStartPoint(); + Rectangle2D result = makeBounds(p1.getX(), p1.getY(), 0, 0); + result.add(getEndPoint()); + + if (type == PIE) + result.add(centerX, centerY); + if (containsAngle(0)) + result.add(centerX + rX, centerY); + if (containsAngle(90)) + result.add(centerX, centerY - rY); + if (containsAngle(180)) + result.add(centerX - rX, centerY); + if (containsAngle(270)) + result.add(centerX, centerY + rY); + + return result; + } + + /** + * Construct a bounding box in a precision appropriate for the subclass. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + * @return the rectangle for use in getBounds2D + */ + protected abstract Rectangle2D makeBounds(double x, double y, double w, + double h); + + /** + * Tests if the given angle, in degrees, is included in the arc. + * All angles are normalized to be between 0 and 360 degrees. + * + * @param a the angle to test + * @return true if it is contained + */ + public boolean containsAngle(double a) + { + double start = getAngleStart(); + double extent = getAngleExtent(); + double end = start + extent; + + if (extent == 0) + return false; + + if (extent >= 360 || extent <= -360) + return true; + + if (extent < 0) + { + end = start; + start += extent; + } + + start %= 360; + while (start < 0) + start += 360; + + end %= 360; + while (end < start) + end += 360; + + a %= 360; + while (a < start) + a += 360; + + return a >= start && a < end; // starting angle included, ending angle not + } + + /** + * Determines if the arc contains the given point. If the bounding box + * is empty, then this will return false. + * + * The area considered 'inside' an arc of type OPEN is the same as the + * area inside an equivalent filled CHORD-type arc. The area considered + * 'inside' a CHORD-type arc is the same as the filled area. + * + * @param x the x coordinate to test + * @param y the y coordinate to test + * @return true if the point is inside the arc + */ + public boolean contains(double x, double y) + { + double w = getWidth(); + double h = getHeight(); + double extent = getAngleExtent(); + if (w <= 0 || h <= 0 || extent == 0) + return false; + + double mx = getX() + w / 2; + double my = getY() + h / 2; + double dx = (x - mx) * 2 / w; + double dy = (y - my) * 2 / h; + if ((dx * dx + dy * dy) >= 1.0) + return false; + + double angle = Math.toDegrees(Math.atan2(-dy, dx)); + if (getArcType() == PIE) + return containsAngle(angle); + + double a1 = Math.toRadians(getAngleStart()); + double a2 = Math.toRadians(getAngleStart() + extent); + double x1 = mx + getWidth() * Math.cos(a1) / 2; + double y1 = my - getHeight() * Math.sin(a1) / 2; + double x2 = mx + getWidth() * Math.cos(a2) / 2; + double y2 = my - getHeight() * Math.sin(a2) / 2; + double sgn = ((x2 - x1) * (my - y1) - (mx - x1) * (y2 - y1)) * ((x2 - x1) * (y + - y1) - (x - x1) * (y2 - y1)); + + if (Math.abs(extent) > 180) + { + if (containsAngle(angle)) + return true; + return sgn > 0; + } + else + { + if (! containsAngle(angle)) + return false; + return sgn < 0; + } + } + + /** + * Tests if a given rectangle intersects the area of the arc. + * + * For a definition of the 'inside' area, see the contains() method. + * @see #contains(double, double) + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @return true if the two shapes share common points + */ + public boolean intersects(double x, double y, double w, double h) + { + double extent = getAngleExtent(); + if (extent == 0) + return false; + + if (contains(x, y) || contains(x, y + h) || contains(x + w, y) + || contains(x + w, y + h)) + return true; + + Rectangle2D rect = new Rectangle2D.Double(x, y, w, h); + + double a = getWidth() / 2.0; + double b = getHeight() / 2.0; + + double mx = getX() + a; + double my = getY() + b; + double x1 = mx + a * Math.cos(Math.toRadians(getAngleStart())); + double y1 = my - b * Math.sin(Math.toRadians(getAngleStart())); + double x2 = mx + a * Math.cos(Math.toRadians(getAngleStart() + extent)); + double y2 = my - b * Math.sin(Math.toRadians(getAngleStart() + extent)); + + if (getArcType() != CHORD) + { + // check intersections against the pie radii + if (rect.intersectsLine(mx, my, x1, y1)) + return true; + if (rect.intersectsLine(mx, my, x2, y2)) + return true; + } + else// check the chord + if (rect.intersectsLine(x1, y1, x2, y2)) + return true; + + // Check the Arc segment against the four edges + double dx; + + // Check the Arc segment against the four edges + double dy; + dy = y - my; + dx = a * Math.sqrt(1 - ((dy * dy) / (b * b))); + if (! java.lang.Double.isNaN(dx)) + { + if (mx + dx >= x && mx + dx <= x + w + && containsAngle(Math.toDegrees(Math.atan2(-dy, dx)))) + return true; + if (mx - dx >= x && mx - dx <= x + w + && containsAngle(Math.toDegrees(Math.atan2(-dy, -dx)))) + return true; + } + dy = (y + h) - my; + dx = a * Math.sqrt(1 - ((dy * dy) / (b * b))); + if (! java.lang.Double.isNaN(dx)) + { + if (mx + dx >= x && mx + dx <= x + w + && containsAngle(Math.toDegrees(Math.atan2(-dy, dx)))) + return true; + if (mx - dx >= x && mx - dx <= x + w + && containsAngle(Math.toDegrees(Math.atan2(-dy, -dx)))) + return true; + } + dx = x - mx; + dy = b * Math.sqrt(1 - ((dx * dx) / (a * a))); + if (! java.lang.Double.isNaN(dy)) + { + if (my + dy >= y && my + dy <= y + h + && containsAngle(Math.toDegrees(Math.atan2(-dy, dx)))) + return true; + if (my - dy >= y && my - dy <= y + h + && containsAngle(Math.toDegrees(Math.atan2(dy, dx)))) + return true; + } + + dx = (x + w) - mx; + dy = b * Math.sqrt(1 - ((dx * dx) / (a * a))); + if (! java.lang.Double.isNaN(dy)) + { + if (my + dy >= y && my + dy <= y + h + && containsAngle(Math.toDegrees(Math.atan2(-dy, dx)))) + return true; + if (my - dy >= y && my - dy <= y + h + && containsAngle(Math.toDegrees(Math.atan2(dy, dx)))) + return true; + } + + // Check whether the arc is contained within the box + if (rect.contains(mx, my)) + return true; + + return false; + } + + /** + * Tests if a given rectangle is contained in the area of the arc. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @return true if the arc contains the rectangle + */ + public boolean contains(double x, double y, double w, double h) + { + double extent = getAngleExtent(); + if (extent == 0) + return false; + + if (! (contains(x, y) && contains(x, y + h) && contains(x + w, y) + && contains(x + w, y + h))) + return false; + + Rectangle2D rect = new Rectangle2D.Double(x, y, w, h); + + double a = getWidth() / 2.0; + double b = getHeight() / 2.0; + + double mx = getX() + a; + double my = getY() + b; + double x1 = mx + a * Math.cos(Math.toRadians(getAngleStart())); + double y1 = my - b * Math.sin(Math.toRadians(getAngleStart())); + double x2 = mx + a * Math.cos(Math.toRadians(getAngleStart() + extent)); + double y2 = my - b * Math.sin(Math.toRadians(getAngleStart() + extent)); + if (getArcType() != CHORD) + { + // check intersections against the pie radii + if (rect.intersectsLine(mx, my, x1, y1)) + return false; + + if (rect.intersectsLine(mx, my, x2, y2)) + return false; + } + else if (rect.intersectsLine(x1, y1, x2, y2)) + return false; + return true; + } + + /** + * Tests if a given rectangle is contained in the area of the arc. + * + * @param r the rectangle + * @return true if the arc contains the rectangle + */ + public boolean contains(Rectangle2D r) + { + return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Returns an iterator over this arc, with an optional transformation. + * This iterator is threadsafe, so future modifications to the arc do not + * affect the iteration. + * + * @param at the transformation, or null + * @return a path iterator + */ + public PathIterator getPathIterator(AffineTransform at) + { + return new ArcIterator(this, at); + } + + /** + * This class is used to iterate over an arc. Since ellipses are a subclass + * of arcs, this is used by Ellipse2D as well. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + static final class ArcIterator implements PathIterator + { + /** The current iteration. */ + private int current; + + /** The last iteration. */ + private final int limit; + + /** The optional transformation. */ + private final AffineTransform xform; + + /** The x coordinate of the bounding box. */ + private final double x; + + /** The y coordinate of the bounding box. */ + private final double y; + + /** The width of the bounding box. */ + private final double w; + + /** The height of the bounding box. */ + private final double h; + + /** The start angle, in radians (not degrees). */ + private final double start; + + /** The extent angle, in radians (not degrees). */ + private final double extent; + + /** The arc closure type. */ + private final int type; + + /** + * Construct a new iterator over an arc. + * + * @param a the arc + * @param xform the transform + */ + public ArcIterator(Arc2D a, AffineTransform xform) + { + this.xform = xform; + x = a.getX(); + y = a.getY(); + w = a.getWidth(); + h = a.getHeight(); + double start = Math.toRadians(a.getAngleStart()); + double extent = Math.toRadians(a.getAngleExtent()); + + this.start = start; + this.extent = extent; + + type = a.type; + if (w < 0 || h < 0) + limit = -1; + else if (extent == 0) + limit = type; + else if (Math.abs(extent) <= Math.PI / 2.0) + limit = type + 1; + else if (Math.abs(extent) <= Math.PI) + limit = type + 2; + else if (Math.abs(extent) <= 3.0 * (Math.PI / 2.0)) + limit = type + 3; + else + limit = type + 4; + } + + /** + * Construct a new iterator over an ellipse. + * + * @param e the ellipse + * @param xform the transform + */ + public ArcIterator(Ellipse2D e, AffineTransform xform) + { + this.xform = xform; + x = e.getX(); + y = e.getY(); + w = e.getWidth(); + h = e.getHeight(); + start = 0; + extent = 2 * Math.PI; + type = CHORD; + limit = (w < 0 || h < 0) ? -1 : 5; + } + + /** + * Return the winding rule. + * + * @return {@link PathIterator#WIND_NON_ZERO} + */ + public int getWindingRule() + { + return WIND_NON_ZERO; + } + + /** + * Test if the iteration is complete. + * + * @return true if more segments exist + */ + public boolean isDone() + { + return current > limit; + } + + /** + * Advance the iterator. + */ + public void next() + { + current++; + } + + /** + * Put the current segment into the array, and return the segment type. + * + * @param coords an array of 6 elements + * @return the segment type + * @throws NullPointerException if coords is null + * @throws ArrayIndexOutOfBoundsException if coords is too small + */ + public int currentSegment(float[] coords) + { + double[] double_coords = new double[6]; + int code = currentSegment(double_coords); + for (int i = 0; i < 6; ++i) + coords[i] = (float) double_coords[i]; + return code; + } + + /** + * Put the current segment into the array, and return the segment type. + * + * @param coords an array of 6 elements + * @return the segment type + * @throws NullPointerException if coords is null + * @throws ArrayIndexOutOfBoundsException if coords is too small + */ + public int currentSegment(double[] coords) + { + double rx = w / 2; + double ry = h / 2; + double xmid = x + rx; + double ymid = y + ry; + + if (current > limit) + throw new NoSuchElementException("arc iterator out of bounds"); + + if (current == 0) + { + coords[0] = xmid + rx * Math.cos(start); + coords[1] = ymid - ry * Math.sin(start); + if (xform != null) + xform.transform(coords, 0, coords, 0, 1); + return SEG_MOVETO; + } + + if (type != OPEN && current == limit) + return SEG_CLOSE; + + if ((current == limit - 1) && (type == PIE)) + { + coords[0] = xmid; + coords[1] = ymid; + if (xform != null) + xform.transform(coords, 0, coords, 0, 1); + return SEG_LINETO; + } + + // note that this produces a cubic approximation of the arc segment, + // not a true ellipsoid. there's no ellipsoid path segment code, + // unfortunately. the cubic approximation looks about right, though. + double kappa = (Math.sqrt(2.0) - 1.0) * (4.0 / 3.0); + double quad = (Math.PI / 2.0); + + double curr_begin; + double curr_extent; + if (extent > 0) + { + curr_begin = start + (current - 1) * quad; + curr_extent = Math.min((start + extent) - curr_begin, quad); + } + else + { + curr_begin = start - (current - 1) * quad; + curr_extent = Math.max((start + extent) - curr_begin, -quad); + } + + double portion_of_a_quadrant = Math.abs(curr_extent / quad); + + double x0 = xmid + rx * Math.cos(curr_begin); + double y0 = ymid - ry * Math.sin(curr_begin); + + double x1 = xmid + rx * Math.cos(curr_begin + curr_extent); + double y1 = ymid - ry * Math.sin(curr_begin + curr_extent); + + AffineTransform trans = new AffineTransform(); + double[] cvec = new double[2]; + double len = kappa * portion_of_a_quadrant; + double angle = curr_begin; + + // in a hypothetical "first quadrant" setting, our first control + // vector would be sticking up, from [1,0] to [1,kappa]. + // + // let us recall however that in java2d, y coords are upside down + // from what one would consider "normal" first quadrant rules, so we + // will *subtract* the y value of this control vector from our first + // point. + cvec[0] = 0; + if (extent > 0) + cvec[1] = len; + else + cvec[1] = -len; + + trans.scale(rx, ry); + trans.rotate(angle); + trans.transform(cvec, 0, cvec, 0, 1); + coords[0] = x0 + cvec[0]; + coords[1] = y0 - cvec[1]; + + // control vector #2 would, ideally, be sticking out and to the + // right, in a first quadrant arc segment. again, subtraction of y. + cvec[0] = 0; + if (extent > 0) + cvec[1] = -len; + else + cvec[1] = len; + + trans.rotate(curr_extent); + trans.transform(cvec, 0, cvec, 0, 1); + coords[2] = x1 + cvec[0]; + coords[3] = y1 - cvec[1]; + + // end point + coords[4] = x1; + coords[5] = y1; + + if (xform != null) + xform.transform(coords, 0, coords, 0, 3); + + return SEG_CUBICTO; + } + } // class ArcIterator + + /** + * This class implements an arc in double precision. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + */ + public static class Double extends Arc2D + { + /** The x coordinate of the box bounding the ellipse of this arc. */ + public double x; + + /** The y coordinate of the box bounding the ellipse of this arc. */ + public double y; + + /** The width of the box bounding the ellipse of this arc. */ + public double width; + + /** The height of the box bounding the ellipse of this arc. */ + public double height; + + /** The start angle of this arc, in degrees. */ + public double start; + + /** The extent angle of this arc, in degrees. */ + public double extent; + + /** + * Create a new, open arc at (0,0) with 0 extent. + */ + public Double() + { + super(OPEN); + } + + /** + * Create a new arc of the given type at (0,0) with 0 extent. + * + * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + */ + public Double(int type) + { + super(type); + } + + /** + * Create a new arc with the given dimensions. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + * @param start the start angle, in degrees + * @param extent the extent, in degrees + * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + */ + public Double(double x, double y, double w, double h, double start, + double extent, int type) + { + super(type); + this.x = x; + this.y = y; + width = w; + height = h; + this.start = start; + this.extent = extent; + } + + /** + * Create a new arc with the given dimensions. + * + * @param r the bounding box + * @param start the start angle, in degrees + * @param extent the extent, in degrees + * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + * @throws NullPointerException if r is null + */ + public Double(Rectangle2D r, double start, double extent, int type) + { + super(type); + x = r.getX(); + y = r.getY(); + width = r.getWidth(); + height = r.getHeight(); + this.start = start; + this.extent = extent; + } + + /** + * Return the x coordinate of the bounding box. + * + * @return the value of x + */ + public double getX() + { + return x; + } + + /** + * Return the y coordinate of the bounding box. + * + * @return the value of y + */ + public double getY() + { + return y; + } + + /** + * Return the width of the bounding box. + * + * @return the value of width + */ + public double getWidth() + { + return width; + } + + /** + * Return the height of the bounding box. + * + * @return the value of height + */ + public double getHeight() + { + return height; + } + + /** + * Return the start angle of the arc, in degrees. + * + * @return the value of start + */ + public double getAngleStart() + { + return start; + } + + /** + * Return the extent of the arc, in degrees. + * + * @return the value of extent + */ + public double getAngleExtent() + { + return extent; + } + + /** + * Tests if the arc contains points. + * + * @return true if the arc has no interior + */ + public boolean isEmpty() + { + return width <= 0 || height <= 0; + } + + /** + * Sets the arc to the given dimensions. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + * @param start the start angle, in degrees + * @param extent the extent, in degrees + * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + */ + public void setArc(double x, double y, double w, double h, double start, + double extent, int type) + { + this.x = x; + this.y = y; + width = w; + height = h; + this.start = start; + this.extent = extent; + setArcType(type); + } + + /** + * Sets the start angle of the arc. + * + * @param start the new start angle + */ + public void setAngleStart(double start) + { + this.start = start; + } + + /** + * Sets the extent angle of the arc. + * + * @param extent the new extent angle + */ + public void setAngleExtent(double extent) + { + this.extent = extent; + } + + /** + * Creates a tight bounding box given dimensions that more precise than + * the bounding box of the ellipse. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + */ + protected Rectangle2D makeBounds(double x, double y, double w, double h) + { + return new Rectangle2D.Double(x, y, w, h); + } + } // class Double + + /** + * This class implements an arc in float precision. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + */ + public static class Float extends Arc2D + { + /** The x coordinate of the box bounding the ellipse of this arc. */ + public float x; + + /** The y coordinate of the box bounding the ellipse of this arc. */ + public float y; + + /** The width of the box bounding the ellipse of this arc. */ + public float width; + + /** The height of the box bounding the ellipse of this arc. */ + public float height; + + /** The start angle of this arc, in degrees. */ + public float start; + + /** The extent angle of this arc, in degrees. */ + public float extent; + + /** + * Create a new, open arc at (0,0) with 0 extent. + */ + public Float() + { + super(OPEN); + } + + /** + * Create a new arc of the given type at (0,0) with 0 extent. + * + * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + */ + public Float(int type) + { + super(type); + } + + /** + * Create a new arc with the given dimensions. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + * @param start the start angle, in degrees + * @param extent the extent, in degrees + * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + */ + public Float(float x, float y, float w, float h, float start, + float extent, int type) + { + super(type); + this.x = x; + this.y = y; + width = w; + height = h; + this.start = start; + this.extent = extent; + } + + /** + * Create a new arc with the given dimensions. + * + * @param r the bounding box + * @param start the start angle, in degrees + * @param extent the extent, in degrees + * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + * @throws NullPointerException if r is null + */ + public Float(Rectangle2D r, float start, float extent, int type) + { + super(type); + x = (float) r.getX(); + y = (float) r.getY(); + width = (float) r.getWidth(); + height = (float) r.getHeight(); + this.start = start; + this.extent = extent; + } + + /** + * Return the x coordinate of the bounding box. + * + * @return the value of x + */ + public double getX() + { + return x; + } + + /** + * Return the y coordinate of the bounding box. + * + * @return the value of y + */ + public double getY() + { + return y; + } + + /** + * Return the width of the bounding box. + * + * @return the value of width + */ + public double getWidth() + { + return width; + } + + /** + * Return the height of the bounding box. + * + * @return the value of height + */ + public double getHeight() + { + return height; + } + + /** + * Return the start angle of the arc, in degrees. + * + * @return the value of start + */ + public double getAngleStart() + { + return start; + } + + /** + * Return the extent of the arc, in degrees. + * + * @return the value of extent + */ + public double getAngleExtent() + { + return extent; + } + + /** + * Tests if the arc contains points. + * + * @return true if the arc has no interior + */ + public boolean isEmpty() + { + return width <= 0 || height <= 0; + } + + /** + * Sets the arc to the given dimensions. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + * @param start the start angle, in degrees + * @param extent the extent, in degrees + * @param type the arc type: {@link #OPEN}, {@link #CHORD}, or {@link #PIE} + * @throws IllegalArgumentException if type is invalid + */ + public void setArc(double x, double y, double w, double h, double start, + double extent, int type) + { + this.x = (float) x; + this.y = (float) y; + width = (float) w; + height = (float) h; + this.start = (float) start; + this.extent = (float) extent; + setArcType(type); + } + + /** + * Sets the start angle of the arc. + * + * @param start the new start angle + */ + public void setAngleStart(double start) + { + this.start = (float) start; + } + + /** + * Sets the extent angle of the arc. + * + * @param extent the new extent angle + */ + public void setAngleExtent(double extent) + { + this.extent = (float) extent; + } + + /** + * Creates a tight bounding box given dimensions that more precise than + * the bounding box of the ellipse. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + */ + protected Rectangle2D makeBounds(double x, double y, double w, double h) + { + return new Rectangle2D.Float((float) x, (float) y, (float) w, (float) h); + } + } // class Float +} // class Arc2D diff --git a/libjava/classpath/java/awt/geom/Area.java b/libjava/classpath/java/awt/geom/Area.java new file mode 100644 index 000000000..a1eaf63f3 --- /dev/null +++ b/libjava/classpath/java/awt/geom/Area.java @@ -0,0 +1,3312 @@ +/* Area.java -- represents a shape built by constructive area geometry + Copyright (C) 2002, 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.geom; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.util.Vector; + + +/** + * The Area class represents any area for the purpose of + * Constructive Area Geometry (CAG) manipulations. CAG manipulations + * work as an area-wise form of boolean logic, where the basic operations are: + * <P><li>Add (in boolean algebra: A <B>or</B> B)<BR> + * <li>Subtract (in boolean algebra: A <B>and</B> (<B>not</B> B) )<BR> + * <li>Intersect (in boolean algebra: A <B>and</B> B)<BR> + * <li>Exclusive Or <BR> + * <img src="doc-files/Area-1.png" width="342" height="302" + * alt="Illustration of CAG operations" /><BR> + * Above is an illustration of the CAG operations on two ring shapes.<P> + * + * The contains and intersects() methods are also more accurate than the + * specification of #Shape requires.<P> + * + * Please note that constructing an Area can be slow + * (Self-intersection resolving is proportional to the square of + * the number of segments).<P> + * @see #add(Area) + * @see #subtract(Area) + * @see #intersect(Area) + * @see #exclusiveOr(Area) + * + * @author Sven de Marothy (sven@physto.se) + * + * @since 1.2 + * @status Works, but could be faster and more reliable. + */ +public class Area implements Shape, Cloneable +{ + /** + * General numerical precision + */ + private static final double EPSILON = 1E-11; + + /** + * recursive subdivision epsilon - (see getRecursionDepth) + */ + private static final double RS_EPSILON = 1E-13; + + /** + * Snap distance - points within this distance are considered equal + */ + private static final double PE_EPSILON = 1E-11; + + /** + * Segment vectors containing solid areas and holes + * This is package-private to avoid an accessor method. + */ + Vector solids; + + /** + * Segment vectors containing solid areas and holes + * This is package-private to avoid an accessor method. + */ + Vector holes; + + /** + * Vector (temporary) storing curve-curve intersections + */ + private Vector cc_intersections; + + /** + * Winding rule WIND_NON_ZERO used, after construction, + * this is irrelevant. + */ + private int windingRule; + + /** + * Constructs an empty Area + */ + public Area() + { + solids = new Vector(); + holes = new Vector(); + } + + /** + * Constructs an Area from any given Shape. <P> + * + * If the Shape is self-intersecting, the created Area will consist + * of non-self-intersecting subpaths, and any inner paths which + * are found redundant in accordance with the Shape's winding rule + * will not be included. + * + * @param s the shape (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>s</code> is <code>null</code>. + */ + public Area(Shape s) + { + this(); + + Vector p = makeSegment(s); + + // empty path + if (p == null) + return; + + // delete empty paths + for (int i = 0; i < p.size(); i++) + if (((Segment) p.elementAt(i)).getSignedArea() == 0.0) + p.remove(i--); + + /* + * Resolve self intersecting paths into non-intersecting + * solids and holes. + * Algorithm is as follows: + * 1: Create nodes at all self intersections + * 2: Put all segments into a list + * 3: Grab a segment, follow it, change direction at each node, + * removing segments from the list in the process + * 4: Repeat (3) until no segments remain in the list + * 5: Remove redundant paths and sort into solids and holes + */ + Vector paths = new Vector(); + Segment v; + + for (int i = 0; i < p.size(); i++) + { + Segment path = (Segment) p.elementAt(i); + createNodesSelf(path); + } + + if (p.size() > 1) + { + for (int i = 0; i < p.size() - 1; i++) + for (int j = i + 1; j < p.size(); j++) + { + Segment path1 = (Segment) p.elementAt(i); + Segment path2 = (Segment) p.elementAt(j); + createNodes(path1, path2); + } + } + + // we have intersecting points. + Vector segments = new Vector(); + + for (int i = 0; i < p.size(); i++) + { + Segment path = v = (Segment) p.elementAt(i); + do + { + segments.add(v); + v = v.next; + } + while (v != path); + } + + paths = weilerAtherton(segments); + deleteRedundantPaths(paths); + } + + /** + * Performs an add (union) operation on this area with another Area.<BR> + * @param area - the area to be unioned with this one + */ + public void add(Area area) + { + if (equals(area)) + return; + if (area.isEmpty()) + return; + + Area B = (Area) area.clone(); + + Vector pathA = new Vector(); + Vector pathB = new Vector(); + pathA.addAll(solids); + pathA.addAll(holes); + pathB.addAll(B.solids); + pathB.addAll(B.holes); + + int nNodes = 0; + + for (int i = 0; i < pathA.size(); i++) + { + Segment a = (Segment) pathA.elementAt(i); + for (int j = 0; j < pathB.size(); j++) + { + Segment b = (Segment) pathB.elementAt(j); + nNodes += createNodes(a, b); + } + } + + Vector paths = new Vector(); + Segment v; + + // we have intersecting points. + Vector segments = new Vector(); + + // In a union operation, we keep all + // segments of A oustide B and all B outside A + for (int i = 0; i < pathA.size(); i++) + { + v = (Segment) pathA.elementAt(i); + Segment path = v; + do + { + if (v.isSegmentOutside(area)) + segments.add(v); + v = v.next; + } + while (v != path); + } + + for (int i = 0; i < pathB.size(); i++) + { + v = (Segment) pathB.elementAt(i); + Segment path = v; + do + { + if (v.isSegmentOutside(this)) + segments.add(v); + v = v.next; + } + while (v != path); + } + + paths = weilerAtherton(segments); + deleteRedundantPaths(paths); + } + + /** + * Performs a subtraction operation on this Area.<BR> + * @param area the area to be subtracted from this area. + * @throws NullPointerException if <code>area</code> is <code>null</code>. + */ + public void subtract(Area area) + { + if (isEmpty() || area.isEmpty()) + return; + + if (equals(area)) + { + reset(); + return; + } + + Vector pathA = new Vector(); + Area B = (Area) area.clone(); + pathA.addAll(solids); + pathA.addAll(holes); + + // reverse the directions of B paths. + setDirection(B.holes, true); + setDirection(B.solids, false); + + Vector pathB = new Vector(); + pathB.addAll(B.solids); + pathB.addAll(B.holes); + + int nNodes = 0; + + // create nodes + for (int i = 0; i < pathA.size(); i++) + { + Segment a = (Segment) pathA.elementAt(i); + for (int j = 0; j < pathB.size(); j++) + { + Segment b = (Segment) pathB.elementAt(j); + nNodes += createNodes(a, b); + } + } + + Vector paths = new Vector(); + + // we have intersecting points. + Vector segments = new Vector(); + + // In a subtraction operation, we keep all + // segments of A oustide B and all B within A + // We outsideness-test only one segment in each path + // and the segments before and after any node + for (int i = 0; i < pathA.size(); i++) + { + Segment v = (Segment) pathA.elementAt(i); + Segment path = v; + if (v.isSegmentOutside(area) && v.node == null) + segments.add(v); + boolean node = false; + do + { + if ((v.node != null || node)) + { + node = (v.node != null); + if (v.isSegmentOutside(area)) + segments.add(v); + } + v = v.next; + } + while (v != path); + } + + for (int i = 0; i < pathB.size(); i++) + { + Segment v = (Segment) pathB.elementAt(i); + Segment path = v; + if (! v.isSegmentOutside(this) && v.node == null) + segments.add(v); + v = v.next; + boolean node = false; + do + { + if ((v.node != null || node)) + { + node = (v.node != null); + if (! v.isSegmentOutside(this)) + segments.add(v); + } + v = v.next; + } + while (v != path); + } + + paths = weilerAtherton(segments); + deleteRedundantPaths(paths); + } + + /** + * Performs an intersection operation on this Area.<BR> + * @param area - the area to be intersected with this area. + * @throws NullPointerException if <code>area</code> is <code>null</code>. + */ + public void intersect(Area area) + { + if (isEmpty() || area.isEmpty()) + { + reset(); + return; + } + if (equals(area)) + return; + + Vector pathA = new Vector(); + Area B = (Area) area.clone(); + pathA.addAll(solids); + pathA.addAll(holes); + + Vector pathB = new Vector(); + pathB.addAll(B.solids); + pathB.addAll(B.holes); + + int nNodes = 0; + + // create nodes + for (int i = 0; i < pathA.size(); i++) + { + Segment a = (Segment) pathA.elementAt(i); + for (int j = 0; j < pathB.size(); j++) + { + Segment b = (Segment) pathB.elementAt(j); + nNodes += createNodes(a, b); + } + } + + Vector paths = new Vector(); + + // we have intersecting points. + Vector segments = new Vector(); + + // In an intersection operation, we keep all + // segments of A within B and all B within A + // (The rest must be redundant) + // We outsideness-test only one segment in each path + // and the segments before and after any node + for (int i = 0; i < pathA.size(); i++) + { + Segment v = (Segment) pathA.elementAt(i); + Segment path = v; + if (! v.isSegmentOutside(area) && v.node == null) + segments.add(v); + boolean node = false; + do + { + if ((v.node != null || node)) + { + node = (v.node != null); + if (! v.isSegmentOutside(area)) + segments.add(v); + } + v = v.next; + } + while (v != path); + } + + for (int i = 0; i < pathB.size(); i++) + { + Segment v = (Segment) pathB.elementAt(i); + Segment path = v; + if (! v.isSegmentOutside(this) && v.node == null) + segments.add(v); + v = v.next; + boolean node = false; + do + { + if ((v.node != null || node)) + { + node = (v.node != null); + if (! v.isSegmentOutside(this)) + segments.add(v); + } + v = v.next; + } + while (v != path); + } + + paths = weilerAtherton(segments); + deleteRedundantPaths(paths); + } + + /** + * Performs an exclusive-or operation on this Area.<BR> + * @param area - the area to be XORed with this area. + * @throws NullPointerException if <code>area</code> is <code>null</code>. + */ + public void exclusiveOr(Area area) + { + if (area.isEmpty()) + return; + + if (isEmpty()) + { + Area B = (Area) area.clone(); + solids = B.solids; + holes = B.holes; + return; + } + if (equals(area)) + { + reset(); + return; + } + + Vector pathA = new Vector(); + + Area B = (Area) area.clone(); + Vector pathB = new Vector(); + pathA.addAll(solids); + pathA.addAll(holes); + + // reverse the directions of B paths. + setDirection(B.holes, true); + setDirection(B.solids, false); + pathB.addAll(B.solids); + pathB.addAll(B.holes); + + int nNodes = 0; + + for (int i = 0; i < pathA.size(); i++) + { + Segment a = (Segment) pathA.elementAt(i); + for (int j = 0; j < pathB.size(); j++) + { + Segment b = (Segment) pathB.elementAt(j); + nNodes += createNodes(a, b); + } + } + + Vector paths = new Vector(); + Segment v; + + // we have intersecting points. + Vector segments = new Vector(); + + // In an XOR operation, we operate on all segments + for (int i = 0; i < pathA.size(); i++) + { + v = (Segment) pathA.elementAt(i); + Segment path = v; + do + { + segments.add(v); + v = v.next; + } + while (v != path); + } + + for (int i = 0; i < pathB.size(); i++) + { + v = (Segment) pathB.elementAt(i); + Segment path = v; + do + { + segments.add(v); + v = v.next; + } + while (v != path); + } + + paths = weilerAtherton(segments); + deleteRedundantPaths(paths); + } + + /** + * Clears the Area object, creating an empty area. + */ + public void reset() + { + solids = new Vector(); + holes = new Vector(); + } + + /** + * Returns whether this area encloses any area. + * @return true if the object encloses any area. + */ + public boolean isEmpty() + { + if (solids.size() == 0) + return true; + + double totalArea = 0; + for (int i = 0; i < solids.size(); i++) + totalArea += Math.abs(((Segment) solids.elementAt(i)).getSignedArea()); + for (int i = 0; i < holes.size(); i++) + totalArea -= Math.abs(((Segment) holes.elementAt(i)).getSignedArea()); + if (totalArea <= EPSILON) + return true; + + return false; + } + + /** + * Determines whether the Area consists entirely of line segments + * @return true if the Area lines-only, false otherwise + */ + public boolean isPolygonal() + { + for (int i = 0; i < holes.size(); i++) + if (! ((Segment) holes.elementAt(i)).isPolygonal()) + return false; + for (int i = 0; i < solids.size(); i++) + if (! ((Segment) solids.elementAt(i)).isPolygonal()) + return false; + return true; + } + + /** + * Determines if the Area is rectangular.<P> + * + * This is strictly qualified. An area is considered rectangular if:<BR> + * <li>It consists of a single polygonal path.<BR> + * <li>It is oriented parallel/perpendicular to the xy axis<BR> + * <li>It must be exactly rectangular, i.e. small errors induced by + * transformations may cause a false result, although the area is + * visibly rectangular.<P> + * @return true if the above criteria are met, false otherwise + */ + public boolean isRectangular() + { + if (isEmpty()) + return true; + + if (holes.size() != 0 || solids.size() != 1) + return false; + + Segment path = (Segment) solids.elementAt(0); + if (! path.isPolygonal()) + return false; + + int nCorners = 0; + Segment s = path; + do + { + Segment s2 = s.next; + double d1 = (s.P2.getX() - s.P1.getX())*(s2.P2.getX() - s2.P1.getX())/ + ((s.P1.distance(s.P2)) * (s2.P1.distance(s2.P2))); + double d2 = (s.P2.getY() - s.P1.getY())*(s2.P2.getY() - s2.P1.getY())/ + ((s.P1.distance(s.P2)) * (s2.P1.distance(s2.P2))); + double dotproduct = d1 + d2; + + // For some reason, only rectangles on the XY axis count. + if (d1 != 0 && d2 != 0) + return false; + + if (Math.abs(dotproduct) == 0) // 90 degree angle + nCorners++; + else if ((Math.abs(1.0 - dotproduct) > 0)) // 0 degree angle? + return false; // if not, return false + + s = s.next; + } + while (s != path); + + return nCorners == 4; + } + + /** + * Returns whether the Area consists of more than one simple + * (non self-intersecting) subpath. + * + * @return true if the Area consists of none or one simple subpath, + * false otherwise. + */ + public boolean isSingular() + { + return (holes.size() == 0 && solids.size() <= 1); + } + + /** + * Returns the bounding box of the Area.<P> Unlike the CubicCurve2D and + * QuadraticCurve2D classes, this method will return the tightest possible + * bounding box, evaluating the extreme points of each curved segment.<P> + * @return the bounding box + */ + public Rectangle2D getBounds2D() + { + if (solids.size() == 0) + return new Rectangle2D.Double(0.0, 0.0, 0.0, 0.0); + + double xmin; + double xmax; + double ymin; + double ymax; + xmin = xmax = ((Segment) solids.elementAt(0)).P1.getX(); + ymin = ymax = ((Segment) solids.elementAt(0)).P1.getY(); + + for (int path = 0; path < solids.size(); path++) + { + Rectangle2D r = ((Segment) solids.elementAt(path)).getPathBounds(); + xmin = Math.min(r.getMinX(), xmin); + ymin = Math.min(r.getMinY(), ymin); + xmax = Math.max(r.getMaxX(), xmax); + ymax = Math.max(r.getMaxY(), ymax); + } + + return (new Rectangle2D.Double(xmin, ymin, (xmax - xmin), (ymax - ymin))); + } + + /** + * Returns the bounds of this object in Rectangle format. + * Please note that this may lead to loss of precision. + * + * @return The bounds. + * @see #getBounds2D() + */ + public Rectangle getBounds() + { + return getBounds2D().getBounds(); + } + + /** + * Create a new area of the same run-time type with the same contents as + * this one. + * + * @return the clone + */ + public Object clone() + { + try + { + Area clone = new Area(); + for (int i = 0; i < solids.size(); i++) + clone.solids.add(((Segment) solids.elementAt(i)).cloneSegmentList()); + for (int i = 0; i < holes.size(); i++) + clone.holes.add(((Segment) holes.elementAt(i)).cloneSegmentList()); + return clone; + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } + + /** + * Compares two Areas. + * + * @param area the area to compare against this area (<code>null</code> + * permitted). + * @return <code>true</code> if the areas are equal, and <code>false</code> + * otherwise. + */ + public boolean equals(Area area) + { + if (area == null) + return false; + + if (! getBounds2D().equals(area.getBounds2D())) + return false; + + if (solids.size() != area.solids.size() + || holes.size() != area.holes.size()) + return false; + + Vector pathA = new Vector(); + pathA.addAll(solids); + pathA.addAll(holes); + Vector pathB = new Vector(); + pathB.addAll(area.solids); + pathB.addAll(area.holes); + + int nPaths = pathA.size(); + boolean[][] match = new boolean[2][nPaths]; + + for (int i = 0; i < nPaths; i++) + { + for (int j = 0; j < nPaths; j++) + { + Segment p1 = (Segment) pathA.elementAt(i); + Segment p2 = (Segment) pathB.elementAt(j); + if (! match[0][i] && ! match[1][j]) + if (p1.pathEquals(p2)) + match[0][i] = match[1][j] = true; + } + } + + boolean result = true; + for (int i = 0; i < nPaths; i++) + result = result && match[0][i] && match[1][i]; + return result; + } + + /** + * Transforms this area by the AffineTransform at. + * + * @param at the transform. + */ + public void transform(AffineTransform at) + { + for (int i = 0; i < solids.size(); i++) + ((Segment) solids.elementAt(i)).transformSegmentList(at); + for (int i = 0; i < holes.size(); i++) + ((Segment) holes.elementAt(i)).transformSegmentList(at); + + // Note that the orientation is not invariant under inversion + if ((at.getType() & AffineTransform.TYPE_FLIP) != 0) + { + setDirection(holes, false); + setDirection(solids, true); + } + } + + /** + * Returns a new Area equal to this one, transformed + * by the AffineTransform at. + * @param at the transform. + * @return the transformed area + * @throws NullPointerException if <code>at</code> is <code>null</code>. + */ + public Area createTransformedArea(AffineTransform at) + { + Area a = (Area) clone(); + a.transform(at); + return a; + } + + /** + * Determines if the point (x,y) is contained within this Area. + * + * @param x the x-coordinate of the point. + * @param y the y-coordinate of the point. + * @return true if the point is contained, false otherwise. + */ + public boolean contains(double x, double y) + { + int n = 0; + for (int i = 0; i < solids.size(); i++) + if (((Segment) solids.elementAt(i)).contains(x, y)) + n++; + + for (int i = 0; i < holes.size(); i++) + if (((Segment) holes.elementAt(i)).contains(x, y)) + n--; + + return (n != 0); + } + + /** + * Determines if the Point2D p is contained within this Area. + * + * @param p the point. + * @return <code>true</code> if the point is contained, <code>false</code> + * otherwise. + * @throws NullPointerException if <code>p</code> is <code>null</code>. + */ + public boolean contains(Point2D p) + { + return contains(p.getX(), p.getY()); + } + + /** + * Determines if the rectangle specified by (x,y) as the upper-left + * and with width w and height h is completely contained within this Area, + * returns false otherwise.<P> + * + * This method should always produce the correct results, unlike for other + * classes in geom. + * + * @param x the x-coordinate of the rectangle. + * @param y the y-coordinate of the rectangle. + * @param w the width of the the rectangle. + * @param h the height of the rectangle. + * @return <code>true</code> if the rectangle is considered contained + */ + public boolean contains(double x, double y, double w, double h) + { + LineSegment[] l = new LineSegment[4]; + l[0] = new LineSegment(x, y, x + w, y); + l[1] = new LineSegment(x, y + h, x + w, y + h); + l[2] = new LineSegment(x, y, x, y + h); + l[3] = new LineSegment(x + w, y, x + w, y + h); + + // Since every segment in the area must a contour + // between inside/outside segments, ANY intersection + // will mean the rectangle is not entirely contained. + for (int i = 0; i < 4; i++) + { + for (int path = 0; path < solids.size(); path++) + { + Segment v; + Segment start; + start = v = (Segment) solids.elementAt(path); + do + { + if (l[i].hasIntersections(v)) + return false; + v = v.next; + } + while (v != start); + } + for (int path = 0; path < holes.size(); path++) + { + Segment v; + Segment start; + start = v = (Segment) holes.elementAt(path); + do + { + if (l[i].hasIntersections(v)) + return false; + v = v.next; + } + while (v != start); + } + } + + // Is any point inside? + if (! contains(x, y)) + return false; + + // Final hoop: Is the rectangle non-intersecting and inside, + // but encloses a hole? + Rectangle2D r = new Rectangle2D.Double(x, y, w, h); + for (int path = 0; path < holes.size(); path++) + if (! ((Segment) holes.elementAt(path)).isSegmentOutside(r)) + return false; + + return true; + } + + /** + * Determines if the Rectangle2D specified by r is completely contained + * within this Area, returns false otherwise.<P> + * + * This method should always produce the correct results, unlike for other + * classes in geom. + * + * @param r the rectangle. + * @return <code>true</code> if the rectangle is considered contained + * + * @throws NullPointerException if <code>r</code> is <code>null</code>. + */ + public boolean contains(Rectangle2D r) + { + return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Determines if the rectangle specified by (x,y) as the upper-left + * and with width w and height h intersects any part of this Area. + * + * @param x the x-coordinate for the rectangle. + * @param y the y-coordinate for the rectangle. + * @param w the width of the rectangle. + * @param h the height of the rectangle. + * @return <code>true</code> if the rectangle intersects the area, + * <code>false</code> otherwise. + */ + public boolean intersects(double x, double y, double w, double h) + { + if (solids.size() == 0) + return false; + + LineSegment[] l = new LineSegment[4]; + l[0] = new LineSegment(x, y, x + w, y); + l[1] = new LineSegment(x, y + h, x + w, y + h); + l[2] = new LineSegment(x, y, x, y + h); + l[3] = new LineSegment(x + w, y, x + w, y + h); + + // Return true on any intersection + for (int i = 0; i < 4; i++) + { + for (int path = 0; path < solids.size(); path++) + { + Segment v; + Segment start; + start = v = (Segment) solids.elementAt(path); + do + { + if (l[i].hasIntersections(v)) + return true; + v = v.next; + } + while (v != start); + } + for (int path = 0; path < holes.size(); path++) + { + Segment v; + Segment start; + start = v = (Segment) holes.elementAt(path); + do + { + if (l[i].hasIntersections(v)) + return true; + v = v.next; + } + while (v != start); + } + } + + // Non-intersecting, Is any point inside? + if (contains(x + w * 0.5, y + h * 0.5)) + return true; + + // What if the rectangle encloses the whole shape? + Point2D p = ((Segment) solids.elementAt(0)).getMidPoint(); + if ((new Rectangle2D.Double(x, y, w, h)).contains(p)) + return true; + return false; + } + + /** + * Determines if the Rectangle2D specified by r intersects any + * part of this Area. + * @param r the rectangle to test intersection with (<code>null</code> + * not permitted). + * @return <code>true</code> if the rectangle intersects the area, + * <code>false</code> otherwise. + * @throws NullPointerException if <code>r</code> is <code>null</code>. + */ + public boolean intersects(Rectangle2D r) + { + return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Returns a PathIterator object defining the contour of this Area, + * transformed by at. + * + * @param at the transform. + * @return A path iterator. + */ + public PathIterator getPathIterator(AffineTransform at) + { + return (new AreaIterator(at)); + } + + /** + * Returns a flattened PathIterator object defining the contour of this + * Area, transformed by at and with a defined flatness. + * + * @param at the transform. + * @param flatness the flatness. + * @return A path iterator. + */ + public PathIterator getPathIterator(AffineTransform at, double flatness) + { + return new FlatteningPathIterator(getPathIterator(at), flatness); + } + + //--------------------------------------------------------------------- + // Non-public methods and classes + + /** + * Private pathiterator object. + */ + private class AreaIterator implements PathIterator + { + private Vector segments; + private int index; + private AffineTransform at; + + // Simple compound type for segments + class IteratorSegment + { + int type; + double[] coords; + + IteratorSegment() + { + coords = new double[6]; + } + } + + /** + * The contructor here does most of the work, + * creates a vector of IteratorSegments, which can + * readily be returned + */ + public AreaIterator(AffineTransform at) + { + this.at = at; + index = 0; + segments = new Vector(); + Vector allpaths = new Vector(); + allpaths.addAll(solids); + allpaths.addAll(holes); + + for (int i = 0; i < allpaths.size(); i++) + { + Segment v = (Segment) allpaths.elementAt(i); + Segment start = v; + + IteratorSegment is = new IteratorSegment(); + is.type = SEG_MOVETO; + is.coords[0] = start.P1.getX(); + is.coords[1] = start.P1.getY(); + segments.add(is); + + do + { + is = new IteratorSegment(); + is.type = v.pathIteratorFormat(is.coords); + segments.add(is); + v = v.next; + } + while (v != start); + + is = new IteratorSegment(); + is.type = SEG_CLOSE; + segments.add(is); + } + } + + public int currentSegment(double[] coords) + { + IteratorSegment s = (IteratorSegment) segments.elementAt(index); + if (at != null) + at.transform(s.coords, 0, coords, 0, 3); + else + for (int i = 0; i < 6; i++) + coords[i] = s.coords[i]; + return (s.type); + } + + public int currentSegment(float[] coords) + { + IteratorSegment s = (IteratorSegment) segments.elementAt(index); + double[] d = new double[6]; + if (at != null) + { + at.transform(s.coords, 0, d, 0, 3); + for (int i = 0; i < 6; i++) + coords[i] = (float) d[i]; + } + else + for (int i = 0; i < 6; i++) + coords[i] = (float) s.coords[i]; + return (s.type); + } + + // Note that the winding rule should not matter here, + // EVEN_ODD is chosen because it renders faster. + public int getWindingRule() + { + return (PathIterator.WIND_EVEN_ODD); + } + + public boolean isDone() + { + return (index >= segments.size()); + } + + public void next() + { + index++; + } + } + + /** + * Performs the fundamental task of the Weiler-Atherton algorithm, + * traverse a list of segments, for each segment: + * Follow it, removing segments from the list and switching paths + * at each node. Do so until the starting segment is reached. + * + * Returns a Vector of the resulting paths. + */ + private Vector weilerAtherton(Vector segments) + { + Vector paths = new Vector(); + while (segments.size() > 0) + { + // Iterate over the path + Segment start = (Segment) segments.elementAt(0); + Segment s = start; + do + { + segments.remove(s); + if (s.node != null) + { // switch over + s.next = s.node; + s.node = null; + } + s = s.next; // continue + } + while (s != start); + + paths.add(start); + } + return paths; + } + + /** + * A small wrapper class to store intersection points + */ + private class Intersection + { + Point2D p; // the 2D point of intersection + double ta; // the parametric value on a + double tb; // the parametric value on b + Segment seg; // segment placeholder for node setting + + public Intersection(Point2D p, double ta, double tb) + { + this.p = p; + this.ta = ta; + this.tb = tb; + } + } + + /** + * Returns the recursion depth necessary to approximate the + * curve by line segments within the error RS_EPSILON. + * + * This is done with Wang's formula: + * L0 = max{0<=i<=N-2}(|xi - 2xi+1 + xi+2|,|yi - 2yi+1 + yi+2|) + * r0 = log4(sqrt(2)*N*(N-1)*L0/8e) + * Where e is the maximum distance error (RS_EPSILON) + */ + private int getRecursionDepth(CubicSegment curve) + { + double x0 = curve.P1.getX(); + double y0 = curve.P1.getY(); + + double x1 = curve.cp1.getX(); + double y1 = curve.cp1.getY(); + + double x2 = curve.cp2.getX(); + double y2 = curve.cp2.getY(); + + double x3 = curve.P2.getX(); + double y3 = curve.P2.getY(); + + double L0 = Math.max(Math.max(Math.abs(x0 - 2 * x1 + x2), + Math.abs(x1 - 2 * x2 + x3)), + Math.max(Math.abs(y0 - 2 * y1 + y2), + Math.abs(y1 - 2 * y2 + y3))); + + double f = Math.sqrt(2) * 6.0 * L0 / (8.0 * RS_EPSILON); + + int r0 = (int) Math.ceil(Math.log(f) / Math.log(4.0)); + return (r0); + } + + /** + * Performs recursive subdivision: + * @param c1 - curve 1 + * @param c2 - curve 2 + * @param depth1 - recursion depth of curve 1 + * @param depth2 - recursion depth of curve 2 + * @param t1 - global parametric value of the first curve's starting point + * @param t2 - global parametric value of the second curve's starting point + * @param w1 - global parametric length of curve 1 + * @param w2 - global parametric length of curve 2 + * + * The final four parameters are for keeping track of the parametric + * value of the curve. For a full curve t = 0, w = 1, w is halved with + * each subdivision. + */ + private void recursiveSubdivide(CubicCurve2D c1, CubicCurve2D c2, + int depth1, int depth2, double t1, + double t2, double w1, double w2) + { + boolean flat1 = depth1 <= 0; + boolean flat2 = depth2 <= 0; + + if (flat1 && flat2) + { + double xlk = c1.getP2().getX() - c1.getP1().getX(); + double ylk = c1.getP2().getY() - c1.getP1().getY(); + + double xnm = c2.getP2().getX() - c2.getP1().getX(); + double ynm = c2.getP2().getY() - c2.getP1().getY(); + + double xmk = c2.getP1().getX() - c1.getP1().getX(); + double ymk = c2.getP1().getY() - c1.getP1().getY(); + double det = xnm * ylk - ynm * xlk; + + if (det + 1.0 == 1.0) + return; + + double detinv = 1.0 / det; + double s = (xnm * ymk - ynm * xmk) * detinv; + double t = (xlk * ymk - ylk * xmk) * detinv; + if ((s < 0.0) || (s > 1.0) || (t < 0.0) || (t > 1.0)) + return; + + double[] temp = new double[2]; + temp[0] = t1 + s * w1; + temp[1] = t2 + t * w1; + cc_intersections.add(temp); + return; + } + + CubicCurve2D.Double c11 = new CubicCurve2D.Double(); + CubicCurve2D.Double c12 = new CubicCurve2D.Double(); + CubicCurve2D.Double c21 = new CubicCurve2D.Double(); + CubicCurve2D.Double c22 = new CubicCurve2D.Double(); + + if (! flat1 && ! flat2) + { + depth1--; + depth2--; + w1 = w1 * 0.5; + w2 = w2 * 0.5; + c1.subdivide(c11, c12); + c2.subdivide(c21, c22); + if (c11.getBounds2D().intersects(c21.getBounds2D())) + recursiveSubdivide(c11, c21, depth1, depth2, t1, t2, w1, w2); + if (c11.getBounds2D().intersects(c22.getBounds2D())) + recursiveSubdivide(c11, c22, depth1, depth2, t1, t2 + w2, w1, w2); + if (c12.getBounds2D().intersects(c21.getBounds2D())) + recursiveSubdivide(c12, c21, depth1, depth2, t1 + w1, t2, w1, w2); + if (c12.getBounds2D().intersects(c22.getBounds2D())) + recursiveSubdivide(c12, c22, depth1, depth2, t1 + w1, t2 + w2, w1, w2); + return; + } + + if (! flat1) + { + depth1--; + c1.subdivide(c11, c12); + w1 = w1 * 0.5; + if (c11.getBounds2D().intersects(c2.getBounds2D())) + recursiveSubdivide(c11, c2, depth1, depth2, t1, t2, w1, w2); + if (c12.getBounds2D().intersects(c2.getBounds2D())) + recursiveSubdivide(c12, c2, depth1, depth2, t1 + w1, t2, w1, w2); + return; + } + + depth2--; + c2.subdivide(c21, c22); + w2 = w2 * 0.5; + if (c1.getBounds2D().intersects(c21.getBounds2D())) + recursiveSubdivide(c1, c21, depth1, depth2, t1, t2, w1, w2); + if (c1.getBounds2D().intersects(c22.getBounds2D())) + recursiveSubdivide(c1, c22, depth1, depth2, t1, t2 + w2, w1, w2); + } + + /** + * Returns a set of interesections between two Cubic segments + * Or null if no intersections were found. + * + * The method used to find the intersection is recursive midpoint + * subdivision. Outline description: + * + * 1) Check if the bounding boxes of the curves intersect, + * 2) If so, divide the curves in the middle and test the bounding + * boxes again, + * 3) Repeat until a maximum recursion depth has been reached, where + * the intersecting curves can be approximated by line segments. + * + * This is a reasonably accurate method, although the recursion depth + * is typically around 20, the bounding-box tests allow for significant + * pruning of the subdivision tree. + * + * This is package-private to avoid an accessor method. + */ + Intersection[] cubicCubicIntersect(CubicSegment curve1, CubicSegment curve2) + { + Rectangle2D r1 = curve1.getBounds(); + Rectangle2D r2 = curve2.getBounds(); + + if (! r1.intersects(r2)) + return null; + + cc_intersections = new Vector(); + recursiveSubdivide(curve1.getCubicCurve2D(), curve2.getCubicCurve2D(), + getRecursionDepth(curve1), getRecursionDepth(curve2), + 0.0, 0.0, 1.0, 1.0); + + if (cc_intersections.size() == 0) + return null; + + Intersection[] results = new Intersection[cc_intersections.size()]; + for (int i = 0; i < cc_intersections.size(); i++) + { + double[] temp = (double[]) cc_intersections.elementAt(i); + results[i] = new Intersection(curve1.evaluatePoint(temp[0]), temp[0], + temp[1]); + } + cc_intersections = null; + return (results); + } + + /** + * Returns the intersections between a line and a quadratic bezier + * Or null if no intersections are found1 + * This is done through combining the line's equation with the + * parametric form of the Bezier and solving the resulting quadratic. + * This is package-private to avoid an accessor method. + */ + Intersection[] lineQuadIntersect(LineSegment l, QuadSegment c) + { + double[] y = new double[3]; + double[] x = new double[3]; + double[] r = new double[3]; + int nRoots; + double x0 = c.P1.getX(); + double y0 = c.P1.getY(); + double x1 = c.cp.getX(); + double y1 = c.cp.getY(); + double x2 = c.P2.getX(); + double y2 = c.P2.getY(); + + double lx0 = l.P1.getX(); + double ly0 = l.P1.getY(); + double lx1 = l.P2.getX(); + double ly1 = l.P2.getY(); + double dx = lx1 - lx0; + double dy = ly1 - ly0; + + // form r(t) = y(t) - x(t) for the bezier + y[0] = y0; + y[1] = 2 * (y1 - y0); + y[2] = (y2 - 2 * y1 + y0); + + x[0] = x0; + x[1] = 2 * (x1 - x0); + x[2] = (x2 - 2 * x1 + x0); + + // a point, not a line + if (dy == 0 && dx == 0) + return null; + + // line on y axis + if (dx == 0 || (dy / dx) > 1.0) + { + double k = dx / dy; + x[0] -= lx0; + y[0] -= ly0; + y[0] *= k; + y[1] *= k; + y[2] *= k; + } + else + { + double k = dy / dx; + x[0] -= lx0; + y[0] -= ly0; + x[0] *= k; + x[1] *= k; + x[2] *= k; + } + + for (int i = 0; i < 3; i++) + r[i] = y[i] - x[i]; + + if ((nRoots = QuadCurve2D.solveQuadratic(r)) > 0) + { + Intersection[] temp = new Intersection[nRoots]; + int intersections = 0; + for (int i = 0; i < nRoots; i++) + { + double t = r[i]; + if (t >= 0.0 && t <= 1.0) + { + Point2D p = c.evaluatePoint(t); + + // if the line is on an axis, snap the point to that axis. + if (dx == 0) + p.setLocation(lx0, p.getY()); + if (dy == 0) + p.setLocation(p.getX(), ly0); + + if (p.getX() <= Math.max(lx0, lx1) + && p.getX() >= Math.min(lx0, lx1) + && p.getY() <= Math.max(ly0, ly1) + && p.getY() >= Math.min(ly0, ly1)) + { + double lineparameter = p.distance(l.P1) / l.P2.distance(l.P1); + temp[i] = new Intersection(p, lineparameter, t); + intersections++; + } + } + else + temp[i] = null; + } + if (intersections == 0) + return null; + + Intersection[] rValues = new Intersection[intersections]; + + for (int i = 0; i < nRoots; i++) + if (temp[i] != null) + rValues[--intersections] = temp[i]; + return (rValues); + } + return null; + } + + /** + * Returns the intersections between a line and a cubic segment + * This is done through combining the line's equation with the + * parametric form of the Bezier and solving the resulting quadratic. + * This is package-private to avoid an accessor method. + */ + Intersection[] lineCubicIntersect(LineSegment l, CubicSegment c) + { + double[] y = new double[4]; + double[] x = new double[4]; + double[] r = new double[4]; + int nRoots; + double x0 = c.P1.getX(); + double y0 = c.P1.getY(); + double x1 = c.cp1.getX(); + double y1 = c.cp1.getY(); + double x2 = c.cp2.getX(); + double y2 = c.cp2.getY(); + double x3 = c.P2.getX(); + double y3 = c.P2.getY(); + + double lx0 = l.P1.getX(); + double ly0 = l.P1.getY(); + double lx1 = l.P2.getX(); + double ly1 = l.P2.getY(); + double dx = lx1 - lx0; + double dy = ly1 - ly0; + + // form r(t) = y(t) - x(t) for the bezier + y[0] = y0; + y[1] = 3 * (y1 - y0); + y[2] = 3 * (y2 + y0 - 2 * y1); + y[3] = y3 - 3 * y2 + 3 * y1 - y0; + + x[0] = x0; + x[1] = 3 * (x1 - x0); + x[2] = 3 * (x2 + x0 - 2 * x1); + x[3] = x3 - 3 * x2 + 3 * x1 - x0; + + // a point, not a line + if (dy == 0 && dx == 0) + return null; + + // line on y axis + if (dx == 0 || (dy / dx) > 1.0) + { + double k = dx / dy; + x[0] -= lx0; + y[0] -= ly0; + y[0] *= k; + y[1] *= k; + y[2] *= k; + y[3] *= k; + } + else + { + double k = dy / dx; + x[0] -= lx0; + y[0] -= ly0; + x[0] *= k; + x[1] *= k; + x[2] *= k; + x[3] *= k; + } + for (int i = 0; i < 4; i++) + r[i] = y[i] - x[i]; + + if ((nRoots = CubicCurve2D.solveCubic(r)) > 0) + { + Intersection[] temp = new Intersection[nRoots]; + int intersections = 0; + for (int i = 0; i < nRoots; i++) + { + double t = r[i]; + if (t >= 0.0 && t <= 1.0) + { + // if the line is on an axis, snap the point to that axis. + Point2D p = c.evaluatePoint(t); + if (dx == 0) + p.setLocation(lx0, p.getY()); + if (dy == 0) + p.setLocation(p.getX(), ly0); + + if (p.getX() <= Math.max(lx0, lx1) + && p.getX() >= Math.min(lx0, lx1) + && p.getY() <= Math.max(ly0, ly1) + && p.getY() >= Math.min(ly0, ly1)) + { + double lineparameter = p.distance(l.P1) / l.P2.distance(l.P1); + temp[i] = new Intersection(p, lineparameter, t); + intersections++; + } + } + else + temp[i] = null; + } + + if (intersections == 0) + return null; + + Intersection[] rValues = new Intersection[intersections]; + for (int i = 0; i < nRoots; i++) + if (temp[i] != null) + rValues[--intersections] = temp[i]; + return (rValues); + } + return null; + } + + /** + * Returns the intersection between two lines, or null if there is no + * intersection. + * This is package-private to avoid an accessor method. + */ + Intersection linesIntersect(LineSegment a, LineSegment b) + { + Point2D P1 = a.P1; + Point2D P2 = a.P2; + Point2D P3 = b.P1; + Point2D P4 = b.P2; + + if (! Line2D.linesIntersect(P1.getX(), P1.getY(), P2.getX(), P2.getY(), + P3.getX(), P3.getY(), P4.getX(), P4.getY())) + return null; + + double x1 = P1.getX(); + double y1 = P1.getY(); + double rx = P2.getX() - x1; + double ry = P2.getY() - y1; + + double x2 = P3.getX(); + double y2 = P3.getY(); + double sx = P4.getX() - x2; + double sy = P4.getY() - y2; + + double determinant = sx * ry - sy * rx; + double nom = (sx * (y2 - y1) + sy * (x1 - x2)); + + // Parallel lines don't intersect. At least we pretend they don't. + if (Math.abs(determinant) < EPSILON) + return null; + + nom = nom / determinant; + + if (nom == 0.0) + return null; + if (nom == 1.0) + return null; + + Point2D p = new Point2D.Double(x1 + nom * rx, y1 + nom * ry); + + return new Intersection(p, p.distance(P1) / P1.distance(P2), + p.distance(P3) / P3.distance(P4)); + } + + /** + * Determines if two points are equal, within an error margin + * 'snap distance' + * This is package-private to avoid an accessor method. + */ + boolean pointEquals(Point2D a, Point2D b) + { + return (a.equals(b) || a.distance(b) < PE_EPSILON); + } + + /** + * Helper method + * Turns a shape into a Vector of Segments + */ + private Vector makeSegment(Shape s) + { + Vector paths = new Vector(); + PathIterator pi = s.getPathIterator(null); + double[] coords = new double[6]; + Segment subpath = null; + Segment current = null; + double cx; + double cy; + double subpathx; + double subpathy; + cx = cy = subpathx = subpathy = 0.0; + + this.windingRule = pi.getWindingRule(); + + while (! pi.isDone()) + { + Segment v; + switch (pi.currentSegment(coords)) + { + case PathIterator.SEG_MOVETO: + if (subpath != null) + { // close existing open path + current.next = new LineSegment(cx, cy, subpathx, subpathy); + current = current.next; + current.next = subpath; + } + subpath = null; + subpathx = cx = coords[0]; + subpathy = cy = coords[1]; + break; + + // replace 'close' with a line-to. + case PathIterator.SEG_CLOSE: + if (subpath != null && (subpathx != cx || subpathy != cy)) + { + current.next = new LineSegment(cx, cy, subpathx, subpathy); + current = current.next; + current.next = subpath; + cx = subpathx; + cy = subpathy; + subpath = null; + } + else if (subpath != null) + { + current.next = subpath; + subpath = null; + } + break; + case PathIterator.SEG_LINETO: + if (cx != coords[0] || cy != coords[1]) + { + v = new LineSegment(cx, cy, coords[0], coords[1]); + if (subpath == null) + { + subpath = current = v; + paths.add(subpath); + } + else + { + current.next = v; + current = current.next; + } + cx = coords[0]; + cy = coords[1]; + } + break; + case PathIterator.SEG_QUADTO: + v = new QuadSegment(cx, cy, coords[0], coords[1], coords[2], + coords[3]); + if (subpath == null) + { + subpath = current = v; + paths.add(subpath); + } + else + { + current.next = v; + current = current.next; + } + cx = coords[2]; + cy = coords[3]; + break; + case PathIterator.SEG_CUBICTO: + v = new CubicSegment(cx, cy, coords[0], coords[1], coords[2], + coords[3], coords[4], coords[5]); + if (subpath == null) + { + subpath = current = v; + paths.add(subpath); + } + else + { + current.next = v; + current = current.next; + } + + // check if the cubic is self-intersecting + double[] lpts = ((CubicSegment) v).getLoop(); + if (lpts != null) + { + // if it is, break off the loop into its own path. + v.subdivideInsert(lpts[0]); + v.next.subdivideInsert((lpts[1] - lpts[0]) / (1.0 - lpts[0])); + + CubicSegment loop = (CubicSegment) v.next; + v.next = loop.next; + loop.next = loop; + + v.P2 = v.next.P1 = loop.P2 = loop.P1; // snap points + paths.add(loop); + current = v.next; + } + + cx = coords[4]; + cy = coords[5]; + break; + } + pi.next(); + } + + if (subpath != null) + { // close any open path + if (subpathx != cx || subpathy != cy) + { + current.next = new LineSegment(cx, cy, subpathx, subpathy); + current = current.next; + current.next = subpath; + } + else + current.next = subpath; + } + + if (paths.size() == 0) + return (null); + + return (paths); + } + + /** + * Find the intersections of two separate closed paths, + * A and B, split the segments at the intersection points, + * and create nodes pointing from one to the other + */ + private int createNodes(Segment A, Segment B) + { + int nNodes = 0; + + Segment a = A; + Segment b = B; + + do + { + do + { + nNodes += a.splitIntersections(b); + b = b.next; + } + while (b != B); + + a = a.next; // move to the next segment + } + while (a != A); // until one wrap. + + return (nNodes); + } + + /** + * Find the intersections of a path with itself. + * Splits the segments at the intersection points, + * and create nodes pointing from one to the other. + */ + private int createNodesSelf(Segment A) + { + int nNodes = 0; + Segment a = A; + + if (A.next == A) + return 0; + + do + { + Segment b = a.next; + do + { + if (b != a) // necessary + nNodes += a.splitIntersections(b); + b = b.next; + } + while (b != A); + a = a.next; // move to the next segment + } + while (a != A); // until one wrap. + + return (nNodes); + } + + /** + * Deletes paths which are redundant from a list, (i.e. solid areas within + * solid areas) Clears any nodes. Sorts the remaining paths into solids + * and holes, sets their orientation and sets the solids and holes lists. + */ + private void deleteRedundantPaths(Vector paths) + { + int npaths = paths.size(); + + int[][] contains = new int[npaths][npaths]; + int[][] windingNumbers = new int[npaths][2]; + int neg; + Rectangle2D[] bb = new Rectangle2D[npaths]; // path bounding boxes + + neg = ((windingRule == PathIterator.WIND_NON_ZERO) ? -1 : 1); + + for (int i = 0; i < npaths; i++) + bb[i] = ((Segment) paths.elementAt(i)).getPathBounds(); + + // Find which path contains which, assign winding numbers + for (int i = 0; i < npaths; i++) + { + Segment pathA = (Segment) paths.elementAt(i); + pathA.nullNodes(); // remove any now-redundant nodes, in case. + int windingA = pathA.hasClockwiseOrientation() ? 1 : neg; + + for (int j = 0; j < npaths; j++) + if (i != j) + { + Segment pathB = (Segment) paths.elementAt(j); + + // A contains B + if (bb[i].intersects(bb[j])) + { + Segment s = pathB.next; + while (s.P1.getY() == s.P2.getY() && s != pathB) + s = s.next; + Point2D p = s.getMidPoint(); + if (pathA.contains(p.getX(), p.getY())) + contains[i][j] = windingA; + } + else + // A does not contain B + contains[i][j] = 0; + } + else + contains[i][j] = windingA; // i == j + } + + for (int i = 0; i < npaths; i++) + { + windingNumbers[i][0] = 0; + for (int j = 0; j < npaths; j++) + windingNumbers[i][0] += contains[j][i]; + windingNumbers[i][1] = contains[i][i]; + } + + Vector solids = new Vector(); + Vector holes = new Vector(); + + if (windingRule == PathIterator.WIND_NON_ZERO) + { + for (int i = 0; i < npaths; i++) + { + if (windingNumbers[i][0] == 0) + holes.add(paths.elementAt(i)); + else if (windingNumbers[i][0] - windingNumbers[i][1] == 0 + && Math.abs(windingNumbers[i][0]) == 1) + solids.add(paths.elementAt(i)); + } + } + else + { + windingRule = PathIterator.WIND_NON_ZERO; + for (int i = 0; i < npaths; i++) + { + if ((windingNumbers[i][0] & 1) == 0) + holes.add(paths.elementAt(i)); + else if ((windingNumbers[i][0] & 1) == 1) + solids.add(paths.elementAt(i)); + } + } + + setDirection(holes, false); + setDirection(solids, true); + this.holes = holes; + this.solids = solids; + } + + /** + * Sets the winding direction of a Vector of paths + * @param clockwise gives the direction, + * true = clockwise, false = counter-clockwise + */ + private void setDirection(Vector paths, boolean clockwise) + { + Segment v; + for (int i = 0; i < paths.size(); i++) + { + v = (Segment) paths.elementAt(i); + if (clockwise != v.hasClockwiseOrientation()) + v.reverseAll(); + } + } + + /** + * Class representing a linked-list of vertices forming a closed polygon, + * convex or concave, without holes. + */ + private abstract class Segment implements Cloneable + { + // segment type, PathIterator segment types are used. + Point2D P1; + Point2D P2; + Segment next; + Segment node; + + Segment() + { + P1 = P2 = null; + node = next = null; + } + + /** + * Reverses the direction of a single segment + */ + abstract void reverseCoords(); + + /** + * Returns the segment's midpoint + */ + abstract Point2D getMidPoint(); + + /** + * Returns the bounding box of this segment + */ + abstract Rectangle2D getBounds(); + + /** + * Transforms a single segment + */ + abstract void transform(AffineTransform at); + + /** + * Returns the PathIterator type of a segment + */ + abstract int getType(); + + /** + */ + abstract int splitIntersections(Segment b); + + /** + * Returns the PathIterator coords of a segment + */ + abstract int pathIteratorFormat(double[] coords); + + /** + * Returns the number of intersections on the positive X axis, + * with the origin at (x,y), used for contains()-testing + * + * (Although that could be done by the line-intersect methods, + * a dedicated method is better to guarantee consitent handling + * of endpoint-special-cases) + */ + abstract int rayCrossing(double x, double y); + + /** + * Subdivides the segment at parametric value t, inserting + * the new segment into the linked list after this, + * such that this becomes [0,t] and this.next becomes [t,1] + */ + abstract void subdivideInsert(double t); + + /** + * Returns twice the area of a curve, relative the P1-P2 line + * Used for area calculations. + */ + abstract double curveArea(); + + /** + * Compare two segments. + */ + abstract boolean equals(Segment b); + + /** + * Determines if this path of segments contains the point (x,y) + */ + boolean contains(double x, double y) + { + Segment v = this; + int crossings = 0; + do + { + int n = v.rayCrossing(x, y); + crossings += n; + v = v.next; + } + while (v != this); + return ((crossings & 1) == 1); + } + + /** + * Nulls all nodes of the path. Clean up any 'hairs'. + */ + void nullNodes() + { + Segment v = this; + do + { + v.node = null; + v = v.next; + } + while (v != this); + } + + /** + * Transforms each segment in the closed path + */ + void transformSegmentList(AffineTransform at) + { + Segment v = this; + do + { + v.transform(at); + v = v.next; + } + while (v != this); + } + + /** + * Determines the winding direction of the path + * By the sign of the area. + */ + boolean hasClockwiseOrientation() + { + return (getSignedArea() > 0.0); + } + + /** + * Returns the bounds of this path + */ + public Rectangle2D getPathBounds() + { + double xmin; + double xmax; + double ymin; + double ymax; + xmin = xmax = P1.getX(); + ymin = ymax = P1.getY(); + + Segment v = this; + do + { + Rectangle2D r = v.getBounds(); + xmin = Math.min(r.getMinX(), xmin); + ymin = Math.min(r.getMinY(), ymin); + xmax = Math.max(r.getMaxX(), xmax); + ymax = Math.max(r.getMaxY(), ymax); + v = v.next; + } + while (v != this); + + return (new Rectangle2D.Double(xmin, ymin, (xmax - xmin), (ymax - ymin))); + } + + /** + * Calculates twice the signed area of the path; + */ + double getSignedArea() + { + Segment s; + double area = 0.0; + + s = this; + do + { + area += s.curveArea(); + + area += s.P1.getX() * s.next.P1.getY() + - s.P1.getY() * s.next.P1.getX(); + s = s.next; + } + while (s != this); + + return area; + } + + /** + * Reverses the orientation of the whole polygon + */ + void reverseAll() + { + reverseCoords(); + Segment v = next; + Segment former = this; + while (v != this) + { + v.reverseCoords(); + Segment vnext = v.next; + v.next = former; + former = v; + v = vnext; + } + next = former; + } + + /** + * Inserts a Segment after this one + */ + void insert(Segment v) + { + Segment n = next; + next = v; + v.next = n; + } + + /** + * Returns if this segment path is polygonal + */ + boolean isPolygonal() + { + Segment v = this; + do + { + if (! (v instanceof LineSegment)) + return false; + v = v.next; + } + while (v != this); + return true; + } + + /** + * Clones this path + */ + Segment cloneSegmentList() throws CloneNotSupportedException + { + Vector list = new Vector(); + Segment v = next; + + while (v != this) + { + list.add(v); + v = v.next; + } + + Segment clone = (Segment) this.clone(); + v = clone; + for (int i = 0; i < list.size(); i++) + { + clone.next = (Segment) ((Segment) list.elementAt(i)).clone(); + clone = clone.next; + } + clone.next = v; + return v; + } + + /** + * Creates a node between this segment and segment b + * at the given intersection + * @return the number of nodes created (0 or 1) + */ + int createNode(Segment b, Intersection i) + { + Point2D p = i.p; + if ((pointEquals(P1, p) || pointEquals(P2, p)) + && (pointEquals(b.P1, p) || pointEquals(b.P2, p))) + return 0; + + subdivideInsert(i.ta); + b.subdivideInsert(i.tb); + + // snap points + b.P2 = b.next.P1 = P2 = next.P1 = i.p; + + node = b.next; + b.node = next; + return 1; + } + + /** + * Creates multiple nodes from a list of intersections, + * This must be done in the order of ascending parameters, + * and the parameters must be recalculated in accordance + * with each split. + * @return the number of nodes created + */ + protected int createNodes(Segment b, Intersection[] x) + { + Vector v = new Vector(); + for (int i = 0; i < x.length; i++) + { + Point2D p = x[i].p; + if (! ((pointEquals(P1, p) || pointEquals(P2, p)) + && (pointEquals(b.P1, p) || pointEquals(b.P2, p)))) + v.add(x[i]); + } + + int nNodes = v.size(); + Intersection[] A = new Intersection[nNodes]; + Intersection[] B = new Intersection[nNodes]; + for (int i = 0; i < nNodes; i++) + A[i] = B[i] = (Intersection) v.elementAt(i); + + // Create two lists sorted by the parameter + // Bubble sort, OK I suppose, since the number of intersections + // cannot be larger than 9 (cubic-cubic worst case) anyway + for (int i = 0; i < nNodes - 1; i++) + { + for (int j = i + 1; j < nNodes; j++) + { + if (A[i].ta > A[j].ta) + { + Intersection swap = A[i]; + A[i] = A[j]; + A[j] = swap; + } + if (B[i].tb > B[j].tb) + { + Intersection swap = B[i]; + B[i] = B[j]; + B[j] = swap; + } + } + } + // subdivide a + Segment s = this; + for (int i = 0; i < nNodes; i++) + { + s.subdivideInsert(A[i].ta); + + // renormalize the parameters + for (int j = i + 1; j < nNodes; j++) + A[j].ta = (A[j].ta - A[i].ta) / (1.0 - A[i].ta); + + A[i].seg = s; + s = s.next; + } + + // subdivide b, set nodes + s = b; + for (int i = 0; i < nNodes; i++) + { + s.subdivideInsert(B[i].tb); + + for (int j = i + 1; j < nNodes; j++) + B[j].tb = (B[j].tb - B[i].tb) / (1.0 - B[i].tb); + + // set nodes + B[i].seg.node = s.next; // node a -> b + s.node = B[i].seg.next; // node b -> a + + // snap points + B[i].seg.P2 = B[i].seg.next.P1 = s.P2 = s.next.P1 = B[i].p; + s = s.next; + } + return nNodes; + } + + /** + * Determines if two paths are equal. + * Colinear line segments are ignored in the comparison. + */ + boolean pathEquals(Segment B) + { + if (! getPathBounds().equals(B.getPathBounds())) + return false; + + Segment startA = getTopLeft(); + Segment startB = B.getTopLeft(); + Segment a = startA; + Segment b = startB; + do + { + if (! a.equals(b)) + return false; + + if (a instanceof LineSegment) + a = ((LineSegment) a).lastCoLinear(); + if (b instanceof LineSegment) + b = ((LineSegment) b).lastCoLinear(); + + a = a.next; + b = b.next; + } + while (a != startA && b != startB); + return true; + } + + /** + * Return the segment with the top-leftmost first point + */ + Segment getTopLeft() + { + Segment v = this; + Segment tl = this; + do + { + if (v.P1.getY() < tl.P1.getY()) + tl = v; + else if (v.P1.getY() == tl.P1.getY()) + { + if (v.P1.getX() < tl.P1.getX()) + tl = v; + } + v = v.next; + } + while (v != this); + return tl; + } + + /** + * Returns if the path has a segment outside a shape + */ + boolean isSegmentOutside(Shape shape) + { + return ! shape.contains(getMidPoint()); + } + } // class Segment + + private class LineSegment extends Segment + { + public LineSegment(double x1, double y1, double x2, double y2) + { + super(); + P1 = new Point2D.Double(x1, y1); + P2 = new Point2D.Double(x2, y2); + } + + public LineSegment(Point2D p1, Point2D p2) + { + super(); + P1 = (Point2D) p1.clone(); + P2 = (Point2D) p2.clone(); + } + + /** + * Clones this segment + */ + public Object clone() + { + return new LineSegment(P1, P2); + } + + /** + * Transforms the segment + */ + void transform(AffineTransform at) + { + P1 = at.transform(P1, null); + P2 = at.transform(P2, null); + } + + /** + * Swap start and end points + */ + void reverseCoords() + { + Point2D p = P1; + P1 = P2; + P2 = p; + } + + /** + * Returns the segment's midpoint + */ + Point2D getMidPoint() + { + return (new Point2D.Double(0.5 * (P1.getX() + P2.getX()), + 0.5 * (P1.getY() + P2.getY()))); + } + + /** + * Returns twice the area of a curve, relative the P1-P2 line + * Obviously, a line does not enclose any area besides the line + */ + double curveArea() + { + return 0; + } + + /** + * Returns the PathIterator type of a segment + */ + int getType() + { + return (PathIterator.SEG_LINETO); + } + + /** + * Subdivides the segment at parametric value t, inserting + * the new segment into the linked list after this, + * such that this becomes [0,t] and this.next becomes [t,1] + */ + void subdivideInsert(double t) + { + Point2D p = new Point2D.Double((P2.getX() - P1.getX()) * t + P1.getX(), + (P2.getY() - P1.getY()) * t + P1.getY()); + insert(new LineSegment(p, P2)); + P2 = p; + next.node = node; + node = null; + } + + /** + * Determines if two line segments are strictly colinear + */ + boolean isCoLinear(LineSegment b) + { + double x1 = P1.getX(); + double y1 = P1.getY(); + double x2 = P2.getX(); + double y2 = P2.getY(); + double x3 = b.P1.getX(); + double y3 = b.P1.getY(); + double x4 = b.P2.getX(); + double y4 = b.P2.getY(); + + if ((y1 - y3) * (x4 - x3) - (x1 - x3) * (y4 - y3) != 0.0) + return false; + + return ((x2 - x1) * (y4 - y3) - (y2 - y1) * (x4 - x3) == 0.0); + } + + /** + * Return the last segment colinear with this one. + * Used in comparing paths. + */ + Segment lastCoLinear() + { + Segment prev = this; + Segment v = next; + + while (v instanceof LineSegment) + { + if (isCoLinear((LineSegment) v)) + { + prev = v; + v = v.next; + } + else + return prev; + } + return prev; + } + + /** + * Compare two segments. + * We must take into account that the lines may be broken into colinear + * subsegments and ignore them. + */ + boolean equals(Segment b) + { + if (! (b instanceof LineSegment)) + return false; + Point2D p1 = P1; + Point2D p3 = b.P1; + + if (! p1.equals(p3)) + return false; + + Point2D p2 = lastCoLinear().P2; + Point2D p4 = ((LineSegment) b).lastCoLinear().P2; + return (p2.equals(p4)); + } + + /** + * Returns a line segment + */ + int pathIteratorFormat(double[] coords) + { + coords[0] = P2.getX(); + coords[1] = P2.getY(); + return (PathIterator.SEG_LINETO); + } + + /** + * Returns if the line has intersections. + */ + boolean hasIntersections(Segment b) + { + if (b instanceof LineSegment) + return (linesIntersect(this, (LineSegment) b) != null); + + if (b instanceof QuadSegment) + return (lineQuadIntersect(this, (QuadSegment) b) != null); + + if (b instanceof CubicSegment) + return (lineCubicIntersect(this, (CubicSegment) b) != null); + + return false; + } + + /** + * Splits intersections into nodes, + * This one handles line-line, line-quadratic, line-cubic + */ + int splitIntersections(Segment b) + { + if (b instanceof LineSegment) + { + Intersection i = linesIntersect(this, (LineSegment) b); + + if (i == null) + return 0; + + return createNode(b, i); + } + + Intersection[] x = null; + + if (b instanceof QuadSegment) + x = lineQuadIntersect(this, (QuadSegment) b); + + if (b instanceof CubicSegment) + x = lineCubicIntersect(this, (CubicSegment) b); + + if (x == null) + return 0; + + if (x.length == 1) + return createNode(b, (Intersection) x[0]); + + return createNodes(b, x); + } + + /** + * Returns the bounding box of this segment + */ + Rectangle2D getBounds() + { + return (new Rectangle2D.Double(Math.min(P1.getX(), P2.getX()), + Math.min(P1.getY(), P2.getY()), + Math.abs(P1.getX() - P2.getX()), + Math.abs(P1.getY() - P2.getY()))); + } + + /** + * Returns the number of intersections on the positive X axis, + * with the origin at (x,y), used for contains()-testing + */ + int rayCrossing(double x, double y) + { + double x0 = P1.getX() - x; + double y0 = P1.getY() - y; + double x1 = P2.getX() - x; + double y1 = P2.getY() - y; + + if (y0 * y1 > 0) + return 0; + + if (x0 < 0 && x1 < 0) + return 0; + + if (y0 == 0.0) + y0 -= EPSILON; + + if (y1 == 0.0) + y1 -= EPSILON; + + if (Line2D.linesIntersect(x0, y0, x1, y1, + EPSILON, 0.0, Double.MAX_VALUE, 0.0)) + return 1; + return 0; + } + } // class LineSegment + + /** + * Quadratic Bezier curve segment + * + * Note: Most peers don't support quadratics directly, so it might make + * sense to represent them as cubics internally and just be done with it. + * I think we should be peer-agnostic, however, and stay faithful to the + * input geometry types as far as possible. + */ + private class QuadSegment extends Segment + { + Point2D cp; // control point + + /** + * Constructor, takes the coordinates of the start, control, + * and end point, respectively. + */ + QuadSegment(double x1, double y1, double cx, double cy, double x2, + double y2) + { + super(); + P1 = new Point2D.Double(x1, y1); + P2 = new Point2D.Double(x2, y2); + cp = new Point2D.Double(cx, cy); + } + + /** + * Clones this segment + */ + public Object clone() + { + return new QuadSegment(P1.getX(), P1.getY(), cp.getX(), cp.getY(), + P2.getX(), P2.getY()); + } + + /** + * Returns twice the area of a curve, relative the P1-P2 line + * + * The area formula can be derived by using Green's formula in the + * plane on the parametric form of the bezier. + */ + double curveArea() + { + double x0 = P1.getX(); + double y0 = P1.getY(); + double x1 = cp.getX(); + double y1 = cp.getY(); + double x2 = P2.getX(); + double y2 = P2.getY(); + + double P = (y2 - 2 * y1 + y0); + double Q = 2 * (y1 - y0); + + double A = (x2 - 2 * x1 + x0); + double B = 2 * (x1 - x0); + + double area = (B * P - A * Q) / 3.0; + return (area); + } + + /** + * Compare two segments. + */ + boolean equals(Segment b) + { + if (! (b instanceof QuadSegment)) + return false; + + return (P1.equals(b.P1) && cp.equals(((QuadSegment) b).cp) + && P2.equals(b.P2)); + } + + /** + * Returns a Point2D corresponding to the parametric value t + * of the curve + */ + Point2D evaluatePoint(double t) + { + double x0 = P1.getX(); + double y0 = P1.getY(); + double x1 = cp.getX(); + double y1 = cp.getY(); + double x2 = P2.getX(); + double y2 = P2.getY(); + + return new Point2D.Double(t * t * (x2 - 2 * x1 + x0) + 2 * t * (x1 - x0) + + x0, + t * t * (y2 - 2 * y1 + y0) + 2 * t * (y1 - y0) + + y0); + } + + /** + * Returns the bounding box of this segment + */ + Rectangle2D getBounds() + { + double x0 = P1.getX(); + double y0 = P1.getY(); + double x1 = cp.getX(); + double y1 = cp.getY(); + double x2 = P2.getX(); + double y2 = P2.getY(); + double r0; + double r1; + + double xmax = Math.max(x0, x2); + double ymax = Math.max(y0, y2); + double xmin = Math.min(x0, x2); + double ymin = Math.min(y0, y2); + + r0 = 2 * (y1 - y0); + r1 = 2 * (y2 - 2 * y1 + y0); + if (r1 != 0.0) + { + double t = -r0 / r1; + if (t > 0.0 && t < 1.0) + { + double y = evaluatePoint(t).getY(); + ymax = Math.max(y, ymax); + ymin = Math.min(y, ymin); + } + } + r0 = 2 * (x1 - x0); + r1 = 2 * (x2 - 2 * x1 + x0); + if (r1 != 0.0) + { + double t = -r0 / r1; + if (t > 0.0 && t < 1.0) + { + double x = evaluatePoint(t).getY(); + xmax = Math.max(x, xmax); + xmin = Math.min(x, xmin); + } + } + + return (new Rectangle2D.Double(xmin, ymin, xmax - xmin, ymax - ymin)); + } + + /** + * Returns a cubic segment corresponding to this curve + */ + CubicSegment getCubicSegment() + { + double x1 = P1.getX() + 2.0 * (cp.getX() - P1.getX()) / 3.0; + double y1 = P1.getY() + 2.0 * (cp.getY() - P1.getY()) / 3.0; + double x2 = cp.getX() + (P2.getX() - cp.getX()) / 3.0; + double y2 = cp.getY() + (P2.getY() - cp.getY()) / 3.0; + + return new CubicSegment(P1.getX(), P1.getY(), x1, y1, x2, y2, P2.getX(), + P2.getY()); + } + + /** + * Returns the segment's midpoint + */ + Point2D getMidPoint() + { + return evaluatePoint(0.5); + } + + /** + * Returns the PathIterator type of a segment + */ + int getType() + { + return (PathIterator.SEG_QUADTO); + } + + /** + * Returns the PathIterator coords of a segment + */ + int pathIteratorFormat(double[] coords) + { + coords[0] = cp.getX(); + coords[1] = cp.getY(); + coords[2] = P2.getX(); + coords[3] = P2.getY(); + return (PathIterator.SEG_QUADTO); + } + + /** + * Returns the number of intersections on the positive X axis, + * with the origin at (x,y), used for contains()-testing + */ + int rayCrossing(double x, double y) + { + double x0 = P1.getX() - x; + double y0 = P1.getY() - y; + double x1 = cp.getX() - x; + double y1 = cp.getY() - y; + double x2 = P2.getX() - x; + double y2 = P2.getY() - y; + double[] r = new double[3]; + int nRoots; + int nCrossings = 0; + + /* check if curve may intersect X+ axis. */ + if ((x0 > 0.0 || x1 > 0.0 || x2 > 0.0) && (y0 * y1 <= 0 || y1 * y2 <= 0)) + { + if (y0 == 0.0) + y0 -= EPSILON; + if (y2 == 0.0) + y2 -= EPSILON; + + r[0] = y0; + r[1] = 2 * (y1 - y0); + r[2] = (y2 - 2 * y1 + y0); + + nRoots = QuadCurve2D.solveQuadratic(r); + for (int i = 0; i < nRoots; i++) + if (r[i] > 0.0f && r[i] < 1.0f) + { + double t = r[i]; + if (t * t * (x2 - 2 * x1 + x0) + 2 * t * (x1 - x0) + x0 > 0.0) + nCrossings++; + } + } + return nCrossings; + } + + /** + * Swap start and end points + */ + void reverseCoords() + { + Point2D temp = P1; + P1 = P2; + P2 = temp; + } + + /** + * Splits intersections into nodes, + * This one handles quadratic-quadratic only, + * Quadratic-line is passed on to the LineSegment class, + * Quadratic-cubic is passed on to the CubicSegment class + */ + int splitIntersections(Segment b) + { + if (b instanceof LineSegment) + return (b.splitIntersections(this)); + + if (b instanceof CubicSegment) + return (b.splitIntersections(this)); + + if (b instanceof QuadSegment) + { + // Use the cubic-cubic intersection routine for quads as well, + // Since a quadratic can be exactly described as a cubic, this + // should not be a problem; + // The recursion depth will be the same in any case. + Intersection[] x = cubicCubicIntersect(getCubicSegment(), + ((QuadSegment) b) + .getCubicSegment()); + if (x == null) + return 0; + + if (x.length == 1) + return createNode(b, (Intersection) x[0]); + + return createNodes(b, x); + } + return 0; + } + + /** + * Subdivides the segment at parametric value t, inserting + * the new segment into the linked list after this, + * such that this becomes [0,t] and this.next becomes [t,1] + */ + void subdivideInsert(double t) + { + double x0 = P1.getX(); + double y0 = P1.getY(); + double x1 = cp.getX(); + double y1 = cp.getY(); + double x2 = P2.getX(); + double y2 = P2.getY(); + + double p10x = x0 + t * (x1 - x0); + double p10y = y0 + t * (y1 - y0); + double p11x = x1 + t * (x2 - x1); + double p11y = y1 + t * (y2 - y1); + double p20x = p10x + t * (p11x - p10x); + double p20y = p10y + t * (p11y - p10y); + + insert(new QuadSegment(p20x, p20y, p11x, p11y, x2, y2)); + P2 = next.P1; + cp.setLocation(p10x, p10y); + + next.node = node; + node = null; + } + + /** + * Transforms the segment + */ + void transform(AffineTransform at) + { + P1 = at.transform(P1, null); + P2 = at.transform(P2, null); + cp = at.transform(cp, null); + } + } // class QuadSegment + + /** + * Cubic Bezier curve segment + */ + private class CubicSegment extends Segment + { + Point2D cp1; // control points + Point2D cp2; // control points + + /** + * Constructor - takes coordinates of the starting point, + * first control point, second control point and end point, + * respecively. + */ + public CubicSegment(double x1, double y1, double c1x, double c1y, + double c2x, double c2y, double x2, double y2) + { + super(); + P1 = new Point2D.Double(x1, y1); + P2 = new Point2D.Double(x2, y2); + cp1 = new Point2D.Double(c1x, c1y); + cp2 = new Point2D.Double(c2x, c2y); + } + + /** + * Clones this segment + */ + public Object clone() + { + return new CubicSegment(P1.getX(), P1.getY(), cp1.getX(), cp1.getY(), + cp2.getX(), cp2.getY(), P2.getX(), P2.getY()); + } + + /** + * Returns twice the area of a curve, relative the P1-P2 line + * + * The area formula can be derived by using Green's formula in the + * plane on the parametric form of the bezier. + */ + double curveArea() + { + double x0 = P1.getX(); + double y0 = P1.getY(); + double x1 = cp1.getX(); + double y1 = cp1.getY(); + double x2 = cp2.getX(); + double y2 = cp2.getY(); + double x3 = P2.getX(); + double y3 = P2.getY(); + + double P = y3 - 3 * y2 + 3 * y1 - y0; + double Q = 3 * (y2 + y0 - 2 * y1); + double R = 3 * (y1 - y0); + + double A = x3 - 3 * x2 + 3 * x1 - x0; + double B = 3 * (x2 + x0 - 2 * x1); + double C = 3 * (x1 - x0); + + double area = (B * P - A * Q) / 5.0 + (C * P - A * R) / 2.0 + + (C * Q - B * R) / 3.0; + + return (area); + } + + /** + * Compare two segments. + */ + boolean equals(Segment b) + { + if (! (b instanceof CubicSegment)) + return false; + + return (P1.equals(b.P1) && cp1.equals(((CubicSegment) b).cp1) + && cp2.equals(((CubicSegment) b).cp2) && P2.equals(b.P2)); + } + + /** + * Returns a Point2D corresponding to the parametric value t + * of the curve + */ + Point2D evaluatePoint(double t) + { + double x0 = P1.getX(); + double y0 = P1.getY(); + double x1 = cp1.getX(); + double y1 = cp1.getY(); + double x2 = cp2.getX(); + double y2 = cp2.getY(); + double x3 = P2.getX(); + double y3 = P2.getY(); + + return new Point2D.Double(-(t * t * t) * (x0 - 3 * x1 + 3 * x2 - x3) + + 3 * t * t * (x0 - 2 * x1 + x2) + + 3 * t * (x1 - x0) + x0, + -(t * t * t) * (y0 - 3 * y1 + 3 * y2 - y3) + + 3 * t * t * (y0 - 2 * y1 + y2) + + 3 * t * (y1 - y0) + y0); + } + + /** + * Returns the bounding box of this segment + */ + Rectangle2D getBounds() + { + double x0 = P1.getX(); + double y0 = P1.getY(); + double x1 = cp1.getX(); + double y1 = cp1.getY(); + double x2 = cp2.getX(); + double y2 = cp2.getY(); + double x3 = P2.getX(); + double y3 = P2.getY(); + double[] r = new double[3]; + + double xmax = Math.max(x0, x3); + double ymax = Math.max(y0, y3); + double xmin = Math.min(x0, x3); + double ymin = Math.min(y0, y3); + + r[0] = 3 * (y1 - y0); + r[1] = 6.0 * (y2 + y0 - 2 * y1); + r[2] = 3.0 * (y3 - 3 * y2 + 3 * y1 - y0); + + int n = QuadCurve2D.solveQuadratic(r); + for (int i = 0; i < n; i++) + { + double t = r[i]; + if (t > 0 && t < 1.0) + { + double y = evaluatePoint(t).getY(); + ymax = Math.max(y, ymax); + ymin = Math.min(y, ymin); + } + } + + r[0] = 3 * (x1 - x0); + r[1] = 6.0 * (x2 + x0 - 2 * x1); + r[2] = 3.0 * (x3 - 3 * x2 + 3 * x1 - x0); + n = QuadCurve2D.solveQuadratic(r); + for (int i = 0; i < n; i++) + { + double t = r[i]; + if (t > 0 && t < 1.0) + { + double x = evaluatePoint(t).getX(); + xmax = Math.max(x, xmax); + xmin = Math.min(x, xmin); + } + } + return (new Rectangle2D.Double(xmin, ymin, (xmax - xmin), (ymax - ymin))); + } + + /** + * Returns a CubicCurve2D object corresponding to this segment. + */ + CubicCurve2D getCubicCurve2D() + { + return new CubicCurve2D.Double(P1.getX(), P1.getY(), cp1.getX(), + cp1.getY(), cp2.getX(), cp2.getY(), + P2.getX(), P2.getY()); + } + + /** + * Returns the parametric points of self-intersection if the cubic + * is self-intersecting, null otherwise. + */ + double[] getLoop() + { + double x0 = P1.getX(); + double y0 = P1.getY(); + double x1 = cp1.getX(); + double y1 = cp1.getY(); + double x2 = cp2.getX(); + double y2 = cp2.getY(); + double x3 = P2.getX(); + double y3 = P2.getY(); + double[] r = new double[4]; + double k; + double R; + double T; + double A; + double B; + double[] results = new double[2]; + + R = x3 - 3 * x2 + 3 * x1 - x0; + T = y3 - 3 * y2 + 3 * y1 - y0; + + // A qudratic + if (R == 0.0 && T == 0.0) + return null; + + // true cubic + if (R != 0.0 && T != 0.0) + { + A = 3 * (x2 + x0 - 2 * x1) / R; + B = 3 * (x1 - x0) / R; + + double P = 3 * (y2 + y0 - 2 * y1) / T; + double Q = 3 * (y1 - y0) / T; + + if (A == P || Q == B) + return null; + + k = (Q - B) / (A - P); + } + else + { + if (R == 0.0) + { + // quadratic in x + k = -(3 * (x1 - x0)) / (3 * (x2 + x0 - 2 * x1)); + A = 3 * (y2 + y0 - 2 * y1) / T; + B = 3 * (y1 - y0) / T; + } + else + { + // quadratic in y + k = -(3 * (y1 - y0)) / (3 * (y2 + y0 - 2 * y1)); + A = 3 * (x2 + x0 - 2 * x1) / R; + B = 3 * (x1 - x0) / R; + } + } + + r[0] = -k * k * k - A * k * k - B * k; + r[1] = 3 * k * k + 2 * k * A + 2 * B; + r[2] = -3 * k; + r[3] = 2; + + int n = CubicCurve2D.solveCubic(r); + if (n != 3) + return null; + + // sort r + double t; + for (int i = 0; i < 2; i++) + for (int j = i + 1; j < 3; j++) + if (r[j] < r[i]) + { + t = r[i]; + r[i] = r[j]; + r[j] = t; + } + + if (Math.abs(r[0] + r[2] - k) < 1E-13) + if (r[0] >= 0.0 && r[0] <= 1.0 && r[2] >= 0.0 && r[2] <= 1.0) + if (evaluatePoint(r[0]).distance(evaluatePoint(r[2])) < PE_EPSILON * 10) + { // we snap the points anyway + results[0] = r[0]; + results[1] = r[2]; + return (results); + } + return null; + } + + /** + * Returns the segment's midpoint + */ + Point2D getMidPoint() + { + return evaluatePoint(0.5); + } + + /** + * Returns the PathIterator type of a segment + */ + int getType() + { + return (PathIterator.SEG_CUBICTO); + } + + /** + * Returns the PathIterator coords of a segment + */ + int pathIteratorFormat(double[] coords) + { + coords[0] = cp1.getX(); + coords[1] = cp1.getY(); + coords[2] = cp2.getX(); + coords[3] = cp2.getY(); + coords[4] = P2.getX(); + coords[5] = P2.getY(); + return (PathIterator.SEG_CUBICTO); + } + + /** + * Returns the number of intersections on the positive X axis, + * with the origin at (x,y), used for contains()-testing + */ + int rayCrossing(double x, double y) + { + double x0 = P1.getX() - x; + double y0 = P1.getY() - y; + double x1 = cp1.getX() - x; + double y1 = cp1.getY() - y; + double x2 = cp2.getX() - x; + double y2 = cp2.getY() - y; + double x3 = P2.getX() - x; + double y3 = P2.getY() - y; + double[] r = new double[4]; + int nRoots; + int nCrossings = 0; + + /* check if curve may intersect X+ axis. */ + if ((x0 > 0.0 || x1 > 0.0 || x2 > 0.0 || x3 > 0.0) + && (y0 * y1 <= 0 || y1 * y2 <= 0 || y2 * y3 <= 0)) + { + if (y0 == 0.0) + y0 -= EPSILON; + if (y3 == 0.0) + y3 -= EPSILON; + + r[0] = y0; + r[1] = 3 * (y1 - y0); + r[2] = 3 * (y2 + y0 - 2 * y1); + r[3] = y3 - 3 * y2 + 3 * y1 - y0; + + if ((nRoots = CubicCurve2D.solveCubic(r)) > 0) + for (int i = 0; i < nRoots; i++) + { + if (r[i] > 0.0 && r[i] < 1.0) + { + double t = r[i]; + if (-(t * t * t) * (x0 - 3 * x1 + 3 * x2 - x3) + + 3 * t * t * (x0 - 2 * x1 + x2) + 3 * t * (x1 - x0) + + x0 > 0.0) + nCrossings++; + } + } + } + return nCrossings; + } + + /** + * Swap start and end points + */ + void reverseCoords() + { + Point2D p = P1; + P1 = P2; + P2 = p; + p = cp1; // swap control points + cp1 = cp2; + cp2 = p; + } + + /** + * Splits intersections into nodes, + * This one handles cubic-cubic and cubic-quadratic intersections + */ + int splitIntersections(Segment b) + { + if (b instanceof LineSegment) + return (b.splitIntersections(this)); + + Intersection[] x = null; + + if (b instanceof QuadSegment) + x = cubicCubicIntersect(this, ((QuadSegment) b).getCubicSegment()); + + if (b instanceof CubicSegment) + x = cubicCubicIntersect(this, (CubicSegment) b); + + if (x == null) + return 0; + + if (x.length == 1) + return createNode(b, x[0]); + + return createNodes(b, x); + } + + /** + * Subdivides the segment at parametric value t, inserting + * the new segment into the linked list after this, + * such that this becomes [0,t] and this.next becomes [t,1] + */ + void subdivideInsert(double t) + { + CubicSegment s = (CubicSegment) clone(); + double p1x = (s.cp1.getX() - s.P1.getX()) * t + s.P1.getX(); + double p1y = (s.cp1.getY() - s.P1.getY()) * t + s.P1.getY(); + + double px = (s.cp2.getX() - s.cp1.getX()) * t + s.cp1.getX(); + double py = (s.cp2.getY() - s.cp1.getY()) * t + s.cp1.getY(); + + s.cp2.setLocation((s.P2.getX() - s.cp2.getX()) * t + s.cp2.getX(), + (s.P2.getY() - s.cp2.getY()) * t + s.cp2.getY()); + + s.cp1.setLocation((s.cp2.getX() - px) * t + px, + (s.cp2.getY() - py) * t + py); + + double p2x = (px - p1x) * t + p1x; + double p2y = (py - p1y) * t + p1y; + + double p3x = (s.cp1.getX() - p2x) * t + p2x; + double p3y = (s.cp1.getY() - p2y) * t + p2y; + s.P1.setLocation(p3x, p3y); + + // insert new curve + insert(s); + + // set this curve + cp1.setLocation(p1x, p1y); + cp2.setLocation(p2x, p2y); + P2 = s.P1; + next.node = node; + node = null; + } + + /** + * Transforms the segment + */ + void transform(AffineTransform at) + { + P1 = at.transform(P1, null); + P2 = at.transform(P2, null); + cp1 = at.transform(cp1, null); + cp2 = at.transform(cp2, null); + } + } // class CubicSegment +} // class Area diff --git a/libjava/classpath/java/awt/geom/CubicCurve2D.java b/libjava/classpath/java/awt/geom/CubicCurve2D.java new file mode 100644 index 000000000..5cb11fe77 --- /dev/null +++ b/libjava/classpath/java/awt/geom/CubicCurve2D.java @@ -0,0 +1,1724 @@ +/* CubicCurve2D.java -- represents a parameterized cubic curve in 2-D space + Copyright (C) 2002, 2003, 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.geom; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.util.NoSuchElementException; + + +/** + * A two-dimensional curve that is parameterized with a cubic + * function. + * + * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180" + * alt="A drawing of a CubicCurve2D" /> + * + * @author Eric Blake (ebb9@email.byu.edu) + * @author Graydon Hoare (graydon@redhat.com) + * @author Sascha Brawer (brawer@dandelis.ch) + * @author Sven de Marothy (sven@physto.se) + * + * @since 1.2 + */ +public abstract class CubicCurve2D implements Shape, Cloneable +{ + private static final double BIG_VALUE = java.lang.Double.MAX_VALUE / 10.0; + private static final double EPSILON = 1E-10; + + /** + * Constructs a new CubicCurve2D. Typical users will want to + * construct instances of a subclass, such as {@link + * CubicCurve2D.Float} or {@link CubicCurve2D.Double}. + */ + protected CubicCurve2D() + { + } + + /** + * Returns the <i>x</i> coordinate of the curve’s start + * point. + */ + public abstract double getX1(); + + /** + * Returns the <i>y</i> coordinate of the curve’s start + * point. + */ + public abstract double getY1(); + + /** + * Returns the curve’s start point. + */ + public abstract Point2D getP1(); + + /** + * Returns the <i>x</i> coordinate of the curve’s first + * control point. + */ + public abstract double getCtrlX1(); + + /** + * Returns the <i>y</i> coordinate of the curve’s first + * control point. + */ + public abstract double getCtrlY1(); + + /** + * Returns the curve’s first control point. + */ + public abstract Point2D getCtrlP1(); + + /** + * Returns the <i>x</i> coordinate of the curve’s second + * control point. + */ + public abstract double getCtrlX2(); + + /** + * Returns the <i>y</i> coordinate of the curve’s second + * control point. + */ + public abstract double getCtrlY2(); + + /** + * Returns the curve’s second control point. + */ + public abstract Point2D getCtrlP2(); + + /** + * Returns the <i>x</i> coordinate of the curve’s end + * point. + */ + public abstract double getX2(); + + /** + * Returns the <i>y</i> coordinate of the curve’s end + * point. + */ + public abstract double getY2(); + + /** + * Returns the curve’s end point. + */ + public abstract Point2D getP2(); + + /** + * Changes the curve geometry, separately specifying each coordinate + * value. + * + * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180" + * alt="A drawing of a CubicCurve2D" /> + * + * @param x1 the <i>x</i> coordinate of the curve’s new start + * point. + * + * @param y1 the <i>y</i> coordinate of the curve’s new start + * point. + * + * @param cx1 the <i>x</i> coordinate of the curve’s new + * first control point. + * + * @param cy1 the <i>y</i> coordinate of the curve’s new + * first control point. + * + * @param cx2 the <i>x</i> coordinate of the curve’s new + * second control point. + * + * @param cy2 the <i>y</i> coordinate of the curve’s new + * second control point. + * + * @param x2 the <i>x</i> coordinate of the curve’s new end + * point. + * + * @param y2 the <i>y</i> coordinate of the curve’s new end + * point. + */ + public abstract void setCurve(double x1, double y1, double cx1, double cy1, + double cx2, double cy2, double x2, double y2); + + /** + * Changes the curve geometry, specifying coordinate values in an + * array. + * + * @param coords an array containing the new coordinate values. The + * <i>x</i> coordinate of the new start point is located at + * <code>coords[offset]</code>, its <i>y</i> coordinate at + * <code>coords[offset + 1]</code>. The <i>x</i> coordinate of the + * new first control point is located at <code>coords[offset + + * 2]</code>, its <i>y</i> coordinate at <code>coords[offset + + * 3]</code>. The <i>x</i> coordinate of the new second control + * point is located at <code>coords[offset + 4]</code>, its <i>y</i> + * coordinate at <code>coords[offset + 5]</code>. The <i>x</i> + * coordinate of the new end point is located at <code>coords[offset + * + 6]</code>, its <i>y</i> coordinate at <code>coords[offset + + * 7]</code>. + * + * @param offset the offset of the first coordinate value in + * <code>coords</code>. + */ + public void setCurve(double[] coords, int offset) + { + setCurve(coords[offset++], coords[offset++], coords[offset++], + coords[offset++], coords[offset++], coords[offset++], + coords[offset++], coords[offset++]); + } + + /** + * Changes the curve geometry, specifying coordinate values in + * separate Point objects. + * + * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180" + * alt="A drawing of a CubicCurve2D" /> + * + * <p>The curve does not keep any reference to the passed point + * objects. Therefore, a later change to <code>p1</code>, + * <code>c1</code>, <code>c2</code> or <code>p2</code> will not + * affect the curve geometry. + * + * @param p1 the new start point. + * @param c1 the new first control point. + * @param c2 the new second control point. + * @param p2 the new end point. + */ + public void setCurve(Point2D p1, Point2D c1, Point2D c2, Point2D p2) + { + setCurve(p1.getX(), p1.getY(), c1.getX(), c1.getY(), c2.getX(), c2.getY(), + p2.getX(), p2.getY()); + } + + /** + * Changes the curve geometry, specifying coordinate values in an + * array of Point objects. + * + * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180" + * alt="A drawing of a CubicCurve2D" /> + * + * <p>The curve does not keep references to the passed point + * objects. Therefore, a later change to the <code>pts</code> array + * or any of its elements will not affect the curve geometry. + * + * @param pts an array containing the points. The new start point + * is located at <code>pts[offset]</code>, the new first control + * point at <code>pts[offset + 1]</code>, the new second control + * point at <code>pts[offset + 2]</code>, and the new end point + * at <code>pts[offset + 3]</code>. + * + * @param offset the offset of the start point in <code>pts</code>. + */ + public void setCurve(Point2D[] pts, int offset) + { + setCurve(pts[offset].getX(), pts[offset++].getY(), pts[offset].getX(), + pts[offset++].getY(), pts[offset].getX(), pts[offset++].getY(), + pts[offset].getX(), pts[offset++].getY()); + } + + /** + * Changes the curve geometry to that of another curve. + * + * @param c the curve whose coordinates will be copied. + */ + public void setCurve(CubicCurve2D c) + { + setCurve(c.getX1(), c.getY1(), c.getCtrlX1(), c.getCtrlY1(), + c.getCtrlX2(), c.getCtrlY2(), c.getX2(), c.getY2()); + } + + /** + * Calculates the squared flatness of a cubic curve, directly + * specifying each coordinate value. The flatness is the maximal + * distance of a control point to the line between start and end + * point. + * + * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180" + * alt="A drawing that illustrates the flatness" /> + * + * <p>In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. In comparison to C1, + * control point C2 is father away from the gray line. Therefore, + * the result will be the square of the distance between C2 and the + * gray line, i.e. the squared length of the red line. + * + * @param x1 the <i>x</i> coordinate of the start point P1. + * @param y1 the <i>y</i> coordinate of the start point P1. + * @param cx1 the <i>x</i> coordinate of the first control point C1. + * @param cy1 the <i>y</i> coordinate of the first control point C1. + * @param cx2 the <i>x</i> coordinate of the second control point C2. + * @param cy2 the <i>y</i> coordinate of the second control point C2. + * @param x2 the <i>x</i> coordinate of the end point P2. + * @param y2 the <i>y</i> coordinate of the end point P2. + */ + public static double getFlatnessSq(double x1, double y1, double cx1, + double cy1, double cx2, double cy2, + double x2, double y2) + { + return Math.max(Line2D.ptSegDistSq(x1, y1, x2, y2, cx1, cy1), + Line2D.ptSegDistSq(x1, y1, x2, y2, cx2, cy2)); + } + + /** + * Calculates the flatness of a cubic curve, directly specifying + * each coordinate value. The flatness is the maximal distance of a + * control point to the line between start and end point. + * + * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180" + * alt="A drawing that illustrates the flatness" /> + * + * <p>In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. In comparison to C1, + * control point C2 is father away from the gray line. Therefore, + * the result will be the distance between C2 and the gray line, + * i.e. the length of the red line. + * + * @param x1 the <i>x</i> coordinate of the start point P1. + * @param y1 the <i>y</i> coordinate of the start point P1. + * @param cx1 the <i>x</i> coordinate of the first control point C1. + * @param cy1 the <i>y</i> coordinate of the first control point C1. + * @param cx2 the <i>x</i> coordinate of the second control point C2. + * @param cy2 the <i>y</i> coordinate of the second control point C2. + * @param x2 the <i>x</i> coordinate of the end point P2. + * @param y2 the <i>y</i> coordinate of the end point P2. + */ + public static double getFlatness(double x1, double y1, double cx1, + double cy1, double cx2, double cy2, + double x2, double y2) + { + return Math.sqrt(getFlatnessSq(x1, y1, cx1, cy1, cx2, cy2, x2, y2)); + } + + /** + * Calculates the squared flatness of a cubic curve, specifying the + * coordinate values in an array. The flatness is the maximal + * distance of a control point to the line between start and end + * point. + * + * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180" + * alt="A drawing that illustrates the flatness" /> + * + * <p>In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. In comparison to C1, + * control point C2 is father away from the gray line. Therefore, + * the result will be the square of the distance between C2 and the + * gray line, i.e. the squared length of the red line. + * + * @param coords an array containing the coordinate values. The + * <i>x</i> coordinate of the start point P1 is located at + * <code>coords[offset]</code>, its <i>y</i> coordinate at + * <code>coords[offset + 1]</code>. The <i>x</i> coordinate of the + * first control point C1 is located at <code>coords[offset + + * 2]</code>, its <i>y</i> coordinate at <code>coords[offset + + * 3]</code>. The <i>x</i> coordinate of the second control point C2 + * is located at <code>coords[offset + 4]</code>, its <i>y</i> + * coordinate at <code>coords[offset + 5]</code>. The <i>x</i> + * coordinate of the end point P2 is located at <code>coords[offset + * + 6]</code>, its <i>y</i> coordinate at <code>coords[offset + + * 7]</code>. + * + * @param offset the offset of the first coordinate value in + * <code>coords</code>. + */ + public static double getFlatnessSq(double[] coords, int offset) + { + return getFlatnessSq(coords[offset++], coords[offset++], coords[offset++], + coords[offset++], coords[offset++], coords[offset++], + coords[offset++], coords[offset++]); + } + + /** + * Calculates the flatness of a cubic curve, specifying the + * coordinate values in an array. The flatness is the maximal + * distance of a control point to the line between start and end + * point. + * + * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180" + * alt="A drawing that illustrates the flatness" /> + * + * <p>In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. In comparison to C1, + * control point C2 is father away from the gray line. Therefore, + * the result will be the distance between C2 and the gray line, + * i.e. the length of the red line. + * + * @param coords an array containing the coordinate values. The + * <i>x</i> coordinate of the start point P1 is located at + * <code>coords[offset]</code>, its <i>y</i> coordinate at + * <code>coords[offset + 1]</code>. The <i>x</i> coordinate of the + * first control point C1 is located at <code>coords[offset + + * 2]</code>, its <i>y</i> coordinate at <code>coords[offset + + * 3]</code>. The <i>x</i> coordinate of the second control point C2 + * is located at <code>coords[offset + 4]</code>, its <i>y</i> + * coordinate at <code>coords[offset + 5]</code>. The <i>x</i> + * coordinate of the end point P2 is located at <code>coords[offset + * + 6]</code>, its <i>y</i> coordinate at <code>coords[offset + + * 7]</code>. + * + * @param offset the offset of the first coordinate value in + * <code>coords</code>. + */ + public static double getFlatness(double[] coords, int offset) + { + return Math.sqrt(getFlatnessSq(coords[offset++], coords[offset++], + coords[offset++], coords[offset++], + coords[offset++], coords[offset++], + coords[offset++], coords[offset++])); + } + + /** + * Calculates the squared flatness of this curve. The flatness is + * the maximal distance of a control point to the line between start + * and end point. + * + * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180" + * alt="A drawing that illustrates the flatness" /> + * + * <p>In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. In comparison to C1, + * control point C2 is father away from the gray line. Therefore, + * the result will be the square of the distance between C2 and the + * gray line, i.e. the squared length of the red line. + */ + public double getFlatnessSq() + { + return getFlatnessSq(getX1(), getY1(), getCtrlX1(), getCtrlY1(), + getCtrlX2(), getCtrlY2(), getX2(), getY2()); + } + + /** + * Calculates the flatness of this curve. The flatness is the + * maximal distance of a control point to the line between start and + * end point. + * + * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180" + * alt="A drawing that illustrates the flatness" /> + * + * <p>In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. In comparison to C1, + * control point C2 is father away from the gray line. Therefore, + * the result will be the distance between C2 and the gray line, + * i.e. the length of the red line. + */ + public double getFlatness() + { + return Math.sqrt(getFlatnessSq(getX1(), getY1(), getCtrlX1(), getCtrlY1(), + getCtrlX2(), getCtrlY2(), getX2(), getY2())); + } + + /** + * Subdivides this curve into two halves. + * + * <p><img src="doc-files/CubicCurve2D-3.png" width="700" + * height="180" alt="A drawing that illustrates the effects of + * subdividing a CubicCurve2D" /> + * + * @param left a curve whose geometry will be set to the left half + * of this curve, or <code>null</code> if the caller is not + * interested in the left half. + * + * @param right a curve whose geometry will be set to the right half + * of this curve, or <code>null</code> if the caller is not + * interested in the right half. + */ + public void subdivide(CubicCurve2D left, CubicCurve2D right) + { + // Use empty slots at end to share single array. + double[] d = new double[] + { + getX1(), getY1(), getCtrlX1(), getCtrlY1(), getCtrlX2(), + getCtrlY2(), getX2(), getY2(), 0, 0, 0, 0, 0, 0 + }; + subdivide(d, 0, d, 0, d, 6); + if (left != null) + left.setCurve(d, 0); + if (right != null) + right.setCurve(d, 6); + } + + /** + * Subdivides a cubic curve into two halves. + * + * <p><img src="doc-files/CubicCurve2D-3.png" width="700" + * height="180" alt="A drawing that illustrates the effects of + * subdividing a CubicCurve2D" /> + * + * @param src the curve to be subdivided. + * + * @param left a curve whose geometry will be set to the left half + * of <code>src</code>, or <code>null</code> if the caller is not + * interested in the left half. + * + * @param right a curve whose geometry will be set to the right half + * of <code>src</code>, or <code>null</code> if the caller is not + * interested in the right half. + */ + public static void subdivide(CubicCurve2D src, CubicCurve2D left, + CubicCurve2D right) + { + src.subdivide(left, right); + } + + /** + * Subdivides a cubic curve into two halves, passing all coordinates + * in an array. + * + * <p><img src="doc-files/CubicCurve2D-3.png" width="700" + * height="180" alt="A drawing that illustrates the effects of + * subdividing a CubicCurve2D" /> + * + * <p>The left end point and the right start point will always be + * identical. Memory-concious programmers thus may want to pass the + * same array for both <code>left</code> and <code>right</code>, and + * set <code>rightOff</code> to <code>leftOff + 6</code>. + * + * @param src an array containing the coordinates of the curve to be + * subdivided. The <i>x</i> coordinate of the start point P1 is + * located at <code>src[srcOff]</code>, its <i>y</i> at + * <code>src[srcOff + 1]</code>. The <i>x</i> coordinate of the + * first control point C1 is located at <code>src[srcOff + + * 2]</code>, its <i>y</i> at <code>src[srcOff + 3]</code>. The + * <i>x</i> coordinate of the second control point C2 is located at + * <code>src[srcOff + 4]</code>, its <i>y</i> at <code>src[srcOff + + * 5]</code>. The <i>x</i> coordinate of the end point is located at + * <code>src[srcOff + 6]</code>, its <i>y</i> at <code>src[srcOff + + * 7]</code>. + * + * @param srcOff an offset into <code>src</code>, specifying + * the index of the start point’s <i>x</i> coordinate. + * + * @param left an array that will receive the coordinates of the + * left half of <code>src</code>. It is acceptable to pass + * <code>src</code>. A caller who is not interested in the left half + * can pass <code>null</code>. + * + * @param leftOff an offset into <code>left</code>, specifying the + * index where the start point’s <i>x</i> coordinate will be + * stored. + * + * @param right an array that will receive the coordinates of the + * right half of <code>src</code>. It is acceptable to pass + * <code>src</code> or <code>left</code>. A caller who is not + * interested in the right half can pass <code>null</code>. + * + * @param rightOff an offset into <code>right</code>, specifying the + * index where the start point’s <i>x</i> coordinate will be + * stored. + */ + public static void subdivide(double[] src, int srcOff, double[] left, + int leftOff, double[] right, int rightOff) + { + // To understand this code, please have a look at the image + // "CubicCurve2D-3.png" in the sub-directory "doc-files". + double src_C1_x; + double src_C1_y; + double src_C2_x; + double src_C2_y; + double left_P1_x; + double left_P1_y; + double left_C1_x; + double left_C1_y; + double left_C2_x; + double left_C2_y; + double right_C1_x; + double right_C1_y; + double right_C2_x; + double right_C2_y; + double right_P2_x; + double right_P2_y; + double Mid_x; // Mid = left.P2 = right.P1 + double Mid_y; // Mid = left.P2 = right.P1 + + left_P1_x = src[srcOff]; + left_P1_y = src[srcOff + 1]; + src_C1_x = src[srcOff + 2]; + src_C1_y = src[srcOff + 3]; + src_C2_x = src[srcOff + 4]; + src_C2_y = src[srcOff + 5]; + right_P2_x = src[srcOff + 6]; + right_P2_y = src[srcOff + 7]; + + left_C1_x = (left_P1_x + src_C1_x) / 2; + left_C1_y = (left_P1_y + src_C1_y) / 2; + right_C2_x = (right_P2_x + src_C2_x) / 2; + right_C2_y = (right_P2_y + src_C2_y) / 2; + Mid_x = (src_C1_x + src_C2_x) / 2; + Mid_y = (src_C1_y + src_C2_y) / 2; + left_C2_x = (left_C1_x + Mid_x) / 2; + left_C2_y = (left_C1_y + Mid_y) / 2; + right_C1_x = (Mid_x + right_C2_x) / 2; + right_C1_y = (Mid_y + right_C2_y) / 2; + Mid_x = (left_C2_x + right_C1_x) / 2; + Mid_y = (left_C2_y + right_C1_y) / 2; + + if (left != null) + { + left[leftOff] = left_P1_x; + left[leftOff + 1] = left_P1_y; + left[leftOff + 2] = left_C1_x; + left[leftOff + 3] = left_C1_y; + left[leftOff + 4] = left_C2_x; + left[leftOff + 5] = left_C2_y; + left[leftOff + 6] = Mid_x; + left[leftOff + 7] = Mid_y; + } + + if (right != null) + { + right[rightOff] = Mid_x; + right[rightOff + 1] = Mid_y; + right[rightOff + 2] = right_C1_x; + right[rightOff + 3] = right_C1_y; + right[rightOff + 4] = right_C2_x; + right[rightOff + 5] = right_C2_y; + right[rightOff + 6] = right_P2_x; + right[rightOff + 7] = right_P2_y; + } + } + + /** + * Finds the non-complex roots of a cubic equation, placing the + * results into the same array as the equation coefficients. The + * following equation is being solved: + * + * <blockquote><code>eqn[3]</code> · <i>x</i><sup>3</sup> + * + <code>eqn[2]</code> · <i>x</i><sup>2</sup> + * + <code>eqn[1]</code> · <i>x</i> + * + <code>eqn[0]</code> + * = 0 + * </blockquote> + * + * <p>For some background about solving cubic equations, see the + * article <a + * href="http://planetmath.org/encyclopedia/CubicFormula.html" + * >“Cubic Formula”</a> in <a + * href="http://planetmath.org/" >PlanetMath</a>. For an extensive + * library of numerical algorithms written in the C programming + * language, see the <a href= "http://www.gnu.org/software/gsl/">GNU + * Scientific Library</a>, from which this implementation was + * adapted. + * + * @param eqn an array with the coefficients of the equation. When + * this procedure has returned, <code>eqn</code> will contain the + * non-complex solutions of the equation, in no particular order. + * + * @return the number of non-complex solutions. A result of 0 + * indicates that the equation has no non-complex solutions. A + * result of -1 indicates that the equation is constant (i.e., + * always or never zero). + * + * @see #solveCubic(double[], double[]) + * @see QuadCurve2D#solveQuadratic(double[],double[]) + * + * @author Brian Gough (bjg@network-theory.com) + * (original C implementation in the <a href= + * "http://www.gnu.org/software/gsl/">GNU Scientific Library</a>) + * + * @author Sascha Brawer (brawer@dandelis.ch) + * (adaptation to Java) + */ + public static int solveCubic(double[] eqn) + { + return solveCubic(eqn, eqn); + } + + /** + * Finds the non-complex roots of a cubic equation. The following + * equation is being solved: + * + * <blockquote><code>eqn[3]</code> · <i>x</i><sup>3</sup> + * + <code>eqn[2]</code> · <i>x</i><sup>2</sup> + * + <code>eqn[1]</code> · <i>x</i> + * + <code>eqn[0]</code> + * = 0 + * </blockquote> + * + * <p>For some background about solving cubic equations, see the + * article <a + * href="http://planetmath.org/encyclopedia/CubicFormula.html" + * >“Cubic Formula”</a> in <a + * href="http://planetmath.org/" >PlanetMath</a>. For an extensive + * library of numerical algorithms written in the C programming + * language, see the <a href= "http://www.gnu.org/software/gsl/">GNU + * Scientific Library</a>, from which this implementation was + * adapted. + * + * @see QuadCurve2D#solveQuadratic(double[],double[]) + * + * @param eqn an array with the coefficients of the equation. + * + * @param res an array into which the non-complex roots will be + * stored. The results may be in an arbitrary order. It is safe to + * pass the same array object reference for both <code>eqn</code> + * and <code>res</code>. + * + * @return the number of non-complex solutions. A result of 0 + * indicates that the equation has no non-complex solutions. A + * result of -1 indicates that the equation is constant (i.e., + * always or never zero). + * + * @author Brian Gough (bjg@network-theory.com) + * (original C implementation in the <a href= + * "http://www.gnu.org/software/gsl/">GNU Scientific Library</a>) + * + * @author Sascha Brawer (brawer@dandelis.ch) + * (adaptation to Java) + */ + public static int solveCubic(double[] eqn, double[] res) + { + // Adapted from poly/solve_cubic.c in the GNU Scientific Library + // (GSL), revision 1.7 of 2003-07-26. For the original source, see + // http://www.gnu.org/software/gsl/ + // + // Brian Gough, the author of that code, has granted the + // permission to use it in GNU Classpath under the GNU Classpath + // license, and has assigned the copyright to the Free Software + // Foundation. + // + // The Java implementation is very similar to the GSL code, but + // not a strict one-to-one copy. For example, GSL would sort the + // result. + + double a; + double b; + double c; + double q; + double r; + double Q; + double R; + double c3; + double Q3; + double R2; + double CR2; + double CQ3; + + // If the cubic coefficient is zero, we have a quadratic equation. + c3 = eqn[3]; + if (c3 == 0) + return QuadCurve2D.solveQuadratic(eqn, res); + + // Divide the equation by the cubic coefficient. + c = eqn[0] / c3; + b = eqn[1] / c3; + a = eqn[2] / c3; + + // We now need to solve x^3 + ax^2 + bx + c = 0. + q = a * a - 3 * b; + r = 2 * a * a * a - 9 * a * b + 27 * c; + + Q = q / 9; + R = r / 54; + + Q3 = Q * Q * Q; + R2 = R * R; + + CR2 = 729 * r * r; + CQ3 = 2916 * q * q * q; + + if (R == 0 && Q == 0) + { + // The GNU Scientific Library would return three identical + // solutions in this case. + res[0] = -a / 3; + return 1; + } + + if (CR2 == CQ3) + { + /* this test is actually R2 == Q3, written in a form suitable + for exact computation with integers */ + /* Due to finite precision some double roots may be missed, and + considered to be a pair of complex roots z = x +/- epsilon i + close to the real axis. */ + double sqrtQ = Math.sqrt(Q); + + if (R > 0) + { + res[0] = -2 * sqrtQ - a / 3; + res[1] = sqrtQ - a / 3; + } + else + { + res[0] = -sqrtQ - a / 3; + res[1] = 2 * sqrtQ - a / 3; + } + return 2; + } + + if (CR2 < CQ3) /* equivalent to R2 < Q3 */ + { + double sqrtQ = Math.sqrt(Q); + double sqrtQ3 = sqrtQ * sqrtQ * sqrtQ; + double theta = Math.acos(R / sqrtQ3); + double norm = -2 * sqrtQ; + res[0] = norm * Math.cos(theta / 3) - a / 3; + res[1] = norm * Math.cos((theta + 2.0 * Math.PI) / 3) - a / 3; + res[2] = norm * Math.cos((theta - 2.0 * Math.PI) / 3) - a / 3; + + // The GNU Scientific Library sorts the results. We don't. + return 3; + } + + double sgnR = (R >= 0 ? 1 : -1); + double A = -sgnR * Math.pow(Math.abs(R) + Math.sqrt(R2 - Q3), 1.0 / 3.0); + double B = Q / A; + res[0] = A + B - a / 3; + return 1; + } + + /** + * Determines whether a position lies inside the area bounded + * by the curve and the straight line connecting its end points. + * + * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180" + * alt="A drawing of the area spanned by the curve" /> + * + * <p>The above drawing illustrates in which area points are + * considered “inside” a CubicCurve2D. + */ + public boolean contains(double x, double y) + { + if (! getBounds2D().contains(x, y)) + return false; + + return ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0); + } + + /** + * Determines whether a point lies inside the area bounded + * by the curve and the straight line connecting its end points. + * + * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180" + * alt="A drawing of the area spanned by the curve" /> + * + * <p>The above drawing illustrates in which area points are + * considered “inside” a CubicCurve2D. + */ + public boolean contains(Point2D p) + { + return contains(p.getX(), p.getY()); + } + + /** + * Determines whether any part of a rectangle is inside the area bounded + * by the curve and the straight line connecting its end points. + * + * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180" + * alt="A drawing of the area spanned by the curve" /> + * + * <p>The above drawing illustrates in which area points are + * considered “inside” in a CubicCurve2D. + * @see #contains(double, double) + */ + public boolean intersects(double x, double y, double w, double h) + { + if (! getBounds2D().contains(x, y, w, h)) + return false; + + /* Does any edge intersect? */ + if (getAxisIntersections(x, y, true, w) != 0 /* top */ + || getAxisIntersections(x, y + h, true, w) != 0 /* bottom */ + || getAxisIntersections(x + w, y, false, h) != 0 /* right */ + || getAxisIntersections(x, y, false, h) != 0) /* left */ + return true; + + /* No intersections, is any point inside? */ + if ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0) + return true; + + return false; + } + + /** + * Determines whether any part of a Rectangle2D is inside the area bounded + * by the curve and the straight line connecting its end points. + * @see #intersects(double, double, double, double) + */ + public boolean intersects(Rectangle2D r) + { + return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Determine whether a rectangle is entirely inside the area that is bounded + * by the curve and the straight line connecting its end points. + * + * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180" + * alt="A drawing of the area spanned by the curve" /> + * + * <p>The above drawing illustrates in which area points are + * considered “inside” a CubicCurve2D. + * @see #contains(double, double) + */ + public boolean contains(double x, double y, double w, double h) + { + if (! getBounds2D().intersects(x, y, w, h)) + return false; + + /* Does any edge intersect? */ + if (getAxisIntersections(x, y, true, w) != 0 /* top */ + || getAxisIntersections(x, y + h, true, w) != 0 /* bottom */ + || getAxisIntersections(x + w, y, false, h) != 0 /* right */ + || getAxisIntersections(x, y, false, h) != 0) /* left */ + return false; + + /* No intersections, is any point inside? */ + if ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0) + return true; + + return false; + } + + /** + * Determine whether a Rectangle2D is entirely inside the area that is + * bounded by the curve and the straight line connecting its end points. + * + * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180" + * alt="A drawing of the area spanned by the curve" /> + * + * <p>The above drawing illustrates in which area points are + * considered “inside” a CubicCurve2D. + * @see #contains(double, double) + */ + public boolean contains(Rectangle2D r) + { + return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Determines the smallest rectangle that encloses the + * curve’s start, end and control points. + */ + public Rectangle getBounds() + { + return getBounds2D().getBounds(); + } + + public PathIterator getPathIterator(final AffineTransform at) + { + return new PathIterator() + { + /** Current coordinate. */ + private int current = 0; + + public int getWindingRule() + { + return WIND_NON_ZERO; + } + + public boolean isDone() + { + return current >= 2; + } + + public void next() + { + current++; + } + + public int currentSegment(float[] coords) + { + int result; + switch (current) + { + case 0: + coords[0] = (float) getX1(); + coords[1] = (float) getY1(); + result = SEG_MOVETO; + break; + case 1: + coords[0] = (float) getCtrlX1(); + coords[1] = (float) getCtrlY1(); + coords[2] = (float) getCtrlX2(); + coords[3] = (float) getCtrlY2(); + coords[4] = (float) getX2(); + coords[5] = (float) getY2(); + result = SEG_CUBICTO; + break; + default: + throw new NoSuchElementException("cubic iterator out of bounds"); + } + if (at != null) + at.transform(coords, 0, coords, 0, 3); + return result; + } + + public int currentSegment(double[] coords) + { + int result; + switch (current) + { + case 0: + coords[0] = getX1(); + coords[1] = getY1(); + result = SEG_MOVETO; + break; + case 1: + coords[0] = getCtrlX1(); + coords[1] = getCtrlY1(); + coords[2] = getCtrlX2(); + coords[3] = getCtrlY2(); + coords[4] = getX2(); + coords[5] = getY2(); + result = SEG_CUBICTO; + break; + default: + throw new NoSuchElementException("cubic iterator out of bounds"); + } + if (at != null) + at.transform(coords, 0, coords, 0, 3); + return result; + } + }; + } + + public PathIterator getPathIterator(AffineTransform at, double flatness) + { + return new FlatteningPathIterator(getPathIterator(at), flatness); + } + + /** + * Create a new curve with the same contents as this one. + * + * @return the clone. + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } + + /** + * Helper method used by contains() and intersects() methods, that + * returns the number of curve/line intersections on a given axis + * extending from a certain point. + * + * @param x x coordinate of the origin point + * @param y y coordinate of the origin point + * @param useYaxis axis used, if true the positive Y axis is used, + * false uses the positive X axis. + * + * This is an implementation of the line-crossings algorithm, + * Detailed in an article on Eric Haines' page: + * http://www.acm.org/tog/editors/erich/ptinpoly/ + * + * A special-case not adressed in this code is self-intersections + * of the curve, e.g. if the axis intersects the self-itersection, + * the degenerate roots of the polynomial will erroneously count as + * a single intersection of the curve, and not two. + */ + private int getAxisIntersections(double x, double y, boolean useYaxis, + double distance) + { + int nCrossings = 0; + double a0; + double a1; + double a2; + double a3; + double b0; + double b1; + double b2; + double b3; + double[] r = new double[4]; + int nRoots; + + a0 = a3 = 0.0; + + if (useYaxis) + { + a0 = getY1() - y; + a1 = getCtrlY1() - y; + a2 = getCtrlY2() - y; + a3 = getY2() - y; + b0 = getX1() - x; + b1 = getCtrlX1() - x; + b2 = getCtrlX2() - x; + b3 = getX2() - x; + } + else + { + a0 = getX1() - x; + a1 = getCtrlX1() - x; + a2 = getCtrlX2() - x; + a3 = getX2() - x; + b0 = getY1() - y; + b1 = getCtrlY1() - y; + b2 = getCtrlY2() - y; + b3 = getY2() - y; + } + + /* If the axis intersects a start/endpoint, shift it up by some small + amount to guarantee the line is 'inside' + If this is not done, bad behaviour may result for points on that axis.*/ + if (a0 == 0.0 || a3 == 0.0) + { + double small = getFlatness() * EPSILON; + if (a0 == 0.0) + a0 -= small; + if (a3 == 0.0) + a3 -= small; + } + + if (useYaxis) + { + if (Line2D.linesIntersect(b0, a0, b3, a3, EPSILON, 0.0, distance, 0.0)) + nCrossings++; + } + else + { + if (Line2D.linesIntersect(a0, b0, a3, b3, 0.0, EPSILON, 0.0, distance)) + nCrossings++; + } + + r[0] = a0; + r[1] = 3 * (a1 - a0); + r[2] = 3 * (a2 + a0 - 2 * a1); + r[3] = a3 - 3 * a2 + 3 * a1 - a0; + + if ((nRoots = solveCubic(r)) != 0) + for (int i = 0; i < nRoots; i++) + { + double t = r[i]; + if (t >= 0.0 && t <= 1.0) + { + double crossing = -(t * t * t) * (b0 - 3 * b1 + 3 * b2 - b3) + + 3 * t * t * (b0 - 2 * b1 + b2) + + 3 * t * (b1 - b0) + b0; + if (crossing > 0.0 && crossing <= distance) + nCrossings++; + } + } + + return (nCrossings); + } + + /** + * A two-dimensional curve that is parameterized with a cubic + * function and stores coordinate values in double-precision + * floating-point format. + * + * @see CubicCurve2D.Float + * + * @author Eric Blake (ebb9@email.byu.edu) + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class Double extends CubicCurve2D + { + /** + * The <i>x</i> coordinate of the curve’s start point. + */ + public double x1; + + /** + * The <i>y</i> coordinate of the curve’s start point. + */ + public double y1; + + /** + * The <i>x</i> coordinate of the curve’s first control point. + */ + public double ctrlx1; + + /** + * The <i>y</i> coordinate of the curve’s first control point. + */ + public double ctrly1; + + /** + * The <i>x</i> coordinate of the curve’s second control point. + */ + public double ctrlx2; + + /** + * The <i>y</i> coordinate of the curve’s second control point. + */ + public double ctrly2; + + /** + * The <i>x</i> coordinate of the curve’s end point. + */ + public double x2; + + /** + * The <i>y</i> coordinate of the curve’s end point. + */ + public double y2; + + /** + * Constructs a new CubicCurve2D that stores its coordinate values + * in double-precision floating-point format. All points are + * initially at position (0, 0). + */ + public Double() + { + } + + /** + * Constructs a new CubicCurve2D that stores its coordinate values + * in double-precision floating-point format, specifying the + * initial position of each point. + * + * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180" + * alt="A drawing of a CubicCurve2D" /> + * + * @param x1 the <i>x</i> coordinate of the curve’s start + * point. + * + * @param y1 the <i>y</i> coordinate of the curve’s start + * point. + * + * @param cx1 the <i>x</i> coordinate of the curve’s first + * control point. + * + * @param cy1 the <i>y</i> coordinate of the curve’s first + * control point. + * + * @param cx2 the <i>x</i> coordinate of the curve’s second + * control point. + * + * @param cy2 the <i>y</i> coordinate of the curve’s second + * control point. + * + * @param x2 the <i>x</i> coordinate of the curve’s end + * point. + * + * @param y2 the <i>y</i> coordinate of the curve’s end + * point. + */ + public Double(double x1, double y1, double cx1, double cy1, double cx2, + double cy2, double x2, double y2) + { + this.x1 = x1; + this.y1 = y1; + ctrlx1 = cx1; + ctrly1 = cy1; + ctrlx2 = cx2; + ctrly2 = cy2; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Returns the <i>x</i> coordinate of the curve’s start + * point. + */ + public double getX1() + { + return x1; + } + + /** + * Returns the <i>y</i> coordinate of the curve’s start + * point. + */ + public double getY1() + { + return y1; + } + + /** + * Returns the curve’s start point. + */ + public Point2D getP1() + { + return new Point2D.Double(x1, y1); + } + + /** + * Returns the <i>x</i> coordinate of the curve’s first + * control point. + */ + public double getCtrlX1() + { + return ctrlx1; + } + + /** + * Returns the <i>y</i> coordinate of the curve’s first + * control point. + */ + public double getCtrlY1() + { + return ctrly1; + } + + /** + * Returns the curve’s first control point. + */ + public Point2D getCtrlP1() + { + return new Point2D.Double(ctrlx1, ctrly1); + } + + /** + * Returns the <i>x</i> coordinate of the curve’s second + * control point. + */ + public double getCtrlX2() + { + return ctrlx2; + } + + /** + * Returns the <i>y</i> coordinate of the curve’s second + * control point. + */ + public double getCtrlY2() + { + return ctrly2; + } + + /** + * Returns the curve’s second control point. + */ + public Point2D getCtrlP2() + { + return new Point2D.Double(ctrlx2, ctrly2); + } + + /** + * Returns the <i>x</i> coordinate of the curve’s end + * point. + */ + public double getX2() + { + return x2; + } + + /** + * Returns the <i>y</i> coordinate of the curve’s end + * point. + */ + public double getY2() + { + return y2; + } + + /** + * Returns the curve’s end point. + */ + public Point2D getP2() + { + return new Point2D.Double(x2, y2); + } + + /** + * Changes the curve geometry, separately specifying each coordinate + * value. + * + * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180" + * alt="A drawing of a CubicCurve2D" /> + * + * @param x1 the <i>x</i> coordinate of the curve’s new start + * point. + * + * @param y1 the <i>y</i> coordinate of the curve’s new start + * point. + * + * @param cx1 the <i>x</i> coordinate of the curve’s new + * first control point. + * + * @param cy1 the <i>y</i> coordinate of the curve’s new + * first control point. + * + * @param cx2 the <i>x</i> coordinate of the curve’s new + * second control point. + * + * @param cy2 the <i>y</i> coordinate of the curve’s new + * second control point. + * + * @param x2 the <i>x</i> coordinate of the curve’s new end + * point. + * + * @param y2 the <i>y</i> coordinate of the curve’s new end + * point. + */ + public void setCurve(double x1, double y1, double cx1, double cy1, + double cx2, double cy2, double x2, double y2) + { + this.x1 = x1; + this.y1 = y1; + ctrlx1 = cx1; + ctrly1 = cy1; + ctrlx2 = cx2; + ctrly2 = cy2; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Determines the smallest rectangle that encloses the + * curve’s start, end and control points. As the + * illustration below shows, the invisible control points may cause + * the bounds to be much larger than the area that is actually + * covered by the curve. + * + * <p><img src="doc-files/CubicCurve2D-2.png" width="350" height="180" + * alt="An illustration of the bounds of a CubicCurve2D" /> + */ + public Rectangle2D getBounds2D() + { + double nx1 = Math.min(Math.min(x1, ctrlx1), Math.min(ctrlx2, x2)); + double ny1 = Math.min(Math.min(y1, ctrly1), Math.min(ctrly2, y2)); + double nx2 = Math.max(Math.max(x1, ctrlx1), Math.max(ctrlx2, x2)); + double ny2 = Math.max(Math.max(y1, ctrly1), Math.max(ctrly2, y2)); + return new Rectangle2D.Double(nx1, ny1, nx2 - nx1, ny2 - ny1); + } + } + + /** + * A two-dimensional curve that is parameterized with a cubic + * function and stores coordinate values in single-precision + * floating-point format. + * + * @see CubicCurve2D.Float + * + * @author Eric Blake (ebb9@email.byu.edu) + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class Float extends CubicCurve2D + { + /** + * The <i>x</i> coordinate of the curve’s start point. + */ + public float x1; + + /** + * The <i>y</i> coordinate of the curve’s start point. + */ + public float y1; + + /** + * The <i>x</i> coordinate of the curve’s first control point. + */ + public float ctrlx1; + + /** + * The <i>y</i> coordinate of the curve’s first control point. + */ + public float ctrly1; + + /** + * The <i>x</i> coordinate of the curve’s second control point. + */ + public float ctrlx2; + + /** + * The <i>y</i> coordinate of the curve’s second control point. + */ + public float ctrly2; + + /** + * The <i>x</i> coordinate of the curve’s end point. + */ + public float x2; + + /** + * The <i>y</i> coordinate of the curve’s end point. + */ + public float y2; + + /** + * Constructs a new CubicCurve2D that stores its coordinate values + * in single-precision floating-point format. All points are + * initially at position (0, 0). + */ + public Float() + { + } + + /** + * Constructs a new CubicCurve2D that stores its coordinate values + * in single-precision floating-point format, specifying the + * initial position of each point. + * + * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180" + * alt="A drawing of a CubicCurve2D" /> + * + * @param x1 the <i>x</i> coordinate of the curve’s start + * point. + * + * @param y1 the <i>y</i> coordinate of the curve’s start + * point. + * + * @param cx1 the <i>x</i> coordinate of the curve’s first + * control point. + * + * @param cy1 the <i>y</i> coordinate of the curve’s first + * control point. + * + * @param cx2 the <i>x</i> coordinate of the curve’s second + * control point. + * + * @param cy2 the <i>y</i> coordinate of the curve’s second + * control point. + * + * @param x2 the <i>x</i> coordinate of the curve’s end + * point. + * + * @param y2 the <i>y</i> coordinate of the curve’s end + * point. + */ + public Float(float x1, float y1, float cx1, float cy1, float cx2, + float cy2, float x2, float y2) + { + this.x1 = x1; + this.y1 = y1; + ctrlx1 = cx1; + ctrly1 = cy1; + ctrlx2 = cx2; + ctrly2 = cy2; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Returns the <i>x</i> coordinate of the curve’s start + * point. + */ + public double getX1() + { + return x1; + } + + /** + * Returns the <i>y</i> coordinate of the curve’s start + * point. + */ + public double getY1() + { + return y1; + } + + /** + * Returns the curve’s start point. + */ + public Point2D getP1() + { + return new Point2D.Float(x1, y1); + } + + /** + * Returns the <i>x</i> coordinate of the curve’s first + * control point. + */ + public double getCtrlX1() + { + return ctrlx1; + } + + /** + * Returns the <i>y</i> coordinate of the curve’s first + * control point. + */ + public double getCtrlY1() + { + return ctrly1; + } + + /** + * Returns the curve’s first control point. + */ + public Point2D getCtrlP1() + { + return new Point2D.Float(ctrlx1, ctrly1); + } + + /** + * Returns the <i>s</i> coordinate of the curve’s second + * control point. + */ + public double getCtrlX2() + { + return ctrlx2; + } + + /** + * Returns the <i>y</i> coordinate of the curve’s second + * control point. + */ + public double getCtrlY2() + { + return ctrly2; + } + + /** + * Returns the curve’s second control point. + */ + public Point2D getCtrlP2() + { + return new Point2D.Float(ctrlx2, ctrly2); + } + + /** + * Returns the <i>x</i> coordinate of the curve’s end + * point. + */ + public double getX2() + { + return x2; + } + + /** + * Returns the <i>y</i> coordinate of the curve’s end + * point. + */ + public double getY2() + { + return y2; + } + + /** + * Returns the curve’s end point. + */ + public Point2D getP2() + { + return new Point2D.Float(x2, y2); + } + + /** + * Changes the curve geometry, separately specifying each coordinate + * value as a double-precision floating-point number. + * + * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180" + * alt="A drawing of a CubicCurve2D" /> + * + * @param x1 the <i>x</i> coordinate of the curve’s new start + * point. + * + * @param y1 the <i>y</i> coordinate of the curve’s new start + * point. + * + * @param cx1 the <i>x</i> coordinate of the curve’s new + * first control point. + * + * @param cy1 the <i>y</i> coordinate of the curve’s new + * first control point. + * + * @param cx2 the <i>x</i> coordinate of the curve’s new + * second control point. + * + * @param cy2 the <i>y</i> coordinate of the curve’s new + * second control point. + * + * @param x2 the <i>x</i> coordinate of the curve’s new end + * point. + * + * @param y2 the <i>y</i> coordinate of the curve’s new end + * point. + */ + public void setCurve(double x1, double y1, double cx1, double cy1, + double cx2, double cy2, double x2, double y2) + { + this.x1 = (float) x1; + this.y1 = (float) y1; + ctrlx1 = (float) cx1; + ctrly1 = (float) cy1; + ctrlx2 = (float) cx2; + ctrly2 = (float) cy2; + this.x2 = (float) x2; + this.y2 = (float) y2; + } + + /** + * Changes the curve geometry, separately specifying each coordinate + * value as a single-precision floating-point number. + * + * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180" + * alt="A drawing of a CubicCurve2D" /> + * + * @param x1 the <i>x</i> coordinate of the curve’s new start + * point. + * + * @param y1 the <i>y</i> coordinate of the curve’s new start + * point. + * + * @param cx1 the <i>x</i> coordinate of the curve’s new + * first control point. + * + * @param cy1 the <i>y</i> coordinate of the curve’s new + * first control point. + * + * @param cx2 the <i>x</i> coordinate of the curve’s new + * second control point. + * + * @param cy2 the <i>y</i> coordinate of the curve’s new + * second control point. + * + * @param x2 the <i>x</i> coordinate of the curve’s new end + * point. + * + * @param y2 the <i>y</i> coordinate of the curve’s new end + * point. + */ + public void setCurve(float x1, float y1, float cx1, float cy1, float cx2, + float cy2, float x2, float y2) + { + this.x1 = x1; + this.y1 = y1; + ctrlx1 = cx1; + ctrly1 = cy1; + ctrlx2 = cx2; + ctrly2 = cy2; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Determines the smallest rectangle that encloses the + * curve’s start, end and control points. As the + * illustration below shows, the invisible control points may cause + * the bounds to be much larger than the area that is actually + * covered by the curve. + * + * <p><img src="doc-files/CubicCurve2D-2.png" width="350" height="180" + * alt="An illustration of the bounds of a CubicCurve2D" /> + */ + public Rectangle2D getBounds2D() + { + float nx1 = Math.min(Math.min(x1, ctrlx1), Math.min(ctrlx2, x2)); + float ny1 = Math.min(Math.min(y1, ctrly1), Math.min(ctrly2, y2)); + float nx2 = Math.max(Math.max(x1, ctrlx1), Math.max(ctrlx2, x2)); + float ny2 = Math.max(Math.max(y1, ctrly1), Math.max(ctrly2, y2)); + return new Rectangle2D.Float(nx1, ny1, nx2 - nx1, ny2 - ny1); + } + } +} diff --git a/libjava/classpath/java/awt/geom/Dimension2D.java b/libjava/classpath/java/awt/geom/Dimension2D.java new file mode 100644 index 000000000..6b5ce8830 --- /dev/null +++ b/libjava/classpath/java/awt/geom/Dimension2D.java @@ -0,0 +1,118 @@ +/* Dimension2D.java -- abstraction of a dimension + Copyright (C) 1999, 2000, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.geom; + +/** + * This stores a dimension in 2-dimensional space - a width (along the x-axis) + * and height (along the y-axis). The storage is left to subclasses. + * + * @author Per Bothner (bothner@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ +public abstract class Dimension2D implements Cloneable +{ + /** + * The default constructor. + */ + protected Dimension2D() + { + } + + /** + * Get the width of this dimension. A negative result, while legal, is + * undefined in meaning. + * + * @return the width + */ + public abstract double getWidth(); + + /** + * Get the height of this dimension. A negative result, while legal, is + * undefined in meaning. + * + * @return the height + */ + public abstract double getHeight(); + + /** + * Set the size of this dimension to the requested values. Loss of precision + * may occur. + * + * @param w the new width + * @param h the new height + */ + public abstract void setSize(double w, double h); + + /** + * Set the size of this dimension to the requested value. Loss of precision + * may occur. + * + * @param d the dimension containing the new values + * + * @throws NullPointerException if d is null + */ + public void setSize(Dimension2D d) + { + setSize(d.getWidth(), d.getHeight()); + } + + /** + * Create a new dimension of the same run-time type with the same contents + * as this one. + * + * @return the clone + * + * @exception OutOfMemoryError If there is not enough memory available. + * + * @since 1.2 + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } +} // class Dimension2D diff --git a/libjava/classpath/java/awt/geom/Ellipse2D.java b/libjava/classpath/java/awt/geom/Ellipse2D.java new file mode 100644 index 000000000..3bbf2f010 --- /dev/null +++ b/libjava/classpath/java/awt/geom/Ellipse2D.java @@ -0,0 +1,413 @@ +/* Ellipse2D.java -- represents an ellipse in 2-D space + Copyright (C) 2000, 2002, 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.geom; + + +/** + * Ellipse2D is the shape of an ellipse. + * <BR> + * <img src="doc-files/Ellipse-1.png" width="347" height="221" + * alt="A drawing of an ellipse" /><BR> + * The ellipse is defined by it's bounding box (shown in red), + * and is defined by the implicit curve:<BR> + * <blockquote>(<i>x</i>/<i>a</i>)<sup>2</sup> + + * (<i>y</i>/<i>b</i>)<sup>2</sup> = 1<BR><BR></blockquote> + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * + * @since 1.2 + */ +public abstract class Ellipse2D extends RectangularShape +{ + /** + * Ellipse2D is defined as abstract. + * Implementing classes are Ellipse2D.Float and Ellipse2D.Double. + */ + protected Ellipse2D() + { + } + + /** + * Determines if a point is contained within the ellipse. <P> + * @param x - x coordinate of the point. + * @param y - y coordinate of the point. + * @return true if the point is within the ellipse, false otherwise. + */ + public boolean contains(double x, double y) + { + double rx = getWidth() / 2; + double ry = getHeight() / 2; + double tx = (x - (getX() + rx)) / rx; + double ty = (y - (getY() + ry)) / ry; + return tx * tx + ty * ty < 1.0; + } + + /** + * Determines if a rectangle is completely contained within the + * ellipse. <P> + * @param x - x coordinate of the upper-left corner of the rectangle + * @param y - y coordinate of the upper-left corner of the rectangle + * @param w - width of the rectangle + * @param h - height of the rectangle + * @return true if the rectangle is completely contained, false otherwise. + */ + public boolean contains(double x, double y, double w, double h) + { + double x2 = x + w; + double y2 = y + h; + return (contains(x, y) && contains(x, y2) && contains(x2, y) + && contains(x2, y2)); + } + + /** + * Returns a PathIterator object corresponding to the ellipse.<P> + * + * Note: An ellipse cannot be represented exactly in PathIterator + * segments, the outline is thefore approximated with cubic + * Bezier segments. + * + * @param at an optional transform. + * @return A path iterator. + */ + public PathIterator getPathIterator(AffineTransform at) + { + // An ellipse is just a complete arc. + return new Arc2D.ArcIterator(this, at); + } + + /** + * Determines if a rectangle intersects any part of the ellipse.<P> + * @param x - x coordinate of the upper-left corner of the rectangle + * @param y - y coordinate of the upper-left corner of the rectangle + * @param w - width of the rectangle + * @param h - height of the rectangle + * @return true if the rectangle intersects the ellipse, false otherwise. + */ + public boolean intersects(double x, double y, double w, double h) + { + Rectangle2D r = new Rectangle2D.Double(x, y, w, h); + if (! r.intersects(getX(), getY(), getWidth(), getHeight())) + return false; + + if (contains(x, y) || contains(x, y + h) || contains(x + w, y) + || contains(x + w, y + h)) + return true; + + Line2D l1 = new Line2D.Double(getX(), getY() + (getHeight() / 2), + getX() + getWidth(), + getY() + (getHeight() / 2)); + Line2D l2 = new Line2D.Double(getX() + (getWidth() / 2), getY(), + getX() + (getWidth() / 2), + getY() + getHeight()); + + if (l1.intersects(r) || l2.intersects(r)) + return true; + + return false; + } + + /** + * An {@link Ellipse2D} that stores its coordinates using <code>double</code> + * primitives. + */ + public static class Double extends Ellipse2D + { + /** + * The height of the ellipse. + */ + public double height; + + /** + * The width of the ellipse. + */ + public double width; + + /** + * The upper-left x coordinate of the bounding-box + */ + public double x; + + /** + * The upper-left y coordinate of the bounding-box + */ + public double y; + + /** + * Creates a new Ellipse2D with an upper-left coordinate of (0,0) + * and a zero size. + */ + public Double() + { + } + + /** + * Creates a new Ellipse2D within a given rectangle + * using double-precision coordinates.<P> + * @param x - x coordinate of the upper-left of the bounding rectangle + * @param y - y coordinate of the upper-left of the bounding rectangle + * @param w - width of the ellipse + * @param h - height of the ellipse + */ + public Double(double x, double y, double w, double h) + { + this.x = x; + this.y = y; + height = h; + width = w; + } + + /** + * Returns the bounding-box of the ellipse. + * @return The bounding box. + */ + public Rectangle2D getBounds2D() + { + return new Rectangle2D.Double(x, y, width, height); + } + + /** + * Returns the height of the ellipse. + * @return The height of the ellipse. + */ + public double getHeight() + { + return height; + } + + /** + * Returns the width of the ellipse. + * @return The width of the ellipse. + */ + public double getWidth() + { + return width; + } + + /** + * Returns x coordinate of the upper-left corner of + * the ellipse's bounding-box. + * @return The x coordinate. + */ + public double getX() + { + return x; + } + + /** + * Returns y coordinate of the upper-left corner of + * the ellipse's bounding-box. + * @return The y coordinate. + */ + public double getY() + { + return y; + } + + /** + * Returns <code>true</code> if the ellipse encloses no area, and + * <code>false</code> otherwise. + * + * @return A boolean. + */ + public boolean isEmpty() + { + return height <= 0 || width <= 0; + } + + /** + * Sets the geometry of the ellipse's bounding box.<P> + * + * @param x - x coordinate of the upper-left of the bounding rectangle + * @param y - y coordinate of the upper-left of the bounding rectangle + * @param w - width of the ellipse + * @param h - height of the ellipse + */ + public void setFrame(double x, double y, double w, double h) + { + this.x = x; + this.y = y; + height = h; + width = w; + } + } // class Double + + /** + * An {@link Ellipse2D} that stores its coordinates using <code>float</code> + * primitives. + */ + public static class Float extends Ellipse2D + { + /** + * The height of the ellipse. + */ + public float height; + + /** + * The width of the ellipse. + */ + public float width; + + /** + * The upper-left x coordinate of the bounding-box + */ + public float x; + + /** + * The upper-left y coordinate of the bounding-box + */ + public float y; + + /** + * Creates a new Ellipse2D with an upper-left coordinate of (0,0) + * and a zero size. + */ + public Float() + { + } + + /** + * Creates a new Ellipse2D within a given rectangle + * using floating-point precision.<P> + * @param x - x coordinate of the upper-left of the bounding rectangle + * @param y - y coordinate of the upper-left of the bounding rectangle + * @param w - width of the ellipse + * @param h - height of the ellipse + * + */ + public Float(float x, float y, float w, float h) + { + this.x = x; + this.y = y; + this.height = h; + this.width = w; + } + + /** + * Returns the bounding-box of the ellipse. + * @return The bounding box. + */ + public Rectangle2D getBounds2D() + { + return new Rectangle2D.Float(x, y, width, height); + } + + /** + * Returns the height of the ellipse. + * @return The height of the ellipse. + */ + public double getHeight() + { + return height; + } + + /** + * Returns the width of the ellipse. + * @return The width of the ellipse. + */ + public double getWidth() + { + return width; + } + + /** + * Returns x coordinate of the upper-left corner of + * the ellipse's bounding-box. + * @return The x coordinate. + */ + public double getX() + { + return x; + } + + /** + * Returns y coordinate of the upper-left corner of + * the ellipse's bounding-box. + * @return The y coordinate. + */ + public double getY() + { + return y; + } + + /** + * Returns <code>true</code> if the ellipse encloses no area, and + * <code>false</code> otherwise. + * + * @return A boolean. + */ + public boolean isEmpty() + { + return height <= 0 || width <= 0; + } + + /** + * Sets the geometry of the ellipse's bounding box.<P> + * + * @param x - x coordinate of the upper-left of the bounding rectangle + * @param y - y coordinate of the upper-left of the bounding rectangle + * @param w - width of the ellipse + * @param h - height of the ellipse + */ + public void setFrame(float x, float y, float w, float h) + { + this.x = x; + this.y = y; + height = h; + width = w; + } + + /** + * Sets the geometry of the ellipse's bounding box. + * + * Note: This leads to a loss of precision.<P> + * + * @param x - x coordinate of the upper-left of the bounding rectangle + * @param y - y coordinate of the upper-left of the bounding rectangle + * @param w - width of the ellipse + * @param h - height of the ellipse + */ + public void setFrame(double x, double y, double w, double h) + { + this.x = (float) x; + this.y = (float) y; + height = (float) h; + width = (float) w; + } + } // class Float +} // class Ellipse2D diff --git a/libjava/classpath/java/awt/geom/FlatteningPathIterator.java b/libjava/classpath/java/awt/geom/FlatteningPathIterator.java new file mode 100644 index 000000000..629936bf7 --- /dev/null +++ b/libjava/classpath/java/awt/geom/FlatteningPathIterator.java @@ -0,0 +1,579 @@ +/* FlatteningPathIterator.java -- Approximates curves by straight lines + Copyright (C) 2003 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.geom; + +import java.util.NoSuchElementException; + + +/** + * A PathIterator for approximating curved path segments by sequences + * of straight lines. Instances of this class will only return + * segments of type {@link PathIterator#SEG_MOVETO}, {@link + * PathIterator#SEG_LINETO}, and {@link PathIterator#SEG_CLOSE}. + * + * <p>The accuracy of the approximation is determined by two + * parameters: + * + * <ul><li>The <i>flatness</i> is a threshold value for deciding when + * a curved segment is consided flat enough for being approximated by + * a single straight line. Flatness is defined as the maximal distance + * of a curve control point to the straight line that connects the + * curve start and end. A lower flatness threshold means a closer + * approximation. See {@link QuadCurve2D#getFlatness()} and {@link + * CubicCurve2D#getFlatness()} for drawings which illustrate the + * meaning of flatness.</li> + * + * <li>The <i>recursion limit</i> imposes an upper bound for how often + * a curved segment gets subdivided. A limit of <i>n</i> means that + * for each individual quadratic and cubic Bézier spline + * segment, at most 2<sup><small><i>n</i></small></sup> {@link + * PathIterator#SEG_LINETO} segments will be created.</li></ul> + * + * <p><b>Memory Efficiency:</b> The memory consumption grows linearly + * with the recursion limit. Neither the <i>flatness</i> parameter nor + * the number of segments in the flattened path will affect the memory + * consumption. + * + * <p><b>Thread Safety:</b> Multiple threads can safely work on + * separate instances of this class. However, multiple threads should + * not concurrently access the same instance, as no synchronization is + * performed. + * + * @see <a href="doc-files/FlatteningPathIterator-1.html" + * >Implementation Note</a> + * + * @author Sascha Brawer (brawer@dandelis.ch) + * + * @since 1.2 + */ +public class FlatteningPathIterator + implements PathIterator +{ + /** + * The PathIterator whose curved segments are being approximated. + */ + private final PathIterator srcIter; + + + /** + * The square of the flatness threshold value, which determines when + * a curve segment is considered flat enough that no further + * subdivision is needed. + * + * <p>Calculating flatness actually produces the squared flatness + * value. To avoid the relatively expensive calculation of a square + * root for each curve segment, we perform all flatness comparisons + * on squared values. + * + * @see QuadCurve2D#getFlatnessSq() + * @see CubicCurve2D#getFlatnessSq() + */ + private final double flatnessSq; + + + /** + * The maximal number of subdivions that are performed to + * approximate a quadratic or cubic curve segment. + */ + private final int recursionLimit; + + + /** + * A stack for holding the coordinates of subdivided segments. + * + * @see <a href="doc-files/FlatteningPathIterator-1.html" + * >Implementation Note</a> + */ + private double[] stack; + + + /** + * The current stack size. + * + * @see <a href="doc-files/FlatteningPathIterator-1.html" + * >Implementation Note</a> + */ + private int stackSize; + + + /** + * The number of recursions that were performed to arrive at + * a segment on the stack. + * + * @see <a href="doc-files/FlatteningPathIterator-1.html" + * >Implementation Note</a> + */ + private int[] recLevel; + + + + private final double[] scratch = new double[6]; + + + /** + * The segment type of the last segment that was returned by + * the source iterator. + */ + private int srcSegType; + + + /** + * The current <i>x</i> position of the source iterator. + */ + private double srcPosX; + + + /** + * The current <i>y</i> position of the source iterator. + */ + private double srcPosY; + + + /** + * A flag that indicates when this path iterator has finished its + * iteration over path segments. + */ + private boolean done; + + + /** + * Constructs a new PathIterator for approximating an input + * PathIterator with straight lines. The approximation works by + * recursive subdivisons, until the specified flatness threshold is + * not exceeded. + * + * <p>There will not be more than 10 nested recursion steps, which + * means that a single <code>SEG_QUADTO</code> or + * <code>SEG_CUBICTO</code> segment is approximated by at most + * 2<sup><small>10</small></sup> = 1024 straight lines. + */ + public FlatteningPathIterator(PathIterator src, double flatness) + { + this(src, flatness, 10); + } + + + /** + * Constructs a new PathIterator for approximating an input + * PathIterator with straight lines. The approximation works by + * recursive subdivisons, until the specified flatness threshold is + * not exceeded. Additionally, the number of recursions is also + * bound by the specified recursion limit. + */ + public FlatteningPathIterator(PathIterator src, double flatness, + int limit) + { + if (flatness < 0 || limit < 0) + throw new IllegalArgumentException(); + + srcIter = src; + flatnessSq = flatness * flatness; + recursionLimit = limit; + fetchSegment(); + } + + + /** + * Returns the maximally acceptable flatness. + * + * @see QuadCurve2D#getFlatness() + * @see CubicCurve2D#getFlatness() + */ + public double getFlatness() + { + return Math.sqrt(flatnessSq); + } + + + /** + * Returns the maximum number of recursive curve subdivisions. + */ + public int getRecursionLimit() + { + return recursionLimit; + } + + + // Documentation will be copied from PathIterator. + public int getWindingRule() + { + return srcIter.getWindingRule(); + } + + + // Documentation will be copied from PathIterator. + public boolean isDone() + { + return done; + } + + + // Documentation will be copied from PathIterator. + public void next() + { + if (stackSize > 0) + { + --stackSize; + if (stackSize > 0) + { + switch (srcSegType) + { + case PathIterator.SEG_QUADTO: + subdivideQuadratic(); + return; + + case PathIterator.SEG_CUBICTO: + subdivideCubic(); + return; + + default: + throw new IllegalStateException(); + } + } + } + + srcIter.next(); + fetchSegment(); + } + + + // Documentation will be copied from PathIterator. + public int currentSegment(double[] coords) + { + if (done) + throw new NoSuchElementException(); + + switch (srcSegType) + { + case PathIterator.SEG_CLOSE: + return srcSegType; + + case PathIterator.SEG_MOVETO: + case PathIterator.SEG_LINETO: + coords[0] = srcPosX; + coords[1] = srcPosY; + return srcSegType; + + case PathIterator.SEG_QUADTO: + if (stackSize == 0) + { + coords[0] = srcPosX; + coords[1] = srcPosY; + } + else + { + int sp = stack.length - 4 * stackSize; + coords[0] = stack[sp + 2]; + coords[1] = stack[sp + 3]; + } + return PathIterator.SEG_LINETO; + + case PathIterator.SEG_CUBICTO: + if (stackSize == 0) + { + coords[0] = srcPosX; + coords[1] = srcPosY; + } + else + { + int sp = stack.length - 6 * stackSize; + coords[0] = stack[sp + 4]; + coords[1] = stack[sp + 5]; + } + return PathIterator.SEG_LINETO; + } + + throw new IllegalStateException(); + } + + + // Documentation will be copied from PathIterator. + public int currentSegment(float[] coords) + { + if (done) + throw new NoSuchElementException(); + + switch (srcSegType) + { + case PathIterator.SEG_CLOSE: + return srcSegType; + + case PathIterator.SEG_MOVETO: + case PathIterator.SEG_LINETO: + coords[0] = (float) srcPosX; + coords[1] = (float) srcPosY; + return srcSegType; + + case PathIterator.SEG_QUADTO: + if (stackSize == 0) + { + coords[0] = (float) srcPosX; + coords[1] = (float) srcPosY; + } + else + { + int sp = stack.length - 4 * stackSize; + coords[0] = (float) stack[sp + 2]; + coords[1] = (float) stack[sp + 3]; + } + return PathIterator.SEG_LINETO; + + case PathIterator.SEG_CUBICTO: + if (stackSize == 0) + { + coords[0] = (float) srcPosX; + coords[1] = (float) srcPosY; + } + else + { + int sp = stack.length - 6 * stackSize; + coords[0] = (float) stack[sp + 4]; + coords[1] = (float) stack[sp + 5]; + } + return PathIterator.SEG_LINETO; + } + + throw new IllegalStateException(); + } + + + /** + * Fetches the next segment from the source iterator. + */ + private void fetchSegment() + { + int sp; + + if (srcIter.isDone()) + { + done = true; + return; + } + + srcSegType = srcIter.currentSegment(scratch); + + switch (srcSegType) + { + case PathIterator.SEG_CLOSE: + return; + + case PathIterator.SEG_MOVETO: + case PathIterator.SEG_LINETO: + srcPosX = scratch[0]; + srcPosY = scratch[1]; + return; + + case PathIterator.SEG_QUADTO: + if (recursionLimit == 0) + { + srcPosX = scratch[2]; + srcPosY = scratch[3]; + stackSize = 0; + return; + } + sp = 4 * recursionLimit; + stackSize = 1; + if (stack == null) + { + stack = new double[sp + /* 4 + 2 */ 6]; + recLevel = new int[recursionLimit + 1]; + } + recLevel[0] = 0; + stack[sp] = srcPosX; // P1.x + stack[sp + 1] = srcPosY; // P1.y + stack[sp + 2] = scratch[0]; // C.x + stack[sp + 3] = scratch[1]; // C.y + srcPosX = stack[sp + 4] = scratch[2]; // P2.x + srcPosY = stack[sp + 5] = scratch[3]; // P2.y + subdivideQuadratic(); + break; + + case PathIterator.SEG_CUBICTO: + if (recursionLimit == 0) + { + srcPosX = scratch[4]; + srcPosY = scratch[5]; + stackSize = 0; + return; + } + sp = 6 * recursionLimit; + stackSize = 1; + if ((stack == null) || (stack.length < sp + 8)) + { + stack = new double[sp + /* 6 + 2 */ 8]; + recLevel = new int[recursionLimit + 1]; + } + recLevel[0] = 0; + stack[sp] = srcPosX; // P1.x + stack[sp + 1] = srcPosY; // P1.y + stack[sp + 2] = scratch[0]; // C1.x + stack[sp + 3] = scratch[1]; // C1.y + stack[sp + 4] = scratch[2]; // C2.x + stack[sp + 5] = scratch[3]; // C2.y + srcPosX = stack[sp + 6] = scratch[4]; // P2.x + srcPosY = stack[sp + 7] = scratch[5]; // P2.y + subdivideCubic(); + return; + } + } + + + /** + * Repeatedly subdivides the quadratic curve segment that is on top + * of the stack. The iteration terminates when the recursion limit + * has been reached, or when the resulting segment is flat enough. + */ + private void subdivideQuadratic() + { + int sp; + int level; + + sp = stack.length - 4 * stackSize - 2; + level = recLevel[stackSize - 1]; + while ((level < recursionLimit) + && (QuadCurve2D.getFlatnessSq(stack, sp) >= flatnessSq)) + { + recLevel[stackSize] = recLevel[stackSize - 1] = ++level; + QuadCurve2D.subdivide(stack, sp, stack, sp - 4, stack, sp); + ++stackSize; + sp -= 4; + } + } + + + /** + * Repeatedly subdivides the cubic curve segment that is on top + * of the stack. The iteration terminates when the recursion limit + * has been reached, or when the resulting segment is flat enough. + */ + private void subdivideCubic() + { + int sp; + int level; + + sp = stack.length - 6 * stackSize - 2; + level = recLevel[stackSize - 1]; + while ((level < recursionLimit) + && (CubicCurve2D.getFlatnessSq(stack, sp) >= flatnessSq)) + { + recLevel[stackSize] = recLevel[stackSize - 1] = ++level; + + CubicCurve2D.subdivide(stack, sp, stack, sp - 6, stack, sp); + ++stackSize; + sp -= 6; + } + } + + + /* These routines were useful for debugging. Since they would + * just bloat the implementation, they are commented out. + * + * + + private static String segToString(int segType, double[] d, int offset) + { + String s; + + switch (segType) + { + case PathIterator.SEG_CLOSE: + return "SEG_CLOSE"; + + case PathIterator.SEG_MOVETO: + return "SEG_MOVETO (" + d[offset] + ", " + d[offset + 1] + ")"; + + case PathIterator.SEG_LINETO: + return "SEG_LINETO (" + d[offset] + ", " + d[offset + 1] + ")"; + + case PathIterator.SEG_QUADTO: + return "SEG_QUADTO (" + d[offset] + ", " + d[offset + 1] + + ") (" + d[offset + 2] + ", " + d[offset + 3] + ")"; + + case PathIterator.SEG_CUBICTO: + return "SEG_CUBICTO (" + d[offset] + ", " + d[offset + 1] + + ") (" + d[offset + 2] + ", " + d[offset + 3] + + ") (" + d[offset + 4] + ", " + d[offset + 5] + ")"; + } + + throw new IllegalStateException(); + } + + + private void dumpQuadraticStack(String msg) + { + int sp = stack.length - 4 * stackSize - 2; + int i = 0; + System.err.print(" " + msg + ":"); + while (sp < stack.length) + { + System.err.print(" (" + stack[sp] + ", " + stack[sp+1] + ")"); + if (i < recLevel.length) + System.out.print("/" + recLevel[i++]); + if (sp + 3 < stack.length) + System.err.print(" [" + stack[sp+2] + ", " + stack[sp+3] + "]"); + sp += 4; + } + System.err.println(); + } + + + private void dumpCubicStack(String msg) + { + int sp = stack.length - 6 * stackSize - 2; + int i = 0; + System.err.print(" " + msg + ":"); + while (sp < stack.length) + { + System.err.print(" (" + stack[sp] + ", " + stack[sp+1] + ")"); + if (i < recLevel.length) + System.out.print("/" + recLevel[i++]); + if (sp + 3 < stack.length) + { + System.err.print(" [" + stack[sp+2] + ", " + stack[sp+3] + "]"); + System.err.print(" [" + stack[sp+4] + ", " + stack[sp+5] + "]"); + } + sp += 6; + } + System.err.println(); + } + + * + * + */ +} diff --git a/libjava/classpath/java/awt/geom/GeneralPath.java b/libjava/classpath/java/awt/geom/GeneralPath.java new file mode 100644 index 000000000..99f1905e2 --- /dev/null +++ b/libjava/classpath/java/awt/geom/GeneralPath.java @@ -0,0 +1,992 @@ +/* GeneralPath.java -- represents a shape built from subpaths + Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.geom; + +import java.awt.Rectangle; +import java.awt.Shape; + + +/** + * A general geometric path, consisting of any number of subpaths + * constructed out of straight lines and cubic or quadratic Bezier + * curves. + * + * <p>The inside of the curve is defined for drawing purposes by a winding + * rule. Either the WIND_EVEN_ODD or WIND_NON_ZERO winding rule can be chosen. + * + * <p><img src="doc-files/GeneralPath-1.png" width="300" height="210" + * alt="A drawing of a GeneralPath" /> + * <p>The EVEN_ODD winding rule defines a point as inside a path if: + * A ray from the point towards infinity in an arbitrary direction + * intersects the path an odd number of times. Points <b>A</b> and + * <b>C</b> in the image are considered to be outside the path. + * (both intersect twice) + * Point <b>B</b> intersects once, and is inside. + * + * <p>The NON_ZERO winding rule defines a point as inside a path if: + * The path intersects the ray in an equal number of opposite directions. + * Point <b>A</b> in the image is outside (one intersection in the + * ’up’ + * direction, one in the ’down’ direction) Point <b>B</b> in + * the image is inside (one intersection ’down’) + * Point <b>C</b> in the image is inside (two intersections in the + * ’down’ direction) + * + * @see Line2D + * @see CubicCurve2D + * @see QuadCurve2D + * + * @author Sascha Brawer (brawer@dandelis.ch) + * @author Sven de Marothy (sven@physto.se) + * + * @since 1.2 + */ +public final class GeneralPath implements Shape, Cloneable +{ + /** Same constant as {@link PathIterator#WIND_EVEN_ODD}. */ + public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD; + + /** Same constant as {@link PathIterator#WIND_NON_ZERO}. */ + public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO; + + /** Initial size if not specified. */ + private static final int INIT_SIZE = 10; + + /** A big number, but not so big it can't survive a few float operations */ + private static final double BIG_VALUE = Double.MAX_VALUE / 10.0; + + /** The winding rule. + * This is package-private to avoid an accessor method. + */ + int rule; + + /** + * The path type in points. Note that xpoints[index] and ypoints[index] maps + * to types[index]; the control points of quad and cubic paths map as + * well but are ignored. + * This is package-private to avoid an accessor method. + */ + byte[] types; + + /** + * The list of all points seen. Since you can only append floats, it makes + * sense for these to be float[]. I have no idea why Sun didn't choose to + * allow a general path of double precision points. + * Note: Storing x and y coords seperately makes for a slower transforms, + * But it speeds up and simplifies box-intersection checking a lot. + * These are package-private to avoid accessor methods. + */ + float[] xpoints; + float[] ypoints; + + /** The index of the most recent moveto point, or null. */ + private int subpath = -1; + + /** The next available index into points. + * This is package-private to avoid an accessor method. + */ + int index; + + /** + * Constructs a GeneralPath with the default (NON_ZERO) + * winding rule and initial capacity (20). + */ + public GeneralPath() + { + this(WIND_NON_ZERO, INIT_SIZE); + } + + /** + * Constructs a GeneralPath with a specific winding rule + * and the default initial capacity (20). + * @param rule the winding rule ({@link #WIND_NON_ZERO} or + * {@link #WIND_EVEN_ODD}) + * + * @throws IllegalArgumentException if <code>rule</code> is not one of the + * listed values. + */ + public GeneralPath(int rule) + { + this(rule, INIT_SIZE); + } + + /** + * Constructs a GeneralPath with a specific winding rule + * and the initial capacity. The initial capacity should be + * the approximate number of path segments to be used. + * @param rule the winding rule ({@link #WIND_NON_ZERO} or + * {@link #WIND_EVEN_ODD}) + * @param capacity the inital capacity, in path segments + * + * @throws IllegalArgumentException if <code>rule</code> is not one of the + * listed values. + */ + public GeneralPath(int rule, int capacity) + { + if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) + throw new IllegalArgumentException(); + this.rule = rule; + if (capacity < INIT_SIZE) + capacity = INIT_SIZE; + types = new byte[capacity]; + xpoints = new float[capacity]; + ypoints = new float[capacity]; + } + + /** + * Constructs a GeneralPath from an arbitrary shape object. + * The Shapes PathIterator path and winding rule will be used. + * + * @param s the shape (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>shape</code> is <code>null</code>. + */ + public GeneralPath(Shape s) + { + types = new byte[INIT_SIZE]; + xpoints = new float[INIT_SIZE]; + ypoints = new float[INIT_SIZE]; + PathIterator pi = s.getPathIterator(null); + setWindingRule(pi.getWindingRule()); + append(pi, false); + } + + /** + * Adds a new point to a path. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + */ + public void moveTo(float x, float y) + { + subpath = index; + ensureSize(index + 1); + types[index] = PathIterator.SEG_MOVETO; + xpoints[index] = x; + ypoints[index++] = y; + } + + /** + * Appends a straight line to the current path. + * @param x x coordinate of the line endpoint. + * @param y y coordinate of the line endpoint. + */ + public void lineTo(float x, float y) + { + ensureSize(index + 1); + types[index] = PathIterator.SEG_LINETO; + xpoints[index] = x; + ypoints[index++] = y; + } + + /** + * Appends a quadratic Bezier curve to the current path. + * @param x1 x coordinate of the control point + * @param y1 y coordinate of the control point + * @param x2 x coordinate of the curve endpoint. + * @param y2 y coordinate of the curve endpoint. + */ + public void quadTo(float x1, float y1, float x2, float y2) + { + ensureSize(index + 2); + types[index] = PathIterator.SEG_QUADTO; + xpoints[index] = x1; + ypoints[index++] = y1; + xpoints[index] = x2; + ypoints[index++] = y2; + } + + /** + * Appends a cubic Bezier curve to the current path. + * @param x1 x coordinate of the first control point + * @param y1 y coordinate of the first control point + * @param x2 x coordinate of the second control point + * @param y2 y coordinate of the second control point + * @param x3 x coordinate of the curve endpoint. + * @param y3 y coordinate of the curve endpoint. + */ + public void curveTo(float x1, float y1, float x2, float y2, float x3, + float y3) + { + ensureSize(index + 3); + types[index] = PathIterator.SEG_CUBICTO; + xpoints[index] = x1; + ypoints[index++] = y1; + xpoints[index] = x2; + ypoints[index++] = y2; + xpoints[index] = x3; + ypoints[index++] = y3; + } + + /** + * Closes the current subpath by drawing a line + * back to the point of the last moveTo, unless the path is already closed. + */ + public void closePath() + { + if (index >= 1 && types[index - 1] == PathIterator.SEG_CLOSE) + return; + ensureSize(index + 1); + types[index] = PathIterator.SEG_CLOSE; + xpoints[index] = xpoints[subpath]; + ypoints[index++] = ypoints[subpath]; + } + + /** + * Appends the segments of a Shape to the path. If <code>connect</code> is + * true, the new path segments are connected to the existing one with a line. + * The winding rule of the Shape is ignored. + * + * @param s the shape (<code>null</code> not permitted). + * @param connect whether to connect the new shape to the existing path. + * + * @throws NullPointerException if <code>s</code> is <code>null</code>. + */ + public void append(Shape s, boolean connect) + { + append(s.getPathIterator(null), connect); + } + + /** + * Appends the segments of a PathIterator to this GeneralPath. + * Optionally, the initial {@link PathIterator#SEG_MOVETO} segment + * of the appended path is changed into a {@link + * PathIterator#SEG_LINETO} segment. + * + * @param iter the PathIterator specifying which segments shall be + * appended (<code>null</code> not permitted). + * + * @param connect <code>true</code> for substituting the initial + * {@link PathIterator#SEG_MOVETO} segment by a {@link + * PathIterator#SEG_LINETO}, or <code>false</code> for not + * performing any substitution. If this GeneralPath is currently + * empty, <code>connect</code> is assumed to be <code>false</code>, + * thus leaving the initial {@link PathIterator#SEG_MOVETO} + * unchanged. + */ + public void append(PathIterator iter, boolean connect) + { + // A bad implementation of this method had caused Classpath bug #6076. + float[] f = new float[6]; + while (! iter.isDone()) + { + switch (iter.currentSegment(f)) + { + case PathIterator.SEG_MOVETO: + if (! connect || (index == 0)) + { + moveTo(f[0], f[1]); + break; + } + if ((index >= 1) && (types[index - 1] == PathIterator.SEG_CLOSE) + && (f[0] == xpoints[index - 1]) + && (f[1] == ypoints[index - 1])) + break; + + // Fall through. + case PathIterator.SEG_LINETO: + lineTo(f[0], f[1]); + break; + case PathIterator.SEG_QUADTO: + quadTo(f[0], f[1], f[2], f[3]); + break; + case PathIterator.SEG_CUBICTO: + curveTo(f[0], f[1], f[2], f[3], f[4], f[5]); + break; + case PathIterator.SEG_CLOSE: + closePath(); + break; + } + + connect = false; + iter.next(); + } + } + + /** + * Returns the path’s current winding rule. + * + * @return {@link #WIND_EVEN_ODD} or {@link #WIND_NON_ZERO}. + */ + public int getWindingRule() + { + return rule; + } + + /** + * Sets the path’s winding rule, which controls which areas are + * considered ’inside’ or ’outside’ the path + * on drawing. Valid rules are WIND_EVEN_ODD for an even-odd winding rule, + * or WIND_NON_ZERO for a non-zero winding rule. + * + * @param rule the rule ({@link #WIND_EVEN_ODD} or {@link #WIND_NON_ZERO}). + */ + public void setWindingRule(int rule) + { + if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) + throw new IllegalArgumentException(); + this.rule = rule; + } + + /** + * Returns the current appending point of the path. + * + * @return The point. + */ + public Point2D getCurrentPoint() + { + if (subpath < 0) + return null; + return new Point2D.Float(xpoints[index - 1], ypoints[index - 1]); + } + + /** + * Resets the path. All points and segments are destroyed. + */ + public void reset() + { + subpath = -1; + index = 0; + } + + /** + * Applies a transform to the path. + * + * @param xform the transform (<code>null</code> not permitted). + */ + public void transform(AffineTransform xform) + { + double nx; + double ny; + double[] m = new double[6]; + xform.getMatrix(m); + for (int i = 0; i < index; i++) + { + nx = m[0] * xpoints[i] + m[2] * ypoints[i] + m[4]; + ny = m[1] * xpoints[i] + m[3] * ypoints[i] + m[5]; + xpoints[i] = (float) nx; + ypoints[i] = (float) ny; + } + } + + /** + * Creates a transformed version of the path. + * @param xform the transform to apply + * @return a new transformed GeneralPath + */ + public Shape createTransformedShape(AffineTransform xform) + { + GeneralPath p = new GeneralPath(this); + p.transform(xform); + return p; + } + + /** + * Returns the path’s bounding box. + */ + public Rectangle getBounds() + { + return getBounds2D().getBounds(); + } + + /** + * Returns the path’s bounding box, in <code>float</code> precision + */ + public Rectangle2D getBounds2D() + { + float x1; + float y1; + float x2; + float y2; + + if (index > 0) + { + x1 = x2 = xpoints[0]; + y1 = y2 = ypoints[0]; + } + else + x1 = x2 = y1 = y2 = 0.0f; + + for (int i = 0; i < index; i++) + { + x1 = Math.min(xpoints[i], x1); + y1 = Math.min(ypoints[i], y1); + x2 = Math.max(xpoints[i], x2); + y2 = Math.max(ypoints[i], y2); + } + return (new Rectangle2D.Float(x1, y1, x2 - x1, y2 - y1)); + } + + /** + * Evaluates if a point is within the GeneralPath, + * The NON_ZERO winding rule is used, regardless of the + * set winding rule. + * @param x x coordinate of the point to evaluate + * @param y y coordinate of the point to evaluate + * @return true if the point is within the path, false otherwise + */ + public boolean contains(double x, double y) + { + return (getWindingNumber(x, y) != 0); + } + + /** + * Evaluates if a Point2D is within the GeneralPath, + * The NON_ZERO winding rule is used, regardless of the + * set winding rule. + * @param p The Point2D to evaluate + * @return true if the point is within the path, false otherwise + */ + public boolean contains(Point2D p) + { + return contains(p.getX(), p.getY()); + } + + /** + * Evaluates if a rectangle is completely contained within the path. + * This method will return false in the cases when the box + * intersects an inner segment of the path. + * (i.e.: The method is accurate for the EVEN_ODD winding rule) + */ + public boolean contains(double x, double y, double w, double h) + { + if (! getBounds2D().intersects(x, y, w, h)) + return false; + + /* Does any edge intersect? */ + if (getAxisIntersections(x, y, false, w) != 0 /* top */ + || getAxisIntersections(x, y + h, false, w) != 0 /* bottom */ + || getAxisIntersections(x + w, y, true, h) != 0 /* right */ + || getAxisIntersections(x, y, true, h) != 0) /* left */ + return false; + + /* No intersections, is any point inside? */ + if (getWindingNumber(x, y) != 0) + return true; + + return false; + } + + /** + * Evaluates if a rectangle is completely contained within the path. + * This method will return false in the cases when the box + * intersects an inner segment of the path. + * (i.e.: The method is accurate for the EVEN_ODD winding rule) + * @param r the rectangle + * @return <code>true</code> if the rectangle is completely contained + * within the path, <code>false</code> otherwise + */ + public boolean contains(Rectangle2D r) + { + return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Evaluates if a rectangle intersects the path. + * @param x x coordinate of the rectangle + * @param y y coordinate of the rectangle + * @param w width of the rectangle + * @param h height of the rectangle + * @return <code>true</code> if the rectangle intersects the path, + * <code>false</code> otherwise + */ + public boolean intersects(double x, double y, double w, double h) + { + /* Does any edge intersect? */ + if (getAxisIntersections(x, y, false, w) != 0 /* top */ + || getAxisIntersections(x, y + h, false, w) != 0 /* bottom */ + || getAxisIntersections(x + w, y, true, h) != 0 /* right */ + || getAxisIntersections(x, y, true, h) != 0) /* left */ + return true; + + /* No intersections, is any point inside? */ + if (getWindingNumber(x, y) != 0) + return true; + + return false; + } + + /** + * Evaluates if a Rectangle2D intersects the path. + * @param r The rectangle + * @return <code>true</code> if the rectangle intersects the path, + * <code>false</code> otherwise + */ + public boolean intersects(Rectangle2D r) + { + return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * A PathIterator that iterates over the segments of a GeneralPath. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ + private static class GeneralPathIterator implements PathIterator + { + /** + * The number of coordinate values for each segment type. + */ + private static final int[] NUM_COORDS = { + /* 0: SEG_MOVETO */ 1, + /* 1: SEG_LINETO */ 1, + /* 2: SEG_QUADTO */ 2, + /* 3: SEG_CUBICTO */ 3, + /* 4: SEG_CLOSE */ 0}; + + /** + * The GeneralPath whose segments are being iterated. + * This is package-private to avoid an accessor method. + */ + final GeneralPath path; + + /** + * The affine transformation used to transform coordinates. + */ + private final AffineTransform transform; + + /** + * The current position of the iterator. + */ + private int pos; + + /** + * Constructs a new iterator for enumerating the segments of a + * GeneralPath. + * + * @param path the path to enumerate + * @param transform an affine transformation for projecting the returned + * points, or <code>null</code> to return the original points + * without any mapping. + */ + GeneralPathIterator(GeneralPath path, AffineTransform transform) + { + this.path = path; + this.transform = transform; + } + + /** + * Returns the current winding rule of the GeneralPath. + */ + public int getWindingRule() + { + return path.rule; + } + + /** + * Determines whether the iterator has reached the last segment in + * the path. + */ + public boolean isDone() + { + return pos >= path.index; + } + + /** + * Advances the iterator position by one segment. + */ + public void next() + { + int seg; + + /* + * Increment pos by the number of coordinate pairs. + */ + seg = path.types[pos]; + if (seg == SEG_CLOSE) + pos++; + else + pos += NUM_COORDS[seg]; + } + + /** + * Returns the current segment in float coordinates. + */ + public int currentSegment(float[] coords) + { + int seg; + int numCoords; + + seg = path.types[pos]; + numCoords = NUM_COORDS[seg]; + if (numCoords > 0) + { + for (int i = 0; i < numCoords; i++) + { + coords[i << 1] = path.xpoints[pos + i]; + coords[(i << 1) + 1] = path.ypoints[pos + i]; + } + + if (transform != null) + transform.transform( /* src */ + coords, /* srcOffset */ + 0, /* dest */ coords, /* destOffset */ + 0, /* numPoints */ numCoords); + } + return seg; + } + + /** + * Returns the current segment in double coordinates. + */ + public int currentSegment(double[] coords) + { + int seg; + int numCoords; + + seg = path.types[pos]; + numCoords = NUM_COORDS[seg]; + if (numCoords > 0) + { + for (int i = 0; i < numCoords; i++) + { + coords[i << 1] = (double) path.xpoints[pos + i]; + coords[(i << 1) + 1] = (double) path.ypoints[pos + i]; + } + if (transform != null) + transform.transform( /* src */ + coords, /* srcOffset */ + 0, /* dest */ coords, /* destOffset */ + 0, /* numPoints */ numCoords); + } + return seg; + } + } + + /** + * Creates a PathIterator for iterating along the segments of the path. + * + * @param at an affine transformation for projecting the returned + * points, or <code>null</code> to let the created iterator return + * the original points without any mapping. + */ + public PathIterator getPathIterator(AffineTransform at) + { + return new GeneralPathIterator(this, at); + } + + /** + * Creates a new FlatteningPathIterator for the path + */ + public PathIterator getPathIterator(AffineTransform at, double flatness) + { + return new FlatteningPathIterator(getPathIterator(at), flatness); + } + + /** + * Creates a new shape of the same run-time type with the same contents + * as this one. + * + * @return the clone + * + * @exception OutOfMemoryError If there is not enough memory available. + * + * @since 1.2 + */ + public Object clone() + { + // This class is final; no need to use super.clone(). + return new GeneralPath(this); + } + + /** + * Helper method - ensure the size of the data arrays, + * otherwise, reallocate new ones twice the size + * + * @param size the minimum array size. + */ + private void ensureSize(int size) + { + if (subpath < 0) + throw new IllegalPathStateException("need initial moveto"); + if (size <= xpoints.length) + return; + byte[] b = new byte[types.length << 1]; + System.arraycopy(types, 0, b, 0, index); + types = b; + float[] f = new float[xpoints.length << 1]; + System.arraycopy(xpoints, 0, f, 0, index); + xpoints = f; + f = new float[ypoints.length << 1]; + System.arraycopy(ypoints, 0, f, 0, index); + ypoints = f; + } + + /** + * Helper method - Get the total number of intersections from (x,y) along + * a given axis, within a given distance. + */ + private int getAxisIntersections(double x, double y, boolean useYaxis, + double distance) + { + return (evaluateCrossings(x, y, false, useYaxis, distance)); + } + + /** + * Helper method - returns the winding number of a point. + */ + private int getWindingNumber(double x, double y) + { + /* Evaluate the crossings from x,y to infinity on the y axis (arbitrary + choice). Note that we don't actually use Double.INFINITY, since that's + slower, and may cause problems. */ + return (evaluateCrossings(x, y, true, true, BIG_VALUE)); + } + + /** + * Helper method - evaluates the number of intersections on an axis from + * the point (x,y) to the point (x,y+distance) or (x+distance,y). + * @param x x coordinate. + * @param y y coordinate. + * @param neg True if opposite-directed intersections should cancel, + * false to sum all intersections. + * @param useYaxis Use the Y axis, false uses the X axis. + * @param distance Interval from (x,y) on the selected axis to find + * intersections. + */ + private int evaluateCrossings(double x, double y, boolean neg, + boolean useYaxis, double distance) + { + float cx = 0.0f; + float cy = 0.0f; + float firstx = 0.0f; + float firsty = 0.0f; + + int negative = (neg) ? -1 : 1; + double x0; + double x1; + double x2; + double x3; + double y0; + double y1; + double y2; + double y3; + double[] r = new double[4]; + int nRoots; + double epsilon = 0.0; + int pos = 0; + int windingNumber = 0; + boolean pathStarted = false; + + if (index == 0) + return (0); + if (useYaxis) + { + float[] swap1; + swap1 = ypoints; + ypoints = xpoints; + xpoints = swap1; + double swap2; + swap2 = y; + y = x; + x = swap2; + } + + /* Get a value which is hopefully small but not insignificant relative + the path. */ + epsilon = ypoints[0] * 1E-7; + + if(epsilon == 0) + epsilon = 1E-7; + + pos = 0; + while (pos < index) + { + switch (types[pos]) + { + case PathIterator.SEG_MOVETO: + if (pathStarted) // close old path + { + x0 = cx; + y0 = cy; + x1 = firstx; + y1 = firsty; + + if (y0 == 0.0) + y0 -= epsilon; + if (y1 == 0.0) + y1 -= epsilon; + if (Line2D.linesIntersect(x0, y0, x1, y1, + epsilon, 0.0, distance, 0.0)) + windingNumber += (y1 < y0) ? 1 : negative; + + cx = firstx; + cy = firsty; + } + cx = firstx = xpoints[pos] - (float) x; + cy = firsty = ypoints[pos++] - (float) y; + pathStarted = true; + break; + case PathIterator.SEG_CLOSE: + x0 = cx; + y0 = cy; + x1 = firstx; + y1 = firsty; + + if (y0 == 0.0) + y0 -= epsilon; + if (y1 == 0.0) + y1 -= epsilon; + if (Line2D.linesIntersect(x0, y0, x1, y1, + epsilon, 0.0, distance, 0.0)) + windingNumber += (y1 < y0) ? 1 : negative; + + cx = firstx; + cy = firsty; + pos++; + pathStarted = false; + break; + case PathIterator.SEG_LINETO: + x0 = cx; + y0 = cy; + x1 = xpoints[pos] - (float) x; + y1 = ypoints[pos++] - (float) y; + + if (y0 == 0.0) + y0 -= epsilon; + if (y1 == 0.0) + y1 -= epsilon; + if (Line2D.linesIntersect(x0, y0, x1, y1, + epsilon, 0.0, distance, 0.0)) + windingNumber += (y1 < y0) ? 1 : negative; + + cx = xpoints[pos - 1] - (float) x; + cy = ypoints[pos - 1] - (float) y; + break; + case PathIterator.SEG_QUADTO: + x0 = cx; + y0 = cy; + x1 = xpoints[pos] - x; + y1 = ypoints[pos++] - y; + x2 = xpoints[pos] - x; + y2 = ypoints[pos++] - y; + + /* check if curve may intersect X+ axis. */ + if ((x0 > 0.0 || x1 > 0.0 || x2 > 0.0) + && (y0 * y1 <= 0 || y1 * y2 <= 0)) + { + if (y0 == 0.0) + y0 -= epsilon; + if (y2 == 0.0) + y2 -= epsilon; + + r[0] = y0; + r[1] = 2 * (y1 - y0); + r[2] = (y2 - 2 * y1 + y0); + + /* degenerate roots (=tangent points) do not + contribute to the winding number. */ + if ((nRoots = QuadCurve2D.solveQuadratic(r)) == 2) + for (int i = 0; i < nRoots; i++) + { + float t = (float) r[i]; + if (t > 0.0f && t < 1.0f) + { + double crossing = t * t * (x2 - 2 * x1 + x0) + + 2 * t * (x1 - x0) + x0; + if (crossing >= 0.0 && crossing <= distance) + windingNumber += (2 * t * (y2 - 2 * y1 + y0) + + 2 * (y1 - y0) < 0) ? 1 : negative; + } + } + } + + cx = xpoints[pos - 1] - (float) x; + cy = ypoints[pos - 1] - (float) y; + break; + case PathIterator.SEG_CUBICTO: + x0 = cx; + y0 = cy; + x1 = xpoints[pos] - x; + y1 = ypoints[pos++] - y; + x2 = xpoints[pos] - x; + y2 = ypoints[pos++] - y; + x3 = xpoints[pos] - x; + y3 = ypoints[pos++] - y; + + /* check if curve may intersect X+ axis. */ + if ((x0 > 0.0 || x1 > 0.0 || x2 > 0.0 || x3 > 0.0) + && (y0 * y1 <= 0 || y1 * y2 <= 0 || y2 * y3 <= 0)) + { + if (y0 == 0.0) + y0 -= epsilon; + if (y3 == 0.0) + y3 -= epsilon; + + r[0] = y0; + r[1] = 3 * (y1 - y0); + r[2] = 3 * (y2 + y0 - 2 * y1); + r[3] = y3 - 3 * y2 + 3 * y1 - y0; + + if ((nRoots = CubicCurve2D.solveCubic(r)) != 0) + for (int i = 0; i < nRoots; i++) + { + float t = (float) r[i]; + if (t > 0.0 && t < 1.0) + { + double crossing = -(t * t * t) * (x0 - 3 * x1 + + 3 * x2 - x3) + + 3 * t * t * (x0 - 2 * x1 + x2) + + 3 * t * (x1 - x0) + x0; + if (crossing >= 0 && crossing <= distance) + windingNumber += (3 * t * t * (y3 + 3 * y1 + - 3 * y2 - y0) + + 6 * t * (y0 - 2 * y1 + y2) + + 3 * (y1 - y0) < 0) ? 1 : negative; + } + } + } + + cx = xpoints[pos - 1] - (float) x; + cy = ypoints[pos - 1] - (float) y; + break; + } + } + + // swap coordinates back + if (useYaxis) + { + float[] swap; + swap = ypoints; + ypoints = xpoints; + xpoints = swap; + } + return (windingNumber); + } +} // class GeneralPath diff --git a/libjava/classpath/java/awt/geom/IllegalPathStateException.java b/libjava/classpath/java/awt/geom/IllegalPathStateException.java new file mode 100644 index 000000000..4d190c748 --- /dev/null +++ b/libjava/classpath/java/awt/geom/IllegalPathStateException.java @@ -0,0 +1,71 @@ +/* IllegalPathStateException.java -- an operation was in an illegal path state + Copyright (C) 2000, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.geom; + +/** + * Thrown when an operation on a path is in an illegal state, such as appending + * a segment to a <code>GeneralPath</code> without an initial moveto. + * + * @author Tom Tromey (tromey@cygnus.com) + * @see GeneralPath + * @status updated to 1.4 + */ +public class IllegalPathStateException extends RuntimeException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -5158084205220481094L; + + /** + * Create an exception with no message. + */ + public IllegalPathStateException() + { + } + + /** + * Create an exception with a message. + * + * @param msg the message + */ + public IllegalPathStateException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/java/awt/geom/Line2D.java b/libjava/classpath/java/awt/geom/Line2D.java new file mode 100644 index 000000000..c92aab004 --- /dev/null +++ b/libjava/classpath/java/awt/geom/Line2D.java @@ -0,0 +1,1182 @@ +/* Line2D.java -- represents a line in 2-D space, plus operations on a line + Copyright (C) 2000, 2001, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.geom; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.util.NoSuchElementException; + +/** + * Represents a directed line bewteen two points in (x,y) Cartesian space. + * Remember, on-screen graphics have increasing x from left-to-right, and + * increasing y from top-to-bottom. The storage is left to subclasses. + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @author David Gilbert + * @since 1.2 + * @status updated to 1.4 + */ +public abstract class Line2D implements Shape, Cloneable +{ + /** + * The default constructor. + */ + protected Line2D() + { + } + + /** + * Return the x coordinate of the first point. + * + * @return the starting x coordinate + */ + public abstract double getX1(); + + /** + * Return the y coordinate of the first point. + * + * @return the starting y coordinate + */ + public abstract double getY1(); + + /** + * Return the first point. + * + * @return the starting point + */ + public abstract Point2D getP1(); + + /** + * Return the x coordinate of the second point. + * + * @return the ending x coordinate + */ + public abstract double getX2(); + + /** + * Return the y coordinate of the second point. + * + * @return the ending y coordinate + */ + public abstract double getY2(); + + /** + * Return the second point. + * + * @return the ending point + */ + public abstract Point2D getP2(); + + /** + * Set the coordinates of the line to the given coordinates. Loss of + * precision may occur due to rounding issues. + * + * @param x1 the first x coordinate + * @param y1 the first y coordinate + * @param x2 the second x coordinate + * @param y2 the second y coordinate + */ + public abstract void setLine(double x1, double y1, double x2, double y2); + + /** + * Set the coordinates to the given points. + * + * @param p1 the first point + * @param p2 the second point + * @throws NullPointerException if either point is null + */ + public void setLine(Point2D p1, Point2D p2) + { + setLine(p1.getX(), p1.getY(), p2.getX(), p2.getY()); + } + + /** + * Set the coordinates to those of the given line. + * + * @param l the line to copy + * @throws NullPointerException if l is null + */ + public void setLine(Line2D l) + { + setLine(l.getX1(), l.getY1(), l.getX2(), l.getY2()); + } + + /** + * Computes the relative rotation direction needed to pivot the line about + * the first point in order to have the second point colinear with point p. + * Because of floating point rounding, don't expect this to be a perfect + * measure of colinearity. The answer is 1 if the line has a shorter rotation + * in the direction of the positive X axis to the negative Y axis + * (counter-clockwise in the default Java coordinate system), or -1 if the + * shortest rotation is in the opposite direction (clockwise). If p + * is already colinear, the return value is -1 if it lies beyond the first + * point, 0 if it lies in the segment, or 1 if it lies beyond the second + * point. If the first and second point are coincident, this returns 0. + * + * @param x1 the first x coordinate + * @param y1 the first y coordinate + * @param x2 the second x coordinate + * @param y2 the second y coordinate + * @param px the reference x coordinate + * @param py the reference y coordinate + * @return the relative rotation direction + */ + public static int relativeCCW(double x1, double y1, double x2, double y2, + double px, double py) + { + if ((x1 == x2 && y1 == y2) + || (x1 == px && y1 == py)) + return 0; // Coincident points. + // Translate to the origin. + x2 -= x1; + y2 -= y1; + px -= x1; + py -= y1; + double slope2 = y2 / x2; + double slopep = py / px; + if (slope2 == slopep || (x2 == 0 && px == 0)) + return y2 > 0 // Colinear. + ? (py < 0 ? -1 : py > y2 ? 1 : 0) + : (py > 0 ? -1 : py < y2 ? 1 : 0); + if (x2 >= 0 && slope2 >= 0) + return px >= 0 // Quadrant 1. + ? (slope2 > slopep ? 1 : -1) + : (slope2 < slopep ? 1 : -1); + if (y2 > 0) + return px < 0 // Quadrant 2. + ? (slope2 > slopep ? 1 : -1) + : (slope2 < slopep ? 1 : -1); + if (slope2 >= 0.0) + return px >= 0 // Quadrant 3. + ? (slope2 < slopep ? 1 : -1) + : (slope2 > slopep ? 1 : -1); + return px < 0 // Quadrant 4. + ? (slope2 < slopep ? 1 : -1) + : (slope2 > slopep ? 1 : -1); + } + + /** + * Computes the relative rotation direction needed to pivot this line about + * the first point in order to have the second point colinear with point p. + * Because of floating point rounding, don't expect this to be a perfect + * measure of colinearity. The answer is 1 if the line has a shorter rotation + * in the direction of the positive X axis to the negative Y axis + * (counter-clockwise in the default Java coordinate system), or -1 if the + * shortest rotation is in the opposite direction (clockwise). If p + * is already colinear, the return value is -1 if it lies beyond the first + * point, 0 if it lies in the segment, or 1 if it lies beyond the second + * point. If the first and second point are coincident, this returns 0. + * + * @param px the reference x coordinate + * @param py the reference y coordinate + * @return the relative rotation direction + * @see #relativeCCW(double, double, double, double, double, double) + */ + public int relativeCCW(double px, double py) + { + return relativeCCW(getX1(), getY1(), getX2(), getY2(), px, py); + } + + /** + * Computes the relative rotation direction needed to pivot this line about + * the first point in order to have the second point colinear with point p. + * Because of floating point rounding, don't expect this to be a perfect + * measure of colinearity. The answer is 1 if the line has a shorter rotation + * in the direction of the positive X axis to the negative Y axis + * (counter-clockwise in the default Java coordinate system), or -1 if the + * shortest rotation is in the opposite direction (clockwise). If p + * is already colinear, the return value is -1 if it lies beyond the first + * point, 0 if it lies in the segment, or 1 if it lies beyond the second + * point. If the first and second point are coincident, this returns 0. + * + * @param p the reference point + * @return the relative rotation direction + * @throws NullPointerException if p is null + * @see #relativeCCW(double, double, double, double, double, double) + */ + public int relativeCCW(Point2D p) + { + return relativeCCW(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); + } + + /** + * Computes twice the (signed) area of the triangle defined by the three + * points. This method is used for intersection testing. + * + * @param x1 the x-coordinate of the first point. + * @param y1 the y-coordinate of the first point. + * @param x2 the x-coordinate of the second point. + * @param y2 the y-coordinate of the second point. + * @param x3 the x-coordinate of the third point. + * @param y3 the y-coordinate of the third point. + * + * @return Twice the area. + */ + private static double area2(double x1, double y1, + double x2, double y2, + double x3, double y3) + { + return (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1); + } + + /** + * Returns <code>true</code> if (x3, y3) lies between (x1, y1) and (x2, y2), + * and false otherwise, This test assumes that the three points are + * collinear, and is used for intersection testing. + * + * @param x1 the x-coordinate of the first point. + * @param y1 the y-coordinate of the first point. + * @param x2 the x-coordinate of the second point. + * @param y2 the y-coordinate of the second point. + * @param x3 the x-coordinate of the third point. + * @param y3 the y-coordinate of the third point. + * + * @return A boolean. + */ + private static boolean between(double x1, double y1, + double x2, double y2, + double x3, double y3) + { + if (x1 != x2) { + return (x1 <= x3 && x3 <= x2) || (x1 >= x3 && x3 >= x2); + } + else { + return (y1 <= y3 && y3 <= y2) || (y1 >= y3 && y3 >= y2); + } + } + + /** + * Test if the line segment (x1,y1)->(x2,y2) intersects the line segment + * (x3,y3)->(x4,y4). + * + * @param x1 the first x coordinate of the first segment + * @param y1 the first y coordinate of the first segment + * @param x2 the second x coordinate of the first segment + * @param y2 the second y coordinate of the first segment + * @param x3 the first x coordinate of the second segment + * @param y3 the first y coordinate of the second segment + * @param x4 the second x coordinate of the second segment + * @param y4 the second y coordinate of the second segment + * @return true if the segments intersect + */ + public static boolean linesIntersect(double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4) + { + double a1, a2, a3, a4; + + // deal with special cases + if ((a1 = area2(x1, y1, x2, y2, x3, y3)) == 0.0) + { + // check if p3 is between p1 and p2 OR + // p4 is collinear also AND either between p1 and p2 OR at opposite ends + if (between(x1, y1, x2, y2, x3, y3)) + { + return true; + } + else + { + if (area2(x1, y1, x2, y2, x4, y4) == 0.0) + { + return between(x3, y3, x4, y4, x1, y1) + || between (x3, y3, x4, y4, x2, y2); + } + else { + return false; + } + } + } + else if ((a2 = area2(x1, y1, x2, y2, x4, y4)) == 0.0) + { + // check if p4 is between p1 and p2 (we already know p3 is not + // collinear) + return between(x1, y1, x2, y2, x4, y4); + } + + if ((a3 = area2(x3, y3, x4, y4, x1, y1)) == 0.0) { + // check if p1 is between p3 and p4 OR + // p2 is collinear also AND either between p1 and p2 OR at opposite ends + if (between(x3, y3, x4, y4, x1, y1)) { + return true; + } + else { + if (area2(x3, y3, x4, y4, x2, y2) == 0.0) { + return between(x1, y1, x2, y2, x3, y3) + || between (x1, y1, x2, y2, x4, y4); + } + else { + return false; + } + } + } + else if ((a4 = area2(x3, y3, x4, y4, x2, y2)) == 0.0) { + // check if p2 is between p3 and p4 (we already know p1 is not + // collinear) + return between(x3, y3, x4, y4, x2, y2); + } + else { // test for regular intersection + return ((a1 > 0.0) ^ (a2 > 0.0)) && ((a3 > 0.0) ^ (a4 > 0.0)); + } + } + + /** + * Test if this line intersects the line given by (x1,y1)->(x2,y2). + * + * @param x1 the first x coordinate of the other segment + * @param y1 the first y coordinate of the other segment + * @param x2 the second x coordinate of the other segment + * @param y2 the second y coordinate of the other segment + * @return true if the segments intersect + * @see #linesIntersect(double, double, double, double, + * double, double, double, double) + */ + public boolean intersectsLine(double x1, double y1, double x2, double y2) + { + return linesIntersect(getX1(), getY1(), getX2(), getY2(), + x1, y1, x2, y2); + } + + /** + * Test if this line intersects the given line. + * + * @param l the other segment + * @return true if the segments intersect + * @throws NullPointerException if l is null + * @see #linesIntersect(double, double, double, double, + * double, double, double, double) + */ + public boolean intersectsLine(Line2D l) + { + return linesIntersect(getX1(), getY1(), getX2(), getY2(), + l.getX1(), l.getY1(), l.getX2(), l.getY2()); + } + + /** + * Measures the square of the shortest distance from the reference point + * to a point on the line segment. If the point is on the segment, the + * result will be 0. + * + * @param x1 the first x coordinate of the segment + * @param y1 the first y coordinate of the segment + * @param x2 the second x coordinate of the segment + * @param y2 the second y coordinate of the segment + * @param px the x coordinate of the point + * @param py the y coordinate of the point + * @return the square of the distance from the point to the segment + * @see #ptSegDist(double, double, double, double, double, double) + * @see #ptLineDistSq(double, double, double, double, double, double) + */ + public static double ptSegDistSq(double x1, double y1, double x2, double y2, + double px, double py) + { + double pd2 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); + + double x, y; + if (pd2 == 0) + { + // Points are coincident. + x = x1; + y = y2; + } + else + { + double u = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / pd2; + + if (u < 0) + { + // "Off the end" + x = x1; + y = y1; + } + else if (u > 1.0) + { + x = x2; + y = y2; + } + else + { + x = x1 + u * (x2 - x1); + y = y1 + u * (y2 - y1); + } + } + + return (x - px) * (x - px) + (y - py) * (y - py); + } + + /** + * Measures the shortest distance from the reference point to a point on + * the line segment. If the point is on the segment, the result will be 0. + * + * @param x1 the first x coordinate of the segment + * @param y1 the first y coordinate of the segment + * @param x2 the second x coordinate of the segment + * @param y2 the second y coordinate of the segment + * @param px the x coordinate of the point + * @param py the y coordinate of the point + * @return the distance from the point to the segment + * @see #ptSegDistSq(double, double, double, double, double, double) + * @see #ptLineDist(double, double, double, double, double, double) + */ + public static double ptSegDist(double x1, double y1, double x2, double y2, + double px, double py) + { + return Math.sqrt(ptSegDistSq(x1, y1, x2, y2, px, py)); + } + + /** + * Measures the square of the shortest distance from the reference point + * to a point on this line segment. If the point is on the segment, the + * result will be 0. + * + * @param px the x coordinate of the point + * @param py the y coordinate of the point + * @return the square of the distance from the point to the segment + * @see #ptSegDistSq(double, double, double, double, double, double) + */ + public double ptSegDistSq(double px, double py) + { + return ptSegDistSq(getX1(), getY1(), getX2(), getY2(), px, py); + } + + /** + * Measures the square of the shortest distance from the reference point + * to a point on this line segment. If the point is on the segment, the + * result will be 0. + * + * @param p the point + * @return the square of the distance from the point to the segment + * @throws NullPointerException if p is null + * @see #ptSegDistSq(double, double, double, double, double, double) + */ + public double ptSegDistSq(Point2D p) + { + return ptSegDistSq(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); + } + + /** + * Measures the shortest distance from the reference point to a point on + * this line segment. If the point is on the segment, the result will be 0. + * + * @param px the x coordinate of the point + * @param py the y coordinate of the point + * @return the distance from the point to the segment + * @see #ptSegDist(double, double, double, double, double, double) + */ + public double ptSegDist(double px, double py) + { + return ptSegDist(getX1(), getY1(), getX2(), getY2(), px, py); + } + + /** + * Measures the shortest distance from the reference point to a point on + * this line segment. If the point is on the segment, the result will be 0. + * + * @param p the point + * @return the distance from the point to the segment + * @throws NullPointerException if p is null + * @see #ptSegDist(double, double, double, double, double, double) + */ + public double ptSegDist(Point2D p) + { + return ptSegDist(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); + } + + /** + * Measures the square of the shortest distance from the reference point + * to a point on the infinite line extended from the segment. If the point + * is on the segment, the result will be 0. If the segment is length 0, + * the distance is to the common endpoint. + * + * @param x1 the first x coordinate of the segment + * @param y1 the first y coordinate of the segment + * @param x2 the second x coordinate of the segment + * @param y2 the second y coordinate of the segment + * @param px the x coordinate of the point + * @param py the y coordinate of the point + * @return the square of the distance from the point to the extended line + * @see #ptLineDist(double, double, double, double, double, double) + * @see #ptSegDistSq(double, double, double, double, double, double) + */ + public static double ptLineDistSq(double x1, double y1, double x2, double y2, + double px, double py) + { + double pd2 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); + + double x, y; + if (pd2 == 0) + { + // Points are coincident. + x = x1; + y = y2; + } + else + { + double u = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / pd2; + x = x1 + u * (x2 - x1); + y = y1 + u * (y2 - y1); + } + + return (x - px) * (x - px) + (y - py) * (y - py); + } + + /** + * Measures the shortest distance from the reference point to a point on + * the infinite line extended from the segment. If the point is on the + * segment, the result will be 0. If the segment is length 0, the distance + * is to the common endpoint. + * + * @param x1 the first x coordinate of the segment + * @param y1 the first y coordinate of the segment + * @param x2 the second x coordinate of the segment + * @param y2 the second y coordinate of the segment + * @param px the x coordinate of the point + * @param py the y coordinate of the point + * @return the distance from the point to the extended line + * @see #ptLineDistSq(double, double, double, double, double, double) + * @see #ptSegDist(double, double, double, double, double, double) + */ + public static double ptLineDist(double x1, double y1, + double x2, double y2, + double px, double py) + { + return Math.sqrt(ptLineDistSq(x1, y1, x2, y2, px, py)); + } + + /** + * Measures the square of the shortest distance from the reference point + * to a point on the infinite line extended from this segment. If the point + * is on the segment, the result will be 0. If the segment is length 0, + * the distance is to the common endpoint. + * + * @param px the x coordinate of the point + * @param py the y coordinate of the point + * @return the square of the distance from the point to the extended line + * @see #ptLineDistSq(double, double, double, double, double, double) + */ + public double ptLineDistSq(double px, double py) + { + return ptLineDistSq(getX1(), getY1(), getX2(), getY2(), px, py); + } + + /** + * Measures the square of the shortest distance from the reference point + * to a point on the infinite line extended from this segment. If the point + * is on the segment, the result will be 0. If the segment is length 0, + * the distance is to the common endpoint. + * + * @param p the point + * @return the square of the distance from the point to the extended line + * @throws NullPointerException if p is null + * @see #ptLineDistSq(double, double, double, double, double, double) + */ + public double ptLineDistSq(Point2D p) + { + return ptLineDistSq(getX1(), getY1(), getX2(), getY2(), + p.getX(), p.getY()); + } + + /** + * Measures the shortest distance from the reference point to a point on + * the infinite line extended from this segment. If the point is on the + * segment, the result will be 0. If the segment is length 0, the distance + * is to the common endpoint. + * + * @param px the x coordinate of the point + * @param py the y coordinate of the point + * @return the distance from the point to the extended line + * @see #ptLineDist(double, double, double, double, double, double) + */ + public double ptLineDist(double px, double py) + { + return ptLineDist(getX1(), getY1(), getX2(), getY2(), px, py); + } + + /** + * Measures the shortest distance from the reference point to a point on + * the infinite line extended from this segment. If the point is on the + * segment, the result will be 0. If the segment is length 0, the distance + * is to the common endpoint. + * + * @param p the point + * @return the distance from the point to the extended line + * @throws NullPointerException if p is null + * @see #ptLineDist(double, double, double, double, double, double) + */ + public double ptLineDist(Point2D p) + { + return ptLineDist(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); + } + + /** + * Test if a point is contained inside the line. Since a line has no area, + * this returns false. + * + * @param x the x coordinate + * @param y the y coordinate + * @return false; the line does not contain points + */ + public boolean contains(double x, double y) + { + return false; + } + + /** + * Test if a point is contained inside the line. Since a line has no area, + * this returns false. + * + * @param p the point + * @return false; the line does not contain points + */ + public boolean contains(Point2D p) + { + return false; + } + + /** + * Tests if this line intersects the interior of the specified rectangle. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @return true if the line intersects the rectangle + */ + public boolean intersects(double x, double y, double w, double h) + { + if (w <= 0 || h <= 0) + return false; + double x1 = getX1(); + double y1 = getY1(); + double x2 = getX2(); + double y2 = getY2(); + + if (x1 >= x && x1 <= x + w && y1 >= y && y1 <= y + h) + return true; + if (x2 >= x && x2 <= x + w && y2 >= y && y2 <= y + h) + return true; + + double x3 = x + w; + double y3 = y + h; + + return (linesIntersect(x1, y1, x2, y2, x, y, x, y3) + || linesIntersect(x1, y1, x2, y2, x, y3, x3, y3) + || linesIntersect(x1, y1, x2, y2, x3, y3, x3, y) + || linesIntersect(x1, y1, x2, y2, x3, y, x, y)); + } + + /** + * Tests if this line intersects the interior of the specified rectangle. + * + * @param r the rectangle + * @return true if the line intersects the rectangle + * @throws NullPointerException if r is null + */ + public boolean intersects(Rectangle2D r) + { + return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Tests if the line contains a rectangle. Since lines have no area, this + * always returns false. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @return false; the line does not contain points + */ + public boolean contains(double x, double y, double w, double h) + { + return false; + } + + /** + * Tests if the line contains a rectangle. Since lines have no area, this + * always returns false. + * + * @param r the rectangle + * @return false; the line does not contain points + */ + public boolean contains(Rectangle2D r) + { + return false; + } + + /** + * Gets a bounding box (not necessarily minimal) for this line. + * + * @return the integer bounding box + * @see #getBounds2D() + */ + public Rectangle getBounds() + { + return getBounds2D().getBounds(); + } + + /** + * Return a path iterator, possibly applying a transform on the result. This + * iterator is not threadsafe. + * + * @param at the transform, or null + * @return a new path iterator + */ + public PathIterator getPathIterator(final AffineTransform at) + { + return new PathIterator() + { + /** Current coordinate. */ + private int current = 0; + + public int getWindingRule() + { + return WIND_NON_ZERO; + } + + public boolean isDone() + { + return current >= 2; + } + + public void next() + { + current++; + } + + public int currentSegment(float[] coords) + { + int result; + switch (current) + { + case 0: + coords[0] = (float) getX1(); + coords[1] = (float) getY1(); + result = SEG_MOVETO; + break; + case 1: + coords[0] = (float) getX2(); + coords[1] = (float) getY2(); + result = SEG_LINETO; + break; + default: + throw new NoSuchElementException("line iterator out of bounds"); + } + if (at != null) + at.transform(coords, 0, coords, 0, 1); + return result; + } + + public int currentSegment(double[] coords) + { + int result; + switch (current) + { + case 0: + coords[0] = getX1(); + coords[1] = getY1(); + result = SEG_MOVETO; + break; + case 1: + coords[0] = getX2(); + coords[1] = getY2(); + result = SEG_LINETO; + break; + default: + throw new NoSuchElementException("line iterator out of bounds"); + } + if (at != null) + at.transform(coords, 0, coords, 0, 1); + return result; + } + }; + } + + /** + * Return a flat path iterator, possibly applying a transform on the result. + * This iterator is not threadsafe. + * + * @param at the transform, or null + * @param flatness ignored, since lines are already flat + * @return a new path iterator + * @see #getPathIterator(AffineTransform) + */ + public PathIterator getPathIterator(AffineTransform at, double flatness) + { + return getPathIterator(at); + } + + /** + * Create a new line of the same run-time type with the same contents as + * this one. + * + * @return the clone + * + * @exception OutOfMemoryError If there is not enough memory available. + * + * @since 1.2 + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } + + /** + * This class defines a point in <code>double</code> precision. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ + public static class Double extends Line2D + { + /** The x coordinate of the first point. */ + public double x1; + + /** The y coordinate of the first point. */ + public double y1; + + /** The x coordinate of the second point. */ + public double x2; + + /** The y coordinate of the second point. */ + public double y2; + + /** + * Construct the line segment (0,0)->(0,0). + */ + public Double() + { + } + + /** + * Construct the line segment with the specified points. + * + * @param x1 the x coordinate of the first point + * @param y1 the y coordinate of the first point + * @param x2 the x coordinate of the second point + * @param y2 the y coordinate of the second point + */ + public Double(double x1, double y1, double x2, double y2) + { + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Construct the line segment with the specified points. + * + * @param p1 the first point + * @param p2 the second point + * @throws NullPointerException if either point is null + */ + public Double(Point2D p1, Point2D p2) + { + x1 = p1.getX(); + y1 = p1.getY(); + x2 = p2.getX(); + y2 = p2.getY(); + } + + /** + * Return the x coordinate of the first point. + * + * @return the value of x1 + */ + public double getX1() + { + return x1; + } + + /** + * Return the y coordinate of the first point. + * + * @return the value of y1 + */ + public double getY1() + { + return y1; + } + + /** + * Return the first point. + * + * @return the point (x1,y1) + */ + public Point2D getP1() + { + return new Point2D.Double(x1, y1); + } + + /** + * Return the x coordinate of the second point. + * + * @return the value of x2 + */ + public double getX2() + { + return x2; + } + + /** + * Return the y coordinate of the second point. + * + * @return the value of y2 + */ + public double getY2() + { + return y2; + } + + /** + * Return the second point. + * + * @return the point (x2,y2) + */ + public Point2D getP2() + { + return new Point2D.Double(x2, y2); + } + + /** + * Set this line to the given points. + * + * @param x1 the new x coordinate of the first point + * @param y1 the new y coordinate of the first point + * @param x2 the new x coordinate of the second point + * @param y2 the new y coordinate of the second point + */ + public void setLine(double x1, double y1, double x2, double y2) + { + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Return the exact bounds of this line segment. + * + * @return the bounding box + */ + public Rectangle2D getBounds2D() + { + double x = Math.min(x1, x2); + double y = Math.min(y1, y2); + double w = Math.abs(x1 - x2); + double h = Math.abs(y1 - y2); + return new Rectangle2D.Double(x, y, w, h); + } + } // class Double + + /** + * This class defines a point in <code>float</code> precision. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ + public static class Float extends Line2D + { + /** The x coordinate of the first point. */ + public float x1; + + /** The y coordinate of the first point. */ + public float y1; + + /** The x coordinate of the second point. */ + public float x2; + + /** The y coordinate of the second point. */ + public float y2; + + /** + * Construct the line segment (0,0)->(0,0). + */ + public Float() + { + } + + /** + * Construct the line segment with the specified points. + * + * @param x1 the x coordinate of the first point + * @param y1 the y coordinate of the first point + * @param x2 the x coordinate of the second point + * @param y2 the y coordinate of the second point + */ + public Float(float x1, float y1, float x2, float y2) + { + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Construct the line segment with the specified points. + * + * @param p1 the first point + * @param p2 the second point + * @throws NullPointerException if either point is null + */ + public Float(Point2D p1, Point2D p2) + { + x1 = (float) p1.getX(); + y1 = (float) p1.getY(); + x2 = (float) p2.getX(); + y2 = (float) p2.getY(); + } + + /** + * Return the x coordinate of the first point. + * + * @return the value of x1 + */ + public double getX1() + { + return x1; + } + + /** + * Return the y coordinate of the first point. + * + * @return the value of y1 + */ + public double getY1() + { + return y1; + } + + /** + * Return the first point. + * + * @return the point (x1,y1) + */ + public Point2D getP1() + { + return new Point2D.Float(x1, y1); + } + + /** + * Return the x coordinate of the second point. + * + * @return the value of x2 + */ + public double getX2() + { + return x2; + } + + /** + * Return the y coordinate of the second point. + * + * @return the value of y2 + */ + public double getY2() + { + return y2; + } + + /** + * Return the second point. + * + * @return the point (x2,y2) + */ + public Point2D getP2() + { + return new Point2D.Float(x2, y2); + } + + /** + * Set this line to the given points. + * + * @param x1 the new x coordinate of the first point + * @param y1 the new y coordinate of the first point + * @param x2 the new x coordinate of the second point + * @param y2 the new y coordinate of the second point + */ + public void setLine(double x1, double y1, double x2, double y2) + { + this.x1 = (float) x1; + this.y1 = (float) y1; + this.x2 = (float) x2; + this.y2 = (float) y2; + } + + /** + * Set this line to the given points. + * + * @param x1 the new x coordinate of the first point + * @param y1 the new y coordinate of the first point + * @param x2 the new x coordinate of the second point + * @param y2 the new y coordinate of the second point + */ + public void setLine(float x1, float y1, float x2, float y2) + { + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Return the exact bounds of this line segment. + * + * @return the bounding box + */ + public Rectangle2D getBounds2D() + { + float x = Math.min(x1, x2); + float y = Math.min(y1, y2); + float w = Math.abs(x1 - x2); + float h = Math.abs(y1 - y2); + return new Rectangle2D.Float(x, y, w, h); + } + } // class Float +} // class Line2D diff --git a/libjava/classpath/java/awt/geom/NoninvertibleTransformException.java b/libjava/classpath/java/awt/geom/NoninvertibleTransformException.java new file mode 100644 index 000000000..7995a52eb --- /dev/null +++ b/libjava/classpath/java/awt/geom/NoninvertibleTransformException.java @@ -0,0 +1,65 @@ +/* NoninvertibleTransformException.java -- a transform can't be inverted + Copyright (C) 2000, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.geom; + +/** + * Thrown if an operation requires an inverse of an + * <code>AffineTransform</code>, but the transform is in a non-invertible + * state. + * + * @author Tom Tromey (tromey@cygnus.com) + * @see AffineTransform + * @status updated to 1.4 + */ +public class NoninvertibleTransformException extends Exception +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 6137225240503990466L; + + /** + * Create an exception with a message. + * + * @param s the message + */ + public NoninvertibleTransformException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/java/awt/geom/PathIterator.java b/libjava/classpath/java/awt/geom/PathIterator.java new file mode 100644 index 000000000..2cd08b9b4 --- /dev/null +++ b/libjava/classpath/java/awt/geom/PathIterator.java @@ -0,0 +1,189 @@ +/* PathIterator.java -- describes a shape by iterating over its vertices + Copyright (C) 2000, 2002, 2003 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.geom; + +/** + * This interface provides a directed path over the boundary of a shape. The + * path can contain 1st through 3rd order Bezier curves (lines, and quadratic + * and cubic splines). A shape can have multiple disjoint paths via the + * MOVETO directive, and can close a circular path back to the previos + * MOVETO via the CLOSE directive. + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see java.awt.Shape + * @see java.awt.Stroke + * @see FlatteningPathIterator + * @since 1.2 + * @status updated to 1.4 + */ +public interface PathIterator +{ + /** + * The even-odd winding mode: a point is internal to the shape if a ray + * from the point to infinity (in any direction) crosses an odd number of + * segments. + */ + int WIND_EVEN_ODD = 0; + + /** + * The non-zero winding mode: a point is internal to the shape if a ray + * from the point to infinity (in any direction) crosses a different number + * of segments headed clockwise than those headed counterclockwise. + */ + int WIND_NON_ZERO = 1; + + /** + * Starts a new subpath. There is no segment from the previous vertex. + */ + int SEG_MOVETO = 0; + + /** + * The current segment is a line. + */ + int SEG_LINETO = 1; + + /** + * The current segment is a quadratic parametric curve. It is interpolated + * as t varies from 0 to 1 over the current point (CP), first control point + * (P1), and final interpolated control point (P2): + * <pre> + * P(t) = B(2,0)*CP + B(2,1)*P1 + B(2,2)*P2 + * 0 <= t <= 1 + * B(n,m) = mth coefficient of nth degree Bernstein polynomial + * = C(n,m) * t^(m) * (1 - t)^(n-m) + * C(n,m) = Combinations of n things, taken m at a time + * = n! / (m! * (n-m)!) + * </pre> + */ + int SEG_QUADTO = 2; + + /** + * The current segment is a cubic parametric curve (more commonly known as + * a Bezier curve). It is interpolated as t varies from 0 to 1 over the + * current point (CP), first control point (P1), the second control point + * (P2), and final interpolated control point (P3): + * <pre> + * P(t) = B(3,0)*CP + B(3,1)*P1 + B(3,2)*P2 + B(3,3)*P3 + * 0 <= t <= 1 + * B(n,m) = mth coefficient of nth degree Bernstein polynomial + * = C(n,m) * t^(m) * (1 - t)^(n-m) + * C(n,m) = Combinations of n things, taken m at a time + * = n! / (m! * (n-m)!) + * </pre> + */ + int SEG_CUBICTO = 3; + + /** + * The current segment closes a loop by an implicit line to the previous + * SEG_MOVETO coordinate. + */ + int SEG_CLOSE = 4; + + /** + * Returns the winding rule to determine which points are inside this path. + * + * @return the winding rule + * @see #WIND_EVEN_ODD + * @see #WIND_NON_ZERO + */ + int getWindingRule(); + + /** + * Tests if the iterator is exhausted. If this returns true, currentSegment + * and next may throw a NoSuchElementException (although this is not + * required). + * + * @return true if the iteration is complete + */ + boolean isDone(); + + /** + * Advance to the next segment in the iteration. It is not specified what + * this does if called when isDone() returns true. + * + * @throws java.util.NoSuchElementException optional when isDone() is true + */ + void next(); + + /** + * Returns the coordinates of the next point(s), as well as the type of + * line segment. The input array must be at least a float[6], to accomodate + * up to three (x,y) point pairs (although if you know the iterator is + * flat, you can probably get by with a float[2]). If the returned type is + * SEG_MOVETO or SEG_LINETO, the first point in the array is modified; if + * the returned type is SEG_QUADTO, the first two points are modified; if + * the returned type is SEG_CUBICTO, all three points are modified; and if + * the returned type is SEG_CLOSE, the array is untouched. + * + * @param coords the array to place the point coordinates in + * @return the segment type + * @throws NullPointerException if coords is null + * @throws ArrayIndexOutOfBoundsException if coords is too small + * @throws java.util.NoSuchElementException optional when isDone() is true + * @see #SEG_MOVETO + * @see #SEG_LINETO + * @see #SEG_QUADTO + * @see #SEG_CUBICTO + * @see #SEG_CLOSE + */ + int currentSegment(float[] coords); + + /** + * Returns the coordinates of the next point(s), as well as the type of + * line segment. The input array must be at least a double[6], to accomodate + * up to three (x,y) point pairs (although if you know the iterator is + * flat, you can probably get by with a double[2]). If the returned type is + * SEG_MOVETO or SEG_LINETO, the first point in the array is modified; if + * the returned type is SEG_QUADTO, the first two points are modified; if + * the returned type is SEG_CUBICTO, all three points are modified; and if + * the returned type is SEG_CLOSE, the array is untouched. + * + * @param coords the array to place the point coordinates in + * @return the segment type + * @throws NullPointerException if coords is null + * @throws ArrayIndexOutOfBoundsException if coords is too small + * @throws java.util.NoSuchElementException optional when isDone() is true + * @see #SEG_MOVETO + * @see #SEG_LINETO + * @see #SEG_QUADTO + * @see #SEG_CUBICTO + * @see #SEG_CLOSE + */ + int currentSegment(double[] coords); +} // interface PathIterator diff --git a/libjava/classpath/java/awt/geom/Point2D.java b/libjava/classpath/java/awt/geom/Point2D.java new file mode 100644 index 000000000..a2689abf8 --- /dev/null +++ b/libjava/classpath/java/awt/geom/Point2D.java @@ -0,0 +1,396 @@ +/* Point2D.java -- generic point in 2-D space + Copyright (C) 1999, 2000, 2002, 2004, 2006, Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.geom; + +/** + * This class implements a generic point in 2D Cartesian space. The storage + * representation is left up to the subclass. Point includes two useful + * nested classes, for float and double storage respectively. + * + * @author Per Bothner (bothner@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ +public abstract class Point2D implements Cloneable +{ + /** + * The default constructor. + * + * @see java.awt.Point + * @see Point2D.Float + * @see Point2D.Double + */ + protected Point2D() + { + } + + /** + * Get the X coordinate, in double precision. + * + * @return the x coordinate + */ + public abstract double getX(); + + /** + * Get the Y coordinate, in double precision. + * + * @return the y coordinate + */ + public abstract double getY(); + + /** + * Set the location of this point to the new coordinates. There may be a + * loss of precision. + * + * @param x the new x coordinate + * @param y the new y coordinate + */ + public abstract void setLocation(double x, double y); + + /** + * Set the location of this point to the new coordinates. There may be a + * loss of precision. + * + * @param p the point to copy + * @throws NullPointerException if p is null + */ + public void setLocation(Point2D p) + { + setLocation(p.getX(), p.getY()); + } + + /** + * Return the square of the distance between two points. + * + * @param x1 the x coordinate of point 1 + * @param y1 the y coordinate of point 1 + * @param x2 the x coordinate of point 2 + * @param y2 the y coordinate of point 2 + * @return (x2 - x1)^2 + (y2 - y1)^2 + */ + public static double distanceSq(double x1, double y1, double x2, double y2) + { + x2 -= x1; + y2 -= y1; + return x2 * x2 + y2 * y2; + } + + /** + * Return the distance between two points. + * + * @param x1 the x coordinate of point 1 + * @param y1 the y coordinate of point 1 + * @param x2 the x coordinate of point 2 + * @param y2 the y coordinate of point 2 + * @return the distance from (x1,y1) to (x2,y2) + */ + public static double distance(double x1, double y1, double x2, double y2) + { + return Math.sqrt(distanceSq(x1, y1, x2, y2)); + } + + /** + * Return the square of the distance from this point to the given one. + * + * @param x the x coordinate of the other point + * @param y the y coordinate of the other point + * @return the square of the distance + */ + public double distanceSq(double x, double y) + { + return distanceSq(getX(), getY(), x, y); + } + + /** + * Return the square of the distance from this point to the given one. + * + * @param p the other point + * @return the square of the distance + * @throws NullPointerException if p is null + */ + public double distanceSq(Point2D p) + { + return distanceSq(getX(), getY(), p.getX(), p.getY()); + } + + /** + * Return the distance from this point to the given one. + * + * @param x the x coordinate of the other point + * @param y the y coordinate of the other point + * @return the distance + */ + public double distance(double x, double y) + { + return distance(getX(), getY(), x, y); + } + + /** + * Return the distance from this point to the given one. + * + * @param p the other point + * @return the distance + * @throws NullPointerException if p is null + */ + public double distance(Point2D p) + { + return distance(getX(), getY(), p.getX(), p.getY()); + } + + /** + * Create a new point of the same run-time type with the same contents as + * this one. + * + * @return the clone + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } + + /** + * Return the hashcode for this point. The formula is not documented, but + * appears to be the same as: + * <pre> + * long l = Double.doubleToLongBits(getY()); + * l = l * 31 ^ Double.doubleToLongBits(getX()); + * return (int) ((l >> 32) ^ l); + * </pre> + * + * @return the hashcode + */ + public int hashCode() + { + // Talk about a fun time reverse engineering this one! + long l = java.lang.Double.doubleToLongBits(getY()); + l = l * 31 ^ java.lang.Double.doubleToLongBits(getX()); + return (int) ((l >> 32) ^ l); + } + + /** + * Compares two points for equality. This returns true if they have the + * same coordinates. + * + * @param o the point to compare + * @return true if it is equal + */ + public boolean equals(Object o) + { + if (! (o instanceof Point2D)) + return false; + Point2D p = (Point2D) o; + return getX() == p.getX() && getY() == p.getY(); + } + + /** + * This class defines a point in <code>double</code> precision. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ + public static class Double extends Point2D + { + /** The X coordinate. */ + public double x; + + /** The Y coordinate. */ + public double y; + + /** + * Create a new point at (0,0). + */ + public Double() + { + } + + /** + * Create a new point at (x,y). + * + * @param x the x coordinate + * @param y the y coordinate + */ + public Double(double x, double y) + { + this.x = x; + this.y = y; + } + + /** + * Return the x coordinate. + * + * @return the x coordinate + */ + public double getX() + { + return x; + } + + /** + * Return the y coordinate. + * + * @return the y coordinate + */ + public double getY() + { + return y; + } + + /** + * Sets the location of this point. + * + * @param x the new x coordinate + * @param y the new y coordinate + */ + public void setLocation(double x, double y) + { + this.x = x; + this.y = y; + } + + /** + * Returns a string representation of this object. The format is: + * <code>"Point2D.Double[" + x + ", " + y + ']'</code>. + * + * @return a string representation of this object + */ + public String toString() + { + return "Point2D.Double[" + x + ", " + y + ']'; + } + } // class Double + + /** + * This class defines a point in <code>float</code> precision. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ + public static class Float extends Point2D + { + /** The X coordinate. */ + public float x; + + /** The Y coordinate. */ + public float y; + + /** + * Create a new point at (0,0). + */ + public Float() + { + } + + /** + * Create a new point at (x,y). + * + * @param x the x coordinate + * @param y the y coordinate + */ + public Float(float x, float y) + { + this.x = x; + this.y = y; + } + + /** + * Return the x coordinate. + * + * @return the x coordinate + */ + public double getX() + { + return x; + } + + /** + * Return the y coordinate. + * + * @return the y coordinate + */ + public double getY() + { + return y; + } + + /** + * Sets the location of this point. + * + * @param x the new x coordinate + * @param y the new y coordinate + */ + public void setLocation(double x, double y) + { + this.x = (float) x; + this.y = (float) y; + } + + /** + * Sets the location of this point. + * + * @param x the new x coordinate + * @param y the new y coordinate + */ + public void setLocation(float x, float y) + { + this.x = x; + this.y = y; + } + + /** + * Returns a string representation of this object. The format is: + * <code>"Point2D.Float[" + x + ", " + y + ']'</code>. + * + * @return a string representation of this object + */ + public String toString() + { + return "Point2D.Float[" + x + ", " + y + ']'; + } + } // class Float +} // class Point2D diff --git a/libjava/classpath/java/awt/geom/QuadCurve2D.java b/libjava/classpath/java/awt/geom/QuadCurve2D.java new file mode 100644 index 000000000..62c829d30 --- /dev/null +++ b/libjava/classpath/java/awt/geom/QuadCurve2D.java @@ -0,0 +1,1467 @@ +/* QuadCurve2D.java -- represents a parameterized quadratic curve in 2-D space + Copyright (C) 2002, 2003, 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.geom; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.util.NoSuchElementException; + +/** + * A two-dimensional curve that is parameterized with a quadratic + * function. + * + * <p><img src="doc-files/QuadCurve2D-1.png" width="350" height="180" + * alt="A drawing of a QuadCurve2D" /> + * + * @author Eric Blake (ebb9@email.byu.edu) + * @author Graydon Hoare (graydon@redhat.com) + * @author Sascha Brawer (brawer@dandelis.ch) + * @author Sven de Marothy (sven@physto.se) + * + * @since 1.2 + */ +public abstract class QuadCurve2D implements Shape, Cloneable +{ + private static final double BIG_VALUE = java.lang.Double.MAX_VALUE / 10.0; + private static final double EPSILON = 1E-10; + + /** + * Constructs a new QuadCurve2D. Typical users will want to + * construct instances of a subclass, such as {@link + * QuadCurve2D.Float} or {@link QuadCurve2D.Double}. + */ + protected QuadCurve2D() + { + } + + /** + * Returns the <i>x</i> coordinate of the curve’s start + * point. + */ + public abstract double getX1(); + + /** + * Returns the <i>y</i> coordinate of the curve’s start + * point. + */ + public abstract double getY1(); + + /** + * Returns the curve’s start point. + */ + public abstract Point2D getP1(); + + /** + * Returns the <i>x</i> coordinate of the curve’s control + * point. + */ + public abstract double getCtrlX(); + + /** + * Returns the <i>y</i> coordinate of the curve’s control + * point. + */ + public abstract double getCtrlY(); + + /** + * Returns the curve’s control point. + */ + public abstract Point2D getCtrlPt(); + + /** + * Returns the <i>x</i> coordinate of the curve’s end + * point. + */ + public abstract double getX2(); + + /** + * Returns the <i>y</i> coordinate of the curve’s end + * point. + */ + public abstract double getY2(); + + /** + * Returns the curve’s end point. + */ + public abstract Point2D getP2(); + + /** + * Changes the curve geometry, separately specifying each coordinate + * value. + * + * @param x1 the <i>x</i> coordinate of the curve’s new start + * point. + * + * @param y1 the <i>y</i> coordinate of the curve’s new start + * point. + * + * @param cx the <i>x</i> coordinate of the curve’s new + * control point. + * + * @param cy the <i>y</i> coordinate of the curve’s new + * control point. + * + * @param x2 the <i>x</i> coordinate of the curve’s new end + * point. + * + * @param y2 the <i>y</i> coordinate of the curve’s new end + * point. + */ + public abstract void setCurve(double x1, double y1, double cx, double cy, + double x2, double y2); + + /** + * Changes the curve geometry, passing coordinate values in an + * array. + * + * @param coords an array containing the new coordinate values. The + * <i>x</i> coordinate of the new start point is located at + * <code>coords[offset]</code>, its <i>y</i> coordinate at + * <code>coords[offset + 1]</code>. The <i>x</i> coordinate of the + * new control point is located at <code>coords[offset + 2]</code>, + * its <i>y</i> coordinate at <code>coords[offset + 3]</code>. The + * <i>x</i> coordinate of the new end point is located at + * <code>coords[offset + 4]</code>, its <i>y</i> coordinate at + * <code>coords[offset + 5]</code>. + * + * @param offset the offset of the first coordinate value in + * <code>coords</code>. + */ + public void setCurve(double[] coords, int offset) + { + setCurve(coords[offset++], coords[offset++], coords[offset++], + coords[offset++], coords[offset++], coords[offset++]); + } + + /** + * Changes the curve geometry, specifying coordinate values in + * separate Point objects. + * + * <p><img src="doc-files/QuadCurve2D-1.png" width="350" height="180" + * alt="A drawing of a QuadCurve2D" /> + * + * <p>The curve does not keep any reference to the passed point + * objects. Therefore, a later change to <code>p1</code>, + * <code>c</code> <code>p2</code> will not affect the curve + * geometry. + * + * @param p1 the new start point. + * @param c the new control point. + * @param p2 the new end point. + */ + public void setCurve(Point2D p1, Point2D c, Point2D p2) + { + setCurve(p1.getX(), p1.getY(), c.getX(), c.getY(), p2.getX(), p2.getY()); + } + + /** + * Changes the curve geometry, specifying coordinate values in an + * array of Point objects. + * + * <p><img src="doc-files/QuadCurve2D-1.png" width="350" height="180" + * alt="A drawing of a QuadCurve2D" /> + * + * <p>The curve does not keep references to the passed point + * objects. Therefore, a later change to the <code>pts</code> array + * or any of its elements will not affect the curve geometry. + * + * @param pts an array containing the points. The new start point + * is located at <code>pts[offset]</code>, the new control + * point at <code>pts[offset + 1]</code>, and the new end point + * at <code>pts[offset + 2]</code>. + * + * @param offset the offset of the start point in <code>pts</code>. + */ + public void setCurve(Point2D[] pts, int offset) + { + setCurve(pts[offset].getX(), pts[offset].getY(), pts[offset + 1].getX(), + pts[offset + 1].getY(), pts[offset + 2].getX(), + pts[offset + 2].getY()); + } + + /** + * Changes the geometry of the curve to that of another curve. + * + * @param c the curve whose coordinates will be copied. + */ + public void setCurve(QuadCurve2D c) + { + setCurve(c.getX1(), c.getY1(), c.getCtrlX(), c.getCtrlY(), c.getX2(), + c.getY2()); + } + + /** + * Calculates the squared flatness of a quadratic curve, directly + * specifying each coordinate value. The flatness is the distance of + * the control point to the line between start and end point. + * + * <p><img src="doc-files/QuadCurve2D-4.png" width="350" height="180" + * alt="A drawing that illustrates the flatness" /> + * + * <p>In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. The result will be the + * the square of the distance between C and the gray line, i.e. + * the squared length of the red line. + * + * @param x1 the <i>x</i> coordinate of the start point P1. + * @param y1 the <i>y</i> coordinate of the start point P1. + * @param cx the <i>x</i> coordinate of the control point C. + * @param cy the <i>y</i> coordinate of the control point C. + * @param x2 the <i>x</i> coordinate of the end point P2. + * @param y2 the <i>y</i> coordinate of the end point P2. + */ + public static double getFlatnessSq(double x1, double y1, double cx, + double cy, double x2, double y2) + { + return Line2D.ptSegDistSq(x1, y1, x2, y2, cx, cy); + } + + /** + * Calculates the flatness of a quadratic curve, directly specifying + * each coordinate value. The flatness is the distance of the + * control point to the line between start and end point. + * + * <p><img src="doc-files/QuadCurve2D-4.png" width="350" height="180" + * alt="A drawing that illustrates the flatness" /> + * + * <p>In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. The result will be the + * the distance between C and the gray line, i.e. the length of + * the red line. + * + * @param x1 the <i>x</i> coordinate of the start point P1. + * @param y1 the <i>y</i> coordinate of the start point P1. + * @param cx the <i>x</i> coordinate of the control point C. + * @param cy the <i>y</i> coordinate of the control point C. + * @param x2 the <i>x</i> coordinate of the end point P2. + * @param y2 the <i>y</i> coordinate of the end point P2. + */ + public static double getFlatness(double x1, double y1, double cx, double cy, + double x2, double y2) + { + return Line2D.ptSegDist(x1, y1, x2, y2, cx, cy); + } + + /** + * Calculates the squared flatness of a quadratic curve, specifying + * the coordinate values in an array. The flatness is the distance + * of the control point to the line between start and end point. + * + * <p><img src="doc-files/QuadCurve2D-4.png" width="350" height="180" + * alt="A drawing that illustrates the flatness" /> + * + * <p>In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. The result will be the + * the square of the distance between C and the gray line, i.e. + * the squared length of the red line. + * + * @param coords an array containing the coordinate values. The + * <i>x</i> coordinate of the start point P1 is located at + * <code>coords[offset]</code>, its <i>y</i> coordinate at + * <code>coords[offset + 1]</code>. The <i>x</i> coordinate of the + * control point C is located at <code>coords[offset + 2]</code>, + * its <i>y</i> coordinate at <code>coords[offset + 3]</code>. The + * <i>x</i> coordinate of the end point P2 is located at + * <code>coords[offset + 4]</code>, its <i>y</i> coordinate at + * <code>coords[offset + 5]</code>. + * + * @param offset the offset of the first coordinate value in + * <code>coords</code>. + */ + public static double getFlatnessSq(double[] coords, int offset) + { + return Line2D.ptSegDistSq(coords[offset], coords[offset + 1], + coords[offset + 4], coords[offset + 5], + coords[offset + 2], coords[offset + 3]); + } + + /** + * Calculates the flatness of a quadratic curve, specifying the + * coordinate values in an array. The flatness is the distance of + * the control point to the line between start and end point. + * + * <p><img src="doc-files/QuadCurve2D-4.png" width="350" height="180" + * alt="A drawing that illustrates the flatness" /> + * + * <p>In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. The result will be the + * the the distance between C and the gray line, i.e. the length of + * the red line. + * + * @param coords an array containing the coordinate values. The + * <i>x</i> coordinate of the start point P1 is located at + * <code>coords[offset]</code>, its <i>y</i> coordinate at + * <code>coords[offset + 1]</code>. The <i>x</i> coordinate of the + * control point C is located at <code>coords[offset + 2]</code>, + * its <i>y</i> coordinate at <code>coords[offset + 3]</code>. The + * <i>x</i> coordinate of the end point P2 is located at + * <code>coords[offset + 4]</code>, its <i>y</i> coordinate at + * <code>coords[offset + 5]</code>. + * + * @param offset the offset of the first coordinate value in + * <code>coords</code>. + */ + public static double getFlatness(double[] coords, int offset) + { + return Line2D.ptSegDist(coords[offset], coords[offset + 1], + coords[offset + 4], coords[offset + 5], + coords[offset + 2], coords[offset + 3]); + } + + /** + * Calculates the squared flatness of this curve. The flatness is + * the distance of the control point to the line between start and + * end point. + * + * <p><img src="doc-files/QuadCurve2D-4.png" width="350" height="180" + * alt="A drawing that illustrates the flatness" /> + * + * <p>In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. The result will be the + * the square of the distance between C and the gray line, i.e. the + * squared length of the red line. + */ + public double getFlatnessSq() + { + return Line2D.ptSegDistSq(getX1(), getY1(), getX2(), getY2(), getCtrlX(), + getCtrlY()); + } + + /** + * Calculates the flatness of this curve. The flatness is the + * distance of the control point to the line between start and end + * point. + * + * <p><img src="doc-files/QuadCurve2D-4.png" width="350" height="180" + * alt="A drawing that illustrates the flatness" /> + * + * <p>In the above drawing, the straight line connecting start point + * P1 and end point P2 is depicted in gray. The result will be the + * the distance between C and the gray line, i.e. the length of the + * red line. + */ + public double getFlatness() + { + return Line2D.ptSegDist(getX1(), getY1(), getX2(), getY2(), getCtrlX(), + getCtrlY()); + } + + /** + * Subdivides this curve into two halves. + * + * <p><img src="doc-files/QuadCurve2D-3.png" width="700" + * height="180" alt="A drawing that illustrates the effects of + * subdividing a QuadCurve2D" /> + * + * @param left a curve whose geometry will be set to the left half + * of this curve, or <code>null</code> if the caller is not + * interested in the left half. + * + * @param right a curve whose geometry will be set to the right half + * of this curve, or <code>null</code> if the caller is not + * interested in the right half. + */ + public void subdivide(QuadCurve2D left, QuadCurve2D right) + { + // Use empty slots at end to share single array. + double[] d = new double[] + { + getX1(), getY1(), getCtrlX(), getCtrlY(), getX2(), getY2(), + 0, 0, 0, 0 + }; + subdivide(d, 0, d, 0, d, 4); + if (left != null) + left.setCurve(d, 0); + if (right != null) + right.setCurve(d, 4); + } + + /** + * Subdivides a quadratic curve into two halves. + * + * <p><img src="doc-files/QuadCurve2D-3.png" width="700" + * height="180" alt="A drawing that illustrates the effects of + * subdividing a QuadCurve2D" /> + * + * @param src the curve to be subdivided. + * + * @param left a curve whose geometry will be set to the left half + * of <code>src</code>, or <code>null</code> if the caller is not + * interested in the left half. + * + * @param right a curve whose geometry will be set to the right half + * of <code>src</code>, or <code>null</code> if the caller is not + * interested in the right half. + */ + public static void subdivide(QuadCurve2D src, QuadCurve2D left, + QuadCurve2D right) + { + src.subdivide(left, right); + } + + /** + * Subdivides a quadratic curve into two halves, passing all + * coordinates in an array. + * + * <p><img src="doc-files/QuadCurve2D-3.png" width="700" + * height="180" alt="A drawing that illustrates the effects of + * subdividing a QuadCurve2D" /> + * + * <p>The left end point and the right start point will always be + * identical. Memory-concious programmers thus may want to pass the + * same array for both <code>left</code> and <code>right</code>, and + * set <code>rightOff</code> to <code>leftOff + 4</code>. + * + * @param src an array containing the coordinates of the curve to be + * subdivided. The <i>x</i> coordinate of the start point is + * located at <code>src[srcOff]</code>, its <i>y</i> at + * <code>src[srcOff + 1]</code>. The <i>x</i> coordinate of the + * control point is located at <code>src[srcOff + 2]</code>, its + * <i>y</i> at <code>src[srcOff + 3]</code>. The <i>x</i> + * coordinate of the end point is located at <code>src[srcOff + + * 4]</code>, its <i>y</i> at <code>src[srcOff + 5]</code>. + * + * @param srcOff an offset into <code>src</code>, specifying + * the index of the start point’s <i>x</i> coordinate. + * + * @param left an array that will receive the coordinates of the + * left half of <code>src</code>. It is acceptable to pass + * <code>src</code>. A caller who is not interested in the left half + * can pass <code>null</code>. + * + * @param leftOff an offset into <code>left</code>, specifying the + * index where the start point’s <i>x</i> coordinate will be + * stored. + * + * @param right an array that will receive the coordinates of the + * right half of <code>src</code>. It is acceptable to pass + * <code>src</code> or <code>left</code>. A caller who is not + * interested in the right half can pass <code>null</code>. + * + * @param rightOff an offset into <code>right</code>, specifying the + * index where the start point’s <i>x</i> coordinate will be + * stored. + */ + public static void subdivide(double[] src, int srcOff, double[] left, + int leftOff, double[] right, int rightOff) + { + double x1; + double y1; + double xc; + double yc; + double x2; + double y2; + + x1 = src[srcOff]; + y1 = src[srcOff + 1]; + xc = src[srcOff + 2]; + yc = src[srcOff + 3]; + x2 = src[srcOff + 4]; + y2 = src[srcOff + 5]; + + if (left != null) + { + left[leftOff] = x1; + left[leftOff + 1] = y1; + } + + if (right != null) + { + right[rightOff + 4] = x2; + right[rightOff + 5] = y2; + } + + x1 = (x1 + xc) / 2; + x2 = (xc + x2) / 2; + xc = (x1 + x2) / 2; + y1 = (y1 + yc) / 2; + y2 = (y2 + yc) / 2; + yc = (y1 + y2) / 2; + + if (left != null) + { + left[leftOff + 2] = x1; + left[leftOff + 3] = y1; + left[leftOff + 4] = xc; + left[leftOff + 5] = yc; + } + + if (right != null) + { + right[rightOff] = xc; + right[rightOff + 1] = yc; + right[rightOff + 2] = x2; + right[rightOff + 3] = y2; + } + } + + /** + * Finds the non-complex roots of a quadratic equation, placing the + * results into the same array as the equation coefficients. The + * following equation is being solved: + * + * <blockquote><code>eqn[2]</code> · <i>x</i><sup>2</sup> + * + <code>eqn[1]</code> · <i>x</i> + * + <code>eqn[0]</code> + * = 0 + * </blockquote> + * + * <p>For some background about solving quadratic equations, see the + * article <a href= + * "http://planetmath.org/encyclopedia/QuadraticFormula.html" + * >“Quadratic Formula”</a> in <a href= + * "http://planetmath.org/">PlanetMath</a>. For an extensive library + * of numerical algorithms written in the C programming language, + * see the <a href="http://www.gnu.org/software/gsl/">GNU Scientific + * Library</a>. + * + * @see #solveQuadratic(double[], double[]) + * @see CubicCurve2D#solveCubic(double[], double[]) + * + * @param eqn an array with the coefficients of the equation. When + * this procedure has returned, <code>eqn</code> will contain the + * non-complex solutions of the equation, in no particular order. + * + * @return the number of non-complex solutions. A result of 0 + * indicates that the equation has no non-complex solutions. A + * result of -1 indicates that the equation is constant (i.e., + * always or never zero). + * + * @author Brian Gough (bjg@network-theory.com) + * (original C implementation in the <a href= + * "http://www.gnu.org/software/gsl/">GNU Scientific Library</a>) + * + * @author Sascha Brawer (brawer@dandelis.ch) + * (adaptation to Java) + */ + public static int solveQuadratic(double[] eqn) + { + return solveQuadratic(eqn, eqn); + } + + /** + * Finds the non-complex roots of a quadratic equation. The + * following equation is being solved: + * + * <blockquote><code>eqn[2]</code> · <i>x</i><sup>2</sup> + * + <code>eqn[1]</code> · <i>x</i> + * + <code>eqn[0]</code> + * = 0 + * </blockquote> + * + * <p>For some background about solving quadratic equations, see the + * article <a href= + * "http://planetmath.org/encyclopedia/QuadraticFormula.html" + * >“Quadratic Formula”</a> in <a href= + * "http://planetmath.org/">PlanetMath</a>. For an extensive library + * of numerical algorithms written in the C programming language, + * see the <a href="http://www.gnu.org/software/gsl/">GNU Scientific + * Library</a>. + * + * @see CubicCurve2D#solveCubic(double[],double[]) + * + * @param eqn an array with the coefficients of the equation. + * + * @param res an array into which the non-complex roots will be + * stored. The results may be in an arbitrary order. It is safe to + * pass the same array object reference for both <code>eqn</code> + * and <code>res</code>. + * + * @return the number of non-complex solutions. A result of 0 + * indicates that the equation has no non-complex solutions. A + * result of -1 indicates that the equation is constant (i.e., + * always or never zero). + * + * @author Brian Gough (bjg@network-theory.com) + * (original C implementation in the <a href= + * "http://www.gnu.org/software/gsl/">GNU Scientific Library</a>) + * + * @author Sascha Brawer (brawer@dandelis.ch) + * (adaptation to Java) + */ + public static int solveQuadratic(double[] eqn, double[] res) + { + // Taken from poly/solve_quadratic.c in the GNU Scientific Library + // (GSL), cvs revision 1.7 of 2003-07-26. For the original source, + // see http://www.gnu.org/software/gsl/ + // + // Brian Gough, the author of that code, has granted the + // permission to use it in GNU Classpath under the GNU Classpath + // license, and has assigned the copyright to the Free Software + // Foundation. + // + // The Java implementation is very similar to the GSL code, but + // not a strict one-to-one copy. For example, GSL would sort the + // result. + double a; + double b; + double c; + double disc; + + c = eqn[0]; + b = eqn[1]; + a = eqn[2]; + + // Check for linear or constant functions. This is not done by the + // GNU Scientific Library. Without this special check, we + // wouldn't return -1 for constant functions, and 2 instead of 1 + // for linear functions. + if (a == 0) + { + if (b == 0) + return -1; + + res[0] = -c / b; + return 1; + } + + disc = b * b - 4 * a * c; + + if (disc < 0) + return 0; + + if (disc == 0) + { + // The GNU Scientific Library returns two identical results here. + // We just return one. + res[0] = -0.5 * b / a; + return 1; + } + + // disc > 0 + if (b == 0) + { + double r; + + r = Math.abs(0.5 * Math.sqrt(disc) / a); + res[0] = -r; + res[1] = r; + } + else + { + double sgnb; + double temp; + + sgnb = (b > 0 ? 1 : -1); + temp = -0.5 * (b + sgnb * Math.sqrt(disc)); + + // The GNU Scientific Library sorts the result here. We don't. + res[0] = temp / a; + res[1] = c / temp; + } + return 2; + } + + /** + * Determines whether a point is inside the area bounded + * by the curve and the straight line connecting its end points. + * + * <p><img src="doc-files/QuadCurve2D-5.png" width="350" height="180" + * alt="A drawing of the area spanned by the curve" /> + * + * <p>The above drawing illustrates in which area points are + * considered “inside” a QuadCurve2D. + */ + public boolean contains(double x, double y) + { + if (! getBounds2D().contains(x, y)) + return false; + + return ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0); + } + + /** + * Determines whether a point is inside the area bounded + * by the curve and the straight line connecting its end points. + * + * <p><img src="doc-files/QuadCurve2D-5.png" width="350" height="180" + * alt="A drawing of the area spanned by the curve" /> + * + * <p>The above drawing illustrates in which area points are + * considered “inside” a QuadCurve2D. + */ + public boolean contains(Point2D p) + { + return contains(p.getX(), p.getY()); + } + + /** + * Determines whether any part of a rectangle is inside the area bounded + * by the curve and the straight line connecting its end points. + * + * <p><img src="doc-files/QuadCurve2D-5.png" width="350" height="180" + * alt="A drawing of the area spanned by the curve" /> + * + * <p>The above drawing illustrates in which area points are + * considered “inside” in a CubicCurve2D. + */ + public boolean intersects(double x, double y, double w, double h) + { + if (! getBounds2D().contains(x, y, w, h)) + return false; + + /* Does any edge intersect? */ + if (getAxisIntersections(x, y, true, w) != 0 /* top */ + || getAxisIntersections(x, y + h, true, w) != 0 /* bottom */ + || getAxisIntersections(x + w, y, false, h) != 0 /* right */ + || getAxisIntersections(x, y, false, h) != 0) /* left */ + return true; + + /* No intersections, is any point inside? */ + if ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0) + return true; + + return false; + } + + /** + * Determines whether any part of a Rectangle2D is inside the area bounded + * by the curve and the straight line connecting its end points. + * @see #intersects(double, double, double, double) + */ + public boolean intersects(Rectangle2D r) + { + return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Determines whether a rectangle is entirely inside the area bounded + * by the curve and the straight line connecting its end points. + * + * <p><img src="doc-files/QuadCurve2D-5.png" width="350" height="180" + * alt="A drawing of the area spanned by the curve" /> + * + * <p>The above drawing illustrates in which area points are + * considered “inside” a QuadCurve2D. + * @see #contains(double, double) + */ + public boolean contains(double x, double y, double w, double h) + { + if (! getBounds2D().intersects(x, y, w, h)) + return false; + + /* Does any edge intersect? */ + if (getAxisIntersections(x, y, true, w) != 0 /* top */ + || getAxisIntersections(x, y + h, true, w) != 0 /* bottom */ + || getAxisIntersections(x + w, y, false, h) != 0 /* right */ + || getAxisIntersections(x, y, false, h) != 0) /* left */ + return false; + + /* No intersections, is any point inside? */ + if ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0) + return true; + + return false; + } + + /** + * Determines whether a Rectangle2D is entirely inside the area that is + * bounded by the curve and the straight line connecting its end points. + * @see #contains(double, double, double, double) + */ + public boolean contains(Rectangle2D r) + { + return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Determines the smallest rectangle that encloses the + * curve’s start, end and control point. As the illustration + * below shows, the invisible control point may cause the bounds to + * be much larger than the area that is actually covered by the + * curve. + * + * <p><img src="doc-files/QuadCurve2D-2.png" width="350" height="180" + * alt="An illustration of the bounds of a QuadCurve2D" /> + */ + public Rectangle getBounds() + { + return getBounds2D().getBounds(); + } + + public PathIterator getPathIterator(final AffineTransform at) + { + return new PathIterator() + { + /** Current coordinate. */ + private int current = 0; + + public int getWindingRule() + { + return WIND_NON_ZERO; + } + + public boolean isDone() + { + return current >= 2; + } + + public void next() + { + current++; + } + + public int currentSegment(float[] coords) + { + int result; + switch (current) + { + case 0: + coords[0] = (float) getX1(); + coords[1] = (float) getY1(); + result = SEG_MOVETO; + break; + case 1: + coords[0] = (float) getCtrlX(); + coords[1] = (float) getCtrlY(); + coords[2] = (float) getX2(); + coords[3] = (float) getY2(); + result = SEG_QUADTO; + break; + default: + throw new NoSuchElementException("quad iterator out of bounds"); + } + if (at != null) + at.transform(coords, 0, coords, 0, 2); + return result; + } + + public int currentSegment(double[] coords) + { + int result; + switch (current) + { + case 0: + coords[0] = getX1(); + coords[1] = getY1(); + result = SEG_MOVETO; + break; + case 1: + coords[0] = getCtrlX(); + coords[1] = getCtrlY(); + coords[2] = getX2(); + coords[3] = getY2(); + result = SEG_QUADTO; + break; + default: + throw new NoSuchElementException("quad iterator out of bounds"); + } + if (at != null) + at.transform(coords, 0, coords, 0, 2); + return result; + } + }; + } + + public PathIterator getPathIterator(AffineTransform at, double flatness) + { + return new FlatteningPathIterator(getPathIterator(at), flatness); + } + + /** + * Creates a new curve with the same contents as this one. + * + * @return the clone. + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } + + /** + * Helper method used by contains() and intersects() methods + * Return the number of curve/line intersections on a given axis + * extending from a certain point. useYaxis is true for using the Y axis, + * @param x x coordinate of the origin point + * @param y y coordinate of the origin point + * @param useYaxis axis to follow, if true the positive Y axis is used, + * false uses the positive X axis. + * + * This is an implementation of the line-crossings algorithm, + * Detailed in an article on Eric Haines' page: + * http://www.acm.org/tog/editors/erich/ptinpoly/ + */ + private int getAxisIntersections(double x, double y, boolean useYaxis, + double distance) + { + int nCrossings = 0; + double a0; + double a1; + double a2; + double b0; + double b1; + double b2; + double[] r = new double[3]; + int nRoots; + + a0 = a2 = 0.0; + + if (useYaxis) + { + a0 = getY1() - y; + a1 = getCtrlY() - y; + a2 = getY2() - y; + b0 = getX1() - x; + b1 = getCtrlX() - x; + b2 = getX2() - x; + } + else + { + a0 = getX1() - x; + a1 = getCtrlX() - x; + a2 = getX2() - x; + b0 = getY1() - y; + b1 = getCtrlY() - y; + b2 = getY2() - y; + } + + /* If the axis intersects a start/endpoint, shift it up by some small + amount to guarantee the line is 'inside' + If this is not done,bad behaviour may result for points on that axis. */ + if (a0 == 0.0 || a2 == 0.0) + { + double small = getFlatness() * EPSILON; + if (a0 == 0.0) + a0 -= small; + + if (a2 == 0.0) + a2 -= small; + } + + r[0] = a0; + r[1] = 2 * (a1 - a0); + r[2] = (a2 - 2 * a1 + a0); + + nRoots = solveQuadratic(r); + for (int i = 0; i < nRoots; i++) + { + double t = r[i]; + if (t >= 0.0 && t <= 1.0) + { + double crossing = t * t * (b2 - 2 * b1 + b0) + 2 * t * (b1 - b0) + + b0; + /* single root is always doubly degenerate in quads */ + if (crossing > 0 && crossing < distance) + nCrossings += (nRoots == 1) ? 2 : 1; + } + } + + if (useYaxis) + { + if (Line2D.linesIntersect(b0, a0, b2, a2, EPSILON, 0.0, distance, 0.0)) + nCrossings++; + } + else + { + if (Line2D.linesIntersect(a0, b0, a2, b2, 0.0, EPSILON, 0.0, distance)) + nCrossings++; + } + + return (nCrossings); + } + + /** + * A two-dimensional curve that is parameterized with a quadratic + * function and stores coordinate values in double-precision + * floating-point format. + * + * @see QuadCurve2D.Float + * + * @author Eric Blake (ebb9@email.byu.edu) + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class Double extends QuadCurve2D + { + /** + * The <i>x</i> coordinate of the curve’s start point. + */ + public double x1; + + /** + * The <i>y</i> coordinate of the curve’s start point. + */ + public double y1; + + /** + * The <i>x</i> coordinate of the curve’s control point. + */ + public double ctrlx; + + /** + * The <i>y</i> coordinate of the curve’s control point. + */ + public double ctrly; + + /** + * The <i>x</i> coordinate of the curve’s end point. + */ + public double x2; + + /** + * The <i>y</i> coordinate of the curve’s end point. + */ + public double y2; + + /** + * Constructs a new QuadCurve2D that stores its coordinate values + * in double-precision floating-point format. All points are + * initially at position (0, 0). + */ + public Double() + { + } + + /** + * Constructs a new QuadCurve2D that stores its coordinate values + * in double-precision floating-point format, specifying the + * initial position of each point. + * + * @param x1 the <i>x</i> coordinate of the curve’s start + * point. + * + * @param y1 the <i>y</i> coordinate of the curve’s start + * point. + * + * @param cx the <i>x</i> coordinate of the curve’s control + * point. + * + * @param cy the <i>y</i> coordinate of the curve’s control + * point. + * + * @param x2 the <i>x</i> coordinate of the curve’s end + * point. + * + * @param y2 the <i>y</i> coordinate of the curve’s end + * point. + */ + public Double(double x1, double y1, double cx, double cy, double x2, + double y2) + { + this.x1 = x1; + this.y1 = y1; + ctrlx = cx; + ctrly = cy; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Returns the <i>x</i> coordinate of the curve’s start + * point. + */ + public double getX1() + { + return x1; + } + + /** + * Returns the <i>y</i> coordinate of the curve’s start + * point. + */ + public double getY1() + { + return y1; + } + + /** + * Returns the curve’s start point. + */ + public Point2D getP1() + { + return new Point2D.Double(x1, y1); + } + + /** + * Returns the <i>x</i> coordinate of the curve’s control + * point. + */ + public double getCtrlX() + { + return ctrlx; + } + + /** + * Returns the <i>y</i> coordinate of the curve’s control + * point. + */ + public double getCtrlY() + { + return ctrly; + } + + /** + * Returns the curve’s control point. + */ + public Point2D getCtrlPt() + { + return new Point2D.Double(ctrlx, ctrly); + } + + /** + * Returns the <i>x</i> coordinate of the curve’s end + * point. + */ + public double getX2() + { + return x2; + } + + /** + * Returns the <i>y</i> coordinate of the curve’s end + * point. + */ + public double getY2() + { + return y2; + } + + /** + * Returns the curve’s end point. + */ + public Point2D getP2() + { + return new Point2D.Double(x2, y2); + } + + /** + * Changes the geometry of the curve. + * + * @param x1 the <i>x</i> coordinate of the curve’s new + * start point. + * + * @param y1 the <i>y</i> coordinate of the curve’s new + * start point. + * + * @param cx the <i>x</i> coordinate of the curve’s new + * control point. + * + * @param cy the <i>y</i> coordinate of the curve’s new + * control point. + * + * @param x2 the <i>x</i> coordinate of the curve’s new + * end point. + * + * @param y2 the <i>y</i> coordinate of the curve’s new + * end point. + */ + public void setCurve(double x1, double y1, double cx, double cy, + double x2, double y2) + { + this.x1 = x1; + this.y1 = y1; + ctrlx = cx; + ctrly = cy; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Determines the smallest rectangle that encloses the + * curve’s start, end and control point. As the + * illustration below shows, the invisible control point may cause + * the bounds to be much larger than the area that is actually + * covered by the curve. + * + * <p><img src="doc-files/QuadCurve2D-2.png" width="350" height="180" + * alt="An illustration of the bounds of a QuadCurve2D" /> + */ + public Rectangle2D getBounds2D() + { + double nx1 = Math.min(Math.min(x1, ctrlx), x2); + double ny1 = Math.min(Math.min(y1, ctrly), y2); + double nx2 = Math.max(Math.max(x1, ctrlx), x2); + double ny2 = Math.max(Math.max(y1, ctrly), y2); + return new Rectangle2D.Double(nx1, ny1, nx2 - nx1, ny2 - ny1); + } + } + + /** + * A two-dimensional curve that is parameterized with a quadratic + * function and stores coordinate values in single-precision + * floating-point format. + * + * @see QuadCurve2D.Double + * + * @author Eric Blake (ebb9@email.byu.edu) + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class Float extends QuadCurve2D + { + /** + * The <i>x</i> coordinate of the curve’s start point. + */ + public float x1; + + /** + * The <i>y</i> coordinate of the curve’s start point. + */ + public float y1; + + /** + * The <i>x</i> coordinate of the curve’s control point. + */ + public float ctrlx; + + /** + * The <i>y</i> coordinate of the curve’s control point. + */ + public float ctrly; + + /** + * The <i>x</i> coordinate of the curve’s end point. + */ + public float x2; + + /** + * The <i>y</i> coordinate of the curve’s end point. + */ + public float y2; + + /** + * Constructs a new QuadCurve2D that stores its coordinate values + * in single-precision floating-point format. All points are + * initially at position (0, 0). + */ + public Float() + { + } + + /** + * Constructs a new QuadCurve2D that stores its coordinate values + * in single-precision floating-point format, specifying the + * initial position of each point. + * + * @param x1 the <i>x</i> coordinate of the curve’s start + * point. + * + * @param y1 the <i>y</i> coordinate of the curve’s start + * point. + * + * @param cx the <i>x</i> coordinate of the curve’s control + * point. + * + * @param cy the <i>y</i> coordinate of the curve’s control + * point. + * + * @param x2 the <i>x</i> coordinate of the curve’s end + * point. + * + * @param y2 the <i>y</i> coordinate of the curve’s end + * point. + */ + public Float(float x1, float y1, float cx, float cy, float x2, float y2) + { + this.x1 = x1; + this.y1 = y1; + ctrlx = cx; + ctrly = cy; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Returns the <i>x</i> coordinate of the curve’s start + * point. + */ + public double getX1() + { + return x1; + } + + /** + * Returns the <i>y</i> coordinate of the curve’s start + * point. + */ + public double getY1() + { + return y1; + } + + /** + * Returns the curve’s start point. + */ + public Point2D getP1() + { + return new Point2D.Float(x1, y1); + } + + /** + * Returns the <i>x</i> coordinate of the curve’s control + * point. + */ + public double getCtrlX() + { + return ctrlx; + } + + /** + * Returns the <i>y</i> coordinate of the curve’s control + * point. + */ + public double getCtrlY() + { + return ctrly; + } + + /** + * Returns the curve’s control point. + */ + public Point2D getCtrlPt() + { + return new Point2D.Float(ctrlx, ctrly); + } + + /** + * Returns the <i>x</i> coordinate of the curve’s end + * point. + */ + public double getX2() + { + return x2; + } + + /** + * Returns the <i>y</i> coordinate of the curve’s end + * point. + */ + public double getY2() + { + return y2; + } + + /** + * Returns the curve’s end point. + */ + public Point2D getP2() + { + return new Point2D.Float(x2, y2); + } + + /** + * Changes the geometry of the curve, specifying coordinate values + * as double-precision floating-point numbers. + * + * @param x1 the <i>x</i> coordinate of the curve’s new + * start point. + * + * @param y1 the <i>y</i> coordinate of the curve’s new + * start point. + * + * @param cx the <i>x</i> coordinate of the curve’s new + * control point. + * + * @param cy the <i>y</i> coordinate of the curve’s new + * control point. + * + * @param x2 the <i>x</i> coordinate of the curve’s new + * end point. + * + * @param y2 the <i>y</i> coordinate of the curve’s new + * end point. + */ + public void setCurve(double x1, double y1, double cx, double cy, + double x2, double y2) + { + this.x1 = (float) x1; + this.y1 = (float) y1; + ctrlx = (float) cx; + ctrly = (float) cy; + this.x2 = (float) x2; + this.y2 = (float) y2; + } + + /** + * Changes the geometry of the curve, specifying coordinate values + * as single-precision floating-point numbers. + * + * @param x1 the <i>x</i> coordinate of the curve’s new + * start point. + * + * @param y1 the <i>y</i> coordinate of the curve’s new + * start point. + * + * @param cx the <i>x</i> coordinate of the curve’s new + * control point. + * + * @param cy the <i>y</i> coordinate of the curve’s new + * control point. + * + * @param x2 the <i>x</i> coordinate of the curve’s new + * end point. + * + * @param y2 the <i>y</i> coordinate of the curve’s new + * end point. + */ + public void setCurve(float x1, float y1, float cx, float cy, float x2, + float y2) + { + this.x1 = x1; + this.y1 = y1; + ctrlx = cx; + ctrly = cy; + this.x2 = x2; + this.y2 = y2; + } + + /** + * Determines the smallest rectangle that encloses the + * curve’s start, end and control point. As the + * illustration below shows, the invisible control point may cause + * the bounds to be much larger than the area that is actually + * covered by the curve. + * + * <p><img src="doc-files/QuadCurve2D-2.png" width="350" height="180" + * alt="An illustration of the bounds of a QuadCurve2D" /> + */ + public Rectangle2D getBounds2D() + { + float nx1 = Math.min(Math.min(x1, ctrlx), x2); + float ny1 = Math.min(Math.min(y1, ctrly), y2); + float nx2 = Math.max(Math.max(x1, ctrlx), x2); + float ny2 = Math.max(Math.max(y1, ctrly), y2); + return new Rectangle2D.Float(nx1, ny1, nx2 - nx1, ny2 - ny1); + } + } +} diff --git a/libjava/classpath/java/awt/geom/Rectangle2D.java b/libjava/classpath/java/awt/geom/Rectangle2D.java new file mode 100644 index 000000000..6a255f953 --- /dev/null +++ b/libjava/classpath/java/awt/geom/Rectangle2D.java @@ -0,0 +1,992 @@ +/* Rectangle2D.java -- generic rectangles in 2-D space + Copyright (C) 2000, 2001, 2002, 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.geom; + +import java.util.NoSuchElementException; + +/** + * This class describes a rectangle by a point (x,y) and dimension (w x h). + * The actual storage is left up to subclasses. + * + * <p>It is valid for a rectangle to have negative width or height; but it + * is considered to have no area or internal points. Therefore, the behavior + * in methods like <code>contains</code> or <code>intersects</code> is + * undefined unless the rectangle has positive width and height. + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ +public abstract class Rectangle2D extends RectangularShape +{ + /** + * The point lies left of the rectangle (p.x < r.x). + * + * @see #outcode(double, double) + */ + public static final int OUT_LEFT = 1; + + /** + * The point lies above the rectangle (p.y < r.y). + * + * @see #outcode(double, double) + */ + public static final int OUT_TOP = 2; + + /** + * The point lies right of the rectangle (p.x > r.maxX). + * + * @see #outcode(double, double) + */ + public static final int OUT_RIGHT = 4; + + /** + * The point lies below of the rectangle (p.y > r.maxY). + * + * @see #outcode(double, double) + */ + public static final int OUT_BOTTOM = 8; + + /** + * Default constructor. + */ + protected Rectangle2D() + { + } + + /** + * Set the bounding box of this rectangle. + * + * @param x the new X coordinate + * @param y the new Y coordinate + * @param w the new width + * @param h the new height + */ + public abstract void setRect(double x, double y, double w, double h); + + /** + * Set the bounding box of this rectangle from the given one. + * + * @param r rectangle to copy + * @throws NullPointerException if r is null + */ + public void setRect(Rectangle2D r) + { + setRect(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Tests if the specified line intersects the interior of this rectangle. + * + * @param x1 the first x coordinate of line segment + * @param y1 the first y coordinate of line segment + * @param x2 the second x coordinate of line segment + * @param y2 the second y coordinate of line segment + * @return true if the line intersects the rectangle + */ + public boolean intersectsLine(double x1, double y1, double x2, double y2) + { + double x = getX(); + double y = getY(); + double w = getWidth(); + double h = getHeight(); + if (w <= 0 || h <= 0) + return false; + + if (x1 >= x && x1 <= x + w && y1 >= y && y1 <= y + h) + return true; + if (x2 >= x && x2 <= x + w && y2 >= y && y2 <= y + h) + return true; + + double x3 = x + w; + double y3 = y + h; + + return (Line2D.linesIntersect(x1, y1, x2, y2, x, y, x, y3) + || Line2D.linesIntersect(x1, y1, x2, y2, x, y3, x3, y3) + || Line2D.linesIntersect(x1, y1, x2, y2, x3, y3, x3, y) + || Line2D.linesIntersect(x1, y1, x2, y2, x3, y, x, y)); + } + + /** + * Tests if the specified line intersects the interior of this rectangle. + * + * @param l the line segment + * @return true if the line intersects the rectangle + * @throws NullPointerException if l is null + */ + public boolean intersectsLine(Line2D l) + { + return intersectsLine(l.getX1(), l.getY1(), l.getX2(), l.getY2()); + } + + /** + * Determine where the point lies with respect to this rectangle. The + * result will be the binary OR of the appropriate bit masks. + * + * @param x the x coordinate to check + * @param y the y coordinate to check + * @return the binary OR of the result + * @see #OUT_LEFT + * @see #OUT_TOP + * @see #OUT_RIGHT + * @see #OUT_BOTTOM + */ + public abstract int outcode(double x, double y); + + /** + * Determine where the point lies with respect to this rectangle. The + * result will be the binary OR of the appropriate bit masks. + * + * @param p the point to check + * @return the binary OR of the result + * @throws NullPointerException if p is null + * @see #OUT_LEFT + * @see #OUT_TOP + * @see #OUT_RIGHT + * @see #OUT_BOTTOM + */ + public int outcode(Point2D p) + { + return outcode(p.getX(), p.getY()); + } + + /** + * Set the bounding box of this rectangle. + * + * @param x the new X coordinate + * @param y the new Y coordinate + * @param w the new width + * @param h the new height + */ + public void setFrame(double x, double y, double w, double h) + { + setRect(x, y, w, h); + } + + /** + * Returns the bounds of this rectangle. A pretty useless method, as this + * is already a rectangle. + * + * @return a copy of this rectangle + */ + public Rectangle2D getBounds2D() + { + return (Rectangle2D) clone(); + } + + /** + * Test if the given point is contained in the rectangle. + * + * @param x the x coordinate of the point + * @param y the y coordinate of the point + * @return true if (x,y) is in the rectangle + */ + public boolean contains(double x, double y) + { + double mx = getX(); + double my = getY(); + double w = getWidth(); + double h = getHeight(); + return w > 0 && h > 0 && x >= mx && x < mx + w && y >= my && y < my + h; + } + + /** + * Tests if the given rectangle intersects this one. In other words, test if + * the two rectangles share at least one internal point. + * + * @param x the x coordinate of the other rectangle + * @param y the y coordinate of the other rectangle + * @param w the width of the other rectangle + * @param h the height of the other rectangle + * @return true if the rectangles intersect + */ + public boolean intersects(double x, double y, double w, double h) + { + double mx = getX(); + double my = getY(); + double mw = getWidth(); + double mh = getHeight(); + return w > 0 && h > 0 && mw > 0 && mh > 0 + && x < mx + mw && x + w > mx && y < my + mh && y + h > my; + } + + /** + * Tests if this rectangle contains the given one. In other words, test if + * this rectangle contains all points in the given one. + * + * @param x the x coordinate of the other rectangle + * @param y the y coordinate of the other rectangle + * @param w the width of the other rectangle + * @param h the height of the other rectangle + * @return true if this rectangle contains the other + */ + public boolean contains(double x, double y, double w, double h) + { + double mx = getX(); + double my = getY(); + double mw = getWidth(); + double mh = getHeight(); + return w > 0 && h > 0 && mw > 0 && mh > 0 + && x >= mx && x + w <= mx + mw && y >= my && y + h <= my + mh; + } + + /** + * Return a new rectangle which is the intersection of this and the given + * one. The result will be empty if there is no intersection. + * + * @param r the rectangle to be intersected + * @return the intersection + * @throws NullPointerException if r is null + */ + public abstract Rectangle2D createIntersection(Rectangle2D r); + + /** + * Intersects a pair of rectangles, and places the result in the + * destination; this can be used to avoid object creation. This method + * even works when the destination is also a source, although you stand + * to lose the original data. + * + * @param src1 the first source + * @param src2 the second source + * @param dest the destination for the intersection + * @throws NullPointerException if any rectangle is null + */ + public static void intersect(Rectangle2D src1, Rectangle2D src2, + Rectangle2D dest) + { + double x = Math.max(src1.getX(), src2.getX()); + double y = Math.max(src1.getY(), src2.getY()); + double maxx = Math.min(src1.getMaxX(), src2.getMaxX()); + double maxy = Math.min(src1.getMaxY(), src2.getMaxY()); + dest.setRect(x, y, maxx - x, maxy - y); + } + + /** + * Return a new rectangle which is the union of this and the given one. + * + * @param r the rectangle to be merged + * @return the union + * @throws NullPointerException if r is null + */ + public abstract Rectangle2D createUnion(Rectangle2D r); + + /** + * Joins a pair of rectangles, and places the result in the destination; + * this can be used to avoid object creation. This method even works when + * the destination is also a source, although you stand to lose the + * original data. + * + * @param src1 the first source + * @param src2 the second source + * @param dest the destination for the union + * @throws NullPointerException if any rectangle is null + */ + public static void union(Rectangle2D src1, Rectangle2D src2, + Rectangle2D dest) + { + double x = Math.min(src1.getX(), src2.getX()); + double y = Math.min(src1.getY(), src2.getY()); + double maxx = Math.max(src1.getMaxX(), src2.getMaxX()); + double maxy = Math.max(src1.getMaxY(), src2.getMaxY()); + dest.setRect(x, y, maxx - x, maxy - y); + } + + /** + * Modifies this rectangle so that it represents the smallest rectangle + * that contains both the existing rectangle and the specified point. + * However, if the point falls on one of the two borders which are not + * inside the rectangle, a subsequent call to <code>contains</code> may + * return false. + * + * @param newx the X coordinate of the point to add to this rectangle + * @param newy the Y coordinate of the point to add to this rectangle + */ + public void add(double newx, double newy) + { + double minx = Math.min(getX(), newx); + double maxx = Math.max(getMaxX(), newx); + double miny = Math.min(getY(), newy); + double maxy = Math.max(getMaxY(), newy); + setRect(minx, miny, maxx - minx, maxy - miny); + } + + /** + * Modifies this rectangle so that it represents the smallest rectangle + * that contains both the existing rectangle and the specified point. + * However, if the point falls on one of the two borders which are not + * inside the rectangle, a subsequent call to <code>contains</code> may + * return false. + * + * @param p the point to add to this rectangle + * @throws NullPointerException if p is null + */ + public void add(Point2D p) + { + add(p.getX(), p.getY()); + } + + /** + * Modifies this rectangle so that it represents the smallest rectangle + * that contains both the existing rectangle and the specified rectangle. + * + * @param r the rectangle to add to this rectangle + * @throws NullPointerException if r is null + * @see #union(Rectangle2D, Rectangle2D, Rectangle2D) + */ + public void add(Rectangle2D r) + { + union(this, r, this); + } + + /** + * Return an iterator along the shape boundary. If the optional transform + * is provided, the iterator is transformed accordingly. Each call returns + * a new object, independent from others in use. This iterator is thread + * safe; modifications to the rectangle do not affect the results of this + * path instance. + * + * @param at an optional transform to apply to the iterator + * @return a new iterator over the boundary + * @since 1.2 + */ + public PathIterator getPathIterator(final AffineTransform at) + { + final double minx = getX(); + final double miny = getY(); + final double maxx = minx + getWidth(); + final double maxy = miny + getHeight(); + return new PathIterator() + { + /** Current coordinate. */ + private int current = (maxx <= minx && maxy <= miny) ? 6 : 0; + + public int getWindingRule() + { + // A test program showed that Sun J2SE 1.3.1 and 1.4.1_01 + // return WIND_NON_ZERO paths. While this does not really + // make any difference for rectangles (because they are not + // self-intersecting), it seems appropriate to behave + // identically. + + return WIND_NON_ZERO; + } + + public boolean isDone() + { + return current > 5; + } + + public void next() + { + current++; + } + + public int currentSegment(float[] coords) + { + switch (current) + { + case 1: + coords[0] = (float) maxx; + coords[1] = (float) miny; + break; + case 2: + coords[0] = (float) maxx; + coords[1] = (float) maxy; + break; + case 3: + coords[0] = (float) minx; + coords[1] = (float) maxy; + break; + case 0: + case 4: + coords[0] = (float) minx; + coords[1] = (float) miny; + break; + case 5: + return SEG_CLOSE; + default: + throw new NoSuchElementException("rect iterator out of bounds"); + } + if (at != null) + at.transform(coords, 0, coords, 0, 1); + return current == 0 ? SEG_MOVETO : SEG_LINETO; + } + + public int currentSegment(double[] coords) + { + switch (current) + { + case 1: + coords[0] = maxx; + coords[1] = miny; + break; + case 2: + coords[0] = maxx; + coords[1] = maxy; + break; + case 3: + coords[0] = minx; + coords[1] = maxy; + break; + case 0: + case 4: + coords[0] = minx; + coords[1] = miny; + break; + case 5: + return SEG_CLOSE; + default: + throw new NoSuchElementException("rect iterator out of bounds"); + } + if (at != null) + at.transform(coords, 0, coords, 0, 1); + return current == 0 ? SEG_MOVETO : SEG_LINETO; + } + }; + } + + /** + * Return an iterator along the shape boundary. If the optional transform + * is provided, the iterator is transformed accordingly. Each call returns + * a new object, independent from others in use. This iterator is thread + * safe; modifications to the rectangle do not affect the results of this + * path instance. As the rectangle is already flat, the flatness parameter + * is ignored. + * + * @param at an optional transform to apply to the iterator + * @param flatness the maximum distance for deviation from the real boundary + * @return a new iterator over the boundary + * @since 1.2 + */ + public PathIterator getPathIterator(AffineTransform at, double flatness) + { + return getPathIterator(at); + } + + /** + * Return the hashcode for this rectangle. The formula is not documented, but + * appears to be the same as: + * <pre> + * long l = Double.doubleToLongBits(getX()) + * + 37 * Double.doubleToLongBits(getY()) + * + 43 * Double.doubleToLongBits(getWidth()) + * + 47 * Double.doubleToLongBits(getHeight()); + * return (int) ((l >> 32) ^ l); + * </pre> + * + * @return the hashcode + */ + public int hashCode() + { + // Talk about a fun time reverse engineering this one! + long l = java.lang.Double.doubleToLongBits(getX()) + + 37 * java.lang.Double.doubleToLongBits(getY()) + + 43 * java.lang.Double.doubleToLongBits(getWidth()) + + 47 * java.lang.Double.doubleToLongBits(getHeight()); + return (int) ((l >> 32) ^ l); + } + + /** + * Tests this rectangle for equality against the specified object. This + * will be true if an only if the specified object is an instance of + * Rectangle2D with the same coordinates and dimensions. + * + * @param obj the object to test against for equality + * @return true if the specified object is equal to this one + */ + public boolean equals(Object obj) + { + if (! (obj instanceof Rectangle2D)) + return false; + Rectangle2D r = (Rectangle2D) obj; + return r.getX() == getX() && r.getY() == getY() + && r.getWidth() == getWidth() && r.getHeight() == getHeight(); + } + + /** + * This class defines a rectangle in <code>double</code> precision. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ + public static class Double extends Rectangle2D + { + /** The x coordinate of the lower left corner. */ + public double x; + + /** The y coordinate of the lower left corner. */ + public double y; + + /** The width of the rectangle. */ + public double width; + + /** The height of the rectangle. */ + public double height; + + /** + * Create a rectangle at (0,0) with width 0 and height 0. + */ + public Double() + { + } + + /** + * Create a rectangle with the given values. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + */ + public Double(double x, double y, double w, double h) + { + this.x = x; + this.y = y; + width = w; + height = h; + } + + /** + * Return the X coordinate. + * + * @return the value of x + */ + public double getX() + { + return x; + } + + /** + * Return the Y coordinate. + * + * @return the value of y + */ + public double getY() + { + return y; + } + + /** + * Return the width. + * + * @return the value of width + */ + public double getWidth() + { + return width; + } + + /** + * Return the height. + * + * @return the value of height + */ + public double getHeight() + { + return height; + } + + /** + * Test if the rectangle is empty. + * + * @return true if width or height is not positive + */ + public boolean isEmpty() + { + return width <= 0 || height <= 0; + } + + /** + * Set the contents of this rectangle to those specified. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + */ + public void setRect(double x, double y, double w, double h) + { + this.x = x; + this.y = y; + width = w; + height = h; + } + + /** + * Set the contents of this rectangle to those specified. + * + * @param r the rectangle to copy + * @throws NullPointerException if r is null + */ + public void setRect(Rectangle2D r) + { + x = r.getX(); + y = r.getY(); + width = r.getWidth(); + height = r.getHeight(); + } + + /** + * Determine where the point lies with respect to this rectangle. The + * result will be the binary OR of the appropriate bit masks. + * + * @param x the x coordinate to check + * @param y the y coordinate to check + * @return the binary OR of the result + * @see #OUT_LEFT + * @see #OUT_TOP + * @see #OUT_RIGHT + * @see #OUT_BOTTOM + * @since 1.2 + */ + public int outcode(double x, double y) + { + int result = 0; + if (width <= 0) + result |= OUT_LEFT | OUT_RIGHT; + else if (x < this.x) + result |= OUT_LEFT; + else if (x > this.x + width) + result |= OUT_RIGHT; + if (height <= 0) + result |= OUT_BOTTOM | OUT_TOP; + else if (y < this.y) // Remember that +y heads top-to-bottom. + result |= OUT_TOP; + else if (y > this.y + height) + result |= OUT_BOTTOM; + return result; + } + + /** + * Returns the bounds of this rectangle. A pretty useless method, as this + * is already a rectangle. + * + * @return a copy of this rectangle + */ + public Rectangle2D getBounds2D() + { + return new Double(x, y, width, height); + } + + /** + * Return a new rectangle which is the intersection of this and the given + * one. The result will be empty if there is no intersection. + * + * @param r the rectangle to be intersected + * @return the intersection + * @throws NullPointerException if r is null + */ + public Rectangle2D createIntersection(Rectangle2D r) + { + Double res = new Double(); + intersect(this, r, res); + return res; + } + + /** + * Return a new rectangle which is the union of this and the given one. + * + * @param r the rectangle to be merged + * @return the union + * @throws NullPointerException if r is null + */ + public Rectangle2D createUnion(Rectangle2D r) + { + Double res = new Double(); + union(this, r, res); + return res; + } + + /** + * Returns a string representation of this rectangle. This is in the form + * <code>getClass().getName() + "[x=" + x + ",y=" + y + ",w=" + width + * + ",h=" + height + ']'</code>. + * + * @return a string representation of this rectangle + */ + public String toString() + { + return getClass().getName() + "[x=" + x + ",y=" + y + ",w=" + width + + ",h=" + height + ']'; + } + } + + /** + * This class defines a rectangle in <code>float</code> precision. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ + public static class Float extends Rectangle2D + { + /** The x coordinate of the lower left corner. */ + public float x; + + /** The y coordinate of the lower left corner. */ + public float y; + + /** The width of the rectangle. */ + public float width; + + /** The height of the rectangle. */ + public float height; + + /** + * Create a rectangle at (0,0) with width 0 and height 0. + */ + public Float() + { + } + + /** + * Create a rectangle with the given values. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + */ + public Float(float x, float y, float w, float h) + { + this.x = x; + this.y = y; + width = w; + height = h; + } + + /** + * Create a rectangle with the given values. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + */ + Float(double x, double y, double w, double h) + { + this.x = (float) x; + this.y = (float) y; + width = (float) w; + height = (float) h; + } + + /** + * Return the X coordinate. + * + * @return the value of x + */ + public double getX() + { + return x; + } + + /** + * Return the Y coordinate. + * + * @return the value of y + */ + public double getY() + { + return y; + } + + /** + * Return the width. + * + * @return the value of width + */ + public double getWidth() + { + return width; + } + + /** + * Return the height. + * + * @return the value of height + */ + public double getHeight() + { + return height; + } + + /** + * Test if the rectangle is empty. + * + * @return true if width or height is not positive + */ + public boolean isEmpty() + { + return width <= 0 || height <= 0; + } + + /** + * Set the contents of this rectangle to those specified. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + */ + public void setRect(float x, float y, float w, float h) + { + this.x = x; + this.y = y; + width = w; + height = h; + } + + /** + * Set the contents of this rectangle to those specified. + * + * @param x the x coordinate + * @param y the y coordinate + * @param w the width + * @param h the height + */ + public void setRect(double x, double y, double w, double h) + { + this.x = (float) x; + this.y = (float) y; + width = (float) w; + height = (float) h; + } + + /** + * Set the contents of this rectangle to those specified. + * + * @param r the rectangle to copy + * @throws NullPointerException if r is null + */ + public void setRect(Rectangle2D r) + { + x = (float) r.getX(); + y = (float) r.getY(); + width = (float) r.getWidth(); + height = (float) r.getHeight(); + } + + /** + * Determine where the point lies with respect to this rectangle. The + * result will be the binary OR of the appropriate bit masks. + * + * @param x the x coordinate to check + * @param y the y coordinate to check + * @return the binary OR of the result + * @see #OUT_LEFT + * @see #OUT_TOP + * @see #OUT_RIGHT + * @see #OUT_BOTTOM + * @since 1.2 + */ + public int outcode(double x, double y) + { + int result = 0; + if (width <= 0) + result |= OUT_LEFT | OUT_RIGHT; + else if (x < this.x) + result |= OUT_LEFT; + else if (x > this.x + width) + result |= OUT_RIGHT; + if (height <= 0) + result |= OUT_BOTTOM | OUT_TOP; + else if (y < this.y) // Remember that +y heads top-to-bottom. + result |= OUT_TOP; + else if (y > this.y + height) + result |= OUT_BOTTOM; + return result; + } + + /** + * Returns the bounds of this rectangle. A pretty useless method, as this + * is already a rectangle. + * + * @return a copy of this rectangle + */ + public Rectangle2D getBounds2D() + { + return new Float(x, y, width, height); + } + + /** + * Return a new rectangle which is the intersection of this and the given + * one. The result will be empty if there is no intersection. + * + * @param r the rectangle to be intersected + * @return the intersection + * @throws NullPointerException if r is null + */ + public Rectangle2D createIntersection(Rectangle2D r) + { + Float res = new Float(); + intersect(this, r, res); + return res; + } + + /** + * Return a new rectangle which is the union of this and the given one. + * + * @param r the rectangle to be merged + * @return the union + * @throws NullPointerException if r is null + */ + public Rectangle2D createUnion(Rectangle2D r) + { + Float res = new Float(); + union(this, r, res); + return res; + } + + /** + * Returns a string representation of this rectangle. This is in the form + * <code>getClass().getName() + "[x=" + x + ",y=" + y + ",w=" + width + * + ",h=" + height + ']'</code>. + * + * @return a string representation of this rectangle + */ + public String toString() + { + return getClass().getName() + "[x=" + x + ",y=" + y + ",w=" + width + + ",h=" + height + ']'; + } + } +} diff --git a/libjava/classpath/java/awt/geom/RectangularShape.java b/libjava/classpath/java/awt/geom/RectangularShape.java new file mode 100644 index 000000000..68bc451cc --- /dev/null +++ b/libjava/classpath/java/awt/geom/RectangularShape.java @@ -0,0 +1,382 @@ +/* RectangularShape.java -- a rectangular frame for several generic shapes + Copyright (C) 2000, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.geom; + +import java.awt.Rectangle; +import java.awt.Shape; + +/** + * This class provides a generic framework, and several helper methods, for + * subclasses which represent geometric objects inside a rectangular frame. + * This does not specify any geometry except for the bounding box. + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @see Arc2D + * @see Ellipse2D + * @see Rectangle2D + * @see RoundRectangle2D + * @status updated to 1.4 + */ +public abstract class RectangularShape implements Shape, Cloneable +{ + /** + * Default constructor. + */ + protected RectangularShape() + { + } + + /** + * Get the x coordinate of the upper-left corner of the framing rectangle. + * + * @return the x coordinate + */ + public abstract double getX(); + + /** + * Get the y coordinate of the upper-left corner of the framing rectangle. + * + * @return the y coordinate + */ + public abstract double getY(); + + /** + * Get the width of the framing rectangle. + * + * @return the width + */ + public abstract double getWidth(); + + /** + * Get the height of the framing rectangle. + * + * @return the height + */ + public abstract double getHeight(); + + /** + * Get the minimum x coordinate in the frame. This is misnamed, or else + * Sun has a bug, because the implementation returns getX() even when + * getWidth() is negative. + * + * @return the minimum x coordinate + */ + public double getMinX() + { + return getX(); + } + + /** + * Get the minimum y coordinate in the frame. This is misnamed, or else + * Sun has a bug, because the implementation returns getY() even when + * getHeight() is negative. + * + * @return the minimum y coordinate + */ + public double getMinY() + { + return getY(); + } + + /** + * Get the maximum x coordinate in the frame. This is misnamed, or else + * Sun has a bug, because the implementation returns getX()+getWidth() even + * when getWidth() is negative. + * + * @return the maximum x coordinate + */ + public double getMaxX() + { + return getX() + getWidth(); + } + + /** + * Get the maximum y coordinate in the frame. This is misnamed, or else + * Sun has a bug, because the implementation returns getY()+getHeight() even + * when getHeight() is negative. + * + * @return the maximum y coordinate + */ + public double getMaxY() + { + return getY() + getHeight(); + } + + /** + * Return the x coordinate of the center point of the framing rectangle. + * + * @return the central x coordinate + */ + public double getCenterX() + { + return getX() + getWidth() / 2; + } + + /** + * Return the y coordinate of the center point of the framing rectangle. + * + * @return the central y coordinate + */ + public double getCenterY() + { + return getY() + getHeight() / 2; + } + + /** + * Return the frame around this object. Note that this may be a looser + * bounding box than getBounds2D. + * + * @return the frame, in double precision + * @see #setFrame(double, double, double, double) + */ + public Rectangle2D getFrame() + { + return new Rectangle2D.Double(getX(), getY(), getWidth(), getHeight()); + } + + /** + * Test if the shape is empty, meaning that no points are inside it. + * + * @return true if the shape is empty + */ + public abstract boolean isEmpty(); + + /** + * Set the framing rectangle of this shape to the given coordinate and size. + * + * @param x the new x coordinate + * @param y the new y coordinate + * @param w the new width + * @param h the new height + * @see #getFrame() + */ + public abstract void setFrame(double x, double y, double w, double h); + + /** + * Set the framing rectangle of this shape to the given coordinate and size. + * + * @param p the new point + * @param d the new dimension + * @throws NullPointerException if p or d is null + * @see #getFrame() + */ + public void setFrame(Point2D p, Dimension2D d) + { + setFrame(p.getX(), p.getY(), d.getWidth(), d.getHeight()); + } + + /** + * Set the framing rectangle of this shape to the given rectangle. + * + * @param r the new framing rectangle + * @throws NullPointerException if r is null + * @see #getFrame() + */ + public void setFrame(Rectangle2D r) + { + setFrame(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Set the framing rectangle of this shape using two points on a diagonal. + * The area will be positive. + * + * @param x1 the first x coordinate + * @param y1 the first y coordinate + * @param x2 the second x coordinate + * @param y2 the second y coordinate + */ + public void setFrameFromDiagonal(double x1, double y1, double x2, double y2) + { + if (x1 > x2) + { + double t = x2; + x2 = x1; + x1 = t; + } + if (y1 > y2) + { + double t = y2; + y2 = y1; + y1 = t; + } + setFrame(x1, y1, x2 - x1, y2 - y1); + } + + /** + * Set the framing rectangle of this shape using two points on a diagonal. + * The area will be positive. + * + * @param p1 the first point + * @param p2 the second point + * @throws NullPointerException if either point is null + */ + public void setFrameFromDiagonal(Point2D p1, Point2D p2) + { + setFrameFromDiagonal(p1.getX(), p1.getY(), p2.getX(), p2.getY()); + } + + /** + * Set the framing rectangle of this shape using the center of the frame, + * and one of the four corners. The area will be positive. + * + * @param centerX the x coordinate at the center + * @param centerY the y coordinate at the center + * @param cornerX the x coordinate at a corner + * @param cornerY the y coordinate at a corner + */ + public void setFrameFromCenter(double centerX, double centerY, + double cornerX, double cornerY) + { + double halfw = Math.abs(cornerX - centerX); + double halfh = Math.abs(cornerY - centerY); + setFrame(centerX - halfw, centerY - halfh, halfw + halfw, halfh + halfh); + } + + /** + * Set the framing rectangle of this shape using the center of the frame, + * and one of the four corners. The area will be positive. + * + * @param center the center point + * @param corner a corner point + * @throws NullPointerException if either point is null + */ + public void setFrameFromCenter(Point2D center, Point2D corner) + { + setFrameFromCenter(center.getX(), center.getY(), + corner.getX(), corner.getY()); + } + + /** + * Tests if a point is inside the boundary of the shape. + * + * @param p the point to test + * @return true if the point is inside the shape + * @throws NullPointerException if p is null + * @see #contains(double, double) + */ + public boolean contains(Point2D p) + { + return contains(p.getX(), p.getY()); + } + + /** + * Tests if a rectangle and this shape share common internal points. + * + * @param r the rectangle to test + * @return true if the rectangle intersects this shpae + * @throws NullPointerException if r is null + * @see #intersects(double, double, double, double) + */ + public boolean intersects(Rectangle2D r) + { + return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Tests if the shape completely contains the given rectangle. + * + * @param r the rectangle to test + * @return true if r is contained in this shape + * @throws NullPointerException if r is null + * @see #contains(double, double, double, double) + */ + public boolean contains(Rectangle2D r) + { + return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + } + + /** + * Returns a bounding box for this shape, in integer format. Notice that you + * may get a tighter bound with getBounds2D. + * + * @return a bounding box + */ + public Rectangle getBounds() + { + double x = getX(); + double y = getY(); + double maxx = Math.ceil(x + getWidth()); + double maxy = Math.ceil(y + getHeight()); + x = Math.floor(x); + y = Math.floor(y); + return new Rectangle((int) x, (int) y, (int) (maxx - x), (int) (maxy - y)); + } + + /** + * Return an iterator along the shape boundary. If the optional transform + * is provided, the iterator is transformed accordingly. The path is + * flattened until all segments differ from the curve by at most the value + * of the flatness parameter, within the limits of the default interpolation + * recursion limit of 1024 segments between actual points. Each call + * returns a new object, independent from others in use. The result is + * threadsafe if and only if the iterator returned by + * {@link #getPathIterator(AffineTransform)} is as well. + * + * @param at an optional transform to apply to the iterator + * @param flatness the desired flatness + * @return a new iterator over the boundary + * @throws IllegalArgumentException if flatness is invalid + * @since 1.2 + */ + public PathIterator getPathIterator(AffineTransform at, double flatness) + { + return new FlatteningPathIterator(getPathIterator(at), flatness); + } + + /** + * Create a new shape of the same run-time type with the same contents as + * this one. + * + * @return the clone + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } +} // class RectangularShape diff --git a/libjava/classpath/java/awt/geom/RoundRectangle2D.java b/libjava/classpath/java/awt/geom/RoundRectangle2D.java new file mode 100644 index 000000000..19a7b4237 --- /dev/null +++ b/libjava/classpath/java/awt/geom/RoundRectangle2D.java @@ -0,0 +1,584 @@ +/* RoundRectangle2D.java -- represents a rectangle with rounded corners + Copyright (C) 2000, 2002, 2003, 2004, 2006, Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.geom; + + + +/** This class implements a rectangle with rounded corners. + * @author Tom Tromey (tromey@cygnus.com) + * @date December 3, 2000 + */ +public abstract class RoundRectangle2D extends RectangularShape +{ + /** + * Return the arc height of this round rectangle. The arc height and width + * control the roundness of the corners of the rectangle. + * + * @return The arc height. + * + * @see #getArcWidth() + */ + public abstract double getArcHeight(); + + /** + * Return the arc width of this round rectangle. The arc width and height + * control the roundness of the corners of the rectangle. + * + * @return The arc width. + * + * @see #getArcHeight() + */ + public abstract double getArcWidth(); + + /** + * Set the values of this round rectangle. + * + * @param x The x coordinate + * @param y The y coordinate + * @param w The width + * @param h The height + * @param arcWidth The arc width + * @param arcHeight The arc height + */ + public abstract void setRoundRect(double x, double y, double w, double h, + double arcWidth, double arcHeight); + + /** + * Create a RoundRectangle2D. This is protected because this class + * is abstract and cannot be instantiated. + */ + protected RoundRectangle2D() + { + } + + /** + * Return true if this object contains the specified point. + * @param x The x coordinate + * @param y The y coordinate + */ + public boolean contains(double x, double y) + { + double mx = getX(); + double mw = getWidth(); + if (x < mx || x >= mx + mw) + return false; + double my = getY(); + double mh = getHeight(); + if (y < my || y >= my + mh) + return false; + + // Now check to see if the point is in range of an arc. + double dy = Math.min(Math.abs(my - y), Math.abs(my + mh - y)); + double dx = Math.min(Math.abs(mx - x), Math.abs(mx + mw - x)); + + // The arc dimensions are that of the corresponding ellipse + // thus a 90 degree segment is half of that. + double aw = getArcWidth() / 2.0; + double ah = getArcHeight() / 2.0; + if (dx > aw || dy > ah) + return true; + + // At this point DX represents the distance from the nearest edge + // of the rectangle. But we want to transform it to represent the + // scaled distance from the center of the ellipse that forms the + // arc. Hence this code: + dy = (ah - dy) / ah; + dx = (aw - dx) / aw; + + return dx * dx + dy * dy <= 1.0; + } + + /** + * Return true if this object contains the specified rectangle + * @param x The x coordinate + * @param y The y coordinate + * @param w The width + * @param h The height + */ + public boolean contains(double x, double y, double w, double h) + { + // We have to check all four points here (for ordinary rectangles + // we can just check opposing corners). + return (contains(x, y) && contains(x, y + h) && contains(x + w, y + h) + && contains(x + w, y)); + } + + /** + * Return a new path iterator which iterates over this rectangle. + * + * @param at An affine transform to apply to the object + */ + public PathIterator getPathIterator(final AffineTransform at) + { + double arcW = Math.min(getArcWidth(), getWidth()); + double arcH = Math.min(getArcHeight(), getHeight()); + + // check for special cases... + if (arcW <= 0 || arcH <= 0) + { + Rectangle2D r = new Rectangle2D.Double(getX(), getY(), getWidth(), + getHeight()); + return r.getPathIterator(at); + } + else if (arcW >= getWidth() && arcH >= getHeight()) + { + Ellipse2D e = new Ellipse2D.Double(getX(), getY(), getWidth(), + getHeight()); + return e.getPathIterator(at); + } + + // otherwise return the standard case... + return new PathIterator() + { + double x = getX(); + double y = getY(); + double w = getWidth(); + double h = getHeight(); + double arcW = Math.min(getArcWidth(), w); + double arcH = Math.min(getArcHeight(), h); + Arc2D.Double arc = new Arc2D.Double(); + PathIterator corner; + int step = -1; + + public int currentSegment(double[] coords) + { + if (corner != null) // steps 1, 3, 5 and 7 + { + int r = corner.currentSegment(coords); + if (r == SEG_MOVETO) + r = SEG_LINETO; + return r; + } + if (step == -1) + { + // move to the start position + coords[0] = x + w - arcW / 2; + coords[1] = y; + } + else if (step == 0) + { + // top line + coords[0] = x + arcW / 2; + coords[1] = y; + } + else if (step == 2) + { + // left line + coords[0] = x; + coords[1] = y + h - arcH / 2; + } + else if (step == 4) + { + // bottom line + coords[0] = x + w - arcW / 2; + coords[1] = y + h; + } + else if (step == 6) + { + // right line + coords[0] = x + w; + coords[1] = y + arcH / 2; + } + if (at != null) + at.transform(coords, 0, coords, 0, 1); + return step == -1 ? SEG_MOVETO : SEG_LINETO; + } + + public int currentSegment(float[] coords) { + if (corner != null) // steps 1, 3, 5 and 7 + { + int r = corner.currentSegment(coords); + if (r == SEG_MOVETO) + r = SEG_LINETO; + return r; + } + if (step == -1) + { + // move to the start position + coords[0] = (float) (x + w - arcW / 2); + coords[1] = (float) y; + } + else if (step == 0) + { + // top line + coords[0] = (float) (x + arcW / 2); + coords[1] = (float) y; + } + else if (step == 2) + { + // left line + coords[0] = (float) x; + coords[1] = (float) (y + h - arcH / 2); + } + else if (step == 4) + { + // bottom line + coords[0] = (float) (x + w - arcW / 2); + coords[1] = (float) (y + h); + } + else if (step == 6) + { + // right line + coords[0] = (float) (x + w); + coords[1] = (float) (y + arcH / 2); + } + if (at != null) + at.transform(coords, 0, coords, 0, 1); + return step == -1 ? SEG_MOVETO : SEG_LINETO; + } + + public int getWindingRule() { + return WIND_NON_ZERO; + } + + public boolean isDone() { + return step >= 8; + } + + public void next() + { + if (corner != null) + { + corner.next(); + if (corner.isDone()) + { + corner = null; + step++; + } + } + else + { + step++; + if (step == 1) + { + // create top left corner + arc.setArc(x, y, arcW, arcH, 90, 90, Arc2D.OPEN); + corner = arc.getPathIterator(at); + } + else if (step == 3) + { + // create bottom left corner + arc.setArc(x, y + h - arcH, arcW, arcH, 180, 90, + Arc2D.OPEN); + corner = arc.getPathIterator(at); + } + else if (step == 5) + { + // create bottom right corner + arc.setArc(x + w - arcW, y + h - arcH, arcW, arcH, 270, 90, + Arc2D.OPEN); + corner = arc.getPathIterator(at); + } + else if (step == 7) + { + // create top right corner + arc.setArc(x + w - arcW, y, arcW, arcH, 0, 90, Arc2D.OPEN); + corner = arc.getPathIterator(at); + } + } + } + }; + } + + /** + * Return true if the given rectangle intersects this shape. + * @param x The x coordinate + * @param y The y coordinate + * @param w The width + * @param h The height + */ + public boolean intersects(double x, double y, double w, double h) + { + // Check if any corner is within the rectangle + return (contains(x, y) || contains(x, y + h) || contains(x + w, y + h) + || contains(x + w, y)); + } + + /** + * Set the boundary of this round rectangle. + * @param x The x coordinate + * @param y The y coordinate + * @param w The width + * @param h The height + */ + public void setFrame(double x, double y, double w, double h) + { + // This is a bit lame. + setRoundRect(x, y, w, h, getArcWidth(), getArcHeight()); + } + + /** + * Set the values of this round rectangle to be the same as those + * of the argument. + * @param rr The round rectangle to copy + */ + public void setRoundRect(RoundRectangle2D rr) + { + setRoundRect(rr.getX(), rr.getY(), rr.getWidth(), rr.getHeight(), + rr.getArcWidth(), rr.getArcHeight()); + } + + /** + * A subclass of RoundRectangle which keeps its parameters as + * doubles. + */ + public static class Double extends RoundRectangle2D + { + /** The height of the corner arc. */ + public double archeight; + + /** The width of the corner arc. */ + public double arcwidth; + + /** The x coordinate of this object. */ + public double x; + + /** The y coordinate of this object. */ + public double y; + + /** The width of this object. */ + public double width; + + /** The height of this object. */ + public double height; + + /** + * Construct a new instance, with all parameters set to 0. + */ + public Double() + { + } + + /** + * Construct a new instance with the given arguments. + * @param x The x coordinate + * @param y The y coordinate + * @param w The width + * @param h The height + * @param arcWidth The arc width + * @param arcHeight The arc height + */ + public Double(double x, double y, double w, double h, double arcWidth, + double arcHeight) + { + this.x = x; + this.y = y; + this.width = w; + this.height = h; + this.arcwidth = arcWidth; + this.archeight = arcHeight; + } + + public double getArcHeight() + { + return archeight; + } + + public double getArcWidth() + { + return arcwidth; + } + + public Rectangle2D getBounds2D() + { + return new Rectangle2D.Double(x, y, width, height); + } + + public double getX() + { + return x; + } + + public double getY() + { + return y; + } + + public double getWidth() + { + return width; + } + + public double getHeight() + { + return height; + } + + public boolean isEmpty() + { + return width <= 0 || height <= 0; + } + + public void setRoundRect(double x, double y, double w, double h, + double arcWidth, double arcHeight) + { + this.x = x; + this.y = y; + this.width = w; + this.height = h; + this.arcwidth = arcWidth; + this.archeight = arcHeight; + } + } // class Double + + /** + * A subclass of RoundRectangle which keeps its parameters as + * floats. + */ + public static class Float extends RoundRectangle2D + { + /** The height of the corner arc. */ + public float archeight; + + /** The width of the corner arc. */ + public float arcwidth; + + /** The x coordinate of this object. */ + public float x; + + /** The y coordinate of this object. */ + public float y; + + /** The width of this object. */ + public float width; + + /** The height of this object. */ + public float height; + + /** + * Construct a new instance, with all parameters set to 0. + */ + public Float() + { + } + + /** + * Construct a new instance with the given arguments. + * @param x The x coordinate + * @param y The y coordinate + * @param w The width + * @param h The height + * @param arcWidth The arc width + * @param arcHeight The arc height + */ + public Float(float x, float y, float w, float h, float arcWidth, + float arcHeight) + { + this.x = x; + this.y = y; + this.width = w; + this.height = h; + this.arcwidth = arcWidth; + this.archeight = arcHeight; + } + + public double getArcHeight() + { + return archeight; + } + + public double getArcWidth() + { + return arcwidth; + } + + public Rectangle2D getBounds2D() + { + return new Rectangle2D.Float(x, y, width, height); + } + + public double getX() + { + return x; + } + + public double getY() + { + return y; + } + + public double getWidth() + { + return width; + } + + public double getHeight() + { + return height; + } + + public boolean isEmpty() + { + return width <= 0 || height <= 0; + } + + /** + * Sets the dimensions for this rounded rectangle. + * + * @param x the x-coordinate of the top left corner. + * @param y the y-coordinate of the top left corner. + * @param w the width of the rectangle. + * @param h the height of the rectangle. + * @param arcWidth the arc width. + * @param arcHeight the arc height. + * + * @see #setRoundRect(double, double, double, double, double, double) + */ + public void setRoundRect(float x, float y, float w, float h, + float arcWidth, float arcHeight) + { + this.x = x; + this.y = y; + this.width = w; + this.height = h; + this.arcwidth = arcWidth; + this.archeight = arcHeight; + } + + public void setRoundRect(double x, double y, double w, double h, + double arcWidth, double arcHeight) + { + this.x = (float) x; + this.y = (float) y; + this.width = (float) w; + this.height = (float) h; + this.arcwidth = (float) arcWidth; + this.archeight = (float) arcHeight; + } + } // class Float +} // class RoundRectangle2D diff --git a/libjava/classpath/java/awt/geom/doc-files/Area-1.png b/libjava/classpath/java/awt/geom/doc-files/Area-1.png Binary files differnew file mode 100644 index 000000000..44650f2d8 --- /dev/null +++ b/libjava/classpath/java/awt/geom/doc-files/Area-1.png diff --git a/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-1.png b/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-1.png Binary files differnew file mode 100644 index 000000000..1784509be --- /dev/null +++ b/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-1.png diff --git a/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-2.png b/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-2.png Binary files differnew file mode 100644 index 000000000..1ddae9fc8 --- /dev/null +++ b/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-2.png diff --git a/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-3.png b/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-3.png Binary files differnew file mode 100644 index 000000000..b200dad37 --- /dev/null +++ b/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-3.png diff --git a/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-4.png b/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-4.png Binary files differnew file mode 100644 index 000000000..e57ffdc5c --- /dev/null +++ b/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-4.png diff --git a/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-5.png b/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-5.png Binary files differnew file mode 100644 index 000000000..701ab138f --- /dev/null +++ b/libjava/classpath/java/awt/geom/doc-files/CubicCurve2D-5.png diff --git a/libjava/classpath/java/awt/geom/doc-files/Ellipse-1.png b/libjava/classpath/java/awt/geom/doc-files/Ellipse-1.png Binary files differnew file mode 100644 index 000000000..8317db661 --- /dev/null +++ b/libjava/classpath/java/awt/geom/doc-files/Ellipse-1.png diff --git a/libjava/classpath/java/awt/geom/doc-files/FlatteningPathIterator-1.html b/libjava/classpath/java/awt/geom/doc-files/FlatteningPathIterator-1.html new file mode 100644 index 000000000..5a52d693e --- /dev/null +++ b/libjava/classpath/java/awt/geom/doc-files/FlatteningPathIterator-1.html @@ -0,0 +1,481 @@ +<?xml version="1.0" encoding="US-ASCII"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <title>The GNU Implementation of java.awt.geom.FlatteningPathIterator</title> + <meta name="author" content="Sascha Brawer" /> + <style type="text/css"><!-- + td { white-space: nowrap; } + li { margin: 2mm 0; } + --></style> +</head> +<body> + +<h1>The GNU Implementation of FlatteningPathIterator</h1> + +<p><i><a href="http://www.dandelis.ch/people/brawer/">Sascha +Brawer</a>, November 2003</i></p> + +<p>This document describes the GNU implementation of the class +<code>java.awt.geom.FlatteningPathIterator</code>. It does +<em>not</em> describe how a programmer should use this class; please +refer to the generated API documentation for this purpose. Instead, it +is intended for maintenance programmers who want to understand the +implementation, for example because they want to extend the class or +fix a bug.</p> + + +<h2>Data Structures</h2> + +<p>The algorithm uses a stack. Its allocation is delayed to the time +when the source path iterator actually returns the first curved +segment (either <code>SEG_QUADTO</code> or <code>SEG_CUBICTO</code>). +If the input path does not contain any curved segments, the value of +the <code>stack</code> variable stays <code>null</code>. In this quite +common case, the memory consumption is minimal.</p> + +<dl><dt><code>stack</code></dt><dd>The variable <code>stack</code> is +a <code>double</code> array that holds the start, control and end +points of individual sub-segments.</dd> + +<dt><code>recLevel</code></dt><dd>The variable <code>recLevel</code> +holds how many recursive sub-divisions were needed to calculate a +segment. The original curve has recursion level 0. For each +sub-division, the corresponding recursion level is increased by +one.</dd> + +<dt><code>stackSize</code></dt><dd>Finally, the variable +<code>stackSize</code> indicates how many sub-segments are stored on +the stack.</dd></dl> + +<h2>Algorithm</h2> + +<p>The implementation separately processes each segment that the +base iterator returns.</p> + +<p>In the case of <code>SEG_CLOSE</code>, +<code>SEG_MOVETO</code> and <code>SEG_LINETO</code> segments, the +implementation simply hands the segment to the consumer, without actually +doing anything.</p> + +<p>Any <code>SEG_QUADTO</code> and <code>SEG_CUBICTO</code> segments +need to be flattened. Flattening is performed with a fixed-sized +stack, holding the coordinates of subdivided segments. When the base +iterator returns a <code>SEG_QUADTO</code> and +<code>SEG_CUBICTO</code> segments, it is recursively flattened as +follows:</p> + +<ol><li>Intialization: Allocate memory for the stack (unless a +sufficiently large stack has been allocated previously). Push the +original quadratic or cubic curve onto the stack. Mark that segment as +having a <code>recLevel</code> of zero.</li> + +<li>If the stack is empty, flattening the segment is complete, +and the next segment is fetched from the base iterator.</li> + +<li>If the stack is not empty, pop a curve segment from the +stack. + + <ul><li>If its <code>recLevel</code> exceeds the recursion limit, + hand the current segment to the consumer.</li> + + <li>Calculate the squared flatness of the segment. If it smaller + than <code>flatnessSq</code>, hand the current segment to the + consumer.</li> + + <li>Otherwise, split the segment in two halves. Push the right + half onto the stack. Then, push the left half onto the stack. + Continue with step two.</li></ul></li> +</ol> + +<p>The implementation is slightly complicated by the fact that +consumers <em>pull</em> the flattened segments from the +<code>FlatteningPathIterator</code>. This means that we actually +cannot “hand the curent segment over to the consumer.” +But the algorithm is easier to understand if one assumes a +<em>push</em> paradigm.</p> + + +<h2>Example</h2> + +<p>The following example shows how a +<code>FlatteningPathIterator</code> processes a +<code>SEG_QUADTO</code> segment. It is (arbitrarily) assumed that the +recursion limit was set to 2.</p> + +<blockquote> +<table border="1" cellspacing="0" cellpadding="8"> + <tr align="center" valign="baseline"> + <th></th><th>A</th><th>B</th><th>C</th> + <th>D</th><th>E</th><th>F</th><th>G</th><th>H</th> + </tr> + <tr align="center" valign="baseline"> + <th><code>stack[0]</code></th> + <td>—</td> + <td>—</td> + <td><i>S<sub>ll</sub>.x</i></td> + <td>—</td> + <td>—</td> + <td>—</td> + <td>—</td> + <td>—</td> + </tr> + <tr align="center" valign="baseline"> + <th><code>stack[1]</code></th> + <td>—</td> + <td>—</td> + <td><i>S<sub>ll</sub>.y</i></td> + <td>—</td> + <td>—</td> + <td>—</td> + <td>—</td> + <td>—</td> + </tr> + <tr align="center" valign="baseline"> + <th><code>stack[2]</code></th> + <td>—</td> + <td>—</td> + <td><i>C<sub>ll</sub>.x</i></td> + <td>—</td> + <td>—</td> + <td>—</td> + <td>—</td> + <td>—</td> + </tr> + <tr align="center" valign="baseline"> + <th><code>stack[3]</code></th> + <td>—</td> + <td>—</td> + <td><i>C<sub>ll</sub>.y</i></td> + <td>—</td> + <td>—</td> + <td>—</td> + <td>—</td> + <td>—</td> + </tr> + <tr align="center" valign="baseline"> + <th><code>stack[4]</code></th> + <td>—</td> + <td><i>S<sub>l</sub>.x</i></td> + <td><i>E<sub>ll</sub>.x</i> + = <i>S<sub>lr</sub>.x</i></td> + <td><i>S<sub>lr</sub>.x</i></td> + <td>—</td> + <td><i>S<sub>rl</sub>.x</i></td> + <td>—</td> + <td>—</td> + </tr> + <tr align="center" valign="baseline"> + <th><code>stack[5]</code></th> + <td>—</td> + <td><i>S<sub>l</sub>.y</i></td> + <td><i>E<sub>ll</sub>.x</i> + = <i>S<sub>lr</sub>.y</i></td> + <td><i>S<sub>lr</sub>.y</i></td> + <td>—</td> + <td><i>S<sub>rl</sub>.y</i></td> + <td>—</td> + <td>—</td> + </tr> + <tr align="center" valign="baseline"> + <th><code>stack[6]</code></th> + <td>—</td> + <td><i>C<sub>l</sub>.x</i></td> + <td><i>C<sub>lr</sub>.x</i></td> + <td><i>C<sub>lr</sub>.x</i></td> + <td>—</td> + <td><i>C<sub>rl</sub>.x</i></td> + <td>—</td> + <td>—</td> + </tr> + <tr align="center" valign="baseline"> + <th><code>stack[7]</code></th> + <td>—</td> + <td><i>C<sub>l</sub>.y</i></td> + <td><i>C<sub>lr</sub>.y</i></td> + <td><i>C<sub>lr</sub>.y</i></td> + <td>—</td> + <td><i>C<sub>rl</sub>.y</i></td> + <td>—</td> + <td>—</td> + </tr> + <tr align="center" valign="baseline"> + <th><code>stack[8]</code></th> + <td><i>S.x</i></td> + <td><i>E<sub>l</sub>.x</i> + = <i>S<sub>r</sub>.x</i></td> + <td><i>E<sub>lr</sub>.x</i> + = <i>S<sub>r</sub>.x</i></td> + <td><i>E<sub>lr</sub>.x</i> + = <i>S<sub>r</sub>.x</i></td> + <td><i>S<sub>r</sub>.x</i></td> + <td><i>E<sub>rl</sub>.x</i> + = <i>S<sub>rr</sub>.x</i></td> + <td><i>S<sub>rr</sub>.x</i></td> + <td>—</td> + </tr> + <tr align="center" valign="baseline"> + <th><code>stack[9]</code></th> + <td><i>S.y</i></td> + <td><i>E<sub>l</sub>.y</i> + = <i>S<sub>r</sub>.y</i></td> + <td><i>E<sub>lr</sub>.y</i> + = <i>S<sub>r</sub>.y</i></td> + <td><i>E<sub>lr</sub>.y</i> + = <i>S<sub>r</sub>.y</i></td> + <td><i>S<sub>r</sub>.y</i></td> + <td><i>E<sub>rl</sub>.y</i> + = <i>S<sub>rr</sub>.y</i></td> + <td><i>S<sub>rr</sub>.y</i></td> + <td>—</td> + </tr> + <tr align="center" valign="baseline"> + <th><code>stack[10]</code></th> + <td><i>C.x</i></td> + <td><i>C<sub>r</sub>.x</i></td> + <td><i>C<sub>r</sub>.x</i></td> + <td><i>C<sub>r</sub>.x</i></td> + <td><i>C<sub>r</sub>.x</i></td> + <td><i>C<sub>rr</sub>.x</i></td> + <td><i>C<sub>rr</sub>.x</i></td> + <td>—</td> + </tr> + <tr align="center" valign="baseline"> + <th><code>stack[11]</code></th> + <td><i>C.y</i></td> + <td><i>C<sub>r</sub>.y</i></td> + <td><i>C<sub>r</sub>.y</i></td> + <td><i>C<sub>r</sub>.y</i></td> + <td><i>C<sub>r</sub>.y</i></td> + <td><i>C<sub>rr</sub>.y</i></td> + <td><i>C<sub>rr</sub>.y</i></td> + <td>—</td> + </tr> + <tr align="center" valign="baseline"> + <th><code>stack[12]</code></th> + <td><i>E.x</i></td> + <td><i>E<sub>r</sub>.x</i></td> + <td><i>E<sub>r</sub>.x</i></td> + <td><i>E<sub>r</sub>.x</i></td> + <td><i>E<sub>r</sub>.x</i></td> + <td><i>E<sub>rr</sub>.x</i></td> + <td><i>E<sub>rr</sub>.x</i></td> + <td>—</td> + </tr> + <tr align="center" valign="baseline"> + <th><code>stack[13]</code></th> + <td><i>E.y</i></td> + <td><i>E<sub>r</sub>.y</i></td> + <td><i>E<sub>r</sub>.y</i></td> + <td><i>E<sub>r</sub>.y</i></td> + <td><i>E<sub>r</sub>.y</i></td> + <td><i>E<sub>rr</sub>.y</i></td> + <td><i>E<sub>rr</sub>.x</i></td> + <td>—</td> + </tr> + <tr align="center" valign="baseline"> + <th><code>stackSize</code></th> + <td>1</td> + <td>2</td> + <td>3</td> + <td>2</td> + <td>1</td> + <td>2</td> + <td>1</td> + <td>0</td> + </tr> + <tr align="center" valign="baseline"> + <th><code>recLevel[2]</code></th> + <td>—</td> + <td>—</td> + <td>2</td> + <td>—</td> + <td>—</td> + <td>—</td> + <td>—</td> + <td>—</td> + </tr> + <tr align="center" valign="baseline"> + <th><code>recLevel[1]</code></th> + <td>—</td> + <td>1</td> + <td>2</td> + <td>2</td> + <td>—</td> + <td>2</td> + <td>—</td> + <td>—</td> + </tr> + <tr align="center" valign="baseline"> + <th><code>recLevel[0]</code></th> + <td>0</td> + <td>1</td> + <td>1</td> + <td>1</td> + <td>1</td> + <td>2</td> + <td>2</td> + <td>—</td> + </tr> + </table> +</blockquote> + +<ol> + +<li>The data structures are initialized as follows. + +<ul><li>The segment’s end point <i>E</i>, control point +<i>C</i>, and start point <i>S</i> are pushed onto the stack.</li> + + <li>Currently, the curve in the stack would be approximated by one + single straight line segment (<i>S</i> – <i>E</i>). + Therefore, <code>stackSize</code> is set to 1.</li> + + <li>This single straight line segment is approximating the original + curve, which can be seen as the result of zero recursive + splits. Therefore, <code>recLevel[0]</code> is set to + zero.</li></ul> + +Column A shows the state after the initialization step.</li> + +<li>The algorithm proceeds by taking the topmost curve segment +(<i>S</i> – <i>C</i> – <i>E</i>) from the stack. + + <ul><li>The recursion level of this segment (stored in + <code>recLevel[0]</code>) is zero, which is smaller than + the limit 2.</li> + + <li>The method <code>java.awt.geom.QuadCurve2D.getFlatnessSq</code> + is called to calculate the squared flatness.</li> + + <li>For the sake of argument, we assume that the squared flatness is + exceeding the threshold stored in <code>flatnessSq</code>. Thus, the + curve segment <i>S</i> – <i>C</i> – <i>E</i> gets + subdivided into a left and a right half, namely + <i>S<sub>l</sub></i> – <i>C<sub>l</sub></i> – + <i>E<sub>l</sub></i> and <i>S<sub>r</sub></i> – + <i>C<sub>r</sub></i> – <i>E<sub>r</sub></i>. Both halves are + pushed onto the stack, so the left half is now on top. + + <br /> <br />The left half starts at the same point + as the original curve, so <i>S<sub>l</sub></i> has the same + coordinates as <i>S</i>. Similarly, the end point of the right + half and of the original curve are identical + (<i>E<sub>r</sub></i> = <i>E</i>). More interestingly, the left + half ends where the right half starts. Because + <i>E<sub>l</sub></i> = <i>S<sub>r</sub></i>, their coordinates need + to be stored only once, which amounts to saving 16 bytes (two + <code>double</code> values) for each iteration.</li></ul> + +Column B shows the state after the first iteration.</li> + +<li>Again, the topmost curve segment (<i>S<sub>l</sub></i> +– <i>C<sub>l</sub></i> – <i>E<sub>l</sub></i>) is +taken from the stack. + + <ul><li>The recursion level of this segment (stored in + <code>recLevel[1]</code>) is 1, which is smaller than + the limit 2.</li> + + <li>The method <code>java.awt.geom.QuadCurve2D.getFlatnessSq</code> + is called to calculate the squared flatness.</li> + + <li>Assuming that the segment is still not considered + flat enough, it gets subdivided into a left + (<i>S<sub>ll</sub></i> – <i>C<sub>ll</sub></i> – + <i>E<sub>ll</sub></i>) and a right (<i>S<sub>lr</sub></i> + – <i>C<sub>lr</sub></i> – <i>E<sub>lr</sub></i>) + half.</li></ul> + +Column C shows the state after the second iteration.</li> + +<li>The topmost curve segment (<i>S<sub>ll</sub></i> – +<i>C<sub>ll</sub></i> – <i>E<sub>ll</sub></i>) is popped from +the stack. + + <ul><li>The recursion level of this segment (stored in + <code>recLevel[2]</code>) is 2, which is <em>not</em> smaller than + the limit 2. Therefore, a <code>SEG_LINETO</code> (from + <i>S<sub>ll</sub></i> to <i>E<sub>ll</sub></i>) is passed to the + consumer.</li></ul> + + The new state is shown in column D.</li> + + +<li>The topmost curve segment (<i>S<sub>lr</sub></i> – +<i>C<sub>lr</sub></i> – <i>E<sub>lr</sub></i>) is popped from +the stack. + + <ul><li>The recursion level of this segment (stored in + <code>recLevel[1]</code>) is 2, which is <em>not</em> smaller than + the limit 2. Therefore, a <code>SEG_LINETO</code> (from + <i>S<sub>lr</sub></i> to <i>E<sub>lr</sub></i>) is passed to the + consumer.</li></ul> + + The new state is shown in column E.</li> + +<li>The algorithm proceeds by taking the topmost curve segment +(<i>S<sub>r</sub></i> – <i>C<sub>r</sub></i> – +<i>E<sub>r</sub></i>) from the stack. + + <ul><li>The recursion level of this segment (stored in + <code>recLevel[0]</code>) is 1, which is smaller than + the limit 2.</li> + + <li>The method <code>java.awt.geom.QuadCurve2D.getFlatnessSq</code> + is called to calculate the squared flatness.</li> + + <li>For the sake of argument, we again assume that the squared + flatness is exceeding the threshold stored in + <code>flatnessSq</code>. Thus, the curve segment + (<i>S<sub>r</sub></i> – <i>C<sub>r</sub></i> – + <i>E<sub>r</sub></i>) is subdivided into a left and a right half, + namely + <i>S<sub>rl</sub></i> – <i>C<sub>rl</sub></i> – + <i>E<sub>rl</sub></i> and <i>S<sub>rr</sub></i> – + <i>C<sub>rr</sub></i> – <i>E<sub>rr</sub></i>. Both halves + are pushed onto the stack.</li></ul> + + The new state is shown in column F.</li> + +<li>The topmost curve segment (<i>S<sub>rl</sub></i> – +<i>C<sub>rl</sub></i> – <i>E<sub>rl</sub></i>) is popped from +the stack. + + <ul><li>The recursion level of this segment (stored in + <code>recLevel[2]</code>) is 2, which is <em>not</em> smaller than + the limit 2. Therefore, a <code>SEG_LINETO</code> (from + <i>S<sub>rl</sub></i> to <i>E<sub>rl</sub></i>) is passed to the + consumer.</li></ul> + + The new state is shown in column G.</li> + +<li>The topmost curve segment (<i>S<sub>rr</sub></i> – +<i>C<sub>rr</sub></i> – <i>E<sub>rr</sub></i>) is popped from +the stack. + + <ul><li>The recursion level of this segment (stored in + <code>recLevel[2]</code>) is 2, which is <em>not</em> smaller than + the limit 2. Therefore, a <code>SEG_LINETO</code> (from + <i>S<sub>rr</sub></i> to <i>E<sub>rr</sub></i>) is passed to the + consumer.</li></ul> + + The new state is shown in column H.</li> + +<li>The stack is now empty. The FlatteningPathIterator will fetch the +next segment from the base iterator, and process it.</li> + +</ol> + +<p>In order to split the most recently pushed segment, the +<code>subdivideQuadratic()</code> method passes <code>stack</code> +directly to +<code>QuadCurve2D.subdivide(double[],int,double[],int,double[],int)</code>. +Because the stack grows towards the beginning of the array, no data +needs to be copied around: <code>subdivide</code> will directly store +the result into the stack, which will have the contents shown to the +right.</p> + +</body> +</html> diff --git a/libjava/classpath/java/awt/geom/doc-files/GeneralPath-1.png b/libjava/classpath/java/awt/geom/doc-files/GeneralPath-1.png Binary files differnew file mode 100644 index 000000000..d1d75d575 --- /dev/null +++ b/libjava/classpath/java/awt/geom/doc-files/GeneralPath-1.png diff --git a/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-1.png b/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-1.png Binary files differnew file mode 100644 index 000000000..7c2ec0ea9 --- /dev/null +++ b/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-1.png diff --git a/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-2.png b/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-2.png Binary files differnew file mode 100644 index 000000000..496180c44 --- /dev/null +++ b/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-2.png diff --git a/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-3.png b/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-3.png Binary files differnew file mode 100644 index 000000000..a7557ba7b --- /dev/null +++ b/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-3.png diff --git a/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-4.png b/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-4.png Binary files differnew file mode 100644 index 000000000..835c0643b --- /dev/null +++ b/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-4.png diff --git a/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-5.png b/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-5.png Binary files differnew file mode 100644 index 000000000..72110cd5a --- /dev/null +++ b/libjava/classpath/java/awt/geom/doc-files/QuadCurve2D-5.png diff --git a/libjava/classpath/java/awt/geom/package.html b/libjava/classpath/java/awt/geom/package.html new file mode 100644 index 000000000..c8ee8272f --- /dev/null +++ b/libjava/classpath/java/awt/geom/package.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in java.awt.geom package. + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - java.awt.geom</title></head> + +<body> +<p>Classes to represent 2D objects and different path transformations.</p> + +</body> +</html> diff --git a/libjava/classpath/java/awt/im/InputContext.java b/libjava/classpath/java/awt/im/InputContext.java new file mode 100644 index 000000000..8667272b8 --- /dev/null +++ b/libjava/classpath/java/awt/im/InputContext.java @@ -0,0 +1,438 @@ +/* InputContext.java -- provides the context for text input + Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.im; + +import gnu.java.util.EmptyEnumeration; + +import java.awt.AWTEvent; +import java.awt.AWTException; +import java.awt.Component; +import java.awt.im.spi.InputMethod; +import java.awt.im.spi.InputMethodDescriptor; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.text.AttributedCharacterIterator.Attribute; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Locale; + +/** + * Provides a context for controlling input methods and keyboard layouts. + * This class provides the communication layer between the client component, + * and the various locale-dependent text entry input methods that can be used + * for the client. By default, there is one instance per Window, shared among + * all components, but this limits text entry to one component at a time. + * Thus, text components can create their own instance to allow text entry + * in multiple components at a time. + * + * <p>By using the interfaces of {@link java.awt.im.spi}, you can install + * extensions which allow additional input methods. Some of these may use + * platform native input methods, or keyboard layouts provided by the platform. + * Input methods are unavailable if none have been installed and the platform + * has no underlying native input methods. Extensions are installed as jar + * files, usually accessed in the default extension location or specified by + * the -extdir VM flag. The jar must contain a file named + * "META_INF/services/java.awt.im.spi.InputMethodDescriptor" which lists, + * one entry per line in UTF-8 encoding, each class in the jar that implements + * java.awt.im.spi.InputMethodDescriptor. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @see Component#getInputContext() + * @see Component#enableInputMethods(boolean) + * @since 1.2 + * @status updated to 1.4, but unverified + */ +public class InputContext +{ + /** + * The list of installed input method descriptors. + */ + private static final ArrayList<InputMethodDescriptor> descriptors + = new ArrayList<InputMethodDescriptor>(); + + static + { + Enumeration e; + try + { + e = ClassLoader.getSystemResources + ("META_INF/services/java.awt.im.spi.InputMethodDescriptor"); + } + catch (IOException ex) + { + // XXX Should we do something else? + e = EmptyEnumeration.getInstance(); + } + while (e.hasMoreElements()) + { + URL url = (URL) e.nextElement(); + BufferedReader in; + String line; + try + { + in = new BufferedReader + (new InputStreamReader(url.openConnection().getInputStream(), + "UTF-8")); + line = in.readLine().trim(); + } + catch (IOException ignored) + { + continue; + } + outer: + while (line != null) + { + try + { + if (line.charAt(0) != '#') + { + Class<?> c = Class.forName(line); + descriptors.add((InputMethodDescriptor) c.newInstance()); + } + line = in.readLine().trim(); + } + catch (IOException ex) + { + continue outer; + } + catch (Exception ignored) + { + } + } + } + } + + /** The current input method; null if no input methods are installed. */ + private InputMethod im; + + /** Map of locales to the most recently selected input method. */ + private final HashMap<Locale,InputMethod> recent + = new HashMap<Locale,InputMethod>(); + + /** The list of acceptable character subsets. */ + private Character.Subset[] subsets; + + /** + * Construct an InputContext. This is protected, so clients must use + * {@link #getInstance()} instead. + */ + protected InputContext() + { + } + + /** + * Returns a new InputContext. + * + * @return a new instance, initialized to the default locale if available + */ + public static InputContext getInstance() + { + InputContext ic = new InputContext(); + ic.selectInputMethod(Locale.getDefault()); + return ic; + } + + /** + * Attempts to select an input method or keyboard layout which supports the + * given locale. This returns true if a locale is available and was selected. + * The following steps are taken in choosing an input method:<ul> + * <li>If the currently selected input method or keyboard layout supports + * the requested locale, it remains selected.</li> + * <li>If there is no input method or keyboard layout available that + * supports the requested locale, the current input method or keyboard + * layout remains selected.</li> + * <li>If the user has previously selected an input method or keyboard + * layout for the requested locale from the user interface, then the most + * recently selected such input method or keyboard layout is reselected.</li> + * <li>Otherwise, an input method or keyboard layout that supports the + * requested locale is selected in an implementation dependent way. This + * implementation chooses the first input method which supports the requested + * locale based on the InputMethodDescriptors loaded from the extensions + * installed on the CLASSPATH.</li> + * </ul> + * + * <p>Before switching away from an input method, any currently uncommitted + * text is committed. Not all host operating systems provide API to + * determine the locale of the currently selected native input method or + * keyboard layout, and to select a native input method or keyboard layout + * by locale. For host operating systems that don't provide such API, + * selectInputMethod assumes that native input methods or keyboard layouts + * provided by the host operating system support only the system's default + * locale. + * + * <p>An example of where this may be called is in a multi-language document, + * when moving the insertion point between sections of different locale, so + * that the user may use the input method appropriate to that section of the + * document. + * + * @param locale the desired new locale + * @return true if the new locale is active + * @throws NullPointerException if locale is null + */ + public boolean selectInputMethod(Locale locale) + { + if (im != null && im.setLocale(locale)) + { + recent.put(locale, im); + return true; + } + InputMethod next = recent.get(locale); + if (next != null) + for (int i = 0, limit = descriptors.size(); i < limit; i++) + { + InputMethodDescriptor d = descriptors.get(i); + Locale[] list; + try + { + list = d.getAvailableLocales(); + } + catch (AWTException ignored) + { + continue; + } + for (int j = list.length; --j >= 0; ) + if (locale.equals(list[j])) + { + try + { + next = d.createInputMethod(); + recent.put(locale, next); + } + catch (Exception ignored) + { + continue; + } + } + } + if (next == null) + return false; + // XXX I'm not sure if this does all the necessary steps in the switch. + if (im != null) + { + try + { + next.setCompositionEnabled(im.isCompositionEnabled()); + } + catch (UnsupportedOperationException ignored) + { + } + im.endComposition(); + im.deactivate(false); + im.hideWindows(); + } + im = next; + im.setLocale(locale); + im.setCharacterSubsets(subsets); + return true; + } + + /** + * Returns the current locale of the current input method or keyboard + * layout. Returns null if the input context does not have a current input + * method or keyboard layout or if the current input method's + * {@link InputMethod#getLocale()} method returns null. Not all host + * operating systems provide API to determine the locale of the currently + * selected native input method or keyboard layout. For host operating + * systems that don't provide such API, getLocale assumes that the current + * locale of all native input methods or keyboard layouts provided by the + * host operating system is the system's default locale. + * + * @return the locale of the current input method, or null + * @since 1.3 + */ + public Locale getLocale() + { + return im == null ? null : im.getLocale(); + } + + /** + * Sets the subsets of Unicode characters allowed to be input by the current + * input method, as well as subsequent input methods. The value of null + * implies all characters are legal. Applications should not rely on this + * behavior, since native host input methods may not allow restrictions. + * If no current input method is available, this has no immediate effect. + * + * @param subsets the set of Unicode subsets to accept, or null + */ + public void setCharacterSubsets(Character.Subset[] subsets) + { + this.subsets = subsets; + if (im != null) + im.setCharacterSubsets(subsets); + } + + /** + * Changes the enabled status of the current input method. An input method + * that is enabled for composition interprets incoming events for both + * composition and control purposes, while a disabled input method only + * interprets control commands (including commands to enable itself). + * + * @param enable whether to enable the input method + * @throws UnsupportedOperationException if there is no current input method, + * or the input method does not support enabling + * @see #isCompositionEnabled() + * @since 1.3 + */ + public void setCompositionEnabled(boolean enable) + { + if (im == null) + throw new UnsupportedOperationException(); + im.setCompositionEnabled(enable); + } + + /** + * Find out if the current input method is enabled. + * + * @return true if the current input method is enabled + * @throws UnsupportedOperationException if there is no current input method, + * or the input method does not support enabling + * @see #setCompositionEnabled(boolean) + * @since 1.3 + */ + public boolean isCompositionEnabled() + { + if (im == null) + throw new UnsupportedOperationException(); + return im.isCompositionEnabled(); + } + + /** + * Starts a reconversion operation in the current input method. The input + * method gets the text to reconvert from the client component, using + * {@link InputMethodRequests#getSelectedText(Attribute[])}. Then the + * composed and committed text produced by the operation is sent back to + * the client using a sequence of InputMethodRequests. + * + * @throws UnsupportedOperationException if there is no current input method, + * or the input method does not support reconversion + * @since 1.3 + */ + public void reconvert() + { + if (im == null) + throw new UnsupportedOperationException(); + im.reconvert(); + } + + /** + * Dispatches an event to the current input method. This is called + * automatically by AWT. If no input method is available, then the event + * will never be consumed. + * + * @param event the event to dispatch + * @throws NullPointerException if event is null + */ + public void dispatchEvent(AWTEvent event) + { + if (im != null) + im.dispatchEvent(event); + } + + /** + * Notifies the input context that a client component has been removed from + * its containment hierarchy, or that input method support has been disabled + * for the component. This method is usually called from the client + * component's {@link Component#removeNotify()} method. Potentially pending + * input from input methods for this component is discarded. If no input + * methods are available, then this method has no effect. + * + * @param client the client component + * @throws NullPointerException if client is null + */ + public void removeNotify(Component client) + { + // XXX What to do with client information? + if (im != null) + { + im.deactivate(false); + im.removeNotify(); + } + } + + /** + * Ends any input composition that may currently be going on in this + * context. Depending on the platform and possibly user preferences, this + * may commit or delete uncommitted text. Any changes to the text are + * communicated to the active component using an input method event. If no + * input methods are available, then this method has no effect. This may + * be called for a variety of reasons, such as when the user moves the + * insertion point in the client text outside the range of the composed text, + * or when text is saved to file. + */ + public void endComposition() + { + if (im != null) + im.endComposition(); + } + + /** + * Disposes of the input context and release the resources used by it. + * Called automatically by AWT for the default input context of each + * Window. If no input methods are available, then this method has no + * effect. + */ + public void dispose() + { + if (im != null) + { + im.deactivate(false); + im.dispose(); + } + } + + /** + * Returns a control object from the current input method, or null. A + * control object provides implementation-dependent methods that control + * the behavior of the input method or obtain information from the input + * method. Clients have to compare the result against known input method + * control object types. If no input methods are available or the current + * input method does not provide an input method control object, then null + * is returned. + * + * @return the control object, or null + */ + public Object getInputMethodControlObject() + { + return im == null ? null : im.getControlObject(); + } +} // class InputContext diff --git a/libjava/classpath/java/awt/im/InputMethodHighlight.java b/libjava/classpath/java/awt/im/InputMethodHighlight.java new file mode 100644 index 000000000..a2ee86d44 --- /dev/null +++ b/libjava/classpath/java/awt/im/InputMethodHighlight.java @@ -0,0 +1,189 @@ +/* InputMethodHighlight.java -- highlights the current text selection + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.im; + +import java.awt.Toolkit; +import java.text.Annotation; +import java.text.AttributedCharacterIterator; +import java.util.Map; +import java.awt.font.TextAttribute; + +/** + * This describes the highlight attributes of text composed in an input method. + * The description includes an abstract level (whether text has been converted + * yet, and whether it is selected), and a concrete level (which style + * attributes are used in rendering). If no concrete level is defined, the + * renderer should use + * {@link Toolkit#mapInputMethodHighlight(InputMethodHighlight)}. An example + * of conversion state is kana -> kanji. + * + * <p>Instances of this class are typically used in + * AttributedCharacterIterators, and may be wrapped in Annotations to separate + * text segments. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see AttributedCharacterIterator + * @see Annotation + * @since 1.2 + * @status updated to 1.4 + */ +public class InputMethodHighlight +{ + /** Raw text state (before conversion). */ + public static final int RAW_TEXT = 0; + + /** Converted text state (after conversion). */ + public static final int CONVERTED_TEXT = 1; + + /** Default do-nothing highlighting for unselected raw text. */ + public static final InputMethodHighlight UNSELECTED_RAW_TEXT_HIGHLIGHT + = new InputMethodHighlight(false, RAW_TEXT); + + /** Default do-nothing highlighting for selected raw text. */ + public static final InputMethodHighlight SELECTED_RAW_TEXT_HIGHLIGHT + = new InputMethodHighlight(true, RAW_TEXT); + + /** Default do-nothing highlighting for unselected converted text. */ + public static final InputMethodHighlight UNSELECTED_CONVERTED_TEXT_HIGHLIGHT + = new InputMethodHighlight(false, CONVERTED_TEXT); + + /** Default do-nothing highlighting for selected converted text. */ + public static final InputMethodHighlight SELECTED_CONVERTED_TEXT_HIGHLIGHT + = new InputMethodHighlight(true, CONVERTED_TEXT); + + /** Whether the highlighting applies to selected text. */ + private final boolean selected; + + /** The state of highlighted text. */ + private final int state; + + /** Any variation on the highlighting style. */ + private final int variation; + + /** The unmodifiable map of rendering styles. */ + private final Map<TextAttribute, ?> style; + + /** + * Create an input method highlight style, with variation 0 and null style + * mapping. + * + * @param selected whether the text range is selected + * @param state either {@link #RAW_TEXT} or {@link #CONVERTED_TEXT} + * @throws IllegalArgumentException if state is invalid + */ + public InputMethodHighlight(boolean selected, int state) + { + this(selected, state, 0, null); + } + + /** + * Create an input method highlight style, with null style mapping. + * + * @param selected whether the text range is selected + * @param state either {@link #RAW_TEXT} or {@link #CONVERTED_TEXT} + * @param variation the style variation + * @throws IllegalArgumentException if state is invalid + */ + public InputMethodHighlight(boolean selected, int state, int variation) + { + this(selected, state, variation, null); + } + + /** + * Create an input method highlight style. + * + * @param selected whether the text range is selected + * @param state either {@link #RAW_TEXT} or {@link #CONVERTED_TEXT} + * @param variation the style variation + * @param style an unmodifiable map of rendering styles, or null + * @throws IllegalArgumentException if state is invalid + * @since 1.3 + */ + public InputMethodHighlight(boolean selected, int state, int variation, + Map<TextAttribute, ?> style) + { + if (state != RAW_TEXT && state != CONVERTED_TEXT) + throw new IllegalArgumentException(); + this.selected = selected; + this.state = state; + this.variation = variation; + this.style = style; + } + + /** + * Return whether the highlighting applies to selected text. + * + * @return the selection status + */ + public boolean isSelected() + { + return selected; + } + + /** + * Return the conversion state of the highlighted text. + * + * @return one of {@link #RAW_TEXT} or {@link #CONVERTED_TEXT} + */ + public int getState() + { + return state; + } + + /** + * Return the highlighting style variation. + * + * @return the variation + */ + public int getVariation() + { + return variation; + } + + /** + * Return the rendering style attributes map, or null if it should be the + * default mapping. + * + * @return the style map + * @since 1.3 + */ + public Map<TextAttribute, ?> getStyle() + { + return style; + } +} // class InputMethodHighlight diff --git a/libjava/classpath/java/awt/im/InputMethodRequests.java b/libjava/classpath/java/awt/im/InputMethodRequests.java new file mode 100644 index 000000000..0423358cc --- /dev/null +++ b/libjava/classpath/java/awt/im/InputMethodRequests.java @@ -0,0 +1,155 @@ +/* InputMethodRequests.java -- handles text insertion via input methods + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.im; + +import java.awt.Component; +import java.awt.Rectangle; +import java.awt.font.TextHitInfo; +import java.awt.event.InputMethodListener; +import java.text.AttributedCharacterIterator; +import java.text.AttributedCharacterIterator.Attribute; + +/** + * This interface handles requests made by input methods on text editing + * components. A component must specify a handler for input methods that + * implements this interface, and which supports one of two user interfaces: + * <ul><li><em>on-the-spot</em>: composed text is shown in place</li> + * <li><em>below-the-spot</em>: composed text is in a separate window, + * usually below the main text window, until it is committed into place at + * the insertion point, overwriting any selected text</li></ul> + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see Component#getInputMethodRequests() + * @see InputMethodListener + * @since 1.2 + * @status updated to 1.4 + */ +public interface InputMethodRequests +{ + /** + * Gets the location of a given offset of the text. This can be used to + * position a composition window near the location of where the composed + * text will be inserted. + * + * <p>If the component has composed text (from the most recent + * InputMethodEvent), then offset 0 indicates the location of the first + * character of this composed text. Otherwise, the offset is ignored, and + * the location should be the beginning of the final line of selected + * text (in horizontal left-to-right text, like English, this would be the + * lower left corner of the selction; in vertical top-to-bottom text, like + * Chinese, this would be the top right corner of the selection). + * + * <p>The location returned is a 0-thickness caret (either horizontal or + * vertical, depending on text flow), mapped to absolute screen coordinates. + * + * @param offset offset within composed text, or null + * @return the screen location of the caret at the offset + */ + Rectangle getTextLocation(TextHitInfo offset); + + /** + * Get the text offset for the given screen coordinate. The offset is + * relative to the composed text, and the return is null if it is outside + * the range of composed text. For example, this can be used to find + * where a mouse click should pop up a text composition window. + * + * @param x the x screen coordinate + * @param y the y screen coordinate + * @return a text hit info describing the composed text offset + */ + TextHitInfo getLocationOffset(int x, int y); + + /** + * Gets the offset where the committed text exists in the text editing + * component. This can be used to examine the text surrounding the insert + * position. + * + * @return the offset of the insert position + */ + int getInsertPositionOffset(); + + /** + * Gets an interator which provides access to the text and its attributes, + * except for the uncommitted text. The input method may provide a list of + * attributes it is interested in; and the iterator need not provide + * information on the remaining attributes. If the attribute list is null, + * the iterator must list all attributes. + * + * @param beginIndex the index of the first character in the iteration + * @param endIndex the index of the last character in the iteration + * @param attributes a list of attributes interested in, or null + * @return an iterator over the region of text with its attributes + */ + AttributedCharacterIterator getCommittedText(int beginIndex, int endIndex, + Attribute[] attributes); + + /** + * Gets the length of committed text. + * + * @return the number of committed characters + */ + int getCommittedTextLength(); + + /** + * Gets the latest committed text, and removes it from the component's text + * body. This allows an input method to provide an "Undo" command. In + * general, this should only be supported immediately after a commit, and + * not when other actions intervene; if not supported, simply return null. + * The input method may provide a list of attributes it is interested in; + * and the iterator need not provide information on the remaining attributes. + * If the attribute list is null, the iterator must list all attributes. + * + * @param attributes a list of attributes interested in, or null + * @return the latest committed text, or null + */ + AttributedCharacterIterator cancelLatestCommittedText + (Attribute[] attributes); + + /** + * Gets the currently selected text. One use of this is to implement a + * "Reconvert" feature in an input method, which modifies the selection + * based on the text in the composition window. The input method may + * provide a list of attributes it is interested in; and the iterator need + * not provide information on the remaining attributes. If the attribute + * list is null, the iterator must list all attributes. + * + * @param attributes a list of attributes interested in, or null + * @return the current selection + */ + AttributedCharacterIterator getSelectedText(Attribute[] attributes); +} // interface InputMethodRequests diff --git a/libjava/classpath/java/awt/im/InputSubset.java b/libjava/classpath/java/awt/im/InputSubset.java new file mode 100644 index 000000000..5e7d58e7f --- /dev/null +++ b/libjava/classpath/java/awt/im/InputSubset.java @@ -0,0 +1,129 @@ +/* InputSubset.java -- subsets of Unicode important in text input + Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.im; + +/** + * Defines additional Unicode character blocks for use by input methods. + * These constants encompass several Unicode blocks, or portions thereof, for + * simplification over {@link Character.UnicodeBlock}. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + * @status updated to 1.4 + */ +public final class InputSubset extends Character.Subset +{ + /** + * Constant for all Latin characters, including the characters in the + * BASIC_LATIN, LATIN_1_SUPPLEMENT, LATIN_EXTENDED_A, LATIN_EXTENDED_B + * Unicode character blocks. + */ + public static final InputSubset LATIN = new InputSubset("LATIN"); + + /** + * Constant for the digits included in the BASIC_LATIN Unicode character + * block. + */ + public static final InputSubset LATIN_DIGITS + = new InputSubset("LATIN_DIGITS"); + + /** + * Constant for all Han characters used in writing Traditional Chinese, + * including a subset of the CJK unified ideographs as well as Traditional + * Chinese Han characters that may be defined as surrogate characters. + */ + public static final InputSubset TRADITIONAL_HANZI + = new InputSubset("TRADITIONAL_HANZI"); + + /** + * Constant for all Han characters used in writing Simplified Chinese, + * including a subset of the CJK unified ideographs as well as Simplified + * Chinese Han characters that may be defined as surrogate characters. + */ + public static final InputSubset SIMPLIFIED_HANZI + = new InputSubset("SIMPLIFIED_HANZI"); + + /** + * Constant for all Han characters used in writing Japanese, including a + * subset of the CJK unified ideographs as well as Japanese Han characters + * that may be defined as surrogate characters. + */ + public static final InputSubset KANJI = new InputSubset("KANJI"); + + /** + * Constant for all Han characters used in writing Korean, including a + * subset of the CJK unified ideographs as well as Korean Han characters + * that may be defined as surrogate characters. + */ + public static final InputSubset HANJA = new InputSubset("HANJA"); + + /** + * Constant for the halfwidth katakana subset of the Unicode halfwidth and + * fullwidth forms character block. + */ + public static final InputSubset HALFWIDTH_KATAKANA + = new InputSubset("HALFWIDTH_KATAKANA"); + + /** + * Constant for the fullwidth ASCII variants subset of the Unicode + * halfwidth and fullwidth forms character block. + * + * @since 1.3 + */ + public static final InputSubset FULLWIDTH_LATIN + = new InputSubset("FULLWIDTH_LATIN"); + + /** + * Constant for the fullwidth digits included in the Unicode halfwidth and + * fullwidth forms character block. + * + * @since 1.3 + */ + public static final InputSubset FULLWIDTH_DIGITS + = new InputSubset("FULLWIDTH_DIGITS"); + + /** + * Construct a subset. + * + * @param name the subset name + */ + private InputSubset(String name) + { + super(name); + } +} // class InputSubset diff --git a/libjava/classpath/java/awt/im/package.html b/libjava/classpath/java/awt/im/package.html new file mode 100644 index 000000000..895da66d5 --- /dev/null +++ b/libjava/classpath/java/awt/im/package.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in java.awt.im package. + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - java.awt.im</title></head> + +<body> +<p>Support for text input methods.</p> + +</body> +</html> diff --git a/libjava/classpath/java/awt/im/spi/InputMethod.java b/libjava/classpath/java/awt/im/spi/InputMethod.java new file mode 100644 index 000000000..ebe450841 --- /dev/null +++ b/libjava/classpath/java/awt/im/spi/InputMethod.java @@ -0,0 +1,244 @@ +/* InputMethod.java -- defines an interface for complex text input + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.im.spi; + +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.Rectangle; +import java.awt.im.InputContext; +import java.awt.im.InputMethodRequests; +import java.text.AttributedCharacterIterator.Attribute; +import java.util.Locale; + +/** + * This interface supports complex text input, often for situations where + * the text is more complex than a keyboard will accomodate. For example, + * this can be used for Chinese, Japanese, and Korean, where multiple + * keystrokes are necessary to compose text. This could also support things + * like phonetic English, or reordering Thai. + * + * <p>These contexts can be loaded by the input method framework, using + * {@link InputContext#selectInputMethod(Locale)}. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + * @status updated to 1.4 + */ +public interface InputMethod +{ + /** + * Set the input method context, which ties the input method to a client + * component. This is called once automatically when creating the input + * method. + * + * @param context the context for this input method + * @throws NullPointerException if context is null + */ + void setInputMethodContext(InputMethodContext context); + + /** + * Sets the input locale. If the input method supports that locale, it + * changes its behavior to be consistent with the locale and returns true. + * Otherwise, it returns false. This is called by + * {@link InputContext#selectInputMethod(Locale)} when the user specifies + * a locale, or when the previously selected input method had a locale. + * + * @param locale the locale to use for input + * @return true if the change is successful + * @throws NullPointerException if locale is null + */ + boolean setLocale(Locale locale); + + /** + * Returns the current input locale, or null if none is defined. This is + * called by {@link InputContext#getLocale()}, or before switching input + * methods. + * + * @return the current input locale, or null + */ + Locale getLocale(); + + /** + * Sets the allowed Unicode subsets that this input method can use. Null + * indicates that all characters are allowed. This is called after creation, + * or when switching to this input method, by + * {@link InputContext#setCharacterSubsets(Character.Subset[])}. + * + * @param subsets the accepted subsets for this input method, or null for all + */ + void setCharacterSubsets(Character.Subset[] subsets); + + /** + * Changes the enabled status of this input method. An enabled input method + * accepts incoming events for composition and control purposes, while a + * disabled input method ignores events (except for control purposes). This + * is called by {@link InputContext#setCompositionEnabled(boolean)} or when + * switching from an input method if the previous input method returned + * without exception on {@link #isCompositionEnabled()}. + * + * @param enable whether to enable this input method + * @throws UnsupportedOperationException if enabling/disabling is unsupported + * @see #isCompositionEnabled() + */ + void setCompositionEnabled(boolean enable); + + /** + * Find out if this input method is enabled. This is called by + * {@link InputContext#isCompositionEnabled()}, or when switching input + * methods via {@link InputContext#selectInputMethod(Locale)}. + * + * @return true if this input method is enabled + * @throws UnsupportedOperationException if enabling/disabling is unsupported + * @see #setCompositionEnabled(boolean) + */ + boolean isCompositionEnabled(); + + /** + * Starts a reconversion operation. The input method gets its text from the + * client, using {@link InputMethodRequests#getSelectedText(Attribute[])}. + * Then the composed and committed text produced by the operation is sent + * back to the client using a sequence of InputMethodEvents. This is called + * by {@link InputContext#reconvert()}. + * + * @throws UnsupportedOperationException if reconversion is unsupported + */ + void reconvert(); + + /** + * Dispatch an event to the input method. If input method support is enabled, + * certain events are dispatched to the input method before the client + * component or event listeners. The input method must either consume the + * event or pass it on to the component. Instances of InputEvent, including + * KeyEvent and MouseEvent, are given to this input method. This method is + * called by {@link InputContext#dispatchEvent(AWTEvent)}. + * + * @param event the event to dispatch + * @throws NullPointerException if event is null + */ + void dispatchEvent(AWTEvent event); + + /** + * Notify this input method of changes in the client window. This is called + * when notifications are enabled (see {@link + * InputMethodContext#enableClientWindowNotification(InputMethod, boolean)}, + * if {@link InputContext#removeNotify(Component)} has not been called. + * The following situations trigger a notification:<ul> + * <li>The client window changes in location, size, visibility, + * iconification, or is closed.</li> + * <li>When enabling client notification (or on the first activation after + * enabling if no client existed at the time).</li> + * <li>When activating a new client after <code>removeNotify</code> was + * called on a previous client.</li> + * </ul> + * + * @param bounds the client window's current bounds, or null + */ + void notifyClientWindowChange(Rectangle bounds); + + /** + * Activate this input method for input processing. If the input method + * provides its own windows, it should make them open and visible at this + * time. This method is called when a client component receives a + * FOCUS_GAINED event, or when switching to this input method from another + * one. It is only called when the input method is inactive, assuming that + * new instances begin in an inactive state. + */ + void activate(); + + /** + * Deactivate this input method, either temporarily or permanently for the + * given client. If the input method provides its own windows, it should + * only close those related to the current composition (such as a lookup + * choice panel), while leaving more persistant windows (like a control + * panel) open to avoid screen flicker. Before control is given to another + * input method, {@link #hideWindows()} will be called on this instance. + * This method is called when a client component receives a + * FOCUS_LOST event, when switching to another input method, or before + * {@link #removeNotify()} when the client is removed. + * + * @param isTemporary true if the focus change is temporary + */ + void deactivate(boolean isTemporary); + + /** + * Close or hide all windows opened by this input method. This is called + * before activating a different input method, and before calling + * {@link #dispose()} on this instance. It is only called when the input + * method is inactive. + */ + void hideWindows(); + + /** + * Notify the input method that a client component has been removed from its + * hierarchy, or that input method support has been disabled. This is + * called by {@link InputContext#removeNotify(Component)}, and only when the input + * method is inactive. + */ + void removeNotify(); + + /** + * End any input composition currently taking place. Depending on the + * platform and user preferences, this may commit or delete uncommitted text, + * using input method events. This may be called for a variety of reasons, + * such as when the user moves the insertion point in the client text outside + * the range of the composed text, or when text is saved to file. This is + * called by {@link InputContext#endComposition()}, when switching to a + * new input method, or by {@link InputContext#selectInputMethod(Locale)}. + */ + void endComposition(); + + /** + * Disposes the input method and release any resources it is using. In + * particular, the input method should dispose windows and close files. This + * is called by {@link InputContext#dispose()}, when the input method is + * inactive; and nothing will be called on this instance afterwards. + */ + void dispose(); + + /** + * Returns a control object from this input method, or null. A control object + * provides method to control the behavior of this input method, as well as + * query information about it. The object is implementation dependent, so + * clients must compare the result against known input method control + * object types. This is called by + * {@link InputContext#getInputMethodControlObject()}. + * + * @return the control object, or null + */ + Object getControlObject(); +} // interface InputMethod diff --git a/libjava/classpath/java/awt/im/spi/InputMethodContext.java b/libjava/classpath/java/awt/im/spi/InputMethodContext.java new file mode 100644 index 000000000..aed21e8d3 --- /dev/null +++ b/libjava/classpath/java/awt/im/spi/InputMethodContext.java @@ -0,0 +1,126 @@ +/* InputMethodContext.java -- communication between an input method and client + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.im.spi; + +import java.awt.HeadlessException; +import java.awt.Rectangle; +import java.awt.Window; +import java.awt.font.TextHitInfo; +import java.awt.im.InputMethodRequests; +import java.text.AttributedCharacterIterator; + +import javax.swing.JFrame; + +/** + * Provides methods for the communication context between an input method + * and the client component. This should be passed to + * {@link InputMethod#setInputMethodContext(InputMethodContext)}. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.3 + * @status updated to 1.4 + */ +public interface InputMethodContext extends InputMethodRequests +{ + /** + * Create an input method event and dispatch it to the client. + * + * @param id the event type + * @param text an iterator over the text to be committed + * @param count the count of characters to be committed + * @param caret the insertion point of the commit, or null + * @param visiblePosition the best location to make visible, or null + */ + void dispatchInputMethodEvent(int id, AttributedCharacterIterator text, + int count, TextHitInfo caret, + TextHitInfo visiblePosition); + + /** + * Creates a top-level window for use by the input method. This window should + * float above all document windows and dialogs, not receive focus, and have + * lightweight decorations (such as no title, reduced drag regions). But + * this behavior may be modified to meet the platform style. The title may + * or may not be displayed, depending on the platform. + * + * <p>If attachToInputContext is true, the new window will share the input + * context of the input method, so that events in the new window are + * dispatched to the input method. Also, this supresses deactivate and + * activate calls to the input method caused by setVisible. + * + * @param title the window title, if one is displayed; null becomes "" + * @param attachToInputContext true for the window to share context with + * the input method + * @return the new window for use by the input method + * @throws HeadlessException if GraphicsEnvironment.isHeadless is true + */ + Window createInputMethodWindow(String title, boolean attachToInputContext); + + /** + * Creates a top-level Swing JFrame for use by the input method. This frame + * should float above all document windows and dialogs, not receive focus, + * and have lightweight decorations (such as no title, reduced drag + * regions). But this behavior may be modified to meet the platform style. + * The title may or may not be displayed, depending on the platform. + * + * <p>If attachToInputContext is true, the new window will share the input + * context of the input method, so that events in the new window are + * dispatched to the input method. Also, this supresses deactivate and + * activate calls to the input method caused by setVisible. + * + * @param title the window title, if one is displayed; null becomes "" + * @param attachToInputContext true for the window to share context with + * the input method + * @return the new window for use by the input method + * @throws HeadlessException if GraphicsEnvironment.isHeadless is true + * @since 1.4 + */ + JFrame createInputMethodJFrame(String title, boolean attachToInputContext); + + /** + * Sets whether notification of the client window's location and state should + * be enabled for the input method. When enabled, the input method's + * {@link InputMethod#notifyClientWindowChange(Rectangle)} method is called. + * Notification is automatically disabled when the input method is disposed. + * + * @param inputMethod the method to change status of + * @param enable true to enable notification + */ + void enableClientWindowNotification(InputMethod inputMethod, boolean enable); +} // interface InputMethodContext diff --git a/libjava/classpath/java/awt/im/spi/InputMethodDescriptor.java b/libjava/classpath/java/awt/im/spi/InputMethodDescriptor.java new file mode 100644 index 000000000..ce40ab2b6 --- /dev/null +++ b/libjava/classpath/java/awt/im/spi/InputMethodDescriptor.java @@ -0,0 +1,113 @@ +/* InputMethodDescriptor.java -- enables loading and use of an input method + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.im.spi; + +import java.awt.AWTException; +import java.awt.Image; +import java.awt.im.InputContext; +import java.util.Locale; + +/** + * This interface provides information about an InputMethod before it is + * loaded. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + * @status updated to 1.4 + */ +public interface InputMethodDescriptor +{ + /** + * Returns the locales supported by the input method this describes. This + * allows the selection of input methods by locale (by language only, or + * also by country and variant), via + * {@link InputContext#selectInputMethod(Locale)}. The returned list should + * ignore pass-through locales, so it is usually a subset of locales for + * which {@link InputMethod#setLocale(Locale)} returns true. If + * {@link #hasDynamicLocaleList()} returns true, this is called each time + * information is needed, allowing dynamic addition or removal of supported + * locales. + * + * @return the list of supported locales + * @throws AWTException if the input method is not available + */ + Locale[] getAvailableLocales() throws AWTException; + + /** + * Test whether the input method this describes has a static or dynamic + * locale list. For example, this would return true if the list of supported + * locales depends on adapters currently loaded over a network. + * + * @return true if the locale list is dynamic + */ + boolean hasDynamicLocaleList(); + + /** + * Returns a user visible name of the input locale, displayed in the + * specified locale. The inputLocale parameter must be one obtained from + * the list in {@link #getAvailableLocales()}, or null for a + * locale-independent description of the input method. If a translation to + * the desired display language is not available, another language may be + * used. + * + * @param inputLocale the locale of the input method, or null + * @param displayLanguage the language of the result + * @return the name of the input method when using the given inputLocale + */ + String getInputMethodDisplayName(Locale inputLocale, + Locale displayLanguage); + + /** + * Returns a 16x16 icon for the input locale. The inputLocale parameter + * must be one obtained from the list in {@link #getAvailableLocales()}, or + * null for a locale-independent icon for the input method. + * + * @param inputLocale the locale of the input method, or null + * @return a 16x16 icon for the input method when using the given inputLocale + */ + Image getInputMethodIcon(Locale inputLocale); + + /** + * Creates a new instance of the input method. + * + * @return the newly created input method + * @throws Exception if anything goes wrong + */ + InputMethod createInputMethod() throws Exception; + +} // interface InputMethodDescriptor diff --git a/libjava/classpath/java/awt/im/spi/package.html b/libjava/classpath/java/awt/im/spi/package.html new file mode 100644 index 000000000..c526ee159 --- /dev/null +++ b/libjava/classpath/java/awt/im/spi/package.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in java.awt.im.spi package. + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - java.awt.im.spi</title></head> + +<body> +<p>Interfaces for implementation of text input methods.</p> + +</body> +</html> diff --git a/libjava/classpath/java/awt/image/AffineTransformOp.java b/libjava/classpath/java/awt/image/AffineTransformOp.java new file mode 100644 index 000000000..460804f90 --- /dev/null +++ b/libjava/classpath/java/awt/image/AffineTransformOp.java @@ -0,0 +1,608 @@ +/* AffineTransformOp.java -- This class performs affine + transformation between two images or rasters in 2 dimensions. + Copyright (C) 2004, 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.Arrays; + +/** + * AffineTransformOp performs matrix-based transformations (translations, + * scales, flips, rotations, and shears). + * + * If interpolation is required, nearest neighbour, bilinear, and bicubic + * methods are available. + * + * @author Olga Rodimina (rodimina@redhat.com) + * @author Francis Kung (fkung@redhat.com) + */ +public class AffineTransformOp implements BufferedImageOp, RasterOp +{ + public static final int TYPE_NEAREST_NEIGHBOR = 1; + + public static final int TYPE_BILINEAR = 2; + + /** + * @since 1.5.0 + */ + public static final int TYPE_BICUBIC = 3; + + private AffineTransform transform; + private RenderingHints hints; + + /** + * Construct AffineTransformOp with the given xform and interpolationType. + * Interpolation type can be TYPE_BILINEAR, TYPE_BICUBIC or + * TYPE_NEAREST_NEIGHBOR. + * + * @param xform AffineTransform that will applied to the source image + * @param interpolationType type of interpolation used + * @throws ImagingOpException if the transform matrix is noninvertible + */ + public AffineTransformOp (AffineTransform xform, int interpolationType) + { + this.transform = xform; + if (xform.getDeterminant() == 0) + throw new ImagingOpException(null); + + switch (interpolationType) + { + case TYPE_BILINEAR: + hints = new RenderingHints (RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + break; + case TYPE_BICUBIC: + hints = new RenderingHints (RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BICUBIC); + break; + default: + hints = new RenderingHints (RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); + } + } + + /** + * Construct AffineTransformOp with the given xform and rendering hints. + * + * @param xform AffineTransform that will applied to the source image + * @param hints rendering hints that will be used during transformation + * @throws ImagingOpException if the transform matrix is noninvertible + */ + public AffineTransformOp (AffineTransform xform, RenderingHints hints) + { + this.transform = xform; + this.hints = hints; + if (xform.getDeterminant() == 0) + throw new ImagingOpException(null); + } + + /** + * Creates a new BufferedImage with the size equal to that of the + * transformed image and the correct number of bands. The newly created + * image is created with the specified ColorModel. + * If a ColorModel is not specified, an appropriate ColorModel is used. + * + * @param src the source image. + * @param destCM color model for the destination image (can be null). + * @return a new compatible destination image. + */ + public BufferedImage createCompatibleDestImage (BufferedImage src, + ColorModel destCM) + { + if (destCM != null) + return new BufferedImage(destCM, + createCompatibleDestRaster(src.getRaster()), + src.isAlphaPremultiplied(), null); + + // This behaviour was determined by Mauve testcases, and is compatible + // with the reference implementation + if (src.getType() == BufferedImage.TYPE_INT_ARGB_PRE + || src.getType() == BufferedImage.TYPE_4BYTE_ABGR + || src.getType() == BufferedImage.TYPE_4BYTE_ABGR_PRE) + return new BufferedImage(src.getWidth(), src.getHeight(), src.getType()); + + else + return new BufferedImage(src.getWidth(), src.getHeight(), + BufferedImage.TYPE_INT_ARGB); + } + + /** + * Creates a new WritableRaster with the size equal to the transformed + * source raster and correct number of bands . + * + * @param src the source raster. + * @throws RasterFormatException if resulting width or height of raster is 0. + * @return a new compatible raster. + */ + public WritableRaster createCompatibleDestRaster (Raster src) + { + Rectangle2D rect = getBounds2D(src); + + if (rect.getWidth() == 0 || rect.getHeight() == 0) + throw new RasterFormatException("width or height is 0"); + + return src.createCompatibleWritableRaster((int) rect.getWidth(), + (int) rect.getHeight()); + } + + /** + * Transforms source image using transform specified at the constructor. + * The resulting transformed image is stored in the destination image if one + * is provided; otherwise a new BufferedImage is created and returned. + * + * @param src source image + * @param dst destination image + * @throws IllegalArgumentException if the source and destination image are + * the same + * @return transformed source image. + */ + public final BufferedImage filter (BufferedImage src, BufferedImage dst) + { + if (dst == src) + throw new IllegalArgumentException("src image cannot be the same as " + + "the dst image"); + + // If the destination image is null, then use a compatible BufferedImage + if (dst == null) + dst = createCompatibleDestImage(src, null); + + Graphics2D gr = dst.createGraphics(); + gr.setRenderingHints(hints); + gr.drawImage(src, transform, null); + return dst; + } + + /** + * Transforms source raster using transform specified at the constructor. + * The resulting raster is stored in the destination raster if it is not + * null, otherwise a new raster is created and returned. + * + * @param src source raster + * @param dst destination raster + * @throws IllegalArgumentException if the source and destination are not + * compatible + * @return transformed raster. + */ + public final WritableRaster filter(Raster src, WritableRaster dst) + { + // Initial checks + if (dst == src) + throw new IllegalArgumentException("src image cannot be the same as" + + " the dst image"); + + if (dst == null) + dst = createCompatibleDestRaster(src); + + if (src.getNumBands() != dst.getNumBands()) + throw new IllegalArgumentException("src and dst must have same number" + + " of bands"); + + // Optimization for rasters that can be represented in the RGB colormodel: + // wrap the rasters in images, and let Cairo do the transformation + if (ColorModel.getRGBdefault().isCompatibleSampleModel(src.getSampleModel()) + && ColorModel.getRGBdefault().isCompatibleSampleModel(dst.getSampleModel())) + { + WritableRaster src2 = Raster.createWritableRaster(src.getSampleModel(), + src.getDataBuffer(), + new Point(src.getMinX(), + src.getMinY())); + BufferedImage iSrc = new BufferedImage(ColorModel.getRGBdefault(), + src2, false, null); + BufferedImage iDst = new BufferedImage(ColorModel.getRGBdefault(), dst, + false, null); + + return filter(iSrc, iDst).getRaster(); + } + + // Otherwise, we need to do the transformation in java code... + // Create arrays to hold all the points + double[] dstPts = new double[dst.getHeight() * dst.getWidth() * 2]; + double[] srcPts = new double[dst.getHeight() * dst.getWidth() * 2]; + + // Populate array with all points in the *destination* raster + int i = 0; + for (int x = 0; x < dst.getWidth(); x++) + { + for (int y = 0; y < dst.getHeight(); y++) + { + dstPts[i++] = x; + dstPts[i++] = y; + } + } + Rectangle srcbounds = src.getBounds(); + + // Use an inverse transform to map each point in the destination to + // a point in the source. Note that, while all points in the destination + // matrix are integers, this is not necessarily true for points in the + // source (hence why interpolation is required) + try + { + AffineTransform inverseTx = transform.createInverse(); + inverseTx.transform(dstPts, 0, srcPts, 0, dstPts.length / 2); + } + catch (NoninvertibleTransformException e) + { + // Shouldn't happen since the constructor traps this + throw new ImagingOpException(e.getMessage()); + } + + // Different interpolation methods... + if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)) + filterNearest(src, dst, dstPts, srcPts); + + else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR)) + filterBilinear(src, dst, dstPts, srcPts); + + else // bicubic + filterBicubic(src, dst, dstPts, srcPts); + + return dst; + } + + /** + * Transforms source image using transform specified at the constructor and + * returns bounds of the transformed image. + * + * @param src image to be transformed + * @return bounds of the transformed image. + */ + public final Rectangle2D getBounds2D (BufferedImage src) + { + return getBounds2D (src.getRaster()); + } + + /** + * Returns bounds of the transformed raster. + * + * @param src raster to be transformed + * @return bounds of the transformed raster. + */ + public final Rectangle2D getBounds2D (Raster src) + { + return transform.createTransformedShape(src.getBounds()).getBounds2D(); + } + + /** + * Returns interpolation type used during transformations. + * + * @return interpolation type + */ + public final int getInterpolationType () + { + if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR)) + return TYPE_BILINEAR; + + else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BICUBIC)) + return TYPE_BICUBIC; + + else + return TYPE_NEAREST_NEIGHBOR; + } + + /** + * Returns location of the transformed source point. The resulting point + * is stored in the dstPt if one is specified. + * + * @param srcPt point to be transformed + * @param dstPt destination point + * @return the location of the transformed source point. + */ + public final Point2D getPoint2D (Point2D srcPt, Point2D dstPt) + { + return transform.transform (srcPt, dstPt); + } + + /** + * Returns rendering hints that are used during transformation. + * + * @return the rendering hints used in this Op. + */ + public final RenderingHints getRenderingHints () + { + return hints; + } + + /** + * Returns transform used in transformation between source and destination + * image. + * + * @return the transform used in this Op. + */ + public final AffineTransform getTransform () + { + return transform; + } + + /** + * Perform nearest-neighbour filtering + * + * @param src the source raster + * @param dst the destination raster + * @param dpts array of points on the destination raster + * @param pts array of corresponding points on the source raster + */ + private void filterNearest(Raster src, WritableRaster dst, double[] dpts, + double[] pts) + { + Rectangle srcbounds = src.getBounds(); + + // For all points on the destination raster, copy the value from the + // corrosponding (rounded) source point + for (int i = 0; i < dpts.length; i += 2) + { + int srcX = (int) Math.round(pts[i]) + src.getMinX(); + int srcY = (int) Math.round(pts[i + 1]) + src.getMinY(); + + if (srcbounds.contains(srcX, srcY)) + dst.setDataElements((int) dpts[i] + dst.getMinX(), + (int) dpts[i + 1] + dst.getMinY(), + src.getDataElements(srcX, srcY, null)); + } + } + + /** + * Perform bilinear filtering + * + * @param src the source raster + * @param dst the destination raster + * @param dpts array of points on the destination raster + * @param pts array of corresponding points on the source raster + */ + private void filterBilinear(Raster src, WritableRaster dst, double[] dpts, + double[] pts) + { + Rectangle srcbounds = src.getBounds(); + + Object xyarr = null; + Object xp1arr = null; + Object yp1arr = null; + Object xyp1arr = null; + + double xy; + double xp1; + double yp1; + double xyp1; + + double[] result = new double[src.getNumBands()]; + + // For all points in the destination raster, use bilinear interpolation + // to find the value from the corrosponding source points + for (int i = 0; i < dpts.length; i += 2) + { + int srcX = (int) Math.round(pts[i]) + src.getMinX(); + int srcY = (int) Math.round(pts[i + 1]) + src.getMinY(); + + if (srcbounds.contains(srcX, srcY)) + { + // Corner case at the bottom or right edge; use nearest neighbour + if (pts[i] >= src.getWidth() - 1 + || pts[i + 1] >= src.getHeight() - 1) + dst.setDataElements((int) dpts[i] + dst.getMinX(), + (int) dpts[i + 1] + dst.getMinY(), + src.getDataElements(srcX, srcY, null)); + + // Standard case, apply the bilinear formula + else + { + int x = (int) Math.floor(pts[i] + src.getMinX()); + int y = (int) Math.floor(pts[i + 1] + src.getMinY()); + double xdiff = pts[i] + src.getMinX() - x; + double ydiff = pts[i + 1] + src.getMinY() - y; + + // Get surrounding pixels used in interpolation... optimized + // to use the smallest datatype possible. + if (src.getTransferType() == DataBuffer.TYPE_DOUBLE + || src.getTransferType() == DataBuffer.TYPE_FLOAT) + { + xyarr = src.getPixel(x, y, (double[])xyarr); + xp1arr = src.getPixel(x+1, y, (double[])xp1arr); + yp1arr = src.getPixel(x, y+1, (double[])yp1arr); + xyp1arr = src.getPixel(x+1, y+1, (double[])xyp1arr); + } + else + { + xyarr = src.getPixel(x, y, (int[])xyarr); + xp1arr = src.getPixel(x+1, y, (int[])xp1arr); + yp1arr = src.getPixel(x, y+1, (int[])yp1arr); + xyp1arr = src.getPixel(x+1, y+1, (int[])xyp1arr); + } + // using + // array[] pixels = src.getPixels(x, y, 2, 2, pixels); + // instead of doing four individual src.getPixel() calls + // should be faster, but benchmarking shows that it's not... + + // Run interpolation for each band + for (int j = 0; j < src.getNumBands(); j++) + { + // Pull individual sample values out of array + if (src.getTransferType() == DataBuffer.TYPE_DOUBLE + || src.getTransferType() == DataBuffer.TYPE_FLOAT) + { + xy = ((double[])xyarr)[j]; + xp1 = ((double[])xp1arr)[j]; + yp1 = ((double[])yp1arr)[j]; + xyp1 = ((double[])xyp1arr)[j]; + } + else + { + xy = ((int[])xyarr)[j]; + xp1 = ((int[])xp1arr)[j]; + yp1 = ((int[])yp1arr)[j]; + xyp1 = ((int[])xyp1arr)[j]; + } + + // If all four samples are identical, there's no need to + // calculate anything + if (xy == xp1 && xy == yp1 && xy == xyp1) + result[j] = xy; + + // Run bilinear interpolation formula + else + result[j] = (xy * (1-xdiff) + xp1 * xdiff) + * (1-ydiff) + + (yp1 * (1-xdiff) + xyp1 * xdiff) + * ydiff; + } + + dst.setPixel((int)dpts[i] + dst.getMinX(), + (int)dpts[i+1] + dst.getMinY(), + result); + } + } + } + } + + /** + * Perform bicubic filtering + * based on http://local.wasp.uwa.edu.au/~pbourke/colour/bicubic/ + * + * @param src the source raster + * @param dst the destination raster + * @param dpts array of points on the destination raster + * @param pts array of corresponding points on the source raster + */ + private void filterBicubic(Raster src, WritableRaster dst, double[] dpts, + double[] pts) + { + Rectangle srcbounds = src.getBounds(); + double[] result = new double[src.getNumBands()]; + Object pixels = null; + + // For all points on the destination raster, perform bicubic interpolation + // from corrosponding source points + for (int i = 0; i < dpts.length; i += 2) + { + if (srcbounds.contains((int) Math.round(pts[i]) + src.getMinX(), + (int) Math.round(pts[i + 1]) + src.getMinY())) + { + int x = (int) Math.floor(pts[i] + src.getMinX()); + int y = (int) Math.floor(pts[i + 1] + src.getMinY()); + double dx = pts[i] + src.getMinX() - x; + double dy = pts[i + 1] + src.getMinY() - y; + Arrays.fill(result, 0); + + for (int m = - 1; m < 3; m++) + for (int n = - 1; n < 3; n++) + { + // R(x) = ( P(x+2)^3 - 4 P(x+1)^3 + 6 P(x)^3 - 4 P(x-1)^3 ) / 6 + double r1 = 0; + double r2 = 0; + + // Calculate R(m - dx) + double rx = m - dx + 2; + r1 += rx * rx * rx; + + rx = m - dx + 1; + if (rx > 0) + r1 -= 4 * rx * rx * rx; + + rx = m - dx; + if (rx > 0) + r1 += 6 * rx * rx * rx; + + rx = m - dx - 1; + if (rx > 0) + r1 -= 4 * rx * rx * rx; + + r1 /= 6; + + // Calculate R(dy - n); + rx = dy - n + 2; + if (rx > 0) + r2 += rx * rx * rx; + + rx = dy - n + 1; + if (rx > 0) + r2 -= 4 * rx * rx * rx; + + rx = dy - n; + if (rx > 0) + r2 += 6 * rx * rx * rx; + + rx = dy - n - 1; + if (rx > 0) + r2 -= 4 * rx * rx * rx; + + r2 /= 6; + + // Calculate F(i+m, j+n) R(m - dx) R(dy - n) + // Check corner cases + int srcX = x + m; + if (srcX >= src.getMinX() + src.getWidth()) + srcX = src.getMinX() + src.getWidth() - 1; + else if (srcX < src.getMinX()) + srcX = src.getMinX(); + + int srcY = y + n; + if (srcY >= src.getMinY() + src.getHeight()) + srcY = src.getMinY() + src.getHeight() - 1; + else if (srcY < src.getMinY()) + srcY = src.getMinY(); + + // Calculate once for each band, using the smallest + // datatype possible + if (src.getTransferType() == DataBuffer.TYPE_DOUBLE + || src.getTransferType() == DataBuffer.TYPE_FLOAT) + { + pixels = src.getPixel(srcX, srcY, (double[])pixels); + for (int j = 0; j < result.length; j++) + result[j] += ((double[])pixels)[j] * r1 * r2; + } + else + { + pixels = src.getPixel(srcX, srcY, (int[])pixels); + for (int j = 0; j < result.length; j++) + result[j] += ((int[])pixels)[j] * r1 * r2; + } + } + + // Put it all together + dst.setPixel((int)dpts[i] + dst.getMinX(), + (int)dpts[i+1] + dst.getMinY(), + result); + } + } + } +} diff --git a/libjava/classpath/java/awt/image/AreaAveragingScaleFilter.java b/libjava/classpath/java/awt/image/AreaAveragingScaleFilter.java new file mode 100644 index 000000000..db2335f1c --- /dev/null +++ b/libjava/classpath/java/awt/image/AreaAveragingScaleFilter.java @@ -0,0 +1,268 @@ +/* AreaAveragingScaleFilter.java -- Java class for filtering images + Copyright (C) 1999,2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +/** + * This filter should produce images which do not have image artifacts + * like broken lines which were originally unbroken. The cost is of + * course speed. Using bi-linear interpolation here against 4 pixel + * points should give the desired results although Sun does not + * specify what the exact algorithm should be. + * <br> + * + * @author C. Brian Jones (cbj@gnu.org) + */ +public class AreaAveragingScaleFilter extends ReplicateScaleFilter +{ + /** + * Construct an instance of <code>AreaAveragingScaleFilter</code> which + * should be used in conjunction with a <code>FilteredImageSource</code> + * object. + * + * @param width the width of the destination image + * @param height the height of the destination image + */ + public AreaAveragingScaleFilter(int width, int height) { + super(width, height); + } + + /** + * The <code>ImageProducer</code> should call this method with a + * bit mask of hints from any of <code>RANDOMPIXELORDER</code>, + * <code>TOPDOWNLEFTRIGHT</code>, <code>COMPLETESCANLINES</code>, + * <code>SINGLEPASS</code>, <code>SINGLEFRAME</code> from the + * <code>ImageConsumer</code> interface. + * <br> + * FIXME - more than likely Sun's implementation desires + * <code>TOPDOWNLEFTRIGHT</code> order and this method is overloaded here + * in order to assure that mask is part of the hints added to + * the consumer. + * + * @param flags a bit mask of hints + * @see ImageConsumer + */ + public void setHints(int flags) + { + if (consumer != null) + consumer.setHints(flags); + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as a <code>byte</code> at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the <code>ColorModel</code> used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the <code>pixels</code> array + * @param scansize the width to use in extracting pixels from the <code>pixels</code> array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, byte[] pixels, int offset, int scansize) + { + double rx = ((double) srcWidth) / destWidth; + double ry = ((double) srcHeight) / destHeight; + + int destScansize = (int) Math.round(scansize / rx); + + byte[] destPixels = averagePixels(x, y, w, h, + model, pixels, offset, scansize, + rx, ry, destScansize); + + if (consumer != null) + consumer.setPixels((int) Math.floor(x/rx), (int) Math.floor(y/ry), + (int) Math.ceil(w/rx), (int) Math.ceil(h/ry), + model, destPixels, 0, destScansize); + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as an <code>int</code> at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the <code>ColorModel</code> used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the <code>pixels</code> array + * @param scansize the width to use in extracting pixels from the <code>pixels</code> array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, int[] pixels, int offset, int scansize) + { + double rx = ((double) srcWidth) / destWidth; + double ry = ((double) srcHeight) / destHeight; + + int destScansize = (int) Math.round(scansize / rx); + + int[] destPixels = averagePixels(x, y, w, h, + model, pixels, offset, scansize, + rx, ry, destScansize); + + if (consumer != null) + consumer.setPixels((int) Math.floor(x/rx), (int) Math.floor(y/ry), + (int) Math.ceil(w/rx), (int) Math.ceil(h/ry), + model, destPixels, 0, destScansize); + } + + /** + * This is a really terrible implementation, + * since it uses the nearest-neighbor method. This filter is rarely used though. + * + * @param srcx, srcy - Source rectangle upper-left corner + * @param srcw, srch - Source rectangle width and height + * @param model - Pixel color model + * @param srcPixels - Source pixel data. + * @param srcOffset - Starting offset into the source pixel data array. + * @param srcScansize - Source array scanline size. + * @param rx,ry - Scaling factor. + * @param destScansize - Destination array scanline size. + */ + private byte[] averagePixels(int srcx, int srcy, int srcw, int srch, + ColorModel model, byte[] srcPixels, + int srcOffset, int srcScansize, + double rx, double ry, int destScansize) + { + int destW = (int) Math.ceil(srcw/rx); + int destH = (int) Math.ceil(srch/ry); + byte[] destPixels = new byte[ destW * destH ]; + int sx, sy; + + int w = (int)Math.ceil(rx); + int h = (int)Math.ceil(ry); + + for(int x = 0; x < destW; x++) + for(int y = 0; y < destH; y++) + { + sx = (int) (x * rx); + sy = (int) (y * ry); + + int r,g,b,a; + r = g = b = a = 0; + + for(int i = 0; i < w; i++) + { + for(int j = 0; j < h; j++) + { + int idx = srcx + sx + i + (srcy + sy + j)*srcScansize; + r += model.getRed(srcPixels[ idx ]); + g += model.getGreen(srcPixels[ idx ]); + b += model.getBlue(srcPixels[ idx ]); + a += model.getAlpha(srcPixels[ idx ]); + } + } + + r = r / (w * h); + g = g / (w * h); + b = b / (w * h); + a = a / (w * h); + + // Does this really work? + destPixels[x + destScansize*y] = (byte)model.getDataElement + (new int[]{r, g, b, a}, 0); + } + + return destPixels; + } + + /** + * This is a really terrible implementation, + * since it uses the nearest-neighbor method. This filter is rarely used though. + * + * @param srcx, srcy - Source rectangle upper-left corner + * @param srcw, srch - Source rectangle width and height + * @param model - Pixel color model + * @param srcPixels - Source pixel data. + * @param srcOffset - Starting offset into the source pixel data array. + * @param srcScansize - Source array scanline size. + * @param rx,ry - Scaling factor. + * @param destScansize - Destination array scanline size. + */ + private int[] averagePixels(int srcx, int srcy, int srcw, int srch, + ColorModel model, int[] srcPixels, + int srcOffset, int srcScansize, + double rx, double ry, int destScansize) + { + int destW = (int) Math.ceil(srcw/rx); + int destH = (int) Math.ceil(srch/ry); + int[] destPixels = new int[ destW * destH ]; + int sx, sy; + + int w = (int)Math.ceil(rx); + int h = (int)Math.ceil(ry); + + for(int x = 0; x < destW; x++) + for(int y = 0; y < destH; y++) + { + sx = (int) (x * rx); + sy = (int) (y * ry); + + int r,g,b,a; + r = g = b = a = 0; + + for(int i = 0; i < w; i++) + { + for(int j = 0; j < h; j++) + { + int idx = srcx + sx + i + (srcy + sy + j)*srcScansize; + r += model.getRed(srcPixels[ idx ]); + g += model.getGreen(srcPixels[ idx ]); + b += model.getBlue(srcPixels[ idx ]); + a += model.getAlpha(srcPixels[ idx ]); + } + } + + r = r / (w * h); + g = g / (w * h); + b = b / (w * h); + a = a / (w * h); + + destPixels[x + destScansize*y] = model.getDataElement + (new int[]{r, g, b, a}, 0); + } + + return destPixels; + } +} diff --git a/libjava/classpath/java/awt/image/BandCombineOp.java b/libjava/classpath/java/awt/image/BandCombineOp.java new file mode 100644 index 000000000..f3a6c5756 --- /dev/null +++ b/libjava/classpath/java/awt/image/BandCombineOp.java @@ -0,0 +1,218 @@ +/* BandCombineOp.java - perform a combination on the bands of a raster + Copyright (C) 2004, 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +import java.awt.RenderingHints; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.Arrays; + +/** + * Filter Raster pixels by applying a matrix. + * + * BandCombineOp applies a matrix to each pixel to produce new pixel values. + * The width of the matrix must be the same or one more than the number of + * bands in the source Raster. If one more, the pixels in the source are + * assumed to contain an implicit 1.0 at the end. + * + * The rows of the matrix are multiplied by the pixel to produce the values + * for the destination. Therefore the destination Raster must contain the + * same number of bands as the number of rows in the filter matrix. + * + * This Op assumes that samples are integers; floating point sample types will + * be rounded to their nearest integer value during filtering. + * + * @author Jerry Quinn (jlquinn@optonline.net) + */ +public class BandCombineOp implements RasterOp +{ + private RenderingHints hints; + private float[][] matrix; + + /** + * Construct a BandCombineOp. + * + * @param matrix The matrix to filter pixels with. + * @param hints Rendering hints to apply. Ignored. + * @throws ArrayIndexOutOfBoundsException if the matrix is invalid + */ + public BandCombineOp(float[][] matrix, RenderingHints hints) + { + this.matrix = new float[matrix.length][]; + int width = matrix[0].length; + for (int i = 0; i < matrix.length; i++) + { + this.matrix[i] = new float[width + 1]; + for (int j = 0; j < width; j++) + this.matrix[i][j] = matrix[i][j]; + + // The reference implementation pads the array with a trailing zero... + this.matrix[i][width] = 0; + } + + this.hints = hints; + } + + /** + * Filter Raster pixels through a matrix. Applies the Op matrix to source + * pixes to produce dest pixels. Each row of the matrix is multiplied by the + * src pixel components to produce the dest pixel. If matrix is one more than + * the number of bands in the src, the last element is implicitly multiplied + * by 1, i.e. added to the sum for that dest component. If dest is null, a + * suitable Raster is created. This implementation uses + * createCompatibleDestRaster. + * + * @param src The source Raster. + * @param dest The destination Raster, or null. + * @throws IllegalArgumentException if the destination raster is incompatible + * with the source raster. + * @return The filtered Raster. + * @see java.awt.image.RasterOp#filter(java.awt.image.Raster, + * java.awt.image.WritableRaster) + */ + public WritableRaster filter(Raster src, WritableRaster dest) { + if (dest == null) + dest = createCompatibleDestRaster(src); + else if (dest.getNumBands() != src.getNumBands() + || dest.getTransferType() != src.getTransferType()) + throw new IllegalArgumentException("Destination raster is incompatible with source raster"); + + // Filter the pixels + int[] spix = new int[matrix[0].length - 1]; + int[] spix2 = new int[matrix[0].length - 1]; + int[] dpix = new int[matrix.length]; + for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) + for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) + { + // In case matrix rows have implicit translation + spix[spix.length - 1] = 1; + src.getPixel(x, y, spix); + + // Do not re-calculate if pixel is identical to the last one + // (ie, blocks of the same colour) + if (!Arrays.equals(spix, spix2)) + { + System.arraycopy(spix, 0, spix2, 0, spix.length); + for (int i = 0; i < matrix.length; i++) + { + dpix[i] = 0; + for (int j = 0; j < matrix[0].length - 1; j++) + dpix[i] += spix[j] * (int)matrix[i][j]; + } + } + dest.setPixel(x, y, dpix); + } + + return dest; + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#getBounds2D(java.awt.image.Raster) + */ + public final Rectangle2D getBounds2D(Raster src) + { + return src.getBounds(); + } + + /** + * Creates a new WritableRaster that can be used as the destination for this + * Op. The number of bands in the source raster must equal the number of rows + * in the op matrix, which must also be equal to either the number of columns + * or (columns - 1) in the matrix. + * + * @param src The source raster. + * @return A compatible raster. + * @see java.awt.image.RasterOp#createCompatibleDestRaster(java.awt.image.Raster) + * @throws IllegalArgumentException if the raster is incompatible with the + * matrix. + */ + public WritableRaster createCompatibleDestRaster(Raster src) + { + // Destination raster must have same number of bands as source + if (src.getNumBands() != matrix.length) + throw new IllegalArgumentException("Number of rows in matrix specifies an " + + "incompatible number of bands"); + + // We use -1 and -2 because we previously padded the rows with a trailing 0 + if (src.getNumBands() != matrix[0].length - 1 + && src.getNumBands() != matrix[0].length - 2) + throw new IllegalArgumentException("Incompatible number of bands: " + + "the number of bands in the raster must equal the number of " + + "columns in the matrix, optionally minus one"); + + return src.createCompatibleWritableRaster(); + } + + /** + * Return corresponding destination point for source point. Because this is + * not a geometric operation, it simply returns a copy of the source. + * + * @param src The source point. + * @param dst The destination point. + * @return dst The destination point. + * @see java.awt.image.RasterOp#getPoint2D(java.awt.geom.Point2D, + *java.awt.geom.Point2D) + */ + public final Point2D getPoint2D(Point2D src, Point2D dst) + { + if (dst == null) + return (Point2D)src.clone(); + + dst.setLocation(src); + return dst; + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#getRenderingHints() + */ + public final RenderingHints getRenderingHints() + { + return hints; + } + + /** + * Return the matrix used in this operation. + * + * @return The matrix used in this operation. + */ + public final float[][] getMatrix() + { + return matrix; + } + +} diff --git a/libjava/classpath/java/awt/image/BandedSampleModel.java b/libjava/classpath/java/awt/image/BandedSampleModel.java new file mode 100644 index 000000000..7df6c8548 --- /dev/null +++ b/libjava/classpath/java/awt/image/BandedSampleModel.java @@ -0,0 +1,759 @@ +/* Copyright (C) 2004, 2005, 2006, Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +import gnu.java.awt.Buffers; +import gnu.java.lang.CPStringBuilder; + +/** + * A sample model that reads each sample value from a separate band in the + * {@link DataBuffer}. + * + * @author Jerry Quinn (jlquinn@optonline.net) + */ +public final class BandedSampleModel extends ComponentSampleModel +{ + private int[] bitMasks; + private int[] bitOffsets; + private int[] sampleSize; + private int dataBitOffset; + private int elemBits; + private int numberOfBits; + private int numElems; + + private static int[] createBankArray(int size) + { + int[] result = new int[size]; + for (int i = 0; i < size; i++) + result[i] = i; + return result; + } + + /** + * Creates a new <code>BandedSampleModel</code>. + * + * @param dataType the data buffer type. + * @param w the width (in pixels). + * @param h the height (in pixels). + * @param numBands the number of bands. + */ + public BandedSampleModel(int dataType, int w, int h, int numBands) + { + this(dataType, w, h, w, createBankArray(numBands), new int[numBands]); + } + + /** + * Creates a new <code>BandedSampleModel</code>. + * + * @param dataType the data buffer type. + * @param w the width (in pixels). + * @param h the height (in pixels). + * @param scanlineStride the number of data elements from a pixel in one + * row to the corresponding pixel in the next row. + * @param bankIndices the bank indices. + * @param bandOffsets the band offsets. + */ + public BandedSampleModel(int dataType, int w, int h, int scanlineStride, + int[] bankIndices, int[] bandOffsets) + { + super(dataType, w, h, 1, scanlineStride, bankIndices, bandOffsets); + } + + /** + * Creates a new data buffer that is compatible with this sample model. + * + * @return The new data buffer. + */ + public DataBuffer createDataBuffer() + { + int size = scanlineStride * height; + return Buffers.createBuffer(getDataType(), size, numBanks); + } + + /** + * Creates a new <code>SampleModel</code> that is compatible with this + * model and has the specified width and height. + * + * @param w the width (in pixels, must be greater than zero). + * @param h the height (in pixels, must be greater than zero). + * + * @return The new sample model. + * + * @throws IllegalArgumentException if <code>w</code> or <code>h</code> is + * not greater than zero. + * @throws IllegalArgumentException if <code>w * h</code> exceeds + * <code>Integer.MAX_VALUE</code>. + */ + public SampleModel createCompatibleSampleModel(int w, int h) + { + // NOTE: blackdown 1.4.1 sets all offsets to 0. Sun's 1.4.2 docs + // disagree. + + // Compress offsets so minimum is 0, others w*scanlineStride + int[] newoffsets = new int[bandOffsets.length]; + int[] order = new int[bandOffsets.length]; + for (int i = 0; i < bandOffsets.length; i++) + order[i] = i; + // FIXME: This is N^2, but not a big issue, unless there's a lot of + // bands... + for (int i = 0; i < bandOffsets.length; i++) + for (int j = i + 1; j < bandOffsets.length; j++) + if (bankIndices[order[i]] > bankIndices[order[j]] + || (bankIndices[order[i]] == bankIndices[order[j]] + && bandOffsets[order[i]] > bandOffsets[order[j]])) + { + int t = order[i]; order[i] = order[j]; order[j] = t; + } + int bank = 0; + int offset = 0; + for (int i = 0; i < bandOffsets.length; i++) + { + if (bankIndices[order[i]] != bank) + { + bank = bankIndices[order[i]]; + offset = 0; + } + newoffsets[order[i]] = offset; + offset += w * scanlineStride; + } + + return new BandedSampleModel(dataType, w, h, w, bankIndices, newoffsets); + } + + + public SampleModel createSubsetSampleModel(int[] bands) + { + if (bands.length > bankIndices.length) + throw new + RasterFormatException("BandedSampleModel createSubsetSampleModel too" + +" many bands"); + int[] newoff = new int[bands.length]; + int[] newbanks = new int[bands.length]; + for (int i = 0; i < bands.length; i++) + { + int b = bands[i]; + newoff[i] = bandOffsets[b]; + newbanks[i] = bankIndices[b]; + } + + return new BandedSampleModel(dataType, width, height, scanlineStride, + newbanks, newoff); + } + + /** + * Extract all samples of one pixel and return in an array of transfer type. + * + * Extracts the pixel at x, y from data and stores samples into the array + * obj. If obj is null, a new array of getTransferType() is created. + * + * @param x The x-coordinate of the pixel rectangle to store in + * <code>obj</code>. + * @param y The y-coordinate of the pixel rectangle to store in + * <code>obj</code>. + * @param obj The primitive array to store the pixels into or null to force + * creation. + * @param data The DataBuffer that is the source of the pixel data. + * @return The primitive array containing the pixel data. + * @see java.awt.image.SampleModel#getDataElements(int, int, + * java.lang.Object, java.awt.image.DataBuffer) + */ + public Object getDataElements(int x, int y, Object obj, DataBuffer data) + { + if (x < 0 || y < 0) + throw new ArrayIndexOutOfBoundsException( + "x and y must not be less than 0."); + int pixel = getSample(x, y, 0, data); + switch (getTransferType()) + { + case DataBuffer.TYPE_BYTE: + { + byte[] b = (byte[]) obj; + if (b == null) b = new byte[numBands]; + for (int i = 0; i < numBands; i++) + b[i] = (byte)getSample(x, y, i, data); + return b; + } + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + { + short[] b = (short[]) obj; + if (b == null) b = new short[numBands]; + for (int i = 0; i < numBands; i++) + b[i] = (short)getSample(x, y, i, data); + return b; + } + case DataBuffer.TYPE_INT: + { + int[] b = (int[]) obj; + if (b == null) b = new int[numBands]; + for (int i = 0; i < numBands; i++) + b[i] = getSample(x, y, i, data); + return b; + } + case DataBuffer.TYPE_FLOAT: + { + float[] b = (float[]) obj; + if (b == null) b = new float[numBands]; + for (int i = 0; i < numBands; i++) + b[i] = getSampleFloat(x, y, i, data); + return b; + } + case DataBuffer.TYPE_DOUBLE: + { + double[] b = (double[]) obj; + if (b == null) + b = new double[numBands]; + for (int i = 0; i < numBands; i++) + b[i] = getSample(x, y, i, data); + return b; + } + + default: + // Seems like the only sensible thing to do. + throw new ClassCastException(); + } + } + + /** + * Returns all the samples for the pixel at location <code>(x, y)</code> + * stored in the specified data buffer. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param iArray an array that will be populated with the sample values and + * returned as the result. The size of this array should be equal to the + * number of bands in the model. If the array is <code>null</code>, a new + * array is created. + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The samples for the specified pixel. + * + * @see #setPixel(int, int, int[], DataBuffer) + */ + public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) + { + if (iArray == null) + iArray = new int[numBands]; + for (int i = 0; i < numBands; i++) + iArray[i] = getSample(x, y, i, data); + + return iArray; + } + + /** + * Copy pixels from a region into an array. + * + * Copies the samples of the pixels in the rectangle starting at x, y that + * is w pixels wide and h scanlines high. When there is more than one band, + * the samples stored in order before the next pixel. This ordering isn't + * well specified in Sun's docs as of 1.4.2. + * + * If iArray is null, a new array is allocated, filled, and returned. + * + * @param x The x-coordinate of the pixel rectangle to store in + * <code>iArray</code>. + * @param y The y-coordinate of the pixel rectangle to store in + * <code>iArray</code>. + * @param w The width in pixels of the rectangle. + * @param h The height in pixels of the rectangle. + * @param iArray The int array to store the pixels into or null to force + * creation. + * @param data The DataBuffer that is the source of the pixel data. + * @return The primitive array containing the pixel data. + */ + public int[] getPixels(int x, int y, int w, int h, int[] iArray, + DataBuffer data) + { + if (x < 0 || y < 0) + throw new ArrayIndexOutOfBoundsException( + "x and y must not be less than 0."); + if (iArray == null) + iArray = new int[w * h * numBands]; + int outOffset = 0; + int maxX = x + w; + int maxY = y + h; + for (int yy = x; yy < maxY; yy++) + { + for (int xx = x; xx < maxX; xx++) + { + for (int b = 0; b < numBands; b++) + { + int offset = bandOffsets[b] + yy * scanlineStride + xx; + iArray[outOffset++] = + data.getElem(bankIndices[b], offset); + } + } + } + return iArray; + } + + /** + * Returns a sample value for the pixel at (x, y) in the specified data + * buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample value. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public int getSample(int x, int y, int b, DataBuffer data) + { + int offset = bandOffsets[b] + y * scanlineStride + x; + return data.getElem(bankIndices[b], offset); + } + + /** + * Returns a sample value for the pixel at (x, y) in the specified data + * buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample value. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + * + * @see #getSample(int, int, int, DataBuffer) + */ + public float getSampleFloat(int x, int y, int b, DataBuffer data) + { + int offset = bandOffsets[b] + y * scanlineStride + x; + return data.getElemFloat(bankIndices[b], offset); + } + + /** + * Returns the sample value for the pixel at (x, y) in the specified data + * buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample value. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + * + * @see #getSample(int, int, int, DataBuffer) + */ + public double getSampleDouble(int x, int y, int b, DataBuffer data) + { + int offset = bandOffsets[b] + y * scanlineStride + x; + return data.getElemDouble(bankIndices[b], offset); + } + + /** + * Copy one band's samples from a region into an array. + * + * Copies from one band the samples of the pixels in the rectangle starting + * at x, y that is w pixels wide and h scanlines high. + * + * If iArray is null, a new array is allocated, filled, and returned. + * + * @param x The x-coordinate of the pixel rectangle to store in + * <code>iArray</code>. + * @param y The y-coordinate of the pixel rectangle to store in + * <code>iArray</code>. + * @param w The width in pixels of the rectangle. + * @param h The height in pixels of the rectangle. + * @param b The band to retrieve. + * @param iArray The int array to store the pixels into or null to force + * creation. + * @param data The DataBuffer that is the source of the pixel data. + * @return The primitive array containing the pixel data. + */ + public int[] getSamples(int x, int y, int w, int h, int b, int[] iArray, + DataBuffer data) + { + if (x < 0 || y < 0) + throw new ArrayIndexOutOfBoundsException( + "x and y must not be less than 0."); + if (iArray == null) + iArray = new int[w * h]; + int outOffset = 0; + int maxX = x + w; + int maxY = y + h; + for (int yy = y; yy < maxY; yy++) + { + for (int xx = x; xx < maxX; xx++) + { + int offset = bandOffsets[b] + yy * scanlineStride + xx; + iArray[outOffset++] = + data.getElem(bankIndices[b], offset); + } + } + return iArray; + } + + /** + * Set the pixel at x, y to the value in the first element of the primitive + * array obj. + * + * @param x The x-coordinate of the data elements in <code>obj</code>. + * @param y The y-coordinate of the data elements in <code>obj</code>. + * @param obj The primitive array containing the data elements to set. + * @param data The DataBuffer to store the data elements into. + * @see java.awt.image.SampleModel#setDataElements(int, int, int, int, java.lang.Object, java.awt.image.DataBuffer) + */ + public void setDataElements(int x, int y, Object obj, DataBuffer data) + { + int transferType = getTransferType(); + if (getTransferType() != data.getDataType()) + { + throw new IllegalArgumentException("transfer type ("+ + getTransferType()+"), "+ + "does not match data "+ + "buffer type (" + + data.getDataType() + + ")."); + } + + int offset = y * scanlineStride + x; + + try + { + switch (transferType) + { + case DataBuffer.TYPE_BYTE: + { + DataBufferByte out = (DataBufferByte) data; + byte[] in = (byte[]) obj; + for (int i = 0; i < numBands; i++) + out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i]; + return; + } + case DataBuffer.TYPE_SHORT: + { + DataBufferShort out = (DataBufferShort) data; + short[] in = (short[]) obj; + for (int i = 0; i < numBands; i++) + out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i]; + return; + } + case DataBuffer.TYPE_USHORT: + { + DataBufferUShort out = (DataBufferUShort) data; + short[] in = (short[]) obj; + for (int i = 0; i < numBands; i++) + out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i]; + return; + } + case DataBuffer.TYPE_INT: + { + DataBufferInt out = (DataBufferInt) data; + int[] in = (int[]) obj; + for (int i = 0; i < numBands; i++) + out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i]; + return; + } + case DataBuffer.TYPE_FLOAT: + { + DataBufferFloat out = (DataBufferFloat) data; + float[] in = (float[]) obj; + for (int i = 0; i < numBands; i++) + out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i]; + return; + } + case DataBuffer.TYPE_DOUBLE: + { + DataBufferDouble out = (DataBufferDouble) data; + double[] in = (double[]) obj; + for (int i = 0; i < numBands; i++) + out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i]; + return; + } + default: + throw new ClassCastException("Unsupported data type"); + } + } + catch (ArrayIndexOutOfBoundsException aioobe) + { + String msg = "While writing data elements" + + ", x=" + x + ", y=" + y + + ", width=" + width + ", height=" + height + + ", scanlineStride=" + scanlineStride + + ", offset=" + offset + + ", data.getSize()=" + data.getSize() + + ", data.getOffset()=" + data.getOffset() + + ": " + aioobe; + throw new ArrayIndexOutOfBoundsException(msg); + } + } + + /** + * Sets the samples for the pixel at (x, y) in the specified data buffer to + * the specified values. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param iArray the sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>iArray</code> or + * <code>data</code> is <code>null</code>. + */ + public void setPixel(int x, int y, int[] iArray, DataBuffer data) + { + for (int b = 0; b < numBands; b++) + data.setElem(bankIndices[b], bandOffsets[b] + y * scanlineStride + x, + iArray[b]); + } + + /** + * Sets the sample values for the pixels in the region specified by + * (x, y, w, h) in the specified data buffer. The array is + * ordered by pixels (that is, all the samples for the first pixel are + * grouped together, followed by all the samples for the second pixel, and so + * on). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param iArray the pixel sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>iArray</code> or + * <code>data</code> is <code>null</code>. + */ + public void setPixels(int x, int y, int w, int h, int[] iArray, + DataBuffer data) + { + int inOffset = 0; + for (int hh = 0; hh < h; hh++) + { + for (int ww = 0; ww < w; ww++) + { + int offset = y * scanlineStride + (x + ww); + for (int b = 0; b < numBands; b++) + data.setElem(bankIndices[b], bandOffsets[b] + offset, + iArray[inOffset++]); + } + y++; + } + } + + /** + * Sets the sample value for band <code>b</code> of the pixel at location + * <code>(x, y)</code> in the specified data buffer. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param b the band index. + * @param s the sample value. + * @param data the data buffer (<code>null</code> not permitted). + * + * @see #getSample(int, int, int, DataBuffer) + */ + public void setSample(int x, int y, int b, int s, DataBuffer data) + { + data.setElem(bankIndices[b], bandOffsets[b] + y * scanlineStride + x, s); + } + + /** + * Sets the sample value for a band for the pixel at (x, y) in the + * specified data buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param s the sample value. + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public void setSample(int x, int y, int b, float s, DataBuffer data) + { + data.setElemFloat(bankIndices[b], bandOffsets[b] + y * scanlineStride + x, + s); + } + + /** + * Sets the sample value for a band for the pixel at (x, y) in the + * specified data buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param s the sample value. + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public void setSample(int x, int y, int b, double s, DataBuffer data) + { + data.setElemDouble(bankIndices[b], bandOffsets[b] + y * scanlineStride + x, + s); + } + + /** + * Sets the sample values for one band for the pixels in the region + * specified by (x, y, w, h) in the specified data buffer. + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param iArray the sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>iArray</code> or + * <code>data</code> is <code>null</code>. + */ + public void setSamples(int x, int y, int w, int h, int b, int[] iArray, + DataBuffer data) + { + if (x < 0 || y < 0) + throw new ArrayIndexOutOfBoundsException( + "x and y must not be less than 0."); + int inOffset = 0; + + switch (getTransferType()) + { + case DataBuffer.TYPE_BYTE: + { + DataBufferByte out = (DataBufferByte) data; + byte[] bank = out.getData(bankIndices[b]); + for (int hh = 0; hh < h; hh++) + { + for (int ww = 0; ww < w; ww++) + { + int offset = bandOffsets[b] + y * scanlineStride + (x + ww); + bank[offset] = (byte)iArray[inOffset++]; + } + y++; + } + return; + } + case DataBuffer.TYPE_SHORT: + { + DataBufferShort out = (DataBufferShort) data; + short[] bank = out.getData(bankIndices[b]); + for (int hh = 0; hh < h; hh++) + { + for (int ww = 0; ww < w; ww++) + { + int offset = bandOffsets[b] + y * scanlineStride + (x + ww); + bank[offset] = (short)iArray[inOffset++]; + } + y++; + } + return; + } + case DataBuffer.TYPE_USHORT: + { + DataBufferShort out = (DataBufferShort) data; + short[] bank = out.getData(bankIndices[b]); + for (int hh = 0; hh < h; hh++) + { + for (int ww = 0; ww < w; ww++) + { + int offset = bandOffsets[b] + y * scanlineStride + (x + ww); + bank[offset] = (short)iArray[inOffset++]; + } + y++; + } + return; + } + case DataBuffer.TYPE_INT: + { + DataBufferInt out = (DataBufferInt) data; + int[] bank = out.getData(bankIndices[b]); + for (int hh = 0; hh < h; hh++) + { + for (int ww = 0; ww < w; ww++) + { + int offset = bandOffsets[b] + y * scanlineStride + (x + ww); + bank[offset] = iArray[inOffset++]; + } + y++; + } + return; + } + case DataBuffer.TYPE_FLOAT: + case DataBuffer.TYPE_DOUBLE: + break; + default: + throw new ClassCastException("Unsupported data type"); + } + + // Default implementation probably slower for float and double + for (int hh = 0; hh < h; hh++) + { + for (int ww = 0; ww < w; ww++) + { + int offset = bandOffsets[b] + y * scanlineStride + (x + ww); + data.setElem(bankIndices[b], offset, iArray[inOffset++]); + } + y++; + } + } + + /** + * Creates a String with some information about this SampleModel. + * @return A String describing this SampleModel. + * @see java.lang.Object#toString() + */ + public String toString() + { + CPStringBuilder result = new CPStringBuilder(); + result.append(getClass().getName()); + result.append("["); + result.append("scanlineStride=").append(scanlineStride); + for(int i = 0; i < bitMasks.length; i+=1) + { + result.append(", mask[").append(i).append("]=0x").append( + Integer.toHexString(bitMasks[i])); + } + + result.append("]"); + return result.toString(); + } +} diff --git a/libjava/classpath/java/awt/image/BufferStrategy.java b/libjava/classpath/java/awt/image/BufferStrategy.java new file mode 100644 index 000000000..e86aad60f --- /dev/null +++ b/libjava/classpath/java/awt/image/BufferStrategy.java @@ -0,0 +1,124 @@ +/* BufferStrategy.java -- describes image buffering resources + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import java.awt.BufferCapabilities; +import java.awt.Graphics; + +/** + * This class describes a strategy for managing image buffering + * resources on a Canvas or Window. A given buffer strategy may make + * use of hardware acceleration or take advantage of features of the + * native graphics system. Examples of buffering strategies are + * double or triple buffering using either flipping or blitting. For + * the details of these algorithms see BufferCapabilities. + * + * To use a buffer strategy, you retrieve it from either the current + * GraphicsConfiguration or from the Component on which you'd like to + * draw. Then you can query the strategy's capabilities to make sure + * they're suitable. + * + * If the strategy's capabilities are suitable, you can obtain a + * graphics object and use it to draw with this strategy. Drawing + * with a buffer strategy requires extra care, however. You'll need + * to manually cause the next buffer to be shown on the output device. + * And since buffer strategies are usually implemented with a + * VolatileImage, you must frequently check that the contents of the + * buffer are valid and that the buffer still exists. + * + * A buffer strategy is usually implemented using a VolatileImage. + * + * @see VolatileImage + * @since 1.4 + */ +public abstract class BufferStrategy +{ + /** + * Creates a new buffer strategy. + */ + public BufferStrategy() + { + } + + /** + * Retrieves the capabilities of this buffer strategy. + * + * @return this buffer strategy's capabilities + */ + public abstract BufferCapabilities getCapabilities(); + + /** + * Retrieves a graphics object that can be used to draw using this + * buffer strategy. This method may not be synchronized so be + * careful when calling it from multiple threads. You also must + * manually dispose of this graphics object. + * + * @return a graphics object that can be used to draw using this + * buffer strategy + */ + public abstract Graphics getDrawGraphics(); + + /** + * Returns whether or not the buffer's resources have been reclaimed + * by the native graphics system. If the buffer resources have been + * lost then you'll need to obtain new resources before drawing + * again. For details, see the documentation for VolatileImage. + * + * @return true if the contents were lost, false otherwise + */ + public abstract boolean contentsLost(); + + /** + * Returns whether or not the buffer's resources were re-created and + * cleared to the default background color. If the buffer's + * resources have recently been re-created and initialized then the + * buffer's image may need to be re-rendered. For details, see the + * documentation for VolatileImage. + * + * @return true if the contents were restored, false otherwise + */ + public abstract boolean contentsRestored(); + + /** + * Applies this buffer strategy. In other words, this method brings + * the contents of the back or intermediate buffers to the front + * buffer. + */ + public abstract void show(); +} diff --git a/libjava/classpath/java/awt/image/BufferedImage.java b/libjava/classpath/java/awt/image/BufferedImage.java new file mode 100644 index 000000000..094c71dd1 --- /dev/null +++ b/libjava/classpath/java/awt/image/BufferedImage.java @@ -0,0 +1,839 @@ +/* BufferedImage.java -- + Copyright (C) 2000, 2002, 2003, 2004, 2005, 2006, Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import gnu.java.awt.Buffers; +import gnu.java.awt.ClasspathGraphicsEnvironment; +import gnu.java.awt.ComponentDataBlitOp; +import gnu.java.lang.CPStringBuilder; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.util.Hashtable; +import java.util.Vector; + +/** + * A buffered image always starts at coordinates (0, 0). + * + * The buffered image is not subdivided into multiple tiles. Instead, + * the image consists of one large tile (0,0) with the width and + * height of the image. This tile is always considered to be checked + * out. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public class BufferedImage extends Image + implements WritableRenderedImage, Transparency +{ + public static final int TYPE_CUSTOM = 0, + TYPE_INT_RGB = 1, + TYPE_INT_ARGB = 2, + TYPE_INT_ARGB_PRE = 3, + TYPE_INT_BGR = 4, + TYPE_3BYTE_BGR = 5, + TYPE_4BYTE_ABGR = 6, + TYPE_4BYTE_ABGR_PRE = 7, + TYPE_USHORT_565_RGB = 8, + TYPE_USHORT_555_RGB = 9, + TYPE_BYTE_GRAY = 10, + TYPE_USHORT_GRAY = 11, + TYPE_BYTE_BINARY = 12, + TYPE_BYTE_INDEXED = 13; + + /** + * Vector of TileObservers (or null) + */ + Vector<TileObserver> tileObservers; + + /** + * The image's WritableRaster + */ + WritableRaster raster; + + /** + * The associated ColorModel + */ + ColorModel colorModel; + + /** + * The image's properties (or null) + */ + Hashtable properties; + + /** + * Whether alpha is premultiplied + */ + boolean isPremultiplied; + + /** + * The predefined type, if any. + */ + int type; + + /** + * Creates a new <code>BufferedImage</code> with the specified width, height + * and type. Valid <code>type</code> values are: + * + * <ul> + * <li>{@link #TYPE_INT_RGB}</li> + * <li>{@link #TYPE_INT_ARGB}</li> + * <li>{@link #TYPE_INT_ARGB_PRE}</li> + * <li>{@link #TYPE_INT_BGR}</li> + * <li>{@link #TYPE_3BYTE_BGR}</li> + * <li>{@link #TYPE_4BYTE_ABGR}</li> + * <li>{@link #TYPE_4BYTE_ABGR_PRE}</li> + * <li>{@link #TYPE_USHORT_565_RGB}</li> + * <li>{@link #TYPE_USHORT_555_RGB}</li> + * <li>{@link #TYPE_BYTE_GRAY}</li> + * <li>{@link #TYPE_USHORT_GRAY}</li> + * <li>{@link #TYPE_BYTE_BINARY}</li> + * <li>{@link #TYPE_BYTE_INDEXED}</li> + * </ul> + * + * @param width the width (must be > 0). + * @param height the height (must be > 0). + * @param type the image type (see the list of valid types above). + * + * @throws IllegalArgumentException if <code>width</code> or + * <code>height</code> is less than or equal to zero. + * @throws IllegalArgumentException if <code>type</code> is not one of the + * specified values. + */ + public BufferedImage(int width, int height, int type) + { + SampleModel sm = null; + ColorModel cm = null; + boolean premultiplied = (type == BufferedImage.TYPE_INT_ARGB_PRE + || type == BufferedImage.TYPE_4BYTE_ABGR_PRE); + + switch( type ) + { + case BufferedImage.TYPE_INT_RGB: + sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_INT, + width, height, + new int[]{ 0x00FF0000, + 0x0000FF00, + 0x000000FF } ) ; + cm = new DirectColorModel( 24, 0xff0000, 0xff00, 0xff ); + break; + + case BufferedImage.TYPE_3BYTE_BGR: + sm = new PixelInterleavedSampleModel( DataBuffer.TYPE_BYTE, + width, height, + 3, width * 3, + new int[]{ 2, 1, 0 } ); + cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), + false, false, + BufferedImage.OPAQUE, + DataBuffer.TYPE_BYTE); + break; + + case BufferedImage.TYPE_INT_ARGB: + case BufferedImage.TYPE_INT_ARGB_PRE: + sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_INT, + width, height, + new int[]{ 0x00FF0000, + 0x0000FF00, + 0x000000FF, + 0xFF000000 } ); + if (premultiplied) + cm = new DirectColorModel( ColorSpace.getInstance(ColorSpace.CS_sRGB), + 32, 0xff0000, 0xff00, 0xff, 0xff000000, + true, + Buffers.smallestAppropriateTransferType(32)); + else + cm = new DirectColorModel( 32, 0xff0000, 0xff00, 0xff, 0xff000000 ); + + break; + + case BufferedImage.TYPE_4BYTE_ABGR: + case BufferedImage.TYPE_4BYTE_ABGR_PRE: + sm = new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE, + width, height, + 4, 4*width, + new int[]{3, 2, 1, 0}); + cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), + true, premultiplied, + BufferedImage.TRANSLUCENT, + DataBuffer.TYPE_BYTE); + break; + + case BufferedImage.TYPE_INT_BGR: + sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_INT, + width, height, + new int[]{ 0x000000FF, + 0x0000FF00, + 0x00FF0000 } ) ; + cm = new DirectColorModel( 24, 0xff, 0xff00, 0xff0000 ); + break; + + case BufferedImage.TYPE_USHORT_565_RGB: + sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_USHORT, + width, height, + new int[]{ 0xF800, + 0x7E0, + 0x1F } ) ; + cm = new DirectColorModel( 16, 0xF800, 0x7E0, 0x1F ); + break; + + case BufferedImage.TYPE_USHORT_555_RGB: + sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_USHORT, + width, height, + new int[]{ 0x7C00, + 0x3E0, + 0x1F } ) ; + cm = new DirectColorModel( 15, 0x7C00, 0x3E0, 0x1F ); + break; + + case BufferedImage.TYPE_BYTE_INDEXED: + cm = createDefaultIndexedColorModel( false ); + + case BufferedImage.TYPE_BYTE_GRAY: + sm = new PixelInterleavedSampleModel( DataBuffer.TYPE_BYTE, + width, height, + 1, width, new int[]{ 0 } ); + break; + + case BufferedImage.TYPE_USHORT_GRAY: + sm = new PixelInterleavedSampleModel( DataBuffer.TYPE_USHORT, + width, height, + 1, width, new int[]{ 0 } ); + break; + + case BufferedImage.TYPE_BYTE_BINARY: + cm = createDefaultIndexedColorModel( true ); + sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, + width, height, 1); + break; + + default: + sm = null; + } + + if( sm == null ) + throw new IllegalArgumentException("Unknown predefined image type."); + + if( cm == null ) // only for the grayscale types + { + int buftype; + int[] bits = new int[1]; + if( type == BufferedImage.TYPE_BYTE_GRAY ) + { + buftype = DataBuffer.TYPE_BYTE; + bits[0] = 8; + } + else + { + buftype = DataBuffer.TYPE_USHORT; + bits[0] = 16; + } + ColorSpace graySpace = ColorSpace.getInstance( ColorSpace.CS_GRAY ); + + cm = new ComponentColorModel( graySpace, bits, false, false, + Transparency.OPAQUE, buftype ); + } + + WritableRaster rst = null; + + // Attempt to create an accelerated backend for this image + GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); + if (env instanceof ClasspathGraphicsEnvironment) + rst = ((ClasspathGraphicsEnvironment)env).createRaster(cm, sm); + + // Default to a standard Java raster & databuffer if needed + if (rst == null) + rst = Raster.createWritableRaster(sm, new Point( 0, 0 ) ); + + init(cm, rst, premultiplied, + null, // no properties + type ); + } + + public BufferedImage(int w, int h, int type, IndexColorModel indexcolormodel) + { + if ((type != TYPE_BYTE_BINARY) && (type != TYPE_BYTE_INDEXED)) + throw new IllegalArgumentException("Type must be TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED"); + if( indexcolormodel.getMapSize() > 16 && type == TYPE_BYTE_BINARY ) + throw new IllegalArgumentException("Type TYPE_BYTE_BINARY cannot have a larger than 16-color palette."); + if( indexcolormodel.getMapSize() > 256 ) + throw new IllegalArgumentException("Byte type cannot have a larger than 256-color palette."); + + init( indexcolormodel, + indexcolormodel.createCompatibleWritableRaster(w, h), + indexcolormodel.isAlphaPremultiplied(), + null, // no properties + type ); + } + + public BufferedImage(ColorModel colormodel, WritableRaster writableraster, + boolean premultiplied, Hashtable<?,?> properties) + { + init(colormodel, writableraster, premultiplied, properties, TYPE_CUSTOM); + } + + + private void init(ColorModel cm, WritableRaster writableraster, + boolean premultiplied, Hashtable properties, int type) + { + raster = writableraster; + colorModel = cm; + this.properties = properties; + isPremultiplied = premultiplied; + this.type = type; + } + + /** + * Creates the default palettes for the predefined indexed color types + * (256-color or black-and-white) + * + * @param binary - If <code>true</code>, a black and white palette, + * otherwise a default 256-color palette is returned. + */ + private IndexColorModel createDefaultIndexedColorModel( boolean binary ) + { + if( binary ) + { + byte[] t = new byte[]{ 0, (byte)255 }; + return new IndexColorModel( 1, 2, t, t, t ); + } + + byte[] r = new byte[256]; + byte[] g = new byte[256]; + byte[] b = new byte[256]; + + int index = 0; + for( int i = 0; i < 6; i++ ) + for( int j = 0; j < 6; j++ ) + for( int k = 0; k < 6; k++ ) + { + r[ index ] = (byte)(i * 51); + g[ index ] = (byte)(j * 51); + b[ index ] = (byte)(k * 51); + index++; + } + + while( index < 256 ) + { + r[ index ] = g[ index ] = b[ index ] = + (byte)(18 + (index - 216) * 6); + index++; + } + + return new IndexColorModel( 8, 256, r, g, b ); + } + + public void coerceData(boolean premultiplied) + { + colorModel = colorModel.coerceData(raster, premultiplied); + isPremultiplied = premultiplied; + } + + public WritableRaster copyData(WritableRaster dest) + { + if (dest == null) + dest = raster.createCompatibleWritableRaster(getMinX(), getMinY(), + getWidth(),getHeight()); + + int x = dest.getMinX(); + int y = dest.getMinY(); + int w = dest.getWidth(); + int h = dest.getHeight(); + + // create a src child that has the right bounds... + WritableRaster src = + raster.createWritableChild(x, y, w, h, x, y, + null); // same bands + + if (src.getSampleModel () instanceof ComponentSampleModel + && dest.getSampleModel () instanceof ComponentSampleModel) + // Refer to ComponentDataBlitOp for optimized data blitting: + ComponentDataBlitOp.INSTANCE.filter(src, dest); + + else + { + // slower path + int samples[] = src.getPixels (x, y, w, h, (int [])null); + dest.setPixels (x, y, w, h, samples); + } + return dest; + } + + public Graphics2D createGraphics() + { + GraphicsEnvironment env; + env = GraphicsEnvironment.getLocalGraphicsEnvironment (); + return env.createGraphics (this); + } + + public void flush() + { + } + + public WritableRaster getAlphaRaster() + { + return colorModel.getAlphaRaster(raster); + } + + public ColorModel getColorModel() + { + return colorModel; + } + + public Raster getData() + { + return copyData(null); + /* TODO: this might be optimized by returning the same + raster (not writable) as long as image data doesn't change. */ + } + + public Raster getData(Rectangle rectangle) + { + WritableRaster dest = + raster.createCompatibleWritableRaster(rectangle); + return copyData(dest); + } + + public Graphics getGraphics() + { + return createGraphics(); + } + + public int getHeight() + { + return raster.getHeight(); + } + + public int getHeight(ImageObserver imageobserver) + { + return getHeight(); + } + + public int getMinTileX() + { + return 0; + } + + public int getMinTileY() + { + return 0; + } + + public int getMinX() + { + return 0; + } + + public int getMinY() + { + return 0; + } + + public int getNumXTiles() + { + return 1; + } + + public int getNumYTiles() + { + return 1; + } + + /** + * Returns the value of the specified property, or + * {@link Image#UndefinedProperty} if the property is not defined. + * + * @param string the property key (<code>null</code> not permitted). + * + * @return The property value. + * + * @throws NullPointerException if <code>string</code> is <code>null</code>. + */ + public Object getProperty(String string) + { + if (string == null) + throw new NullPointerException("The property name cannot be null."); + Object result = Image.UndefinedProperty; + if (properties != null) + { + Object v = properties.get(string); + if (v != null) + result = v; + } + return result; + } + + public Object getProperty(String string, ImageObserver imageobserver) + { + return getProperty(string); + } + + /** + * Returns <code>null</code> always. + * + * @return <code>null</code> always. + */ + public String[] getPropertyNames() + { + // This method should always return null, see: + // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4640609 + return null; + } + + public int getRGB(int x, int y) + { + Object rgbElem = raster.getDataElements(x, y, null); + return colorModel.getRGB(rgbElem); + } + + public int[] getRGB(int startX, int startY, int w, int h, int[] rgbArray, + int offset, int scanlineStride) + { + if (rgbArray == null) + { + /* + 000000000000000000 + 00000[#######----- [ = start + -----########----- ] = end + -----#######]00000 + 000000000000000000 + */ + int size = (h-1)*scanlineStride + w; + rgbArray = new int[size]; + } + + int endX = startX + w; + int endY = startY + h; + + /* *TODO*: + Opportunity for optimization by examining color models... + + Perhaps wrap the rgbArray up in a WritableRaster with packed + sRGB color model and perform optimized rendering into the + array. */ + + Object rgbElem = null; + for (int y=startY; y<endY; y++) + { + int xoffset = offset; + for (int x=startX; x<endX; x++) + { + int rgb; + rgbElem = raster.getDataElements(x, y, rgbElem); + rgb = colorModel.getRGB(rgbElem); + rgbArray[xoffset++] = rgb; + } + offset += scanlineStride; + } + return rgbArray; + } + + public WritableRaster getRaster() + { + return raster; + } + + public SampleModel getSampleModel() + { + return raster.getSampleModel(); + } + + public ImageProducer getSource() + { + return new ImageProducer() + { + Vector<ImageConsumer> consumers = new Vector<ImageConsumer>(); + + public void addConsumer(ImageConsumer ic) + { + if(!consumers.contains(ic)) + consumers.add(ic); + } + + public boolean isConsumer(ImageConsumer ic) + { + return consumers.contains(ic); + } + + public void removeConsumer(ImageConsumer ic) + { + consumers.remove(ic); + } + + public void startProduction(ImageConsumer ic) + { + int x = 0; + int y = 0; + int width = getWidth(); + int height = getHeight(); + int stride = width; + int offset = 0; + int[] pixels = getRGB(x, y, + width, height, + (int[])null, offset, stride); + // We already convert the color to RGB in the getRGB call, so + // we pass a simple RGB color model to the consumers. + ColorModel model = new DirectColorModel(32, 0xff0000, 0xff00, 0xff, + 0xff000000); + + consumers.add(ic); + + for(int i = 0; i < consumers.size(); i++) + { + ImageConsumer c = consumers.elementAt(i); + c.setHints(ImageConsumer.SINGLEPASS); + c.setDimensions(getWidth(), getHeight()); + c.setPixels(x, y, width, height, model, pixels, offset, stride); + c.imageComplete(ImageConsumer.STATICIMAGEDONE); + } + } + + public void requestTopDownLeftRightResend(ImageConsumer ic) + { + startProduction(ic); + } + + }; + } + + public Vector<RenderedImage> getSources() + { + return null; + } + + public BufferedImage getSubimage(int x, int y, int w, int h) + { + WritableRaster subRaster = + getRaster().createWritableChild(x, y, w, h, 0, 0, null); + + return new BufferedImage(getColorModel(), subRaster, isPremultiplied, + properties); + } + + public Raster getTile(int tileX, int tileY) + { + return getWritableTile(tileX, tileY); + } + + public int getTileGridXOffset() + { + return 0; // according to javadocs + } + + public int getTileGridYOffset() + { + return 0; // according to javadocs + } + + public int getTileHeight() + { + return getHeight(); // image is one big tile + } + + public int getTileWidth() + { + return getWidth(); // image is one big tile + } + + public int getType() + { + return type; + } + + public int getWidth() + { + return raster.getWidth(); + } + + public int getWidth(ImageObserver imageobserver) + { + return getWidth(); + } + + public WritableRaster getWritableTile(int tileX, int tileY) + { + isTileWritable(tileX, tileY); // for exception + return raster; + } + + private static final Point[] tileIndices = { new Point() }; + + public Point[] getWritableTileIndices() + { + return tileIndices; + } + + public boolean hasTileWriters() + { + return true; + } + + public boolean isAlphaPremultiplied() + { + return isPremultiplied; + } + + public boolean isTileWritable(int tileX, int tileY) + { + if ((tileX != 0) || (tileY != 0)) + throw new ArrayIndexOutOfBoundsException("only tile is (0,0)"); + return true; + } + + public void releaseWritableTile(int tileX, int tileY) + { + isTileWritable(tileX, tileY); // for exception + } + + //public void removeTileObserver(TileObserver tileobserver) {} + + public void setData(Raster src) + { + int x = src.getMinX(); + int y = src.getMinY(); + int w = src.getWidth(); + int h = src.getHeight(); + + // create a dest child that has the right bounds... + WritableRaster dest = + raster.createWritableChild(x, y, w, h, x, y, null); + + if (src.getSampleModel () instanceof ComponentSampleModel + && dest.getSampleModel () instanceof ComponentSampleModel) + + // Refer to ComponentDataBlitOp for optimized data blitting: + ComponentDataBlitOp.INSTANCE.filter(src, dest); + else + { + // slower path + int samples[] = src.getPixels (x, y, w, h, (int [])null); + dest.setPixels (x, y, w, h, samples); + } + } + + public void setRGB(int x, int y, int argb) + { + Object rgbElem = colorModel.getDataElements(argb, null); + raster.setDataElements(x, y, rgbElem); + } + + public void setRGB(int startX, int startY, int w, int h, + int[] argbArray, int offset, int scanlineStride) + { + int endX = startX + w; + int endY = startY + h; + + Object rgbElem = null; + for (int y=startY; y<endY; y++) + { + int xoffset = offset; + for (int x=startX; x<endX; x++) + { + int argb = argbArray[xoffset++]; + rgbElem = colorModel.getDataElements(argb, rgbElem); + raster.setDataElements(x, y, rgbElem); + } + offset += scanlineStride; + } + } + + public String toString() + { + CPStringBuilder buf; + + buf = new CPStringBuilder(/* estimated length */ 120); + buf.append("BufferedImage@"); + buf.append(Integer.toHexString(hashCode())); + buf.append(": type="); + buf.append(type); + buf.append(' '); + buf.append(colorModel); + buf.append(' '); + buf.append(raster); + + return buf.toString(); + } + + + /** + * Adds a tile observer. If the observer is already present, it receives + * multiple notifications. + * + * @param to The TileObserver to add. + */ + public void addTileObserver (TileObserver to) + { + if (tileObservers == null) + tileObservers = new Vector<TileObserver>(); + + tileObservers.add (to); + } + + /** + * Removes a tile observer. If the observer was not registered, + * nothing happens. If the observer was registered for multiple + * notifications, it is now registered for one fewer notification. + * + * @param to The TileObserver to remove. + */ + public void removeTileObserver (TileObserver to) + { + if (tileObservers == null) + return; + + tileObservers.remove (to); + } + + /** + * Return the transparency type. + * + * @return One of {@link #OPAQUE}, {@link #BITMASK}, or {@link #TRANSLUCENT}. + * @see Transparency#getTransparency() + * @since 1.5 + */ + public int getTransparency() + { + return colorModel.getTransparency(); + } +} diff --git a/libjava/classpath/java/awt/image/BufferedImageFilter.java b/libjava/classpath/java/awt/image/BufferedImageFilter.java new file mode 100644 index 000000000..04b6672c6 --- /dev/null +++ b/libjava/classpath/java/awt/image/BufferedImageFilter.java @@ -0,0 +1,110 @@ +/* Copyright (C) 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +import java.awt.Point; + +/** + * The BufferedImageFilter class wraps BufferedImageOp objects in a Filter. + * + * When pixels are pushed through the filter, we create a BufferedImage, + * apply the BufferedImageOp, and pass the filtered pixels to the base class. + * + * @author jlquinn@optonline.net + */ +public class BufferedImageFilter extends ImageFilter implements Cloneable +{ + private BufferedImageOp op; + + /** + * + */ + public BufferedImageFilter(BufferedImageOp op) + { + super(); + if (op == null) + throw new NullPointerException("BufferedImageFilter null" + + " op in constructor"); + this.op = op; + } + + /** + * @return Returns the contained BufferedImageOp. + */ + public BufferedImageOp getBufferedImageOp() + { + return op; + } + + // FIXME: Definitely not sure this is the right thing. I'm not sure how to + // create a compatible sample model that incorporates scansize != w. I + // asume off is handled by the db itself. + public void setPixels(int x, int y, int w, int h, ColorModel model, + byte[] pixels, int off, int scansize) + { + // Create an input BufferedImage + DataBufferByte db = new DataBufferByte(pixels, scansize * h + off, off); + SampleModel sm = model.createCompatibleSampleModel(scansize, h); + WritableRaster wr = new WritableRaster(sm, db, new Point(0, 0)); + BufferedImage in = + new BufferedImage(model, wr, model.isAlphaPremultiplied(), null); + BufferedImage out = op.createCompatibleDestImage(in, model); + op.filter(in, out); + DataBuffer dbout = out.getRaster().getDataBuffer(); + super.setPixels(0, 0, w, h, model, ((DataBufferByte)dbout).getData(), 0, + scansize); + } + + // FIXME: Definitely not sure this is the right thing. I'm not sure how + // to create a compatible sample model that incorporates + // scansize != w. I asume off is handled by the db itself. + public void setPixels(int x, int y, int w, int h, ColorModel model, + int[] pixels, int off, int scansize) + { + // Create an input BufferedImage + DataBufferInt db = new DataBufferInt(pixels, scansize * h + off, off); + SampleModel sm = model.createCompatibleSampleModel(scansize, h); + WritableRaster wr = new WritableRaster(sm, db, new Point(0, 0)); + BufferedImage in = + new BufferedImage(model, wr, model.isAlphaPremultiplied(), null); + BufferedImage out = op.createCompatibleDestImage(in, model); + op.filter(in, out); + DataBuffer dbout = out.getRaster().getDataBuffer(); + super.setPixels(0, 0, w, h, model, ((DataBufferInt)dbout).getData(), 0, + scansize); + } +} diff --git a/libjava/classpath/java/awt/image/BufferedImageOp.java b/libjava/classpath/java/awt/image/BufferedImageOp.java new file mode 100644 index 000000000..1aba4bb09 --- /dev/null +++ b/libjava/classpath/java/awt/image/BufferedImageOp.java @@ -0,0 +1,107 @@ +/* BufferedImageOp.java -- + Copyright (C) 2002, 2006, Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import java.awt.RenderingHints; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * An operation that is performed on one <code>BufferedImage</code> (the + * source) producing a new <code>BufferedImage</code> (the destination). + */ +public interface BufferedImageOp +{ + /** + * Performs an operation on the source image, returning the result in a + * <code>BufferedImage</code>. If <code>dest</code> is <code>null</code>, a + * new <code>BufferedImage</code> will be created by calling the + * {@link #createCompatibleDestImage} method. If <code>dest</code> + * is not <code>null</code>, the result is written to <code>dest</code> then + * returned (this avoids creating a new <code>BufferedImage</code> each + * time this method is called). + * + * @param src the source image. + * @param dst the destination image (<code>null</code> permitted). + * + * @return The filterd image. + */ + BufferedImage filter(BufferedImage src, BufferedImage dst); + + /** + * Returns the bounds of the destination image on the basis of this + * <code>BufferedImageOp</code> being applied to the specified source image. + * + * @param src the source image. + * + * @return The destination bounds. + */ + Rectangle2D getBounds2D(BufferedImage src); + + /** + * Returns a new <code>BufferedImage</code> that can be used by this + * <code>BufferedImageOp</code> as the destination image when filtering + * the specified source image. + * + * @param src the source image. + * @param dstCM the color model for the destination image. + * + * @return A new image that can be used as the destination image. + */ + BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM); + + /** + * Returns the point on the destination image that corresponds to the given + * point on the source image. + * + * @param src the source point. + * @param dst the destination point (<code>null</code> permitted). + * + * @return The destination point. + */ + Point2D getPoint2D(Point2D src, Point2D dst); + + /** + * Returns the rendering hints for this operation. + * + * @return The rendering hints. + */ + RenderingHints getRenderingHints(); + +} diff --git a/libjava/classpath/java/awt/image/ByteLookupTable.java b/libjava/classpath/java/awt/image/ByteLookupTable.java new file mode 100644 index 000000000..89804c55b --- /dev/null +++ b/libjava/classpath/java/awt/image/ByteLookupTable.java @@ -0,0 +1,175 @@ +/* ByteLookupTable.java -- Java class for a pixel translation table. + Copyright (C) 2004, 2005, 2006, Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +/** + * ByteLookupTable represents translation arrays for pixel values. It wraps + * one or more data arrays for each layer (or component) in an image, such as + * Alpha, R, G, and B. When doing translation, the offset is subtracted from + * the pixel values to allow a subset of an array to be used. + * + * @author Jerry Quinn (jlquinn@optonline.net) + * @version 1.0 + */ +public class ByteLookupTable extends LookupTable +{ + // Array of translation tables. + private byte data[][]; + + /** + * Creates a new <code>ByteLookupTable</code> instance. + * + * Offset is subtracted from pixel values when looking up in the translation + * tables. If data.length is one, the same table is applied to all pixel + * components. + * + * @param offset Offset to be subtracted. + * @param data Array of lookup tables (<code>null</code> not permitted). + * @exception IllegalArgumentException if offset < 0 or data.length < 1. + */ + public ByteLookupTable(int offset, byte[][] data) + throws IllegalArgumentException + { + super(offset, data.length); + + // tests show that Sun's implementation creates a new array to store the + // references from the incoming 'data' array - not sure why, but we'll + // match that behaviour just in case it matters... + this.data = new byte[data.length][]; + for (int i = 0; i < data.length; i++) + this.data[i] = data[i]; + } + + /** + * Creates a new <code>ByteLookupTable</code> instance. + * + * Offset is subtracted from pixel values when looking up in the translation + * table. The same table is applied to all pixel components. + * + * @param offset Offset to be subtracted. + * @param data Lookup table for all components (<code>null</code> not + * permitted). + * @exception IllegalArgumentException if offset < 0. + */ + public ByteLookupTable(int offset, byte[] data) + throws IllegalArgumentException + { + super(offset, 1); + if (data == null) + throw new NullPointerException("Null 'data' argument."); + this.data = new byte[][] {data}; + } + + /** + * Return the lookup tables. + * + * @return the tables + */ + public final byte[][] getTable() + { + return data; + } + + /** + * Return translated values for a pixel. + * + * For each value in the pixel src, use the value minus offset as an index + * in the component array and copy the value there to the output for the + * component. If dest is null, the output is a new array, otherwise the + * translated values are written to dest. Dest can be the same array as + * src. + * + * For example, if the pixel src is [2, 4, 3], and offset is 1, the output + * is [comp1[1], comp2[3], comp3[2]], where comp1, comp2, and comp3 are the + * translation arrays. + * + * @param src Component values of a pixel. + * @param dst Destination array for values, or null. + * @return Translated values for the pixel. + */ + public int[] lookupPixel(int[] src, int[] dst) + throws ArrayIndexOutOfBoundsException + { + if (dst == null) + dst = new int[src.length]; + + if (data.length == 1) + for (int i=0; i < src.length; i++) + dst[i] = data[0][src[i] - offset]; + else + for (int i=0; i < src.length; i++) + dst[i] = data[i][src[i] - offset]; + + return dst; + } + + /** + * Return translated values for a pixel. + * + * For each value in the pixel src, use the value minus offset as an index + * in the component array and copy the value there to the output for the + * component. If dest is null, the output is a new array, otherwise the + * translated values are written to dest. Dest can be the same array as + * src. + * + * For example, if the pixel src is [2, 4, 3], and offset is 1, the output + * is [comp1[1], comp2[3], comp3[2]], where comp1, comp2, and comp3 are the + * translation arrays. + * + * @param src Component values of a pixel. + * @param dst Destination array for values, or null. + * @return Translated values for the pixel. + */ + public byte[] lookupPixel(byte[] src, byte[] dst) + throws ArrayIndexOutOfBoundsException + { + if (dst == null) + dst = new byte[src.length]; + + if (data.length == 1) + for (int i=0; i < src.length; i++) + dst[i] = data[0][((int)src[i]) - offset]; + else + for (int i=0; i < src.length; i++) + dst[i] = data[i][((int)src[i]) - offset]; + + return dst; + + } +} diff --git a/libjava/classpath/java/awt/image/ColorConvertOp.java b/libjava/classpath/java/awt/image/ColorConvertOp.java new file mode 100644 index 000000000..b1d6f857d --- /dev/null +++ b/libjava/classpath/java/awt/image/ColorConvertOp.java @@ -0,0 +1,537 @@ +/* ColorConvertOp.java -- + Copyright (C) 2004, 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import gnu.java.awt.Buffers; + +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.RenderingHints; +import java.awt.color.ColorSpace; +import java.awt.color.ICC_ColorSpace; +import java.awt.color.ICC_Profile; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * ColorConvertOp is a filter for converting images or rasters between + * colorspaces, either through a sequence of colorspaces or just from source to + * destination. + * + * Color conversion is done on the color components without alpha. Thus + * if a BufferedImage has alpha premultiplied, this is divided out before + * color conversion, and premultiplication applied if the destination + * requires it. + * + * Color rendering and dithering hints may be applied if specified. This is + * likely platform-dependent. + * + * @author jlquinn@optonline.net + */ +public class ColorConvertOp implements BufferedImageOp, RasterOp +{ + private RenderingHints hints; + private ICC_Profile[] profiles = null; + private ColorSpace[] spaces; + + + /** + * Convert a BufferedImage through a ColorSpace. + * + * Objects created with this constructor can be used to convert + * BufferedImage's to a destination ColorSpace. Attempts to convert Rasters + * with this constructor will result in an IllegalArgumentException when the + * filter(Raster, WritableRaster) method is called. + * + * @param cspace The target color space. + * @param hints Rendering hints to use in conversion, if any (may be null) + * @throws NullPointerException if the ColorSpace is null. + */ + public ColorConvertOp(ColorSpace cspace, RenderingHints hints) + { + if (cspace == null) + throw new NullPointerException(); + spaces = new ColorSpace[]{cspace}; + this.hints = hints; + } + + /** + * Convert from a source colorspace to a destination colorspace. + * + * This constructor takes two ColorSpace arguments as the source and + * destination color spaces. It is usually used with the + * filter(Raster, WritableRaster) method, in which case the source colorspace + * is assumed to correspond to the source Raster, and the destination + * colorspace with the destination Raster. + * + * If used with BufferedImages that do not match the source or destination + * colorspaces specified here, there is an implicit conversion from the + * source image to the source ColorSpace, or the destination ColorSpace to + * the destination image. + * + * @param srcCspace The source ColorSpace. + * @param dstCspace The destination ColorSpace. + * @param hints Rendering hints to use in conversion, if any (may be null). + * @throws NullPointerException if any ColorSpace is null. + */ + public ColorConvertOp(ColorSpace srcCspace, ColorSpace dstCspace, + RenderingHints hints) + { + if (srcCspace == null || dstCspace == null) + throw new NullPointerException(); + spaces = new ColorSpace[]{srcCspace, dstCspace}; + this.hints = hints; + } + + /** + * Convert from a source colorspace to a destinatino colorspace. + * + * This constructor builds a ColorConvertOp from an array of ICC_Profiles. + * The source will be converted through the sequence of color spaces + * defined by the profiles. If the sequence of profiles doesn't give a + * well-defined conversion, an IllegalArgumentException is thrown. + * + * If used with BufferedImages that do not match the source or destination + * colorspaces specified here, there is an implicit conversion from the + * source image to the source ColorSpace, or the destination ColorSpace to + * the destination image. + * + * For Rasters, the first and last profiles must have the same number of + * bands as the source and destination Rasters, respectively. If this is + * not the case, or there fewer than 2 profiles, an IllegalArgumentException + * will be thrown. + * + * @param profiles An array of ICC_Profile's to convert through. + * @param hints Rendering hints to use in conversion, if any (may be null). + * @throws NullPointerException if the profile array is null. + * @throws IllegalArgumentException if the array is not a well-defined + * conversion. + */ + public ColorConvertOp(ICC_Profile[] profiles, RenderingHints hints) + { + if (profiles == null) + throw new NullPointerException(); + + this.hints = hints; + this.profiles = profiles; + + // Create colorspace array with space for src and dest colorspace + // Note that the ICC_ColorSpace constructor will throw an + // IllegalArgumentException if the profile is invalid; thus we check + // for a "well defined conversion" + spaces = new ColorSpace[profiles.length]; + for (int i = 0; i < profiles.length; i++) + spaces[i] = new ICC_ColorSpace(profiles[i]); + } + + /** + * Convert from source color space to destination color space. + * + * Only valid for BufferedImage objects, this Op converts from the source + * image's color space to the destination image's color space. + * + * The destination in the filter(BufferedImage, BufferedImage) method cannot + * be null for this operation, and it also cannot be used with the + * filter(Raster, WritableRaster) method. + * + * @param hints Rendering hints to use in conversion, if any (may be null). + */ + public ColorConvertOp(RenderingHints hints) + { + this.hints = hints; + spaces = new ColorSpace[0]; + } + + /** + * Converts the source image using the conversion path specified in the + * constructor. The resulting image is stored in the destination image if one + * is provided; otherwise a new BufferedImage is created and returned. + * + * The source and destination BufferedImage (if one is supplied) must have + * the same dimensions. + * + * @param src The source image. + * @param dst The destination image. + * @throws IllegalArgumentException if the rasters and/or color spaces are + * incompatible. + * @return The transformed image. + */ + public final BufferedImage filter(BufferedImage src, BufferedImage dst) + { + // TODO: The plan is to create a scanline buffer for intermediate buffers. + // For now we just suck it up and create intermediate buffers. + + if (dst == null && spaces.length == 0) + throw new IllegalArgumentException("Not enough color space information " + + "to complete conversion."); + + if (dst != null + && (src.getHeight() != dst.getHeight() || src.getWidth() != dst.getWidth())) + throw new IllegalArgumentException("Source and destination images have " + + "different dimensions"); + + // Make sure input isn't premultiplied by alpha + if (src.isAlphaPremultiplied()) + { + BufferedImage tmp = createCompatibleDestImage(src, src.getColorModel()); + copyimage(src, tmp); + tmp.coerceData(false); + src = tmp; + } + + // Convert through defined intermediate conversions + BufferedImage tmp; + for (int i = 0; i < spaces.length; i++) + { + if (src.getColorModel().getColorSpace().getType() != spaces[i].getType()) + { + tmp = createCompatibleDestImage(src, + createCompatibleColorModel(src, + spaces[i])); + copyimage(src, tmp); + src = tmp; + } + } + + // No implicit conversion to destination type needed; return result from the + // last intermediate conversions (which was left in src) + if (dst == null) + dst = src; + + // Implicit conversion to destination image's color space + else + copyimage(src, dst); + + return dst; + } + + /** + * Converts the source raster using the conversion path specified in the + * constructor. The resulting raster is stored in the destination raster if + * one is provided; otherwise a new WritableRaster is created and returned. + * + * This operation is not valid with every constructor of this class; see + * the constructors for details. Further, the source raster must have the + * same number of bands as the source ColorSpace, and the destination raster + * must have the same number of bands as the destination ColorSpace. + * + * The source and destination raster (if one is supplied) must also have the + * same dimensions. + * + * @param src The source raster. + * @param dest The destination raster. + * @throws IllegalArgumentException if the rasters and/or color spaces are + * incompatible. + * @return The transformed raster. + */ + public final WritableRaster filter(Raster src, WritableRaster dest) + { + // Various checks to ensure that the rasters and color spaces are compatible + if (spaces.length < 2) + throw new IllegalArgumentException("Not enough information about " + + "source and destination colorspaces."); + + if (spaces[0].getNumComponents() != src.getNumBands() + || (dest != null && spaces[spaces.length - 1].getNumComponents() != dest.getNumBands())) + throw new IllegalArgumentException("Source or destination raster " + + "contains the wrong number of bands."); + + if (dest != null + && (src.getHeight() != dest.getHeight() || src.getWidth() != dest.getWidth())) + throw new IllegalArgumentException("Source and destination rasters " + + "have different dimensions"); + + // Need to iterate through each color space. + // spaces[0] corresponds to the ColorSpace of the source raster, and + // spaces[spaces.length - 1] corresponds to the ColorSpace of the + // destination, with any number (or zero) of intermediate conversions. + + for (int i = 0; i < spaces.length - 2; i++) + { + WritableRaster tmp = createCompatibleDestRaster(src, spaces[i + 1], + false, + src.getTransferType()); + copyraster(src, spaces[i], tmp, spaces[i + 1]); + src = tmp; + } + + // The last conversion is done outside of the loop so that we can + // use the dest raster supplied, instead of creating our own temp raster + if (dest == null) + dest = createCompatibleDestRaster(src, spaces[spaces.length - 1], false, + DataBuffer.TYPE_BYTE); + copyraster(src, spaces[spaces.length - 2], dest, spaces[spaces.length - 1]); + + return dest; + } + + /** + * Creates an empty BufferedImage with the size equal to the source and the + * correct number of bands for the conversion defined in this Op. The newly + * created image is created with the specified ColorModel, or if no ColorModel + * is supplied, an appropriate one is chosen. + * + * @param src The source image. + * @param dstCM A color model for the destination image (may be null). + * @throws IllegalArgumentException if an appropriate colormodel cannot be + * chosen with the information given. + * @return The new compatible destination image. + */ + public BufferedImage createCompatibleDestImage(BufferedImage src, + ColorModel dstCM) + { + if (dstCM == null && spaces.length == 0) + throw new IllegalArgumentException("Don't know the destination " + + "colormodel"); + + if (dstCM == null) + { + dstCM = createCompatibleColorModel(src, spaces[spaces.length - 1]); + } + + return new BufferedImage(dstCM, + createCompatibleDestRaster(src.getRaster(), + dstCM.getColorSpace(), + src.getColorModel().hasAlpha, + dstCM.getTransferType()), + src.isPremultiplied, null); + } + + /** + * Creates a new WritableRaster with the size equal to the source and the + * correct number of bands. + * + * Note, the new Raster will always use a BYTE storage size, regardless of + * the color model or defined destination; this is for compatibility with + * the reference implementation. + * + * @param src The source Raster. + * @throws IllegalArgumentException if there isn't enough colorspace + * information to create a compatible Raster. + * @return The new compatible destination raster. + */ + public WritableRaster createCompatibleDestRaster(Raster src) + { + if (spaces.length < 2) + throw new IllegalArgumentException("Not enough destination colorspace " + + "information"); + + // Create a new raster with the last ColorSpace in the conversion + // chain, and with no alpha (implied) + return createCompatibleDestRaster(src, spaces[spaces.length-1], false, + DataBuffer.TYPE_BYTE); + } + + /** + * Returns the array of ICC_Profiles used to create this Op, or null if the + * Op was created using ColorSpace arguments. + * + * @return The array of ICC_Profiles, or null. + */ + public final ICC_Profile[] getICC_Profiles() + { + return profiles; + } + + /** + * Returns the rendering hints for this op. + * + * @return The rendering hints for this Op, or null. + */ + public final RenderingHints getRenderingHints() + { + return hints; + } + + /** + * Returns the corresponding destination point for a source point. + * Because this is not a geometric operation, the destination and source + * points will be identical. + * + * @param src The source point. + * @param dst The transformed destination point. + * @return The transformed destination point. + */ + public final Point2D getPoint2D(Point2D src, Point2D dst) + { + if (dst == null) + return (Point2D)src.clone(); + + dst.setLocation(src); + return dst; + } + + /** + * Returns the corresponding destination boundary of a source boundary. + * Because this is not a geometric operation, the destination and source + * boundaries will be identical. + * + * @param src The source boundary. + * @return The boundaries of the destination. + */ + public final Rectangle2D getBounds2D(BufferedImage src) + { + return src.getRaster().getBounds(); + } + + /** + * Returns the corresponding destination boundary of a source boundary. + * Because this is not a geometric operation, the destination and source + * boundaries will be identical. + * + * @param src The source boundary. + * @return The boundaries of the destination. + */ + public final Rectangle2D getBounds2D(Raster src) + { + return src.getBounds(); + } + + /** + * Copy a source image to a destination image, respecting their colorspaces + * and performing colorspace conversions if necessary. + * + * @param src The source image. + * @param dst The destination image. + */ + private void copyimage(BufferedImage src, BufferedImage dst) + { + // This is done using Graphics2D in order to respect the rendering hints. + Graphics2D gg = dst.createGraphics(); + + // If no hints are set there is no need to call + // setRenderingHints on the Graphics2D object. + if (hints != null) + gg.setRenderingHints(hints); + + gg.drawImage(src, 0, 0, null); + gg.dispose(); + } + + /** + * Copy a source raster to a destination raster, performing a colorspace + * conversion between the two. The conversion will respect the + * KEY_COLOR_RENDERING rendering hint if one is present. + * + * @param src The source raster. + * @param scs The colorspace of the source raster. + * @dst The destination raster. + * @dcs The colorspace of the destination raster. + */ + private void copyraster(Raster src, ColorSpace scs, WritableRaster dst, ColorSpace dcs) + { + float[] sbuf = new float[src.getNumBands()]; + + if (hints != null + && hints.get(RenderingHints.KEY_COLOR_RENDERING) == + RenderingHints.VALUE_COLOR_RENDER_QUALITY) + { + // use cie for accuracy + for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) + for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) + dst.setPixel(x, y, + dcs.fromCIEXYZ(scs.toCIEXYZ(src.getPixel(x, y, sbuf)))); + } + else + { + // use rgb - it's probably faster + for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) + for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) + dst.setPixel(x, y, + dcs.fromRGB(scs.toRGB(src.getPixel(x, y, sbuf)))); + } + } + + /** + * This method creates a color model with the same colorspace and alpha + * settings as the source image. The created color model will always be a + * ComponentColorModel and have a BYTE transfer type. + * + * @param img The source image. + * @param cs The ColorSpace to use. + * @return A color model compatible with the source image. + */ + private ColorModel createCompatibleColorModel(BufferedImage img, ColorSpace cs) + { + // The choice of ComponentColorModel and DataBuffer.TYPE_BYTE is based on + // Mauve testing of the reference implementation. + return new ComponentColorModel(cs, + img.getColorModel().hasAlpha(), + img.isAlphaPremultiplied(), + img.getColorModel().getTransparency(), + DataBuffer.TYPE_BYTE); + } + + /** + * This method creates a compatible Raster, given a source raster, colorspace, + * alpha value, and transfer type. + * + * @param src The source raster. + * @param cs The ColorSpace to use. + * @param hasAlpha Whether the raster should include a component for an alpha. + * @param transferType The size of a single data element. + * @return A compatible WritableRaster. + */ + private WritableRaster createCompatibleDestRaster(Raster src, ColorSpace cs, + boolean hasAlpha, + int transferType) + { + // The use of a PixelInterleavedSampleModel weas determined using mauve + // tests, based on the reference implementation + + int numComponents = cs.getNumComponents(); + if (hasAlpha) + numComponents++; + + int[] offsets = new int[numComponents]; + for (int i = 0; i < offsets.length; i++) + offsets[i] = i; + + DataBuffer db = Buffers.createBuffer(transferType, + src.getWidth() * src.getHeight() * numComponents, + 1); + return new WritableRaster(new PixelInterleavedSampleModel(transferType, + src.getWidth(), + src.getHeight(), + numComponents, + numComponents * src.getWidth(), + offsets), + db, new Point(src.getMinX(), src.getMinY())); + } +} diff --git a/libjava/classpath/java/awt/image/ColorModel.java b/libjava/classpath/java/awt/image/ColorModel.java new file mode 100644 index 000000000..ede9e31d8 --- /dev/null +++ b/libjava/classpath/java/awt/image/ColorModel.java @@ -0,0 +1,794 @@ +/* ColorModel.java -- + Copyright (C) 1999, 2000, 2002, 2003, 2004, 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import gnu.java.awt.Buffers; + +import java.awt.Point; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.util.Arrays; + +/** + * A color model operates with colors in several formats: + * + * <ul> + * <li>normalized: component samples are in range [0.0, 1.0].</li> + * + * <li>color model pixel value: all the color component samples for a + * sigle pixel packed/encoded in a way natural for the color + * model.</li> + * + * <li>color model pixel int value: only makes sense if the natural + * encoding of a single pixel can fit in a single int value.</li> + * + * <li>array of transferType containing a single pixel: the pixel is + * encoded in the natural way of the color model, taking up as many + * array elements as needed.</li> + * + * <li>sRGB pixel int value: a pixel in sRGB color space, encoded in + * default 0xAARRGGBB format, assumed not alpha premultiplied.</li> + * + * <li>single [0, 255] scaled int samples from default sRGB color + * space. These are always assumed to be alpha non-premultiplied.</li> + * + * <li>arrays of unnormalized component samples of single pixel: these + * samples are scaled and multiplied according to the color model, but + * is otherwise not packed or encoded. Each element of the array is one + * separate component sample. The color model only operate on the + * components from one pixel at a time, but using offsets, allows + * manipulation of arrays that contain the components of more than one + * pixel.</li> + * + * </ul> + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + * @author C. Brian Jones (cbj@gnu.org) + */ +public abstract class ColorModel implements Transparency +{ + protected int pixel_bits; + protected int transferType; + + int[] bits; + ColorSpace cspace; + int transparency; + boolean hasAlpha; + boolean isAlphaPremultiplied; + + /** + * The standard color model for the common sRGB. + */ + private static final ColorModel S_RGB_MODEL = new SRGBColorModel(); + + static int[] nArray(int value, int times) + { + int[] array = new int[times]; + java.util.Arrays.fill(array, value); + return array; + } + + static byte[] nArray(byte value, int times) + { + byte[] array = new byte[times]; + java.util.Arrays.fill(array, value); + return array; + } + + /** + * Constructs the default color model. The default color model + * can be obtained by calling <code>getRGBdefault</code> of this + * class. + * @param bits the number of bits wide used for bit size of pixel values + */ + public ColorModel(int bits) + { + this(bits * 4, // total bits, sRGB, four channels + nArray(bits, 4), // bits for each channel + ColorSpace.getInstance(ColorSpace.CS_sRGB), // sRGB + true, // has alpha + false, // not premultiplied + TRANSLUCENT, + Buffers.smallestAppropriateTransferType(bits * 4)); + } + + /** + * Constructs a ColorModel that translates pixel values to + * color/alpha components. + * + * @exception IllegalArgumentException If the length of the bit array is less + * than the number of color or alpha components in this ColorModel, or if the + * transparency is not a valid value, or if the sum of the number of bits in + * bits is less than 1 or if any of the elements in bits is less than 0. + */ + protected ColorModel(int pixel_bits, int[] bits, ColorSpace cspace, + boolean hasAlpha, boolean isAlphaPremultiplied, + int transparency, int transferType) + { + int bits_sum = 0; + for (int i = 0; i < bits.length; i++) + { + if (bits [i] < 0) + throw new IllegalArgumentException (); + + bits_sum |= bits [i]; + } + + if ((bits.length < cspace.getNumComponents()) + || (bits_sum < 1)) + throw new IllegalArgumentException (); + + this.pixel_bits = pixel_bits; + this.bits = bits; + this.cspace = cspace; + this.hasAlpha = hasAlpha; + this.isAlphaPremultiplied = isAlphaPremultiplied; + this.transparency = transparency; + this.transferType = transferType; + } + + public void finalize() + { + // Do nothing here. + } + + /** + * Returns the default color model which in Sun's case is an instance + * of <code>DirectColorModel</code>. + */ + public static ColorModel getRGBdefault() + { + return S_RGB_MODEL; + } + + public final boolean hasAlpha() + { + return hasAlpha; + } + + public final boolean isAlphaPremultiplied() + { + return isAlphaPremultiplied; + } + + /** + * Get get number of bits wide used for the bit size of pixel values + */ + public int getPixelSize() + { + return pixel_bits; + } + + public int getComponentSize(int componentIdx) + { + return bits[componentIdx]; + } + + public int[] getComponentSize() + { + return bits; + } + + public int getTransparency() + { + return transparency; + } + + public int getNumComponents() + { + return getNumColorComponents() + (hasAlpha ? 1 : 0); + } + + public int getNumColorComponents() + { + return cspace.getNumComponents(); + } + + /** + * Converts pixel value to sRGB and extract red int sample scaled + * to range [0, 255]. + * + * @param pixel pixel value that will be interpreted according to + * the color model, (assumed alpha premultiplied if color model says + * so.) + * + * @return red sample scaled to range [0, 255], from default color + * space sRGB, alpha non-premultiplied. + */ + public abstract int getRed(int pixel); + + /** + * Converts pixel value to sRGB and extract green int sample + * scaled to range [0, 255]. + * + * @see #getRed(int) + */ + public abstract int getGreen(int pixel); + + /** + * Converts pixel value to sRGB and extract blue int sample + * scaled to range [0, 255]. + * + * @see #getRed(int) + */ + public abstract int getBlue(int pixel); + + /** + * Extract alpha int sample from pixel value, scaled to [0, 255]. + * + * @param pixel pixel value that will be interpreted according to + * the color model. + * + * @return alpha sample, scaled to range [0, 255]. + */ + public abstract int getAlpha(int pixel); + + /** + * Converts a pixel int value of the color space of the color + * model to a sRGB pixel int value. + * + * This method is typically overriden in subclasses to provide a + * more efficient implementation. + * + * @param pixel pixel value that will be interpreted according to + * the color model. + * + * @return a pixel in sRGB color space, encoded in default + * 0xAARRGGBB format. */ + public int getRGB(int pixel) + { + return + ((getAlpha(pixel) & 0xff) << 24) | + (( getRed(pixel) & 0xff) << 16) | + ((getGreen(pixel) & 0xff) << 8) | + (( getBlue(pixel) & 0xff) << 0); + } + + + /** + * In this color model we know that the whole pixel value will + * always be contained within the first element of the pixel + * array. + */ + final int getPixelFromArray(Object inData) { + DataBuffer data = + Buffers.createBufferFromData(transferType, inData, 1); + Object da = Buffers.getData(data); + + return data.getElem(0); + } + + /** + * Converts pixel in the given array to sRGB and extract blue int + * sample scaled to range [0-255]. + * + * This method is typically overriden in subclasses to provide a + * more efficient implementation. + * + * @param inData array of transferType containing a single pixel. The + * pixel should be encoded in the natural way of the color model. + */ + public int getRed(Object inData) + { + return getRed(getPixelFromArray(inData)); + } + + /** + * @see #getRed(Object) + */ + public int getGreen(Object inData) + { + return getGreen(getPixelFromArray(inData)); + } + + /** + * @see #getRed(Object) + */ + public int getBlue(Object inData) { + return getBlue(getPixelFromArray(inData)); + } + + /** + * @see #getRed(Object) + */ + public int getAlpha(Object inData) { + return getAlpha(getPixelFromArray(inData)); + } + + /** + * Converts a pixel in the given array of the color space of the + * color model to an sRGB pixel int value. + * + * <p>This method performs the inverse function of + * <code>getDataElements(int rgb, Object pixel)</code>. + * I.e. <code>(rgb == cm.getRGB(cm.getDataElements(rgb, + * null)))</code>. + * + * @param inData array of transferType containing a single pixel. The + * pixel should be encoded in the natural way of the color model. + * + * @return a pixel in sRGB color space, encoded in default + * 0xAARRGGBB format. + * + * @see #getDataElements(int, Object) + */ + public int getRGB(Object inData) + { + return + ((getAlpha(inData) & 0xff) << 24) | + (( getRed(inData) & 0xff) << 16) | + ((getGreen(inData) & 0xff) << 8) | + (( getBlue(inData) & 0xff) << 0); + } + + /** + * Converts an sRGB pixel int value to an array containing a + * single pixel of the color space of the color model. + * + * <p>This method performs the inverse function of + * <code>getRGB(Object inData)</code>. + * + * Outline of conversion process: + * + * <ol> + * + * <li>Convert rgb to normalized [0.0, 1.0] sRGB values.</li> + * + * <li>Convert to color space components using fromRGB in + * ColorSpace.</li> + * + * <li>If color model has alpha and should be premultiplied, + * multiply color space components with alpha value</li> + * + * <li>Scale the components to the correct number of bits.</li> + * + * <li>Arrange the components in the output array</li> + * + * </ol> + * + * @param rgb The color to be converted to dataElements. A pixel + * in sRGB color space, encoded in default 0xAARRGGBB format, + * assumed not alpha premultiplied. + * + * @param pixel to avoid needless creation of arrays, an array to + * use to return the pixel can be given. If null, a suitable array + * will be created. + * + * @return An array of transferType values representing the color, + * in the color model format. The color model defines whether the + * + * @see #getRGB(Object) + */ + public Object getDataElements(int rgb, Object pixel) + { + // subclasses has to implement this method. + throw new UnsupportedOperationException(); + } + + /** + * Fills an array with the unnormalized component samples from a + * pixel value. I.e. decompose the pixel, but not perform any + * color conversion. + * + * This method is typically overriden in subclasses to provide a + * more efficient implementation. + * + * @param pixel pixel value encoded according to the color model. + * + * @return arrays of unnormalized component samples of single + * pixel. The scale and multiplication state of the samples are + * according to the color model. Each component sample is stored + * as a separate element in the array. + */ + public int[] getComponents(int pixel, int[] components, int offset) + { + // subclasses has to implement this method. + throw new UnsupportedOperationException(); + } + + /** + * Fills an array with the unnormalized component samples from an + * array of transferType containing a single pixel. I.e. decompose + * the pixel, but not perform any color conversion. + * + * This method is typically overriden in subclasses to provide a + * more efficient implementation. + * + * @param pixel an array of transferType containing a single pixel. The + * pixel should be encoded in the natural way of the color model. If + * this argument is not an array, as expected, a {@link ClassCastException} + * will be thrown. + * @param components an array that will be filled with the color component + * of the pixel. If this is null, a new array will be allocated + * @param offset index into the components array at which the result + * will be stored + * + * @return arrays of unnormalized component samples of single + * pixel. The scale and multiplication state of the samples are + * according to the color model. Each component sample is stored + * as a separate element in the array. + */ + public int[] getComponents(Object pixel, int[] components, int offset) + { + // subclasses has to implement this method. + throw new UnsupportedOperationException(); + } + + /** + * Convert normalized components to unnormalized components. + */ + public int[] getUnnormalizedComponents(float[] normComponents, + int normOffset, + int[] components, + int offset) + { + int numComponents = getNumComponents(); + if (components == null) + { + components = new int[offset + numComponents]; + } + + for (int i=0; i<numComponents; i++) + { + float in = normComponents[normOffset++]; + int out = (int) (in * ((1<<getComponentSize(i)) - 1)); + components[offset++] = out; + } + return components; + } + + /** + * Convert unnormalized components to normalized components. + */ + public float[] getNormalizedComponents(int[] components, + int offset, + float[] normComponents, + int normOffset) + { + int numComponents = getNumComponents(); + if (normComponents == null) + { + normComponents = new float[normOffset + numComponents]; + } + + for (int i=0; i<numComponents; i++) + { + float in = components[offset++]; + float out = in / ((1<<getComponentSize(i)) - 1); + normComponents[normOffset++] = out; + } + return normComponents; + } + + /** + * Convert unnormalized components to normalized components. + * + * @since 1.4 + */ + public float[] getNormalizedComponents (Object pixel, + float[] normComponents, + int normOffset) + { + int[] components = getComponents(pixel, null, 0); + return getNormalizedComponents(components, 0, normComponents, normOffset); + } + + /** + * Converts the unnormalized component samples from an array to a + * pixel value. I.e. composes the pixel from component samples, but + * does not perform any color conversion or scaling of the samples. + * + * This method performs the inverse function of + * <code>getComponents(int pixel, int[] components, + * int offset)</code>. I.e. + * + * <code>(pixel == cm.getDataElement(cm.getComponents(pixel, null, + * 0), 0))</code>. + * + * This method is overriden in subclasses since this abstract class throws + * UnsupportedOperationException(). + * + * @param components Array of unnormalized component samples of single + * pixel. The scale and multiplication state of the samples are according + * to the color model. Each component sample is stored as a separate element + * in the array. + * @param offset Position of the first value of the pixel in components. + * + * @return pixel value encoded according to the color model. + */ + public int getDataElement(int[] components, int offset) + { + // subclasses have to implement this method. + throw new UnsupportedOperationException(); + } + + /** + * Converts the normalized component samples from an array to a pixel + * value. I.e. composes the pixel from component samples, but does not + * perform any color conversion or scaling of the samples. + * + * This method is typically overriden in subclasses to provide a + * more efficient implementation. The method provided by this abstract + * class converts the components to unnormalized form and returns + * getDataElement(int[], int). + * + * @param components Array of normalized component samples of single pixel. + * The scale and multiplication state of the samples are according to the + * color model. Each component sample is stored as a separate element in the + * array. + * @param offset Position of the first value of the pixel in components. + * + * @return pixel value encoded according to the color model. + * @since 1.4 + */ + public int getDataElement (float[] components, int offset) + { + return + getDataElement(getUnnormalizedComponents(components, offset, null, 0), + 0); + } + + public Object getDataElements(int[] components, int offset, Object obj) + { + // subclasses have to implement this method. + throw new UnsupportedOperationException(); + } + + /** + * Converts the normalized component samples from an array to an array of + * TransferType values. I.e. composes the pixel from component samples, but + * does not perform any color conversion or scaling of the samples. + * + * If obj is null, a new array of TransferType is allocated and returned. + * Otherwise the results are stored in obj and obj is returned. If obj is + * not long enough, ArrayIndexOutOfBounds is thrown. If obj is not an array + * of primitives, ClassCastException is thrown. + * + * This method is typically overriden in subclasses to provide a + * more efficient implementation. The method provided by this abstract + * class converts the components to unnormalized form and returns + * getDataElement(int[], int, Object). + * + * @param components Array of normalized component samples of single pixel. + * The scale and multiplication state of the samples are according to the + * color model. Each component sample is stored as a separate element in the + * array. + * @param offset Position of the first value of the pixel in components. + * @param obj Array of TransferType or null. + * + * @return pixel value encoded according to the color model. + * @throws ArrayIndexOutOfBoundsException + * @throws ClassCastException + * @since 1.4 + */ + public Object getDataElements(float[] components, int offset, Object obj) + { + return + getDataElements(getUnnormalizedComponents(components, offset, null, 0), + 0, obj); + } + + public boolean equals(Object obj) + { + if (!(obj instanceof ColorModel)) return false; + + ColorModel o = (ColorModel) obj; + return + (pixel_bits == o.pixel_bits) && + (transferType == o.transferType) && + (transparency == o.transparency) && + (hasAlpha == o.hasAlpha) && + (isAlphaPremultiplied == o.isAlphaPremultiplied) && + Arrays.equals(bits, o.bits) && + (cspace.equals(o.cspace)); + } + + public final ColorSpace getColorSpace() + { + return cspace; + } + + public ColorModel coerceData(WritableRaster raster, + boolean isAlphaPremultiplied) + { + // This method should always be overridden, but is not abstract. + throw new UnsupportedOperationException(); + } + + void coerceDataWorker(WritableRaster raster, + boolean isAlphaPremultiplied) + { + int w = raster.getWidth(); + int h = raster.getHeight(); + int x = raster.getMinX(); + int y = raster.getMinY(); + int size = w * h; + int numColors = getNumColorComponents(); + int numComponents = getNumComponents(); + int alphaScale = (1 << getComponentSize(numColors)) - 1; + double[] pixels = raster.getPixels(x, y, w, h, (double[]) null); + + for (int i = 0; i < size; i++) + { + double alpha = pixels[i * numComponents + numColors] / alphaScale; + for (int c = 0; c < numColors; c++) + { + int offset = i * numComponents + c; + if (isAlphaPremultiplied) + pixels[offset] = Math.round(pixels[offset] * alpha); + else + pixels[offset] = Math.round(pixels[offset] / alpha); + } + } + + raster.setPixels(0, 0, w, h, pixels); + } + + /** + * Checks if the given raster has a compatible data-layout (SampleModel). + * @param raster The Raster to test. + * @return true if raster is compatible. + */ + public boolean isCompatibleRaster(Raster raster) + { + SampleModel sampleModel = raster.getSampleModel(); + return isCompatibleSampleModel(sampleModel); + } + + // Typically overridden + public WritableRaster createCompatibleWritableRaster(int w, int h) + { + return new WritableRaster(createCompatibleSampleModel(w, h), + new Point(0, 0)); + } + + // Typically overridden + public SampleModel createCompatibleSampleModel(int w, int h) + { + throw new UnsupportedOperationException(); + } + + // Typically overridden + public boolean isCompatibleSampleModel(SampleModel sm) + { + return sm.getTransferType() == transferType; + } + + public final int getTransferType () + { + return transferType; + } + + /** + * Subclasses must override this method if it is possible for the + * color model to have an alpha channel. + * + * @return null, as per JDK 1.3 doc. Subclasses will only return + * null if no alpha raster exists. + */ + public WritableRaster getAlphaRaster(WritableRaster raster) + { + return null; + + /* It is a mystery to me why we couldn't use the following code... + + + if (!hasAlpha()) return null; + + SampleModel sm = raster.getSampleModel(); + int[] alphaBand = { sm.getNumBands() - 1 }; + SampleModel alphaModel = sm.createSubsetSampleModel(alphaBand); + DataBuffer buffer = raster.getDataBuffer(); + Point origin = new Point(0, 0); + return Raster.createWritableRaster(alphaModel, buffer, origin); + + + ...here, and avoided overriding the method in subclasses, + but the Sun docs state that this method always will return + null, and that overriding is required. Oh, well. + */ + } + + String stringParam() + { + return "pixel_bits=" + pixel_bits + + ", cspace=" + cspace + + ", transferType=" + transferType + + ", transparency=" + transparency + + ", hasAlpha=" + hasAlpha + + ", isAlphaPremultiplied=" + isAlphaPremultiplied; + } + + public String toString() + { + return getClass().getName() + "[" + stringParam() + "]"; + } + + /** + * A color model optimized for standard sRGB. + */ + private static class SRGBColorModel + extends DirectColorModel + { + + SRGBColorModel() + { + super(32,0x00FF0000,0x0000FF00,0x000000FF,0xFF000000); + } + + public int getAlpha(Object inData) + { + return ((((int[]) inData)[0]) >> 24) & 0xFF; + } + + public int getBlue(Object inData) + { + return ((((int[]) inData)[0])) & 0xFF; + } + + public int getGreen(Object inData) + { + return ((((int[]) inData)[0]) >> 8) & 0xFF; + } + + public int getRed(Object inData) + { + return ((((int[]) inData)[0]) >> 16) & 0xFF; + } + + public int getRGB(Object inData) + { + return ((int[]) inData)[0]; + } + + public Object getDataElements(int rgb, Object pixel) + { + if(pixel == null) + { + pixel = new int[]{rgb}; + } + else + { + ((int[]) pixel)[0] = rgb; + } + + return pixel; + } + } +} diff --git a/libjava/classpath/java/awt/image/ComponentColorModel.java b/libjava/classpath/java/awt/image/ComponentColorModel.java new file mode 100644 index 000000000..ef0b84f00 --- /dev/null +++ b/libjava/classpath/java/awt/image/ComponentColorModel.java @@ -0,0 +1,408 @@ +/* ComponentColorModel.java -- + Copyright (C) 2000, 2002, 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import gnu.java.awt.Buffers; + +import java.awt.Point; +import java.awt.color.ColorSpace; +import java.util.Arrays; + +public class ComponentColorModel extends ColorModel +{ + // Find sum of all elements of the array. + private static int sum(int[] values) + { + int sum = 0; + for (int i=0; i<values.length; i++) + sum += values[i]; + return sum; + } + + // Create an appropriate array of bits, given a colorspace (ie, number of + // bands), size of the storage data type, and presence of an alpha band. + private static int[] findBits(ColorSpace colorSpace, int transferType, + boolean hasAlpha) + { + int[] bits; + if (hasAlpha) + bits = new int[colorSpace.getNumComponents()+1]; + else + bits = new int[colorSpace.getNumComponents()]; + + Arrays.fill(bits, DataBuffer.getDataTypeSize(transferType)); + + return bits; + } + + public ComponentColorModel(ColorSpace colorSpace, int[] bits, + boolean hasAlpha, + boolean isAlphaPremultiplied, + int transparency, int transferType) + { + super(sum(bits), bits, colorSpace, hasAlpha, isAlphaPremultiplied, + transparency, transferType); + } + + /** + * Construct a new ComponentColorModel. + * + * This constructor makes all bits of each sample significant, so for a + * transferType of DataBuffer.BYTE, the bits per sample is 8, etc. If + * both hasAlpha and isAlphaPremultiplied are true, color samples are + * assumed to be premultiplied by the alpha component. Transparency may be + * one of OPAQUE, BITMASK, or TRANSLUCENT. + * + * @param colorSpace The colorspace for this color model. + * @param hasAlpha True if there is an alpha component. + * @param isAlphaPremultiplied True if colors are already multiplied by + * alpha. + * @param transparency The type of alpha values. + * @param transferType Data type of pixel sample values. + * @since 1.4 + */ + public ComponentColorModel(ColorSpace colorSpace, + boolean hasAlpha, + boolean isAlphaPremultiplied, + int transparency, int transferType) + { + this(colorSpace, findBits(colorSpace, transferType, hasAlpha), hasAlpha, + isAlphaPremultiplied, transparency, transferType); + } + + public int getRed(int pixel) + { + if (getNumComponents()>1) throw new IllegalArgumentException(); + return (int) getRGBFloat(pixel)[0]; + } + + public int getGreen(int pixel) + { + if (getNumComponents()>1) throw new IllegalArgumentException(); + return (int) getRGBFloat(pixel)[0]; + } + + public int getBlue(int pixel) + { + if (getNumComponents()>1) throw new IllegalArgumentException(); + return (int) getRGBFloat(pixel)[0]; + } + + public int getAlpha(int pixel) + { + if (getNumComponents()>1) throw new IllegalArgumentException(); + int shift = 8 - getComponentSize(getNumColorComponents()); + if (shift >= 0) return pixel << shift; + return pixel >> (-shift); + } + + public int getRGB(int pixel) + { + float[] rgb = getRGBFloat(pixel); + int ret = getRGB(rgb); + if (hasAlpha()) ret |= getAlpha(pixel) << 24; + return ret; + } + + + /* Note, it's OK to pass a to large array to toRGB(). Extra + elements are ignored. */ + + private float[] getRGBFloat(int pixel) + { + float[] data = { pixel }; + return cspace.toRGB(data); + } + + private float[] getRGBFloat(Object inData) + { + DataBuffer buffer = + Buffers.createBufferFromData(transferType, inData, + getNumComponents()); + int colors = getNumColorComponents(); + float[] data = new float[colors]; + + // FIXME: unpremultiply data that is premultiplied + for (int i=0; i<colors; i++) + { + float maxValue = (1<<getComponentSize(i))-1; + data[i] = buffer.getElemFloat(i)/maxValue; + } + float[] rgb = cspace.toRGB(data); + return rgb; + } + + public int getRed(Object inData) + { + return (int) getRGBFloat(inData)[0]*255; + } + + public int getGreen(Object inData) + { + return (int) getRGBFloat(inData)[1]*255; + } + + public int getBlue(Object inData) + { + return (int) getRGBFloat(inData)[2]*255; + } + + public int getAlpha(Object inData) + { + DataBuffer buffer = + Buffers.createBufferFromData(transferType, inData, + getNumComponents()); + int shift = 8 - getComponentSize(getNumColorComponents()); + int alpha = buffer.getElem(getNumColorComponents()); + if (shift >= 0) return alpha << shift; + return alpha >> (-shift); + } + + private int getRGB(float[] rgb) + { + /* NOTE: We could cast to byte instead of int here. This would + avoid bits spilling over from one bit field to + another. But, if we assume that floats are in the [0.0, + 1.0] range, this will never happen anyway. */ + + /* Remember to multiply BEFORE casting to int, otherwise, decimal + point data will be lost. */ + int ret = + (((int) (rgb[0]*255F)) << 16) | + (((int) (rgb[1]*255F)) << 8) | + (((int) (rgb[2]*255F)) << 0); + return ret; + } + + /** + * @param inData pixel data of transferType, as returned by the + * getDataElements method in SampleModel. + */ + public int getRGB(Object inData) + { + float[] rgb = getRGBFloat(inData); + int ret = getRGB(rgb); + if (hasAlpha()) ret |= getAlpha(inData) << 24; + return ret; + } + + public Object getDataElements(int rgb, Object pixel) + { + // Convert rgb to [0.0, 1.0] sRGB values. + float[] rgbFloats = { + ((rgb >> 16)&0xff)/255.0F, + ((rgb >> 8)&0xff)/255.0F, + ((rgb >> 0)&0xff)/255.0F + }; + + // Convert from rgb to color space components. + float[] data = cspace.fromRGB(rgbFloats); + DataBuffer buffer = Buffers.createBuffer(transferType, pixel, + getNumComponents()); + int numColors = getNumColorComponents(); + + if (hasAlpha()) + { + float alpha = ((rgb >> 24)&0xff)/255.0F; + + /* If color model has alpha and should be premultiplied, multiply + color space components with alpha value. */ + if (isAlphaPremultiplied()) { + for (int i=0; i<numColors; i++) + data[i] *= alpha; + } + // Scale the alpha sample to the correct number of bits. + alpha *= (1<<(bits[numColors]-1)); + // Arrange the alpha sample in the output array. + buffer.setElemFloat(numColors, alpha); + } + for (int i=0; i<numColors; i++) + { + // Scale the color samples to the correct number of bits. + float value = data[i]*(1<<(bits[i]-1)); + // Arrange the color samples in the output array. + buffer.setElemFloat(i, value); + } + return Buffers.getData(buffer); + } + + public int[] getComponents(int pixel, int[] components, int offset) + { + if (getNumComponents()>1) throw new IllegalArgumentException(); + if (components == null) + components = new int[getNumComponents() + offset]; + components[offset] = pixel; + return components; + } + + public int[] getComponents(Object pixel, int[] components, int offset) + { + DataBuffer buffer = Buffers.createBuffer(transferType, pixel, + getNumComponents()); + int numComponents = getNumComponents(); + + if (components == null) + components = new int[numComponents + offset]; + + for (int i=0; i<numComponents; i++) + components[offset++] = buffer.getElem(i); + + return components; + } + + public int getDataElement(int[] components, int offset) + { + if (getNumComponents()>1) throw new IllegalArgumentException(); + return components[offset]; + } + + public Object getDataElements(int[] components, int offset, Object obj) + { + DataBuffer buffer = Buffers.createBuffer(transferType, obj, + getNumComponents()); + int numComponents = getNumComponents(); + + for (int i=0; i<numComponents; i++) + buffer.setElem(i, components[offset++]); + + return Buffers.getData(buffer); + } + + public ColorModel coerceData(WritableRaster raster, + boolean isAlphaPremultiplied) { + if (this.isAlphaPremultiplied == isAlphaPremultiplied || !hasAlpha()) + return this; + + /* TODO: provide better implementation based on the + assumptions we can make due to the specific type of the + color model. */ + coerceDataWorker(raster, isAlphaPremultiplied); + + return new ComponentColorModel(cspace, hasAlpha, isAlphaPremultiplied, + transparency, transferType); + } + + public boolean isCompatibleRaster(Raster raster) + { + return super.isCompatibleRaster(raster); + // FIXME: Should we test something more here? (Why override?) + } + + public WritableRaster createCompatibleWritableRaster(int w, int h) + { + SampleModel sm = createCompatibleSampleModel(w, h); + Point origin = new Point(0, 0); + return Raster.createWritableRaster(sm, origin); + } + + + /** + * Creates a <code>SampleModel</code> whose arrangement of pixel + * data is compatible to this <code>ColorModel</code>. + * + * @param w the number of pixels in the horizontal direction. + * @param h the number of pixels in the vertical direction. + */ + public SampleModel createCompatibleSampleModel(int w, int h) + { + int pixelStride, scanlineStride; + int[] bandOffsets; + + pixelStride = getNumComponents(); + scanlineStride = pixelStride * w; + + /* We might be able to re-use the same bandOffsets array among + * multiple calls to this method. However, this optimization does + * not seem worthwile because setting up descriptive data + * structures (such as SampleModels) is neglectible in comparision + * to shuffling around masses of pixel data. + */ + bandOffsets = new int[pixelStride]; + for (int i = 0; i < pixelStride; i++) + bandOffsets[i] = i; + + /* FIXME: Think about whether it would make sense to return the + * possibly more efficient PixelInterleavedSampleModel for other + * transferTypes as well. It seems unlikely that this would break + * any user applications, so the Mauve tests on this method + * might be too restrictive. + */ + switch (transferType) + { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + return new PixelInterleavedSampleModel(transferType, w, h, + pixelStride, + scanlineStride, + bandOffsets); + + default: + return new ComponentSampleModel(transferType, w, h, + pixelStride, + scanlineStride, + bandOffsets); + } + } + + + public boolean isCompatibleSampleModel(SampleModel sm) + { + return + (sm instanceof ComponentSampleModel) && + super.isCompatibleSampleModel(sm); + } + + public WritableRaster getAlphaRaster(WritableRaster raster) + { + if (!hasAlpha()) return null; + + SampleModel sm = raster.getSampleModel(); + int[] alphaBand = { sm.getNumBands() - 1 }; + SampleModel alphaModel = sm.createSubsetSampleModel(alphaBand); + DataBuffer buffer = raster.getDataBuffer(); + Point origin = new Point(0, 0); + return Raster.createWritableRaster(alphaModel, buffer, origin); + } + + public boolean equals(Object obj) + { + if (!(obj instanceof ComponentColorModel)) return false; + return super.equals(obj); + } +} diff --git a/libjava/classpath/java/awt/image/ComponentSampleModel.java b/libjava/classpath/java/awt/image/ComponentSampleModel.java new file mode 100644 index 000000000..f32eae319 --- /dev/null +++ b/libjava/classpath/java/awt/image/ComponentSampleModel.java @@ -0,0 +1,755 @@ +/* Copyright (C) 2000, 2002, 2006, Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +import java.util.Arrays; + +/** + * ComponentSampleModel supports a flexible organization of pixel samples in + * memory, permitting pixel samples to be interleaved by band, by scanline, + * and by pixel. + * + * A DataBuffer for this sample model has K banks of data. Pixels have N + * samples, so there are N bands in the DataBuffer. Each band is completely + * contained in one bank of data, but a bank may contain more than one band. + * Each pixel sample is stored in a single data element. + * + * Within a bank, each band begins at an offset stored in bandOffsets. The + * banks containing the band is given by bankIndices. Within the bank, there + * are three dimensions - band, pixel, and scanline. The dimension ordering + * is controlled by bandOffset, pixelStride, and scanlineStride, which means + * that any combination of interleavings is supported. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public class ComponentSampleModel extends SampleModel +{ + /** The offsets to the first sample for each band. */ + protected int[] bandOffsets; + + /** The indices of the bank used to store each band in a data buffer. */ + protected int[] bankIndices; + + /** + * The number of bands in the image. + * @specnote This field shadows the protected numBands in SampleModel. + */ + protected int numBands; + + /** Used when creating data buffers. */ + protected int numBanks; + + /** + * The number of data elements between a sample in one row and the + * corresponding sample in the next row. + */ + protected int scanlineStride; + + /** + * The number of data elements between a sample for one pixel and the + * corresponding sample for the next pixel in the same row. + */ + protected int pixelStride; + + /** + * Creates a new sample model that assumes that all bands are stored in a + * single bank of the {@link DataBuffer}. + * <p> + * Note that the <code>bandOffsets</code> array is copied to internal storage + * to prevent subsequent changes to the array from affecting this object. + * + * @param dataType the data type (one of {@link DataBuffer#TYPE_BYTE}, + * {@link DataBuffer#TYPE_USHORT}, {@link DataBuffer#TYPE_SHORT}, + * {@link DataBuffer#TYPE_INT}, {@link DataBuffer#TYPE_FLOAT} or + * {@link DataBuffer#TYPE_DOUBLE}). + * @param w the width in pixels. + * @param h the height in pixels. + * @param pixelStride the number of data elements in the step from a sample + * in one pixel to the corresponding sample in the next pixel. + * @param scanlineStride the number of data elements in the step from a + * sample in a pixel to the corresponding sample in the pixel in the next + * row. + * @param bandOffsets the offset to the first element for each band, with + * the size of the array defining the number of bands (<code>null</code> + * not permitted). + * + * @throws IllegalArgumentException if <code>dataType</code> is not one of + * the specified values. + * @throws IllegalArgumentException if <code>w</code> is less than or equal + * to zero. + * @throws IllegalArgumentException if <code>h</code> is less than or equal + * to zero. + * @throws IllegalArgumentException if <code>w * h</code> exceeds + * {@link Integer#MAX_VALUE}. + * @throws IllegalArgumentException if <code>pixelStride</code> is negative. + * @throws IllegalArgumentException if <code>scanlineStride</code> is less + * than or equal to zero. + * @throws IllegalArgumentException if <code>bandOffsets</code> has zero + * length. + */ + public ComponentSampleModel(int dataType, + int w, int h, + int pixelStride, + int scanlineStride, + int[] bandOffsets) + { + this(dataType, w, h, pixelStride, scanlineStride, + new int[bandOffsets.length], bandOffsets); + } + + /** + * Creates a new sample model that assumes that all bands are stored in a + * single bank of the {@link DataBuffer}. + * + * @param dataType the data type (one of {@link DataBuffer#TYPE_BYTE}, + * {@link DataBuffer#TYPE_USHORT}, {@link DataBuffer#TYPE_SHORT}, + * {@link DataBuffer#TYPE_INT}, {@link DataBuffer#TYPE_FLOAT} or + * {@link DataBuffer#TYPE_DOUBLE}). + * @param w the width in pixels. + * @param h the height in pixels. + * @param pixelStride the number of data elements in the step from a sample + * in one pixel to the corresponding sample in the next pixel. + * @param scanlineStride the number of data elements in the step from a + * sample in a pixel to the corresponding sample in the pixel in the next + * row. + * @param bankIndices the index of the bank in which each band is stored + * (<code>null</code> not permitted). This array is copied to internal + * storage so that subsequent updates to the array do not affect the sample + * model. + * @param bandOffsets the offset to the first element for each band, with + * the size of the array defining the number of bands (<code>null</code> + * not permitted). This array is copied to internal storage so that + * subsequent updates to the array do not affect the sample model. + * + * @throws IllegalArgumentException if <code>dataType</code> is not one of + * the specified values. + * @throws IllegalArgumentException if <code>w</code> is less than or equal + * to zero. + * @throws IllegalArgumentException if <code>h</code> is less than or equal + * to zero. + * @throws IllegalArgumentException if <code>w * h</code> exceeds + * {@link Integer#MAX_VALUE}. + * @throws IllegalArgumentException if <code>pixelStride</code> is negative. + * @throws IllegalArgumentException if <code>scanlineStride</code> is less + * than or equal to zero. + * @throws IllegalArgumentException if <code>bandOffsets</code> has zero + * length. + */ + public ComponentSampleModel(int dataType, + int w, int h, + int pixelStride, + int scanlineStride, + int[] bankIndices, + int[] bandOffsets) + { + super(dataType, w, h, bandOffsets.length); + + // super permits DataBuffer.TYPE_UNDEFINED but this class doesn't... + if (dataType == DataBuffer.TYPE_UNDEFINED) + throw new IllegalArgumentException("Unsupported dataType."); + + if ((pixelStride < 0) || (scanlineStride < 0) || (bandOffsets.length < 1) + || (bandOffsets.length != bankIndices.length)) + throw new IllegalArgumentException(); + + this.bandOffsets = (int[]) bandOffsets.clone(); + this.bankIndices = (int[]) bankIndices.clone(); + this.numBands = bandOffsets.length; + + this.numBanks = 0; + for (int b = 0; b < bankIndices.length; b++) + this.numBanks = Math.max(this.numBanks, bankIndices[b] + 1); + + this.scanlineStride = scanlineStride; + this.pixelStride = pixelStride; + + } + + /** + * Creates a new sample model that is compatible with this one, but with the + * specified dimensions. + * + * @param w the width (must be greater than zero). + * @param h the height (must be greater than zero). + * + * @return A new sample model. + */ + public SampleModel createCompatibleSampleModel(int w, int h) + { + return new ComponentSampleModel(dataType, w, h, pixelStride, + scanlineStride, bankIndices, + bandOffsets); + } + + /** + * Creates a new sample model that provides access to a subset of the bands + * that this sample model supports. + * + * @param bands the bands (<code>null</code> not permitted). + * + * @return The new sample model. + */ + public SampleModel createSubsetSampleModel(int[] bands) + { + int numBands = bands.length; + + int[] bankIndices = new int[numBands]; + int[] bandOffsets = new int[numBands]; + for (int b = 0; b < numBands; b++) + { + bankIndices[b] = this.bankIndices[bands[b]]; + bandOffsets[b] = this.bandOffsets[bands[b]]; + } + + return new ComponentSampleModel(dataType, width, height, pixelStride, + scanlineStride, bankIndices, + bandOffsets); + } + + /** + * Creates a new data buffer that is compatible with this sample model. + * + * @return The new data buffer. + */ + public DataBuffer createDataBuffer() + { + // Maybe this value should be precalculated in the constructor? + int highestOffset = 0; + for (int b = 0; b < numBands; b++) + highestOffset = Math.max(highestOffset, bandOffsets[b]); + int size = pixelStride * (width - 1) + scanlineStride * (height - 1) + + highestOffset + 1; + + DataBuffer buffer = null; + switch (getTransferType()) + { + case DataBuffer.TYPE_BYTE: + buffer = new DataBufferByte(size, numBanks); + break; + case DataBuffer.TYPE_SHORT: + buffer = new DataBufferShort(size, numBanks); + break; + case DataBuffer.TYPE_USHORT: + buffer = new DataBufferUShort(size, numBanks); + break; + case DataBuffer.TYPE_INT: + buffer = new DataBufferInt(size, numBanks); + break; + case DataBuffer.TYPE_FLOAT: + buffer = new DataBufferFloat(size, numBanks); + break; + case DataBuffer.TYPE_DOUBLE: + buffer = new DataBufferDouble(size, numBanks); + break; + } + return buffer; + } + + /** + * Returns the offset of the sample in band 0 for the pixel at location + * <code>(x, y)</code>. This offset can be used to read a sample value from + * a {@link DataBuffer}. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * + * @return The offset. + * + * @see #getOffset(int, int, int) + */ + public int getOffset(int x, int y) + { + return getOffset(x, y, 0); + } + + /** + * Returns the offset of the sample in band <code>b</code> for the pixel at + * location <code>(x, y)</code>. This offset can be used to read a sample + * value from a {@link DataBuffer}. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param b the band index. + * + * @return The offset. + */ + public int getOffset(int x, int y, int b) + { + return bandOffsets[b] + pixelStride * x + scanlineStride * y; + } + + /** + * Returns the size in bits for each sample (one per band). For this sample + * model, each band has the same sample size and this is determined by the + * data type for the sample model. + * + * @return The sample sizes. + * + * @see SampleModel#getDataType() + */ + public final int[] getSampleSize() + { + int size = DataBuffer.getDataTypeSize(getDataType()); + int[] sizes = new int[numBands]; + + java.util.Arrays.fill(sizes, size); + return sizes; + } + + /** + * Returns the size in bits for the samples in the specified band. In this + * class, the sample size is the same for every band and is determined from + * the data type for the model. + * + * @param band the band index (ignored here). + * + * @return The sample size in bits. + * + * @see SampleModel#getDataType() + */ + public final int getSampleSize(int band) + { + return DataBuffer.getDataTypeSize(getDataType()); + } + + /** + * Returns the indices of the bank(s) in the {@link DataBuffer} used to + * store the samples for each band. The returned array is a copy, so that + * altering it will not impact the sample model. + * + * @return The bank indices. + */ + public final int[] getBankIndices() + { + return (int[]) bankIndices.clone(); + } + + /** + * Returns the offsets to the first sample in each band. The returned array + * is a copy, so that altering it will not impact the sample model. + * + * @return The offsets. + */ + public final int[] getBandOffsets() + { + return (int[]) bandOffsets.clone(); + } + + /** + * Returns the distance (in terms of element indices) between the sample for + * one pixel and the corresponding sample for the equivalent pixel in the + * next row. This is used in the calculation of the element offset for + * retrieving samples from a {@link DataBuffer}. + * + * @return The distance between pixel samples in consecutive rows. + */ + public final int getScanlineStride() + { + return scanlineStride; + } + + /** + * Returns the distance (in terms of element indices) between the sample for + * one pixel and the corresponding sample for the next pixel in a row. This + * is used in the calculation of the element offset for retrieving samples + * from a {@link DataBuffer}. + * + * @return The distance between pixel samples in the same row. + */ + public final int getPixelStride() + { + return pixelStride; + } + + /** + * Returns the number of data elements used to store the samples for one + * pixel. In this model, this is the same as the number of bands. + * + * @return The number of data elements used to store the samples for one + * pixel. + */ + public final int getNumDataElements() + { + return numBands; + } + + /** + * Returns the samples for the pixel at location <code>(x, y)</code> in + * a primitive array (the array type is determined by the data type for + * this model). The <code>obj</code> argument provides an option to supply + * an existing array to hold the result, if this is <code>null</code> a new + * array will be allocated. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param obj a primitive array that, if not <code>null</code>, will be + * used to store and return the sample values. + * @param data the data buffer (<code>null</code> not permitted). + * + * @return An array of sample values for the specified pixel. + */ + public Object getDataElements(int x, int y, Object obj, DataBuffer data) + { + int type = getTransferType(); + int numDataEls = getNumDataElements(); + int offset = y * scanlineStride + x * pixelStride; + switch (type) + { + case DataBuffer.TYPE_BYTE: + byte[] bData; + if (obj == null) + bData = new byte[numDataEls]; + else + bData = (byte[]) obj; + for (int i = 0; i < numDataEls; i++) + { + bData[i] = (byte) data.getElem(bankIndices[i], + offset + bandOffsets[i]); + } + obj = bData; + break; + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short[] sData; + if (obj == null) + sData = new short[numDataEls]; + else + sData = (short[]) obj; + for (int i = 0; i < numDataEls; i++) + { + sData[i] = (short) data.getElem(bankIndices[i], + offset + bandOffsets[i]); + } + obj = sData; + break; + case DataBuffer.TYPE_INT: + int[] iData; + if (obj == null) + iData = new int[numDataEls]; + else + iData = (int[]) obj; + for (int i = 0; i < numDataEls; i++) + { + iData[i] = data.getElem(bankIndices[i], offset + bandOffsets[i]); + } + obj = iData; + break; + case DataBuffer.TYPE_FLOAT: + float[] fData; + if (obj == null) + fData = new float[numDataEls]; + else + fData = (float[]) obj; + for (int i = 0; i < numDataEls; i++) + { + fData[i] = data.getElemFloat(bankIndices[i], + offset + bandOffsets[i]); + } + obj = fData; + break; + case DataBuffer.TYPE_DOUBLE: + double[] dData; + if (obj == null) + dData = new double[numDataEls]; + else + dData = (double[]) obj; + for (int i = 0; i < numDataEls; i++) + { + dData[i] = data.getElemDouble(bankIndices[i], + offset + bandOffsets[i]); + } + obj = dData; + break; + } + return obj; + } + + + /** + * Returns all the samples for the pixel at location <code>(x, y)</code> + * stored in the specified data buffer. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param iArray an array that will be populated with the sample values and + * returned as the result. The size of this array should be equal to the + * number of bands in the model. If the array is <code>null</code>, a new + * array is created. + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The samples for the specified pixel. + * + * @see #setPixel(int, int, int[], DataBuffer) + */ + public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) + { + if (x < 0 || x >= width || y < 0 || y >= height) + throw new ArrayIndexOutOfBoundsException("Pixel (" + x + ", " + y + + ") is out of bounds."); + int offset = pixelStride * x + scanlineStride * y; + if (iArray == null) + iArray = new int[numBands]; + for (int b = 0; b < numBands; b++) + { + iArray[b] = data.getElem(bankIndices[b], offset + bandOffsets[b]); + } + return iArray; + } + + /** + * Returns the samples for all the pixels in a rectangular region. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param w the width. + * @param h the height. + * @param iArray an array that if non-<code>null</code> will be populated + * with the sample values and returned as the result. + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The samples for all the pixels in the rectangle. + */ + public int[] getPixels(int x, int y, int w, int h, int[] iArray, + DataBuffer data) + { + int offset = pixelStride * x + scanlineStride * y; + if (iArray == null) + iArray = new int[numBands * w * h]; + int outOffset = 0; + for (y = 0; y < h; y++) + { + int lineOffset = offset; + for (x = 0; x < w; x++) + { + for (int b = 0; b < numBands; b++) + { + iArray[outOffset++] + = data.getElem(bankIndices[b], lineOffset+bandOffsets[b]); + } + lineOffset += pixelStride; + } + offset += scanlineStride; + } + return iArray; + } + + /** + * Returns the sample for band <code>b</code> of the pixel at + * <code>(x, y)</code> that is stored in the specified data buffer. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param b the band index. + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample value. + * + * @throws ArrayIndexOutOfBoundsException if <code>(x, y)</code> is outside + * the bounds <code>[0, 0, width, height]</code>. + * + * @see #setSample(int, int, int, int, DataBuffer) + */ + public int getSample(int x, int y, int b, DataBuffer data) + { + if (x < 0 || x >= width || y < 0 || y >= height) + throw new ArrayIndexOutOfBoundsException("Sample (" + x + ", " + y + + ") is out of bounds."); + return data.getElem(bankIndices[b], getOffset(x, y, b)); + } + + /** + * Sets the samples for the pixel at location <code>(x, y)</code> from the + * supplied primitive array (the array type must be consistent with the data + * type for this model). + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param obj a primitive array containing the pixel's sample values. + * @param data the data buffer (<code>null</code> not permitted). + * + * @see #setDataElements(int, int, Object, DataBuffer) + */ + public void setDataElements(int x, int y, Object obj, DataBuffer data) + { + int type = getTransferType(); + int numDataEls = getNumDataElements(); + int offset = y * scanlineStride + x * pixelStride; + switch (type) + { + case DataBuffer.TYPE_BYTE: + byte[] bData = (byte[]) obj; + for (int i = 0; i < numDataEls; i++) + { + data.setElem(bankIndices[i], offset + bandOffsets[i], + ((int) bData[i]) & 0xFF); + } + break; + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short[] sData = (short[]) obj; + for (int i = 0; i < numDataEls; i++) + { + data.setElem(bankIndices[i], offset + bandOffsets[i], + ((int) sData[i]) & 0xFFFF); + } + break; + case DataBuffer.TYPE_INT: + int[] iData = (int[]) obj; + for (int i = 0; i < numDataEls; i++) + { + data.setElem(bankIndices[i], offset + bandOffsets[i], iData[i]); + } + break; + case DataBuffer.TYPE_FLOAT: + float[] fData = (float[]) obj; + for (int i = 0; i < numDataEls; i++) + { + data.setElemFloat(bankIndices[i], offset + bandOffsets[i], + fData[i]); + } + break; + case DataBuffer.TYPE_DOUBLE: + double[] dData = (double[]) obj; + for (int i = 0; i < numDataEls; i++) + { + data.setElemDouble(bankIndices[i], offset + bandOffsets[i], + dData[i]); + } + break; + } + } + + /** + * Sets the sample values for the pixel at location <code>(x, y)</code> + * stored in the specified data buffer. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param iArray the pixel sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @see #getPixel(int, int, int[], DataBuffer) + */ + public void setPixel(int x, int y, int[] iArray, DataBuffer data) + { + int offset = pixelStride * x + scanlineStride * y; + for (int b = 0; b < numBands; b++) + data.setElem(bankIndices[b], offset + bandOffsets[b], iArray[b]); + } + + /** + * Sets the sample value for band <code>b</code> of the pixel at location + * <code>(x, y)</code> in the specified data buffer. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param b the band index. + * @param s the sample value. + * @param data the data buffer (<code>null</code> not permitted). + * + * @see #getSample(int, int, int, DataBuffer) + */ + public void setSample(int x, int y, int b, int s, DataBuffer data) + { + data.setElem(bankIndices[b], getOffset(x, y, b), s); + } + + /** + * Tests this sample model for equality with an arbitrary object. Returns + * <code>true</code> if and only if: + * <ul> + * <li><code>obj</code> is not <code>null</code>;</li> + * <li><code>obj</code> is an instance of <code>ComponentSampleModel</code>; + * </li> + * <li>both models have the same values for the <code>dataType</code>, + * <code>width</code>, <code>height</code>, <code>pixelStride</code>, + * <code>scanlineStride</code>, <code>bandOffsets</code> and + * <code>bankIndices</code> fields.</li> + * </ul> + * + * @param obj the object to test (<code>null</code> permitted). + * + * @return <code>true</code> if this sample model is equal to + * <code>obj</code>, and <code>false</code> otherwise. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + if (! (obj instanceof ComponentSampleModel)) + return false; + ComponentSampleModel that = (ComponentSampleModel) obj; + if (this.dataType != that.dataType) + return false; + if (this.width != that.width) + return false; + if (this.height != that.height) + return false; + if (this.pixelStride != that.pixelStride) + return false; + if (this.scanlineStride != that.scanlineStride) + return false; + if (! Arrays.equals(this.bandOffsets, that.bandOffsets)) + return false; + if (! Arrays.equals(this.bankIndices, that.bankIndices)) + return false; + // couldn't find any difference, so... + return true; + } + + /** + * Returns a hash code for this sample model. + * + * @return The hash code. + */ + public int hashCode() + { + // this computation is based on the method described in Chapter 3 + // of Joshua Bloch's Effective Java... + int result = 17; + result = 37 * result + dataType; + result = 37 * result + width; + result = 37 * result + height; + result = 37 * result + pixelStride; + result = 37 * result + scanlineStride; + for (int i = 0; i < bandOffsets.length; i++) + result = 37 * result + bandOffsets[i]; + for (int i = 0; i < bankIndices.length; i++) + result = 37 * result + bankIndices[i]; + return result; + } +} diff --git a/libjava/classpath/java/awt/image/ConvolveOp.java b/libjava/classpath/java/awt/image/ConvolveOp.java new file mode 100644 index 000000000..10b85f446 --- /dev/null +++ b/libjava/classpath/java/awt/image/ConvolveOp.java @@ -0,0 +1,380 @@ +/* ConvolveOp.java -- + Copyright (C) 2004, 2005, 2006, Free Software Foundation -- ConvolveOp + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import java.awt.RenderingHints; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * Convolution filter. + * + * ConvolveOp convolves the source image with a Kernel to generate a + * destination image. This involves multiplying each pixel and its neighbors + * with elements in the kernel to compute a new pixel. + * + * Each band in a Raster is convolved and copied to the destination Raster. + * For BufferedImages, convolution is applied to all components. Color + * conversion will be applied if needed. + * + * Note that this filter ignores whether the source or destination is alpha + * premultiplied. The reference spec states that data will be premultiplied + * prior to convolving and divided back out afterwards (if needed), but testing + * has shown that this is not the case with their implementation. + * + * @author jlquinn@optonline.net + */ +public class ConvolveOp implements BufferedImageOp, RasterOp +{ + /** Edge pixels are set to 0. */ + public static final int EDGE_ZERO_FILL = 0; + + /** Edge pixels are copied from the source. */ + public static final int EDGE_NO_OP = 1; + + private Kernel kernel; + private int edge; + private RenderingHints hints; + + /** + * Construct a ConvolveOp. + * + * The edge condition specifies that pixels outside the area that can be + * filtered are either set to 0 or copied from the source image. + * + * @param kernel The kernel to convolve with. + * @param edgeCondition Either EDGE_ZERO_FILL or EDGE_NO_OP. + * @param hints Rendering hints for color conversion, or null. + */ + public ConvolveOp(Kernel kernel, + int edgeCondition, + RenderingHints hints) + { + this.kernel = kernel; + edge = edgeCondition; + this.hints = hints; + } + + /** + * Construct a ConvolveOp. + * + * The edge condition defaults to EDGE_ZERO_FILL. + * + * @param kernel The kernel to convolve with. + */ + public ConvolveOp(Kernel kernel) + { + this.kernel = kernel; + edge = EDGE_ZERO_FILL; + hints = null; + } + + /** + * Converts the source image using the kernel specified in the + * constructor. The resulting image is stored in the destination image if one + * is provided; otherwise a new BufferedImage is created and returned. + * + * The source and destination BufferedImage (if one is supplied) must have + * the same dimensions. + * + * @param src The source image. + * @param dst The destination image. + * @throws IllegalArgumentException if the rasters and/or color spaces are + * incompatible. + * @return The convolved image. + */ + public final BufferedImage filter(BufferedImage src, BufferedImage dst) + { + if (src == dst) + throw new IllegalArgumentException("Source and destination images " + + "cannot be the same."); + + if (dst == null) + dst = createCompatibleDestImage(src, src.getColorModel()); + + // Make sure source image is premultiplied + BufferedImage src1 = src; + // The spec says we should do this, but mauve testing shows that Sun's + // implementation does not check this. + /* + if (!src.isAlphaPremultiplied()) + { + src1 = createCompatibleDestImage(src, src.getColorModel()); + src.copyData(src1.getRaster()); + src1.coerceData(true); + } + */ + + BufferedImage dst1 = dst; + if (src1.getColorModel().getColorSpace().getType() != dst.getColorModel().getColorSpace().getType()) + dst1 = createCompatibleDestImage(src, src.getColorModel()); + + filter(src1.getRaster(), dst1.getRaster()); + + // Since we don't coerceData above, we don't need to divide it back out. + // This is wrong (one mauve test specifically tests converting a non- + // premultiplied image to a premultiplied image, and it shows that Sun + // simply ignores the premultipled flag, contrary to the spec), but we + // mimic it for compatibility. + /* + if (! dst.isAlphaPremultiplied()) + dst1.coerceData(false); + */ + + // Convert between color models if needed + if (dst1 != dst) + new ColorConvertOp(hints).filter(dst1, dst); + + return dst; + } + + /** + * Creates an empty BufferedImage with the size equal to the source and the + * correct number of bands. The new image is created with the specified + * ColorModel, or if no ColorModel is supplied, an appropriate one is chosen. + * + * @param src The source image. + * @param dstCM A color model for the destination image (may be null). + * @return The new compatible destination image. + */ + public BufferedImage createCompatibleDestImage(BufferedImage src, + ColorModel dstCM) + { + if (dstCM != null) + return new BufferedImage(dstCM, + src.getRaster().createCompatibleWritableRaster(), + src.isAlphaPremultiplied(), null); + + return new BufferedImage(src.getWidth(), src.getHeight(), src.getType()); + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#getRenderingHints() + */ + public final RenderingHints getRenderingHints() + { + return hints; + } + + /** + * Get the edge condition for this Op. + * + * @return The edge condition. + */ + public int getEdgeCondition() + { + return edge; + } + + /** + * Returns (a clone of) the convolution kernel. + * + * @return The convolution kernel. + */ + public final Kernel getKernel() + { + return (Kernel) kernel.clone(); + } + + /** + * Converts the source raster using the kernel specified in the constructor. + * The resulting raster is stored in the destination raster if one is + * provided; otherwise a new WritableRaster is created and returned. + * + * If the convolved value for a sample is outside the range of [0-255], it + * will be clipped. + * + * The source and destination raster (if one is supplied) cannot be the same, + * and must also have the same dimensions. + * + * @param src The source raster. + * @param dest The destination raster. + * @throws IllegalArgumentException if the rasters identical. + * @throws ImagingOpException if the convolution is not possible. + * @return The transformed raster. + */ + public final WritableRaster filter(Raster src, WritableRaster dest) + { + if (src == dest) + throw new IllegalArgumentException("src == dest is not allowed."); + if (kernel.getWidth() > src.getWidth() + || kernel.getHeight() > src.getHeight()) + throw new ImagingOpException("The kernel is too large."); + if (dest == null) + dest = createCompatibleDestRaster(src); + else if (src.getNumBands() != dest.getNumBands()) + throw new ImagingOpException("src and dest have different band counts."); + + // calculate the borders that the op can't reach... + int kWidth = kernel.getWidth(); + int kHeight = kernel.getHeight(); + int left = kernel.getXOrigin(); + int right = Math.max(kWidth - left - 1, 0); + int top = kernel.getYOrigin(); + int bottom = Math.max(kHeight - top - 1, 0); + + // Calculate max sample values for clipping + int[] maxValue = src.getSampleModel().getSampleSize(); + for (int i = 0; i < maxValue.length; i++) + maxValue[i] = (int)Math.pow(2, maxValue[i]) - 1; + + // process the region that is reachable... + int regionW = src.width - left - right; + int regionH = src.height - top - bottom; + float[] kvals = kernel.getKernelData(null); + float[] tmp = new float[kWidth * kHeight]; + + for (int x = 0; x < regionW; x++) + { + for (int y = 0; y < regionH; y++) + { + // FIXME: This needs a much more efficient implementation + for (int b = 0; b < src.getNumBands(); b++) + { + float v = 0; + src.getSamples(x, y, kWidth, kHeight, b, tmp); + for (int i = 0; i < tmp.length; i++) + v += tmp[tmp.length - i - 1] * kvals[i]; + // FIXME: in the above line, I've had to reverse the order of + // the samples array to make the tests pass. I haven't worked + // out why this is necessary. + + // This clipping is is undocumented, but determined by testing. + if (v > maxValue[b]) + v = maxValue[b]; + else if (v < 0) + v = 0; + + dest.setSample(x + kernel.getXOrigin(), y + kernel.getYOrigin(), + b, v); + } + } + } + + // fill in the top border + fillEdge(src, dest, 0, 0, src.width, top, edge); + + // fill in the bottom border + fillEdge(src, dest, 0, src.height - bottom, src.width, bottom, edge); + + // fill in the left border + fillEdge(src, dest, 0, top, left, regionH, edge); + + // fill in the right border + fillEdge(src, dest, src.width - right, top, right, regionH, edge); + + return dest; + } + + /** + * Fills a range of pixels (typically at the edge of a raster) with either + * zero values (if <code>edgeOp</code> is <code>EDGE_ZERO_FILL</code>) or the + * corresponding pixel values from the source raster (if <code>edgeOp</code> + * is <code>EDGE_NO_OP</code>). This utility method is called by the + * {@link #fillEdge(Raster, WritableRaster, int, int, int, int, int)} method. + * + * @param src the source raster. + * @param dest the destination raster. + * @param x the x-coordinate of the top left pixel in the range. + * @param y the y-coordinate of the top left pixel in the range. + * @param w the width of the pixel range. + * @param h the height of the pixel range. + * @param edgeOp indicates how to determine the values for the range + * (either {@link #EDGE_ZERO_FILL} or {@link #EDGE_NO_OP}). + */ + private void fillEdge(Raster src, WritableRaster dest, int x, int y, int w, + int h, int edgeOp) + { + if (w <= 0) + return; + if (h <= 0) + return; + if (edgeOp == EDGE_ZERO_FILL) // fill region with zeroes + { + float[] zeros = new float[src.getNumBands() * w * h]; + dest.setPixels(x, y, w, h, zeros); + } + else // copy pixels from source + { + float[] pixels = new float[src.getNumBands() * w * h]; + src.getPixels(x, y, w, h, pixels); + dest.setPixels(x, y, w, h, pixels); + } + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#createCompatibleDestRaster(java.awt.image.Raster) + */ + public WritableRaster createCompatibleDestRaster(Raster src) + { + return src.createCompatibleWritableRaster(); + } + + /* (non-Javadoc) + * @see java.awt.image.BufferedImageOp#getBounds2D(java.awt.image.BufferedImage) + */ + public final Rectangle2D getBounds2D(BufferedImage src) + { + return src.getRaster().getBounds(); + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#getBounds2D(java.awt.image.Raster) + */ + public final Rectangle2D getBounds2D(Raster src) + { + return src.getBounds(); + } + + /** + * Returns the corresponding destination point for a source point. Because + * this is not a geometric operation, the destination and source points will + * be identical. + * + * @param src The source point. + * @param dst The transformed destination point. + * @return The transformed destination point. + */ + public final Point2D getPoint2D(Point2D src, Point2D dst) + { + if (dst == null) return (Point2D)src.clone(); + dst.setLocation(src); + return dst; + } +} diff --git a/libjava/classpath/java/awt/image/CropImageFilter.java b/libjava/classpath/java/awt/image/CropImageFilter.java new file mode 100644 index 000000000..4d8fb624f --- /dev/null +++ b/libjava/classpath/java/awt/image/CropImageFilter.java @@ -0,0 +1,184 @@ +/* CropImageFilter.java -- Java class for cropping image filter + Copyright (C) 1999, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import java.awt.Rectangle; +import java.util.Hashtable; + +/** + * Currently this filter does almost nothing and needs to be implemented. + * + * @author C. Brian Jones (cbj@gnu.org) + */ +public class CropImageFilter extends ImageFilter +{ + int x; + int y; + int width; + int height; + + /** + * Construct a new <code>CropImageFilter</code> instance. + * + * @param x the x-coordinate location of the top-left of the cropped rectangle + * @param y the y-coordinate location of the top-left of the cropped rectangle + * @param width the width of the cropped rectangle + * @param height the height of the cropped rectangle + */ + public CropImageFilter(int x, int y, int width, int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + /** + * An <code>ImageProducer</code> indicates the size of the image + * being produced using this method. This filter overrides this + * method in order to set the dimentions to the size of the + * cropped rectangle instead of the size of the image. + * + * @param width the width of the image + * @param height the height of the image + */ + public void setDimensions(int width, int height) + { + if (consumer != null) + consumer.setDimensions(this.width, this.height); + } + + /** + * An <code>ImageProducer</code> can set a list of properties + * associated with this image by using this method. + * <br> + * FIXME - What property is set for this class? + * + * @param props the list of properties associated with this image + */ + public void setProperties(Hashtable<?, ?> props) + { + Hashtable<Object, Object> prop2 = (Hashtable<Object, Object>) props; + prop2.put("filters", "CropImageFilter"); + if (consumer != null) + consumer.setProperties(prop2); + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as a <code>byte</code> at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the <code>ColorModel</code> used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the <code>pixels</code> array + * @param scansize the width to use in extracting pixels from the <code>pixels</code> array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, byte[] pixels, int offset, int scansize) + { + Rectangle filterBounds = new Rectangle(this.x, this.y, + this.width, this.height); + Rectangle pixelBounds = new Rectangle(x, y, w, h); + + if (filterBounds.intersects(pixelBounds)) + { + Rectangle bounds = filterBounds.intersection(pixelBounds); + + byte[] cropped = new byte[bounds.width * bounds.height]; + for (int i = 0; i < bounds.height; i++) + { + int start = (bounds.y - pixelBounds.y + i) * scansize + offset; + + for (int j = 0; j < bounds.width; j++) + cropped[i * bounds.width + j] = pixels[start + bounds.x + j]; + } + + if (consumer != null) + consumer.setPixels(0, 0, + bounds.width, bounds.height, + model, cropped, 0, bounds.width); + } + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as an <code>int</code> at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the <code>ColorModel</code> used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the <code>pixels</code> array + * @param scansize the width to use in extracting pixels from the <code>pixels</code> array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, int[] pixels, int offset, int scansize) + { + Rectangle filterBounds = new Rectangle(this.x, this.y, + this.width, this.height); + Rectangle pixelBounds = new Rectangle(x, y, w, h); + + if (filterBounds.intersects(pixelBounds)) + { + Rectangle bounds = filterBounds.intersection(pixelBounds); + + int[] cropped = new int[bounds.width * bounds.height]; + for (int i = 0; i < bounds.height; i++) + { + int start = (bounds.y - pixelBounds.y + i) * scansize + offset; + + for (int j = 0; j < bounds.width; j++) + cropped[i * bounds.width + j] = pixels[start + bounds.x + j]; + } + + if (consumer != null) + consumer.setPixels(0, 0, + bounds.width, bounds.height, + model, cropped, 0, bounds.width); + } + } + +} diff --git a/libjava/classpath/java/awt/image/DataBuffer.java b/libjava/classpath/java/awt/image/DataBuffer.java new file mode 100644 index 000000000..78bc75ba5 --- /dev/null +++ b/libjava/classpath/java/awt/image/DataBuffer.java @@ -0,0 +1,437 @@ +/* Copyright (C) 2000, 2002, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +/** + * Class that manages arrays of data elements. A data buffer consists + * of one or more banks. A bank is a continuous region of data + * elements. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public abstract class DataBuffer +{ + /** + * A constant representing a data type that uses <code>byte</code> primitives + * as the storage unit. + */ + public static final int TYPE_BYTE = 0; + + /** + * A constant representing a data type that uses <code>short</code> + * primitives as the storage unit. + */ + public static final int TYPE_USHORT = 1; + + /** + * A constant representing a data type that uses <code>short</code> + * primitives as the storage unit. + */ + public static final int TYPE_SHORT = 2; + + /** + * A constant representing a data type that uses <code>int</code> + * primitives as the storage unit. + */ + public static final int TYPE_INT = 3; + + /** + * A constant representing a data type that uses <code>float</code> + * primitives as the storage unit. + */ + public static final int TYPE_FLOAT = 4; + + /** + * A constant representing a data type that uses <code>double</code> + * primitives as the storage unit. + */ + public static final int TYPE_DOUBLE = 5; + + /** + * A constant representing an undefined data type. + */ + public static final int TYPE_UNDEFINED = 32; + + /** The type of the data elements stored in the data buffer. */ + protected int dataType; + + /** The number of banks in this buffer. */ + protected int banks = 1; + + /** Offset into the default (0'th) bank). */ + protected int offset; // FIXME: Is offsets[0] always mirrored in offset? + + /** The size of the banks. */ + protected int size; + + /** Offset into each bank. */ + protected int[] offsets; + + /** + * Creates a new <code>DataBuffer</code> with the specified data type and + * size. The <code>dataType</code> should be one of the constants + * {@link #TYPE_BYTE}, {@link #TYPE_SHORT}, {@link #TYPE_USHORT}, + * {@link #TYPE_INT}, {@link #TYPE_FLOAT} and {@link #TYPE_DOUBLE}. + * <p> + * The physical (array-based) storage is allocated by a subclass. + * + * @param dataType the data type. + * @param size the number of elements in the buffer. + */ + protected DataBuffer(int dataType, int size) + { + this(dataType, size, 1); + } + + /** + * Creates a new <code>DataBuffer</code> with the specified data type, + * size and number of banks. The <code>dataType</code> should be one of + * the constants {@link #TYPE_BYTE}, {@link #TYPE_SHORT}, + * {@link #TYPE_USHORT}, {@link #TYPE_INT}, {@link #TYPE_FLOAT} and + * {@link #TYPE_DOUBLE}. + * <p> + * The physical (array-based) storage is allocated by a subclass. + * + * @param dataType the data type. + * @param size the number of elements in the buffer. + * @param numBanks the number of data banks. + */ + protected DataBuffer(int dataType, int size, int numBanks) { + this(dataType, size, numBanks, 0); + } + + /** + * Creates a new <code>DataBuffer</code> with the specified data type, + * size and number of banks. An offset (which applies to all banks) is + * also specified. The <code>dataType</code> should be one of + * the constants {@link #TYPE_BYTE}, {@link #TYPE_SHORT}, + * {@link #TYPE_USHORT}, {@link #TYPE_INT}, {@link #TYPE_FLOAT} and + * {@link #TYPE_DOUBLE}. + * <p> + * The physical (array-based) storage is allocated by a subclass. + * + * @param dataType the data type. + * @param size the number of elements in the buffer. + * @param numBanks the number of data banks. + * @param offset the offset to the first element for all banks. + */ + protected DataBuffer(int dataType, int size, int numBanks, int offset) { + banks = numBanks; + this.dataType = dataType; + this.size = size; + this.offset = offset; + + offsets = new int[ numBanks ]; + for(int i = 0; i < numBanks; i++ ) + offsets[i] = offset; + } + + /** + * Creates a new <code>DataBuffer</code> with the specified data type, + * size and number of banks. An offset (which applies to all banks) is + * also specified. The <code>dataType</code> should be one of + * the constants {@link #TYPE_BYTE}, {@link #TYPE_SHORT}, + * {@link #TYPE_USHORT}, {@link #TYPE_INT}, {@link #TYPE_FLOAT} and + * {@link #TYPE_DOUBLE}. + * <p> + * The physical (array-based) storage is allocated by a subclass. + * + * @param dataType the data type. + * @param size the number of elements in the buffer. + * @param numBanks the number of data banks. + * @param offsets the offsets to the first element for all banks. + * + * @throws ArrayIndexOutOfBoundsException if + * <code>numBanks != offsets.length</code>. + */ + protected DataBuffer(int dataType, int size, int numBanks, int[] offsets) { + if (numBanks != offsets.length) + throw new ArrayIndexOutOfBoundsException(); + + this.dataType = dataType; + this.size = size; + banks = numBanks; + this.offsets = offsets; + + offset = offsets[0]; + } + + /** + * Returns the size (number of bits) of the specified data type. Valid types + * are defined by the constants {@link #TYPE_BYTE}, {@link #TYPE_SHORT}, + * {@link #TYPE_USHORT}, {@link #TYPE_INT}, {@link #TYPE_FLOAT} and + * {@link #TYPE_DOUBLE}. + * + * @param dataType the data type. + * @return The number of bits for the specified data type. + * @throws IllegalArgumentException if <code>dataType < 0</code> or + * <code>dataType > TYPE_DOUBLE</code>. + */ + public static int getDataTypeSize(int dataType) { + // Maybe this should be a lookup table instead. + switch (dataType) + { + case TYPE_BYTE: + return 8; + case TYPE_USHORT: + case TYPE_SHORT: + return 16; + case TYPE_INT: + case TYPE_FLOAT: + return 32; + case TYPE_DOUBLE: + return 64; + default: + throw new IllegalArgumentException(); + } + } + + /** + * Returns the type of the data elements in the data buffer. Valid types + * are defined by the constants {@link #TYPE_BYTE}, {@link #TYPE_SHORT}, + * {@link #TYPE_USHORT}, {@link #TYPE_INT}, {@link #TYPE_FLOAT} and + * {@link #TYPE_DOUBLE}. + * + * @return The type. + */ + public int getDataType() + { + return dataType; + } + + /** + * Returns the size of the data buffer. + * + * @return The size. + */ + public int getSize() + { + return size; + } + + /** + * Returns the element offset for the first data bank. + * + * @return The element offset. + */ + public int getOffset() + { + return offset; + } + + /** + * Returns the offsets for all the data banks used by this + * <code>DataBuffer</code>. + * + * @return The offsets. + */ + public int[] getOffsets() + { + if (offsets == null) + { + // is this necessary? + offsets = new int[1]; + offsets[0] = offset; + } + return offsets; + } + + /** + * Returns the number of data banks for this <code>DataBuffer</code>. + * @return The number of data banks. + */ + public int getNumBanks() + { + return banks; + } + + /** + * Returns an element from the first data bank. The offset (specified in + * the constructor) is added to <code>i</code> before accessing the + * underlying data array. + * + * @param i the element index. + * @return The element. + */ + public int getElem(int i) + { + return getElem(0, i); + } + + /** + * Returns an element from a particular data bank. The offset (specified in + * the constructor) is added to <code>i</code> before accessing the + * underlying data array. + * + * @param bank the bank index. + * @param i the element index. + * @return The element. + */ + public abstract int getElem(int bank, int i); + + /** + * Sets an element in the first data bank. The offset (specified in the + * constructor) is added to <code>i</code> before updating the underlying + * data array. + * + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int i, int val) + { + setElem(0, i, val); + } + + /** + * Sets an element in a particular data bank. The offset (specified in the + * constructor) is added to <code>i</code> before updating the underlying + * data array. + * + * @param bank the data bank index. + * @param i the element index. + * @param val the new element value. + */ + public abstract void setElem(int bank, int i, int val); + + /** + * Returns an element from the first data bank, converted to a + * <code>float</code>. The offset (specified in the constructor) is added + * to <code>i</code> before accessing the underlying data array. + * + * @param i the element index. + * @return The element. + */ + public float getElemFloat(int i) + { + return getElem(i); + } + + /** + * Returns an element from a particular data bank, converted to a + * <code>float</code>. The offset (specified in the constructor) is + * added to <code>i</code> before accessing the underlying data array. + * + * @param bank the bank index. + * @param i the element index. + * @return The element. + */ + public float getElemFloat(int bank, int i) + { + return getElem(bank, i); + } + + /** + * Sets an element in the first data bank. The offset (specified in the + * constructor) is added to <code>i</code> before updating the underlying + * data array. + * + * @param i the element index. + * @param val the new element value. + */ + public void setElemFloat(int i, float val) + { + setElem(i, (int) val); + } + + /** + * Sets an element in a particular data bank. The offset (specified in the + * constructor) is added to <code>i</code> before updating the underlying + * data array. + * + * @param bank the data bank index. + * @param i the element index. + * @param val the new element value. + */ + public void setElemFloat(int bank, int i, float val) + { + setElem(bank, i, (int) val); + } + + /** + * Returns an element from the first data bank, converted to a + * <code>double</code>. The offset (specified in the constructor) is added + * to <code>i</code> before accessing the underlying data array. + * + * @param i the element index. + * @return The element. + */ + public double getElemDouble(int i) + { + return getElem(i); + } + + /** + * Returns an element from a particular data bank, converted to a + * <code>double</code>. The offset (specified in the constructor) is + * added to <code>i</code> before accessing the underlying data array. + * + * @param bank the bank index. + * @param i the element index. + * @return The element. + */ + public double getElemDouble(int bank, int i) + { + return getElem(bank, i); + } + + /** + * Sets an element in the first data bank. The offset (specified in the + * constructor) is added to <code>i</code> before updating the underlying + * data array. + * + * @param i the element index. + * @param val the new element value. + */ + public void setElemDouble(int i, double val) + { + setElem(i, (int) val); + } + + /** + * Sets an element in a particular data bank. The offset (specified in the + * constructor) is added to <code>i</code> before updating the underlying + * data array. + * + * @param bank the data bank index. + * @param i the element index. + * @param val the new element value. + */ + public void setElemDouble(int bank, int i, double val) + { + setElem(bank, i, (int) val); + } +} diff --git a/libjava/classpath/java/awt/image/DataBufferByte.java b/libjava/classpath/java/awt/image/DataBufferByte.java new file mode 100644 index 000000000..01364b07a --- /dev/null +++ b/libjava/classpath/java/awt/image/DataBufferByte.java @@ -0,0 +1,245 @@ +/* Copyright (C) 2000, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +/* This is one of several classes that are nearly identical. Maybe we + should have a central template and generate all these files. This + is one of the cases where templates or macros would have been + useful to have in Java. + + This file has been created using search-replace. My only fear is + that these classes will grow out-of-sync as of a result of changes + that are not propagated to the other files. As always, mirroring + code is a maintenance nightmare. */ + +/** + * A {@link DataBuffer} that uses an array of <code>byte</code> primitives + * to represent each of its banks. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public final class DataBufferByte extends DataBuffer +{ + private byte[] data; + private byte[][] bankData; + + /** + * Creates a new data buffer with a single data bank containing the + * specified number of <code>byte</code> elements. + * + * @param size the number of elements in the data bank. + */ + public DataBufferByte(int size) + { + super(TYPE_BYTE, size, 1, 0); + bankData = new byte[1][]; + data = new byte[size]; + bankData[0] = data; + } + + /** + * Creates a new data buffer with the specified number of data banks, + * each containing the specified number of <code>byte</code> elements. + * + * @param size the number of elements in the data bank. + * @param numBanks the number of data banks. + */ + public DataBufferByte(int size, int numBanks) + { + super(TYPE_BYTE, size, numBanks); + bankData = new byte[numBanks][size]; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data bank. + * <p> + * Note: there is no exception when <code>dataArray</code> is + * <code>null</code>, but in that case an exception will be thrown + * later if you attempt to access the data buffer. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + */ + public DataBufferByte(byte[] dataArray, int size) + { + super(TYPE_BYTE, size, 1, 0); + bankData = new byte[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data bank, with + * the specified offset to the first element. + * <p> + * Note: there is no exception when <code>dataArray</code> is + * <code>null</code>, but in that case an exception will be thrown + * later if you attempt to access the data buffer. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + * @param offset the offset to the first element in the array. + */ + public DataBufferByte(byte[] dataArray, int size, int offset) + { + super(TYPE_BYTE, size, 1, offset); + bankData = new byte[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data banks. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * + * @throws NullPointerException if <code>dataArray</code> is + * <code>null</code>. + */ + public DataBufferByte(byte[][] dataArray, int size) + { + super(TYPE_BYTE, size, dataArray.length); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data banks, with + * the specified offsets to the first element in each bank. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * @param offsets the offsets to the first element in each data bank. + * + * @throws NullPointerException if <code>dataArray</code> is + * <code>null</code>. + */ + public DataBufferByte(byte[][] dataArray, int size, int[] offsets) + { + super(TYPE_BYTE, size, dataArray.length, offsets); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Returns the first data bank. + * + * @return The first data bank. + */ + public byte[] getData() + { + return data; + } + + /** + * Returns a data bank. + * + * @param bank the bank index. + * @return A data bank. + */ + public byte[] getData(int bank) + { + return bankData[bank]; + } + + /** + * Returns the array underlying this <code>DataBuffer</code>. + * + * @return The data banks. + */ + public byte[][] getBankData() + { + return bankData; + } + + /** + * Returns an element from the first data bank. The offset (specified in + * the constructor) is added to <code>i</code> before accessing the + * underlying data array. + * + * @param i the element index. + * @return The element. + */ + public int getElem(int i) + { + return data[i+offset] & 0xff; // get unsigned byte as int + } + + /** + * Returns an element from a particular data bank. The offset (specified in + * the constructor) is added to <code>i</code> before accessing the + * underlying data array. + * + * @param bank the bank index. + * @param i the element index. + * @return The element. + */ + public int getElem(int bank, int i) + { + // get unsigned byte as int + return bankData[bank][i+offsets[bank]] & 0xff; + } + + /** + * Sets an element in the first data bank. The offset (specified in the + * constructor) is added to <code>i</code> before updating the underlying + * data array. + * + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int i, int val) + { + data[i+offset] = (byte) val; + } + + /** + * Sets an element in a particular data bank. The offset (specified in the + * constructor) is added to <code>i</code> before updating the underlying + * data array. + * + * @param bank the data bank index. + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int bank, int i, int val) + { + bankData[bank][i+offsets[bank]] = (byte) val; + } +} diff --git a/libjava/classpath/java/awt/image/DataBufferDouble.java b/libjava/classpath/java/awt/image/DataBufferDouble.java new file mode 100644 index 000000000..31c5ebd8c --- /dev/null +++ b/libjava/classpath/java/awt/image/DataBufferDouble.java @@ -0,0 +1,288 @@ +/* Copyright (C) 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +/* This is one of several classes that are nearly identical. Maybe we + should have a central template and generate all these files. This + is one of the cases where templates or macros would have been + useful to have in Java. + + This file has been created using search-replace. My only fear is + that these classes will grow out-of-sync as of a result of changes + that are not propagated to the other files. As always, mirroring + code is a maintenance nightmare. */ + +/** + * A {@link DataBuffer} that uses an array of <code>double</code> primitives + * to represent each of its banks. + * + * @since 1.4 + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public final class DataBufferDouble + extends DataBuffer +{ + private double[] data; + private double[][] bankData; + + /** + * Creates a new data buffer with a single data bank containing the + * specified number of <code>double</code> elements. + * + * @param size the number of elements in the data bank. + */ + public DataBufferDouble(int size) + { + super(TYPE_DOUBLE, size, 1, 0); + bankData = new double[1][]; + data = new double[size]; + bankData[0] = data; + } + + /** + * Creates a new data buffer with the specified number of data banks, + * each containing the specified number of <code>double</code> elements. + * + * @param size the number of elements in the data bank. + * @param numBanks the number of data banks. + */ + public DataBufferDouble(int size, int numBanks) + { + super(TYPE_DOUBLE, size, numBanks); + bankData = new double[numBanks][size]; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data bank. + * <p> + * Note: there is no exception when <code>dataArray</code> is + * <code>null</code>, but in that case an exception will be thrown + * later if you attempt to access the data buffer. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + */ + public DataBufferDouble(double[] dataArray, int size) + { + super(TYPE_DOUBLE, size, 1, 0); + bankData = new double[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data bank, with + * the specified offset to the first element. + * <p> + * Note: there is no exception when <code>dataArray</code> is + * <code>null</code>, but in that case an exception will be thrown + * later if you attempt to access the data buffer. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + * @param offset the offset to the first element in the array. + */ + public DataBufferDouble(double[] dataArray, int size, int offset) + { + super(TYPE_DOUBLE, size, 1, offset); + bankData = new double[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data banks. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * + * @throws NullPointerException if <code>dataArray</code> is + * <code>null</code>. + */ + public DataBufferDouble(double[][] dataArray, int size) + { + super(TYPE_DOUBLE, size, dataArray.length); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data banks, with + * the specified offsets to the first element in each bank. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * @param offsets the offsets to the first element in each data bank. + * + * @throws NullPointerException if <code>dataArray</code> is + * <code>null</code>. + */ + public DataBufferDouble(double[][] dataArray, int size, int[] offsets) + { + super(TYPE_DOUBLE, size, dataArray.length, offsets); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Returns the first data bank. + * + * @return The first data bank. + */ + public double[] getData() + { + return data; + } + + /** + * Returns a data bank. + * + * @param bank the bank index. + * @return A data bank. + */ + public double[] getData(int bank) + { + return bankData[bank]; + } + + /** + * Returns the array underlying this <code>DataBuffer</code>. + * + * @return The data banks. + */ + public double[][] getBankData() + { + return bankData; + } + + /** + * Returns an element from the first data bank. The offset (specified in + * the constructor) is added to <code>i</code> before accessing the + * underlying data array. + * + * @param i the element index. + * @return The element. + */ + public int getElem(int i) + { + return (int) data[i+offset]; + } + + /** + * Returns an element from a particular data bank. The offset (specified in + * the constructor) is added to <code>i</code> before accessing the + * underlying data array. + * + * @param bank the bank index. + * @param i the element index. + * @return The element. + */ + public int getElem(int bank, int i) + { + return (int) bankData[bank][i+offsets[bank]]; + } + + /** + * Sets an element in the first data bank. The offset (specified in the + * constructor) is added to <code>i</code> before updating the underlying + * data array. + * + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int i, int val) + { + data[i+offset] = val; + } + + /** + * Sets an element in a particular data bank. The offset (specified in the + * constructor) is added to <code>i</code> before updating the underlying + * data array. + * + * @param bank the data bank index. + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int bank, int i, int val) + { + bankData[bank][i+offsets[bank]] = val; + } + + public float getElemFloat(int i) + { + return (float) data[i+offset]; + } + + public float getElemFloat(int bank, int i) + { + return (float) bankData[bank][i+offsets[bank]]; + } + + public void setElemFloat(int i, float val) + { + data[i+offset] = val; + } + + public void setElemFloat(int bank, int i, float val) + { + bankData[bank][i+offsets[bank]] = val; + } + + public double getElemDouble(int i) + { + return data[i + offset]; + } + + public double getElemDouble(int bank, int i) + { + return bankData[bank][i + offsets[bank]]; + } + + public void setElemDouble(int i, double val) + { + data[i + offset] = val; + } + + public void setElemDouble(int bank, int i, double val) + { + bankData[bank][i + offsets[bank]] = val; + } +} diff --git a/libjava/classpath/java/awt/image/DataBufferFloat.java b/libjava/classpath/java/awt/image/DataBufferFloat.java new file mode 100644 index 000000000..44a0a3892 --- /dev/null +++ b/libjava/classpath/java/awt/image/DataBufferFloat.java @@ -0,0 +1,286 @@ +/* Copyright (C) 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +/* This is one of several classes that are nearly identical. Maybe we + should have a central template and generate all these files. This + is one of the cases where templates or macros would have been + useful to have in Java. + + This file has been created using search-replace. My only fear is + that these classes will grow out-of-sync as of a result of changes + that are not propagated to the other files. As always, mirroring + code is a maintenance nightmare. */ + +/** + * A {@link DataBuffer} that uses an array of <code>float</code> primitives + * to represent each of its banks. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public final class DataBufferFloat + extends DataBuffer +{ + private float[] data; + private float[][] bankData; + + /** + * Creates a new data buffer with a single data bank containing the + * specified number of <code>float</code> elements. + * + * @param size the number of elements in the data bank. + */ + public DataBufferFloat(int size) + { + super(TYPE_FLOAT, size, 1, 0); + bankData = new float[1][]; + data = new float[size]; + bankData[0] = data; + } + + /** + * Creates a new data buffer with the specified number of data banks, + * each containing the specified number of <code>float</code> elements. + * + * @param size the number of elements in the data bank. + * @param numBanks the number of data banks. + */ + public DataBufferFloat(int size, int numBanks) + { + super(TYPE_FLOAT, size, numBanks); + bankData = new float[numBanks][size]; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data bank. + * <p> + * Note: there is no exception when <code>dataArray</code> is + * <code>null</code>, but in that case an exception will be thrown + * later if you attempt to access the data buffer. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + */ + public DataBufferFloat(float[] dataArray, int size) + { + super(TYPE_FLOAT, size, 1, 0); + bankData = new float[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data bank, with + * the specified offset to the first element. + * <p> + * Note: there is no exception when <code>dataArray</code> is + * <code>null</code>, but in that case an exception will be thrown + * later if you attempt to access the data buffer. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + * @param offset the offset to the first element in the array. + */ + public DataBufferFloat(float[] dataArray, int size, int offset) + { + super(TYPE_FLOAT, size, 1, offset); + bankData = new float[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data banks. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * + * @throws NullPointerException if <code>dataArray</code> is + * <code>null</code>. + */ + public DataBufferFloat(float[][] dataArray, int size) + { + super(TYPE_FLOAT, size, dataArray.length); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data banks, with + * the specified offsets to the first element in each bank. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * @param offsets the offsets to the first element in each data bank. + * + * @throws NullPointerException if <code>dataArray</code> is + * <code>null</code>. + */ + public DataBufferFloat(float[][] dataArray, int size, int[] offsets) + { + super(TYPE_FLOAT, size, dataArray.length, offsets); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Returns the first data bank. + * + * @return The first data bank. + */ + public float[] getData() + { + return data; + } + + /** + * Returns a data bank. + * + * @param bank the bank index. + * @return A data bank. + */ + public float[] getData(int bank) + { + return bankData[bank]; + } + + /** + * Returns the array underlying this <code>DataBuffer</code>. + * + * @return The data banks. + */ + public float[][] getBankData() + { + return bankData; + } + + /** + * Returns an element from the first data bank. The offset (specified in + * the constructor) is added to <code>i</code> before accessing the + * underlying data array. + * + * @param i the element index. + * @return The element. + */ + public int getElem(int i) + { + return (int) data[i+offset]; + } + + /** + * Returns an element from a particular data bank. The offset (specified in + * the constructor) is added to <code>i</code> before accessing the + * underlying data array. + * + * @param bank the bank index. + * @param i the element index. + * @return The element. + */ + public int getElem(int bank, int i) + { + return (int) bankData[bank][i+offsets[bank]]; + } + + /** + * Sets an element in the first data bank. The offset (specified in the + * constructor) is added to <code>i</code> before updating the underlying + * data array. + * + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int i, int val) + { + data[i+offset] = val; + } + + /** + * Sets an element in a particular data bank. The offset (specified in the + * constructor) is added to <code>i</code> before updating the underlying + * data array. + * + * @param bank the data bank index. + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int bank, int i, int val) + { + bankData[bank][i+offsets[bank]] = val; + } + + public float getElemFloat(int i) + { + return data[i+offset]; + } + + public float getElemFloat(int bank, int i) + { + return bankData[bank][i+offsets[bank]]; + } + + public void setElemFloat(int i, float val) + { + data[i+offset] = val; + } + + public void setElemFloat(int bank, int i, float val) + { + bankData[bank][i+offsets[bank]] = val; + } + + public double getElemDouble(int i) + { + return getElemFloat(i); + } + + public double getElemDouble(int bank, int i) + { + return getElemFloat(bank, i); + } + + public void setElemDouble(int i, double val) + { + setElemFloat(i, (float) val); + } + + public void setElemDouble(int bank, int i, double val) + { + setElemFloat(bank, i, (float) val); + } +} diff --git a/libjava/classpath/java/awt/image/DataBufferInt.java b/libjava/classpath/java/awt/image/DataBufferInt.java new file mode 100644 index 000000000..db9d5bc30 --- /dev/null +++ b/libjava/classpath/java/awt/image/DataBufferInt.java @@ -0,0 +1,244 @@ +/* Copyright (C) 2000, 2002, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +/* This is one of several classes that are nearly identical. Maybe we + should have a central template and generate all these files. This + is one of the cases where templates or macros would have been + useful to have in Java. + + This file has been created using search-replace. My only fear is + that these classes will grow out-of-sync as of a result of changes + that are not propagated to the other files. As always, mirroring + code is a maintenance nightmare. */ + +/** + * A {@link DataBuffer} that uses an array of <code>int</code> primitives + * to represent each of its banks. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public final class DataBufferInt extends DataBuffer +{ + private int[] data; + private int[][] bankData; + + /** + * Creates a new data buffer with a single data bank containing the + * specified number of <code>int</code> elements. + * + * @param size the number of elements in the data bank. + */ + public DataBufferInt(int size) + { + super(TYPE_INT, size, 1, 0); + bankData = new int[1][]; + data = new int[size]; + bankData[0] = data; + } + + /** + * Creates a new data buffer with the specified number of data banks, + * each containing the specified number of <code>int</code> elements. + * + * @param size the number of elements in the data bank. + * @param numBanks the number of data banks. + */ + public DataBufferInt(int size, int numBanks) + { + super(TYPE_INT, size, numBanks); + bankData = new int[numBanks][size]; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data bank. + * <p> + * Note: there is no exception when <code>dataArray</code> is + * <code>null</code>, but in that case an exception will be thrown + * later if you attempt to access the data buffer. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + */ + public DataBufferInt(int[] dataArray, int size) + { + super(TYPE_INT, size, 1, 0); + bankData = new int[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data bank, with + * the specified offset to the first element. + * <p> + * Note: there is no exception when <code>dataArray</code> is + * <code>null</code>, but in that case an exception will be thrown + * later if you attempt to access the data buffer. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + * @param offset the offset to the first element in the array. + */ + public DataBufferInt(int[] dataArray, int size, int offset) + { + super(TYPE_INT, size, 1, offset); + bankData = new int[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data banks. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * + * @throws NullPointerException if <code>dataArray</code> is + * <code>null</code>. + */ + public DataBufferInt(int[][] dataArray, int size) + { + super(TYPE_INT, size, dataArray.length); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data banks, with + * the specified offsets to the first element in each bank. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * @param offsets the offsets to the first element in each data bank. + * + * @throws NullPointerException if <code>dataArray</code> is + * <code>null</code>. + */ + public DataBufferInt(int[][] dataArray, int size, int[] offsets) + { + super(TYPE_INT, size, dataArray.length, offsets); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Returns the first data bank. + * + * @return The first data bank. + */ + public int[] getData() + { + return data; + } + + /** + * Returns a data bank. + * + * @param bank the bank index. + * @return A data bank. + */ + public int[] getData(int bank) + { + return bankData[bank]; + } + + /** + * Returns the array underlying this <code>DataBuffer</code>. + * + * @return The data banks. + */ + public int[][] getBankData() + { + return bankData; + } + + /** + * Returns an element from the first data bank. The <code>offset</code> is + * added to the specified index before accessing the underlying data array. + * + * @param i the element index. + * @return The element. + */ + public int getElem(int i) + { + return data[i+offset]; + } + + /** + * Returns an element from a particular data bank. The <code>offset</code> + * is added to the specified index before accessing the underlying data + * array. + * + * @param bank the bank index. + * @param i the element index. + * @return The element. + */ + public int getElem(int bank, int i) + { + // get unsigned int as int + return bankData[bank][i+offsets[bank]]; + } + + /** + * Sets an element in the first data bank. The offset (specified in the + * constructor) is added to <code>i</code> before updating the underlying + * data array. + * + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int i, int val) + { + data[i+offset] = val; + } + + /** + * Sets an element in a particular data bank. The offset (specified in the + * constructor) is added to <code>i</code> before updating the underlying + * data array. + * + * @param bank the data bank index. + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int bank, int i, int val) + { + bankData[bank][i+offsets[bank]] = val; + } +} diff --git a/libjava/classpath/java/awt/image/DataBufferShort.java b/libjava/classpath/java/awt/image/DataBufferShort.java new file mode 100644 index 000000000..2156d7571 --- /dev/null +++ b/libjava/classpath/java/awt/image/DataBufferShort.java @@ -0,0 +1,245 @@ +/* DataBufferShort.java -- + Copyright (C) 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +/* This is one of several classes that are nearly identical. Maybe we + should have a central template and generate all these files. This + is one of the cases where templates or macros would have been + useful to have in Java. + + This file has been created using search-replace. My only fear is + that these classes will grow out-of-sync as of a result of changes + that are not propagated to the other files. As always, mirroring + code is a maintenance nightmare. */ + +/** + * A {@link DataBuffer} that uses an array of <code>short</code> primitives + * to represent each of its banks. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public final class DataBufferShort extends DataBuffer +{ + private short[] data; + private short[][] bankData; + + /** + * Creates a new data buffer with a single data bank containing the + * specified number of <code>short</code> elements. + * + * @param size the number of elements in the data bank. + */ + public DataBufferShort(int size) + { + super(TYPE_SHORT, size, 1, 0); + bankData = new short[1][]; + data = new short[size]; + bankData[0] = data; + } + + /** + * Creates a new data buffer with the specified number of data banks, + * each containing the specified number of <code>short</code> elements. + * + * @param size the number of elements in the data bank. + * @param numBanks the number of data banks. + */ + public DataBufferShort(int size, int numBanks) + { + super(TYPE_SHORT, size, numBanks); + bankData = new short[numBanks][size]; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data bank. + * <p> + * Note: there is no exception when <code>dataArray</code> is + * <code>null</code>, but in that case an exception will be thrown + * later if you attempt to access the data buffer. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + */ + public DataBufferShort(short[] dataArray, int size) + { + super(TYPE_SHORT, size, 1, 0); + bankData = new short[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data bank, with + * the specified offset to the first element. + * <p> + * Note: there is no exception when <code>dataArray</code> is + * <code>null</code>, but in that case an exception will be thrown + * later if you attempt to access the data buffer. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + * @param offset the offset to the first element in the array. + */ + public DataBufferShort(short[] dataArray, int size, int offset) + { + super(TYPE_SHORT, size, 1, offset); + bankData = new short[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data banks. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * + * @throws NullPointerException if <code>dataArray</code> is + * <code>null</code>. + */ + public DataBufferShort(short[][] dataArray, int size) + { + super(TYPE_SHORT, size, dataArray.length); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data banks, with + * the specified offsets to the first element in each bank. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * @param offsets the offsets to the first element in each data bank. + * + * @throws NullPointerException if <code>dataArray</code> is + * <code>null</code>. + */ + public DataBufferShort(short[][] dataArray, int size, int[] offsets) + { + super(TYPE_SHORT, size, dataArray.length, offsets); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Returns the first data bank. + * + * @return The first data bank. + */ + public short[] getData() + { + return data; + } + + /** + * Returns a data bank. + * + * @param bank the bank index. + * @return A data bank. + */ + public short[] getData(int bank) + { + return bankData[bank]; + } + + /** + * Returns the array underlying this <code>DataBuffer</code>. + * + * @return The data banks. + */ + public short[][] getBankData() + { + return bankData; + } + + /** + * Returns an element from the first data bank. The offset (specified in + * the constructor) is added to <code>i</code> before accessing the + * underlying data array. + * + * @param i the element index. + * @return The element. + */ + public int getElem(int i) + { + return data[i+offset]; + } + + /** + * Returns an element from a particular data bank. The offset (specified in + * the constructor) is added to <code>i</code> before accessing the + * underlying data array. + * + * @param bank the bank index. + * @param i the element index. + * @return The element. + */ + public int getElem(int bank, int i) + { + return bankData[bank][i+offsets[bank]]; + } + + /** + * Sets an element in the first data bank. The offset (specified in the + * constructor) is added to <code>i</code> before updating the underlying + * data array. + * + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int i, int val) + { + data[i+offset] = (short) val; + } + + /** + * Sets an element in a particular data bank. The offset (specified in the + * constructor) is added to <code>i</code> before updating the underlying + * data array. + * + * @param bank the data bank index. + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int bank, int i, int val) + { + bankData[bank][i+offsets[bank]] = (short) val; + } +} diff --git a/libjava/classpath/java/awt/image/DataBufferUShort.java b/libjava/classpath/java/awt/image/DataBufferUShort.java new file mode 100644 index 000000000..d2cadcf0b --- /dev/null +++ b/libjava/classpath/java/awt/image/DataBufferUShort.java @@ -0,0 +1,246 @@ +/* DataBufferUShort.java -- + Copyright (C) 2000, 2002, 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +/* This is one of several classes that are nearly identical. Maybe we + should have a central template and generate all these files. This + is one of the cases where templates or macros would have been + useful to have in Java. + + This file has been created using search-replace. My only fear is + that these classes will grow out-of-sync as of a result of changes + that are not propagated to the other files. As always, mirroring + code is a maintenance nightmare. */ + +/** + * A {@link DataBuffer} that uses an array of <code>short</code> primitives + * to represent each of its banks. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public final class DataBufferUShort extends DataBuffer +{ + private short[] data; + private short[][] bankData; + + /** + * Creates a new data buffer with a single data bank containing the + * specified number of <code>short</code> elements. + * + * @param size the number of elements in the data bank. + */ + public DataBufferUShort(int size) + { + super(TYPE_USHORT, size, 1, 0); + bankData = new short[1][]; + data = new short[size]; + bankData[0] = data; + } + + /** + * Creates a new data buffer with the specified number of data banks, + * each containing the specified number of <code>short</code> elements. + * + * @param size the number of elements in the data bank. + * @param numBanks the number of data banks. + */ + public DataBufferUShort(int size, int numBanks) + { + super(TYPE_USHORT, size, numBanks); + bankData = new short[numBanks][size]; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data bank. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + * + * @throws NullPointerException if dataArray is null + */ + public DataBufferUShort(short[] dataArray, int size) + { + super(TYPE_USHORT, size, 1, 0); + if (dataArray == null) + throw new NullPointerException(); + bankData = new short[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data bank, with + * the specified offset to the first element. + * + * @param dataArray the data bank. + * @param size the number of elements in the data bank. + * @param offset the offset to the first element in the array. + * + * @throws NullPointerException if dataArray is null + */ + public DataBufferUShort(short[] dataArray, int size, int offset) + { + super(TYPE_USHORT, size, 1, offset); + if (dataArray == null) + throw new NullPointerException(); + bankData = new short[1][]; + data = dataArray; + bankData[0] = data; + } + + /** + * Creates a new data buffer backed by the specified data banks. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * + * @throws NullPointerException if <code>dataArray</code> is + * <code>null</code>. + */ + public DataBufferUShort(short[][] dataArray, int size) + { + super(TYPE_USHORT, size, dataArray.length); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Creates a new data buffer backed by the specified data banks, with + * the specified offsets to the first element in each bank. + * + * @param dataArray the data banks. + * @param size the number of elements in the data bank. + * @param offsets the offsets to the first element in each data bank. + * + * @throws NullPointerException if <code>dataArray</code> is + * <code>null</code>. + */ + public DataBufferUShort(short[][] dataArray, int size, int[] offsets) + { + super(TYPE_USHORT, size, dataArray.length, offsets); + bankData = dataArray; + data = bankData[0]; + } + + /** + * Returns the first data bank. + * + * @return The first data bank. + */ + public short[] getData() + { + return data; + } + + /** + * Returns a data bank. + * + * @param bank the bank index. + * @return A data bank. + */ + public short[] getData(int bank) + { + return bankData[bank]; + } + + /** + * Returns the array underlying this <code>DataBuffer</code>. + * + * @return The data banks. + */ + public short[][] getBankData() + { + return bankData; + } + + /** + * Returns an element from the first data bank. The offset (specified in + * the constructor) is added to <code>i</code> before accessing the + * underlying data array. + * + * @param i the element index. + * @return The element. + */ + public int getElem(int i) + { + return data[i+offset] & 0xffff; // get unsigned short as int + } + + /** + * Returns an element from a particular data bank. The offset (specified in + * the constructor) is added to <code>i</code> before accessing the + * underlying data array. + * + * @param bank the bank index. + * @param i the element index. + * @return The element. + */ + public int getElem(int bank, int i) + { + // get unsigned short as int + return bankData[bank][i+offsets[bank]] & 0xffff; + } + + /** + * Sets an element in the first data bank. The offset (specified in the + * constructor) is added to <code>i</code> before updating the underlying + * data array. + * + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int i, int val) + { + data[i+offset] = (short) val; + } + + /** + * Sets an element in a particular data bank. The offset (specified in the + * constructor) is added to <code>i</code> before updating the underlying + * data array. + * + * @param bank the data bank index. + * @param i the element index. + * @param val the new element value. + */ + public void setElem(int bank, int i, int val) + { + bankData[bank][i+offsets[bank]] = (short) val; + } +} diff --git a/libjava/classpath/java/awt/image/DirectColorModel.java b/libjava/classpath/java/awt/image/DirectColorModel.java new file mode 100644 index 000000000..a464fed30 --- /dev/null +++ b/libjava/classpath/java/awt/image/DirectColorModel.java @@ -0,0 +1,435 @@ +/* DirectColorModel.java -- + Copyright (C) 1999, 2000, 2002, 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import gnu.java.awt.Buffers; + +import java.awt.Point; +import java.awt.Transparency; +import java.awt.color.ColorSpace; + +/** + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + * @author C. Brian Jones (cbj@gnu.org) + * @author Mark Benvenuto (mcb54@columbia.edu) + */ +public class DirectColorModel extends PackedColorModel +{ + /** + * For the color model created with this constructor the pixels + * will have fully opaque alpha components with a value of 255. + * Each mask should describe a fully contiguous set of bits in the + * most likely order of alpha, red, green, blue from the most significant + * byte to the least significant byte. + * + * @param pixelBits the number of bits wide used for bit size of pixel values + * @param rmask the bits describing the red component of a pixel + * @param gmask the bits describing the green component of a pixel + * @param bmask the bits describing the blue component of a pixel + */ + public DirectColorModel(int pixelBits, int rmask, int gmask, int bmask) + { + this(ColorSpace.getInstance(ColorSpace.CS_sRGB), pixelBits, + rmask, gmask, bmask, 0, + false, // not alpha premultiplied + Buffers.smallestAppropriateTransferType(pixelBits) // find type + ); + } + + /** + * For the color model created with this constructor the pixels + * will have fully opaque alpha components with a value of 255. + * Each mask should describe a fully contiguous set of bits in the + * most likely order of red, green, blue from the most significant + * byte to the least significant byte. + * + * @param pixelBits the number of bits wide used for bit size of pixel values + * @param rmask the bits describing the red component of a pixel + * @param gmask the bits describing the green component of a pixel + * @param bmask the bits describing the blue component of a pixel + * @param amask the bits describing the alpha component of a pixel + */ + public DirectColorModel(int pixelBits, + int rmask, int gmask, int bmask, int amask) + { + this(ColorSpace.getInstance(ColorSpace.CS_sRGB), pixelBits, + rmask, gmask, bmask, amask, + false, // not alpha premultiplied + Buffers.smallestAppropriateTransferType(pixelBits) // find type + ); + } + + public DirectColorModel(ColorSpace cspace, int pixelBits, + int rmask, int gmask, int bmask, int amask, + boolean isAlphaPremultiplied, + int transferType) + { + super(cspace, pixelBits, + rmask, gmask, bmask, amask, isAlphaPremultiplied, + ((amask == 0) ? Transparency.OPAQUE : Transparency.TRANSLUCENT), + transferType); + } + + public final int getRedMask() + { + return getMask(0); + } + + public final int getGreenMask() + { + return getMask(1); + } + + public final int getBlueMask() + { + return getMask(2); + } + + public final int getAlphaMask() + { + return hasAlpha() ? getMask(3) : 0; + } + + /** + * Get the red component of the given pixel. + * <br> + */ + public final int getRed(int pixel) + { + return extractAndNormalizeSample(pixel, 0); + } + + /** + * Get the green component of the given pixel. + * <br> + */ + public final int getGreen(int pixel) + { + return extractAndNormalizeSample(pixel, 1); + } + + /** + * Get the blue component of the given pixel. + * <br> + */ + public final int getBlue(int pixel) + { + return extractAndNormalizeSample(pixel, 2); + } + + /** + * Get the alpha component of the given pixel. + * <br> + */ + public final int getAlpha(int pixel) + { + if (!hasAlpha()) + return 255; + return extractAndScaleSample(pixel, 3); + } + + private int extractAndNormalizeSample(int pixel, int component) + { + int value = extractAndScaleSample(pixel, component); + if (hasAlpha() && isAlphaPremultiplied() && getAlpha(pixel) != 0) + value = value*255/getAlpha(pixel); + return value; + } + + private int extractAndScaleSample(int pixel, int component) + { + int field = pixel & getMask(component); + int to8BitShift = + 8 - shifts[component] - getComponentSize(component); + return (to8BitShift>0) ? + (field << to8BitShift) : + (field >>> (-to8BitShift)); + } + + /** + * Get the RGB color value of the given pixel using the default + * RGB color model. + * <br> + * + * @param pixel a pixel value + */ + public final int getRGB(int pixel) + { + /* FIXME: The Sun docs show that this method is overridden, but I + don't see any way to improve on the superclass + implementation. */ + return super.getRGB(pixel); + } + + public int getRed(Object inData) + { + return getRed(getPixelFromArray(inData)); + } + + public int getGreen(Object inData) + { + return getGreen(getPixelFromArray(inData)); + } + + public int getBlue(Object inData) + { + return getBlue(getPixelFromArray(inData)); + } + + public int getAlpha(Object inData) + { + return getAlpha(getPixelFromArray(inData)); + } + + public int getRGB(Object inData) + { + return getRGB(getPixelFromArray(inData)); + } + + /** + * Converts a normalized pixel int value in the sRGB color + * space to an array containing a single pixel of the color space + * of the color model. + * + * <p>This method performs the inverse function of + * <code>getRGB(Object inData)</code>. + * + * @param rgb pixel as a normalized sRGB, 0xAARRGGBB value. + * + * @param pixel to avoid needless creation of arrays, an array to + * use to return the pixel can be given. If null, a suitable array + * will be created. + * + * @return array of transferType containing a single pixel. The + * pixel should be encoded in the natural way of the color model. + * + * @see #getRGB(Object) + */ + public Object getDataElements(int rgb, Object pixel) + { + // FIXME: handle alpha multiply + + int pixelValue = 0; + int a = 0; + if (hasAlpha()) { + a = (rgb >>> 24) & 0xff; + pixelValue = valueToField(a, 3, 8); + } + + if (hasAlpha() && isAlphaPremultiplied()) + { + int r, g, b; + /* if r=0xff and a=0xff, then resulting + value will be (r*a)>>>8 == 0xfe... This seems wrong. + We should divide by 255 rather than shifting >>>8 after + multiplying. + + Too bad, shifting is probably less expensive. + r = ((rgb >>> 16) & 0xff)*a; + g = ((rgb >>> 8) & 0xff)*a; + b = ((rgb >>> 0) & 0xff)*a; */ + /* The r, g, b values we calculate are 16 bit. This allows + us to avoid discarding the lower 8 bits obtained if + multiplying with the alpha band. */ + + // using 16 bit values + r = ((rgb >>> 8) & 0xff00)*a/255; + g = ((rgb >>> 0) & 0xff00)*a/255; + b = ((rgb << 8) & 0xff00)*a/255; + pixelValue |= + valueToField(r, 0, 16) | // Red + valueToField(g, 1, 16) | // Green + valueToField(b, 2, 16); // Blue + } + else + { + int r, g, b; + // using 8 bit values + r = (rgb >>> 16) & 0xff; + g = (rgb >>> 8) & 0xff; + b = (rgb >>> 0) & 0xff; + + pixelValue |= + valueToField(r, 0, 8) | // Red + valueToField(g, 1, 8) | // Green + valueToField(b, 2, 8); // Blue + } + + /* In this color model, the whole pixel fits in the first element + of the array. */ + DataBuffer buffer = Buffers.createBuffer(transferType, pixel, 1); + buffer.setElem(0, pixelValue); + return Buffers.getData(buffer); + } + + /** + * Converts a value to the correct field bits based on the + * information derived from the field masks. + * + * @param highBit the position of the most significant bit in the + * val parameter. + */ + private int valueToField(int val, int component, int highBit) + { + int toFieldShift = + getComponentSize(component) + shifts[component] - highBit; + int ret = (toFieldShift>0) ? + (val << toFieldShift) : + (val >>> (-toFieldShift)); + return ret & getMask(component); + } + + /** + * Converts a 16 bit value to the correct field bits based on the + * information derived from the field masks. + */ + private int value16ToField(int val, int component) + { + int toFieldShift = getComponentSize(component) + shifts[component] - 16; + return (toFieldShift>0) ? + (val << toFieldShift) : + (val >>> (-toFieldShift)); + } + + /** + * Fills an array with the unnormalized component samples from a + * pixel value. I.e. decompose the pixel, but not perform any + * color conversion. + */ + public final int[] getComponents(int pixel, int[] components, int offset) + { + int numComponents = getNumComponents(); + if (components == null) components = new int[offset + numComponents]; + + for (int b=0; b<numComponents; b++) + components[offset++] = (pixel&getMask(b)) >>> shifts[b]; + + return components; + } + + public final int[] getComponents(Object pixel, int[] components, + int offset) + { + return getComponents(getPixelFromArray(pixel), components, offset); + } + + /** + * Creates a <code>WriteableRaster</code> that has a <code>SampleModel</code> + * that is compatible with this <code>ColorModel</code>. + * + * @param w the width of the writeable raster to create + * @param h the height of the writeable raster to create + * + * @throws IllegalArgumentException if <code>w</code> or <code>h</code> + * is less than or equal to zero + */ + public final WritableRaster createCompatibleWritableRaster(int w, int h) + { + // Sun also makes this check here. + if(w <= 0 || h <= 0) + throw new IllegalArgumentException("width (=" + w + ") and height (=" + + h + ") must be > 0"); + + SampleModel sm = createCompatibleSampleModel(w, h); + Point origin = new Point(0, 0); + return Raster.createWritableRaster(sm, origin); + } + + public int getDataElement(int[] components, int offset) + { + int numComponents = getNumComponents(); + int pixelValue = 0; + + for (int c=0; c<numComponents; c++) + pixelValue |= (components[offset++] << shifts[c]) & getMask(c); + + return pixelValue; + } + + public Object getDataElements(int[] components, int offset, Object obj) + { + /* In this color model, the whole pixel fits in the first element + of the array. */ + int pixelValue = getDataElement(components, offset); + + DataBuffer buffer = Buffers.createBuffer(transferType, obj, 1); + buffer.setElem(0, pixelValue); + return Buffers.getData(buffer); + } + + public final ColorModel coerceData (WritableRaster raster, + boolean isAlphaPremultiplied) + { + if (this.isAlphaPremultiplied == isAlphaPremultiplied || !hasAlpha()) + return this; + + /* TODO: provide better implementation based on the + assumptions we can make due to the specific type of the + color model. */ + coerceDataWorker(raster, isAlphaPremultiplied); + + return new DirectColorModel(cspace, pixel_bits, getRedMask(), + getGreenMask(), getBlueMask(), getAlphaMask(), + isAlphaPremultiplied, transferType); + } + + public boolean isCompatibleRaster(Raster raster) + { + /* FIXME: the Sun docs say this method is overridden here, + but I don't see any way to improve upon the implementation + in ColorModel. */ + return super.isCompatibleRaster(raster); + } + + String stringParam() + { + return super.stringParam() + + ", redMask=" + Integer.toHexString(getRedMask()) + + ", greenMask=" + Integer.toHexString(getGreenMask()) + + ", blueMask=" + Integer.toHexString(getBlueMask()) + + ", alphaMask=" + Integer.toHexString(getAlphaMask()); + } + + public String toString() + { + /* FIXME: Again, docs say override, but how do we improve upon the + superclass implementation? */ + return super.toString(); + } +} diff --git a/libjava/classpath/java/awt/image/FilteredImageSource.java b/libjava/classpath/java/awt/image/FilteredImageSource.java new file mode 100644 index 000000000..f56a93ad1 --- /dev/null +++ b/libjava/classpath/java/awt/image/FilteredImageSource.java @@ -0,0 +1,124 @@ +/* FilteredImageSource.java -- Java class for providing image data + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import java.util.Hashtable; + +/** + * + * @see ImageConsumer + * @author C. Brian Jones (cbj@gnu.org) + */ +public class FilteredImageSource implements ImageProducer +{ + ImageProducer ip; + ImageFilter filter; + Hashtable consumers = new Hashtable(); + + /** + * The given filter is applied to the given image producer + * to create a new image producer. + */ + public FilteredImageSource(ImageProducer ip, ImageFilter filter) { + this.ip = ip; + this.filter = filter; + } + + /** + * Used to register an <code>ImageConsumer</code> with this + * <code>ImageProducer</code>. + */ + public synchronized void addConsumer(ImageConsumer ic) { + if (consumers.containsKey(ic)) + return; + + ImageFilter f = filter.getFilterInstance(ic); + consumers.put(ic, f); + ip.addConsumer(f); + } + + /** + * Used to determine if the given <code>ImageConsumer</code> is + * already registered with this <code>ImageProducer</code>. + */ + public synchronized boolean isConsumer(ImageConsumer ic) { + ImageFilter f = (ImageFilter)consumers.get(ic); + if (f != null) + return ip.isConsumer(f); + return false; + } + + /** + * Used to remove an <code>ImageConsumer</code> from the list of + * registered consumers for this <code>ImageProducer</code>. + */ + public synchronized void removeConsumer(ImageConsumer ic) { + ImageFilter f = (ImageFilter)consumers.remove(ic); + if (f != null) + ip.removeConsumer(f); + } + + /** + * Used to register an <code>ImageConsumer</code> with this + * <code>ImageProducer</code> and then immediately start + * reconstruction of the image data to be delivered to all + * registered consumers. + */ + public void startProduction(ImageConsumer ic) { + ImageFilter f; + if (!(consumers.containsKey(ic))) { + f = filter.getFilterInstance(ic); + consumers.put(ic, f); + ip.addConsumer(f); + } else { + f = (ImageFilter)consumers.get( ic ); + } + ip.startProduction(f); + } + + /** + * Used to register an <code>ImageConsumer</code> with this + * <code>ImageProducer</code> and then request that this producer + * resend the image data in the order top-down, left-right. + */ + public void requestTopDownLeftRightResend(ImageConsumer ic) { + ImageFilter f = (ImageFilter)consumers.get(ic); + ip.requestTopDownLeftRightResend(f); + } +} diff --git a/libjava/classpath/java/awt/image/ImageConsumer.java b/libjava/classpath/java/awt/image/ImageConsumer.java new file mode 100644 index 000000000..8f3c2b144 --- /dev/null +++ b/libjava/classpath/java/awt/image/ImageConsumer.java @@ -0,0 +1,216 @@ +/* ImageConsumer.java -- Java interface for image consumption + Copyright (C) 1999, 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import java.util.Hashtable; + +/** + * An object implementing the <code>ImageProducer</code> interface can + * use objects implementing this interface to deliver the image data. + * + * @author C. Brian Jones (cbj@gnu.org) + */ +public interface ImageConsumer +{ + /** + * The pixel order may be random. This should be + * the default assumption of the <code>ImageConsumer</code>. + * + * @see #setHints + */ + int RANDOMPIXELORDER = 1; + + /** + * The pixel order is top-down, left-right. + * + * @see #setHints + */ + int TOPDOWNLEFTRIGHT = 2; + + /** + * The pixel order is in multiples of complete scanlines. + * + * @see #setHints + */ + int COMPLETESCANLINES = 4; + + /** + * The pixels will be delivered in a single pass. There is at + * most one call to <code>setPixels</code> for any single pixel. + * + * @see #setHints + * @see #setPixels(int, int, int, int, ColorModel, int[], int, int) + */ + int SINGLEPASS = 8; + + /** + * The pixels will be delivered with multiple calls to + * <code>setPixels</code>. The image contains a single frame + * which ends when <code>imageComplete</code> is called with the + * <code>STATICIMAGEDONE</code> flag. If the image is constantly + * changing such as with video then the end of each frame is + * marked by a similar call to <code>imageComplete</code> with the + * <code>SINGLEFRAMEDONE</code> flag. + * + * @see #setHints + * @see #imageComplete + */ + int SINGLEFRAME = 16; + + /** + * Indicates an error occurred while producing an image. + * + * @see #imageComplete + */ + int IMAGEERROR = 1; + + /** + * A single frame is complete but more will follow. + * + * @see #imageComplete + */ + int SINGLEFRAMEDONE = 2; + + /** + * The image is complete and no more pixels or frames will follow. + * + * @see #imageComplete + */ + int STATICIMAGEDONE = 3; + + /** + * Production of the image has been aborted. + * + * @see #imageComplete + */ + int IMAGEABORTED = 4; + + /** + * An <code>ImageProducer</code> indicates the size of the image + * being produced using this method. + * + * @param width the width of the image + * @param height the height of the image + */ + void setDimensions(int width, int height); + + /** + * An <code>ImageProducer</code> can set a list of properties + * associated with this image by using this method. + * + * @param props the list of properties associated with this image + */ + void setProperties(Hashtable<?,?> props); + + /** + * This <code>ColorModel</code> should indicate the model used by + * the majority of calls to <code>setPixels</code>. Each call to + * <code>setPixels</code> could however indicate a different + * <code>ColorModel</code>. + * + * @param model the color model to be used most often by setPixels + * @see ColorModel + */ + void setColorModel(ColorModel model); + + /** + * The <code>ImageProducer</code> should call this method with a + * bit mask of hints from any of <code>RANDOMPIXELORDER</code>, + * <code>TOPDOWNLEFTRIGHT</code>, <code>COMPLETESCANLINES</code>, + * <code>SINGLEPASS</code>, <code>SINGLEFRAME</code>. + * + * @param flags a bit mask of hints + */ + void setHints(int flags); + + /** + * Deliver a subset of an ImageProducer's pixels to this ImageConsumer. + * + * Each element of the pixels array represents one pixel. The + * pixel data is formatted according to the color model model. + * The x and y parameters are the coordinates of the block of + * pixels being delivered to this ImageConsumer. They are + * specified relative to the top left corner of the image being + * produced. Likewise, w and h are the pixel block's dimensions. + * + * @param x x coordinate of pixel block + * @param y y coordinate of pixel block + * @param w width of pixel block + * @param h height of pixel block + * @param model color model used to interpret pixel data + * @param pixels pixel block data + * @param offset offset into pixels array + * @param scansize width of one row in the pixel block + */ + void setPixels(int x, int y, int w, int h, + ColorModel model, byte[] pixels, int offset, int scansize); + + /** + * Deliver a subset of an ImageProducer's pixels to this ImageConsumer. + * + * Each element of the pixels array represents one pixel. The + * pixel data is formatted according to the color model model. + * The x and y parameters are the coordinates of the rectangular + * region of pixels being delivered to this ImageConsumer, + * specified relative to the top left corner of the image being + * produced. Likewise, w and h are the pixel region's dimensions. + * + * @param x x coordinate of pixel block + * @param y y coordinate of pixel block + * @param w width of pixel block + * @param h height of pixel block + * @param model color model used to interpret pixel data + * @param pixels pixel block data + * @param offset offset into pixels array + * @param scansize width of one row in the pixel block + */ + void setPixels(int x, int y, int w, int h, + ColorModel model, int[] pixels, int offset, int scansize); + + /** + * The <code>ImageProducer</code> calls this method to indicate a + * single frame or the entire image is complete. The method is + * also used to indicate an error in loading or producing the + * image. + * + * @param status the status of image production, represented by a + * bitwise OR of ImageConsumer flags + */ + void imageComplete(int status); +} diff --git a/libjava/classpath/java/awt/image/ImageFilter.java b/libjava/classpath/java/awt/image/ImageFilter.java new file mode 100644 index 000000000..10df82e25 --- /dev/null +++ b/libjava/classpath/java/awt/image/ImageFilter.java @@ -0,0 +1,226 @@ +/* ImageFilter.java -- Java class for filtering images + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import java.util.Hashtable; + +/** + * The <code>ImageFilter</code> class is a base class which can be + * extended to provide different types of filters for an image. By + * default this class does nothing to an image passing through it. + * + * @author C. Brian Jones (cbj@gnu.org) + */ +public class ImageFilter implements ImageConsumer, Cloneable +{ + /** + * The consumer this filter is filtering an image data stream for. + * It is initialized in the method <code>getFilterInstance</code>. + */ + protected ImageConsumer consumer = null; + + /** + * The <code>ImageConsumer</code> can use this method to request + * the pixels be delivered in top-down, left-right order. + * <br> + * The filter can respond in three different ways. + * <ul> + * <li>The default behavior is to forward the request to the + * <code>ImageProducer</code> + * using the method <code>requestTopDownLeftRightResend</code> + * and using the filter as the consumer.</li> + * <li>The filter has the pixels and can retransmit them in the + * top-down, left-right order.</li> + * <li>The filter can do nothing when this method is called.</li> + * </ul> + */ + public void resendTopDownLeftRight(ImageProducer ip) + { + ip.requestTopDownLeftRightResend(this); + } + + /** + * By default, returns a shallow copy of the object created by + * <code>Object.clone()</code> + * + * @see java.lang.Object#clone () + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + // This should never happen as this class implements the + // Cloneable interface. + throw new InternalError (); + } + } + + /** + * This is the only method which can set the + * <code>ImageConsumer</code> for this filter. By default a clone + * of this filter with the appropriate consumer set is returned. + * + * @see #clone () + */ + public ImageFilter getFilterInstance(ImageConsumer ic) + { + ImageFilter f = (ImageFilter)clone(); + f.consumer = ic; + return f; + } + + /** + * An <code>ImageProducer</code> indicates the size of the image + * being produced using this method. A filter can override this + * method to intercept these calls from the producer in order to + * change either the width or the height before in turn calling + * the consumer's <code>setDimensions</code> method. + * + * @param width the width of the image + * @param height the height of the image + */ + public void setDimensions(int width, int height) + { + consumer.setDimensions(width, height); + } + + /** + * An <code>ImageProducer</code> can set a list of properties + * associated with this image by using this method. + * + * @param props the list of properties associated with this image + */ + public void setProperties(Hashtable<?,?> props) + { + Hashtable copy = (Hashtable) props.clone(); + Object o = copy.get("filters"); + if (o == null) + copy.put("filters", toString()); + else if (o instanceof String) + copy.put("filters", ((String) o) + toString()); + + consumer.setProperties(copy); + } + + /** + * Override this method to process calls to this method from the + * <code>ImageProducer</code>. By default the <code>setColorModel</code> + * method of the consumer is called with the specified <code>model</code>. + * + * @param model the color model to be used most often by setPixels + * + * @see ColorModel + */ + public void setColorModel(ColorModel model) + { + consumer.setColorModel(model); + } + + /** + * The <code>ImageProducer</code> should call this method with a + * bit mask of hints from any of <code>RANDOMPIXELORDER</code>, + * <code>TOPDOWNLEFTRIGHT</code>, <code>COMPLETESCANLINES</code>, + * <code>SINGLEPASS</code>, <code>SINGLEFRAME</code> from the + * <code>ImageConsumer</code> interface. + * + * @param flags a bit mask of hints + * @see ImageConsumer + */ + public void setHints(int flags) + { + consumer.setHints(flags); + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as a <code>byte</code> at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the <code>ColorModel</code> used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the <code>pixels</code> array + * @param scansize the width to use in extracting pixels from the <code>pixels</code> array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, byte[] pixels, int offset, + int scansize) + { + consumer.setPixels(x, y, w, h, model, pixels, offset, scansize); + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as an <code>int</code> at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the <code>ColorModel</code> used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the <code>pixels</code> array + * @param scansize the width to use in extracting pixels from the <code>pixels</code> array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, int[] pixels, int offset, + int scansize) + { + consumer.setPixels(x, y, w, h, model, pixels, offset, scansize); + } + + /** + * The <code>ImageProducer</code> calls this method to indicate a + * single frame or the entire image is complete. The method is + * also used to indicate an error in loading or producing the + * image. + */ + public void imageComplete(int status) + { + consumer.imageComplete(status); + } +} diff --git a/libjava/classpath/java/awt/image/ImageObserver.java b/libjava/classpath/java/awt/image/ImageObserver.java new file mode 100644 index 000000000..e63d4bba1 --- /dev/null +++ b/libjava/classpath/java/awt/image/ImageObserver.java @@ -0,0 +1,129 @@ +/* ImageObserver.java -- Java interface for asynchronous updates to an image + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import java.awt.Image; + +/** + * An object implementing the <code>ImageObserver</code> interface can + * receive updates on image construction from an + * <code>ImageProducer</code> asynchronously. + * + * @see ImageProducer + * @author C. Brian Jones (cbj@gnu.org) + */ +public interface ImageObserver +{ + /** + * The width of the image has been provided as the + * <code>width</code> argument to <code>imageUpdate</code>. + * + * @see #imageUpdate + */ + int WIDTH = 1; + + /** + * The height of the image has been provided as the + * <code>height</code> argument to <code>imageUpdate</code>. + * + * @see #imageUpdate + */ + int HEIGHT = 2; + + /** + * The properties of the image have been provided. + * + * @see #imageUpdate + * @see java.awt.Image#getProperty (java.lang.String, java.awt.image.ImageObserver) + */ + int PROPERTIES = 4; + + /** + * More pixels are now available for drawing a scaled variation of + * the image. + * + * @see #imageUpdate + */ + int SOMEBITS = 8; + + /** + * All the pixels needed to draw a complete frame of a multi-frame + * image are available. + * + * @see #imageUpdate + */ + int FRAMEBITS = 16; + + /** + * An image with a single frame, a static image, is complete. + * + * @see #imageUpdate + */ + int ALLBITS = 32; + + /** + * An error was encountered while producing the image. + * + * @see #imageUpdate + */ + int ERROR = 64; + + /** + * Production of the image was aborted. + * + * @see #imageUpdate + */ + int ABORT = 128; + + /** + * This is a callback method for an asynchronous image producer to + * provide updates on the production of the image as it happens. + * + * @param image the image the update refers to + * @param flags a bit mask indicating what is provided with this update + * @param x the x coordinate of the image + * @param y the y coordinate of the image + * @param width the width of the image + * @param height the height of the image + * + * @see java.awt.Image + */ + boolean imageUpdate(Image image, int flags, int x, + int y, int width, int height); +} diff --git a/libjava/classpath/java/awt/image/ImageProducer.java b/libjava/classpath/java/awt/image/ImageProducer.java new file mode 100644 index 000000000..c0f9ad4c7 --- /dev/null +++ b/libjava/classpath/java/awt/image/ImageProducer.java @@ -0,0 +1,84 @@ +/* ImageProducer.java -- Java interface for image production + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +/** + * An object implementing the <code>ImageProducer</code> interface can + * produce data for images. Each image has a corresponding + * <code>ImageProducer</code> which is needed for things such as + * resizing the image. + * + * @see ImageConsumer + * @author C. Brian Jones (cbj@gnu.org) + */ +public interface ImageProducer +{ + /** + * Used to register an <code>ImageConsumer</code> with this + * <code>ImageProducer</code>. + */ + void addConsumer(ImageConsumer ic); + + /** + * Used to determine if the given <code>ImageConsumer</code> is + * already registered with this <code>ImageProducer</code>. + */ + boolean isConsumer(ImageConsumer ic); + + /** + * Used to remove an <code>ImageConsumer</code> from the list of + * registered consumers for this <code>ImageProducer</code>. + */ + void removeConsumer(ImageConsumer ic); + + /** + * Used to register an <code>ImageConsumer</code> with this + * <code>ImageProducer</code> and then immediately start + * reconstruction of the image data to be delivered to all + * registered consumers. + */ + void startProduction(ImageConsumer ic); + + /** + * Used to register an <code>ImageConsumer</code> with this + * <code>ImageProducer</code> and then request that this producer + * resend the image data in the order top-down, left-right. + */ + void requestTopDownLeftRightResend(ImageConsumer ic); +} diff --git a/libjava/classpath/java/awt/image/ImagingOpException.java b/libjava/classpath/java/awt/image/ImagingOpException.java new file mode 100644 index 000000000..ca40e9ed3 --- /dev/null +++ b/libjava/classpath/java/awt/image/ImagingOpException.java @@ -0,0 +1,66 @@ +/* ImagingOpException.java -- indicates an imaging filter failure + Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +/** + * This exception is thrown when <code>BufferedImageOp</code> or + * <code>RasterOp</code> filters cannot process an image. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see BufferedImageOp + * @see RasterOp + * @status updated to 1.4 + */ +public class ImagingOpException extends RuntimeException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 8026288481846276658L; + + /** + * Create a new instance with a descriptive error message. + * + * @param message the descriptive error message + */ + public ImagingOpException(String message) + { + super(message); + } +} // class ImagingOpException diff --git a/libjava/classpath/java/awt/image/IndexColorModel.java b/libjava/classpath/java/awt/image/IndexColorModel.java new file mode 100644 index 000000000..340d38e89 --- /dev/null +++ b/libjava/classpath/java/awt/image/IndexColorModel.java @@ -0,0 +1,736 @@ +/* IndexColorModel.java -- Java class for interpreting Pixel objects + Copyright (C) 1999, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +import gnu.java.awt.Buffers; + +import java.awt.color.ColorSpace; +import java.math.BigInteger; + +/** + * Color model similar to pseudo visual in X11. + * <br><br> + * This color model maps linear pixel values to actual RGB and alpha colors. + * Thus, pixel values are indexes into the color map. Each color component is + * an 8-bit unsigned value. + * <br><br> + * The <code>IndexColorModel</code> supports a map of valid pixels, allowing + * the representation of holes in the the color map. The valid map is + * represented as a {@link BigInteger} where each bit indicates the validity + * of the map entry with the same index. + * <br><br> + * Colors can have alpha components for transparency support. If alpha + * component values aren't given, color values are opaque. The model also + * supports a reserved pixel value to represent completely transparent colors, + * no matter what the actual color component values are. + * <br><br> + * <code>IndexColorModel</code> supports anywhere from 1 to 16 bit index + * values. The allowed transfer types are {@link DataBuffer#TYPE_BYTE} and + * {@link DataBuffer#TYPE_USHORT}. + * + * @author C. Brian Jones (cbj@gnu.org) + */ +public class IndexColorModel extends ColorModel +{ + private int map_size; + private boolean opaque; // no alpha, but doesn't account for trans + private int trans = -1; + private int[] rgb; + private BigInteger validBits = BigInteger.ZERO; + + /** + * Creates a new indexed color model for <code>size</code> color elements + * with no alpha component. Each array must contain at least + * <code>size</code> elements. For each array, the i-th color is described + * by reds[i], greens[i] and blues[i]. + * + * @param bits the number of bits needed to represent <code>size</code> + * colors. + * @param size the number of colors in the color map. + * @param reds the red component of all colors. + * @param greens the green component of all colors. + * @param blues the blue component of all colors. + * + * @throws IllegalArgumentException if <code>bits</code> < 1 or + * <code>bits</code> > 16. + * @throws NullPointerException if any of the arrays is <code>null</code>. + * @throws ArrayIndexOutOfBoundsException if <code>size</code> is greater + * than the length of the component arrays. + */ + public IndexColorModel(int bits, int size, byte[] reds, byte[] greens, + byte[] blues) + { + this(bits, size, reds, greens, blues, (byte[]) null); + } + + /** + * Creates a new indexed color model for <code>size</code> color elements. + * Each array must contain at least <code>size</code> elements. For each + * array, the i-th color is described by reds[i], greens[i] and blues[i]. + * All the colors are opaque except for the transparent color. + * + * @param bits the number of bits needed to represent <code>size</code> + * colors + * @param size the number of colors in the color map + * @param reds the red component of all colors + * @param greens the green component of all colors + * @param blues the blue component of all colors + * @param trans the index of the transparent color (use -1 for no + * transparent color). + * + * @throws IllegalArgumentException if <code>bits</code> < 1 or + * <code>bits</code> > 16. + * @throws NullPointerException if any of the arrays is <code>null</code>. + * @throws ArrayIndexOutOfBoundsException if <code>size</code> is greater + * than the length of the component arrays. + */ + public IndexColorModel(int bits, int size, byte[] reds, byte[] greens, + byte[] blues, int trans) + { + super(bits, nArray(8, (0 <= trans && trans < size) ? 4 : 3), + ColorSpace.getInstance(ColorSpace.CS_sRGB), + (0 <= trans && trans < size), // hasAlpha + false, OPAQUE, + Buffers.smallestAppropriateTransferType(bits)); + if (bits < 1) + throw new IllegalArgumentException("bits < 1"); + if (bits > 16) + throw new IllegalArgumentException("bits > 16"); + if (size < 1) + throw new IllegalArgumentException("size < 1"); + map_size = size; + rgb = createColorMap(bits, size); + for (int i = 0; i < size; i++) + { + rgb[i] = (0xff000000 + | ((reds[i] & 0xff) << 16) + | ((greens[i] & 0xff) << 8) + | (blues[i] & 0xff)); + } + + setTransparentPixel(trans); + + // Generate a bigint with 1's for every pixel + validBits = validBits.setBit(size).subtract(BigInteger.ONE); + } + + /** + * Creates a new indexed color model for <code>size</code> color elements + * including alpha. Each array must contain at least <code>size</code> + * elements. For each array, the i-th color is described + * by reds[i], greens[i], blues[i] and alphas[i]. + * + * @param bits the number of bits needed to represent <code>size</code> + * colors. + * @param size the number of colors in the color map. + * @param reds the red component of all colors. + * @param greens the green component of all colors. + * @param blues the blue component of all colors. + * @param alphas the alpha component of all colors (<code>null</code> + * permitted). + * + * @throws IllegalArgumentException if <code>bits</code> < 1 or + * <code>bits</code> > 16. + * @throws NullPointerException if <code>reds</code>, <code>greens</code> or + * <code>blues</code> is <code>null</code>. + * @throws ArrayIndexOutOfBoundsException if <code>size</code> is greater + * than the length of the component arrays. + */ + public IndexColorModel(int bits, int size, byte[] reds, byte[] greens, + byte[] blues, byte[] alphas) + { + super(bits, nArray(8, (alphas == null ? 3 : 4)), + ColorSpace.getInstance(ColorSpace.CS_sRGB), + (alphas != null), false, TRANSLUCENT, + Buffers.smallestAppropriateTransferType(bits)); + if (bits < 1) + throw new IllegalArgumentException("bits < 1"); + if (bits > 16) + throw new IllegalArgumentException("bits > 16"); + if (size < 1) + throw new IllegalArgumentException("size < 1"); + map_size = size; + opaque = (alphas == null); + + rgb = createColorMap(bits, size); + if (alphas == null) + { + for (int i = 0; i < size; i++) + { + rgb[i] = (0xff000000 + | ((reds[i] & 0xff) << 16) + | ((greens[i] & 0xff) << 8) + | (blues[i] & 0xff)); + } + transparency = OPAQUE; + } + else + { + byte alphaZero = (byte) 0x00; + byte alphaOne = (byte) 0xFF; + for (int i = 0; i < size; i++) + { + alphaZero = (byte) (alphaZero | alphas[i]); + alphaOne = (byte) (alphaOne & alphas[i]); + rgb[i] = ((alphas[i] & 0xff) << 24 + | ((reds[i] & 0xff) << 16) + | ((greens[i] & 0xff) << 8) + | (blues[i] & 0xff)); + } + if ((alphaZero == (byte) 0x00) || (alphaOne == (byte) 0xFF)) + transparency = BITMASK; + else + transparency = TRANSLUCENT; + } + + // Generate a bigint with 1's for every pixel + validBits = validBits.setBit(size).subtract(BigInteger.ONE); + } + + /** + * Creates a new indexed color model using the color components in + * <code>cmap</code>. If <code>hasAlpha</code> is <code>true</code> then + * <code>cmap</code> contains an alpha component after each of the red, green + * and blue components. + * + * @param bits the number of bits needed to represent <code>size</code> + * colors + * @param size the number of colors in the color map + * @param cmap packed color components + * @param start the offset of the first color component in <code>cmap</code> + * @param hasAlpha <code>cmap</code> has alpha values + * @throws IllegalArgumentException if bits < 1, bits > 16, or size + * < 1. + * @throws NullPointerException if <code>cmap</code> is <code>null</code>. + */ + public IndexColorModel(int bits, int size, byte[] cmap, int start, + boolean hasAlpha) + { + this(bits, size, cmap, start, hasAlpha, -1); + } + + /** + * Construct an IndexColorModel from an array of red, green, blue, and + * optional alpha components. The component values are interleaved as RGB(A). + * + * @param bits the number of bits needed to represent <code>size</code> + * colors + * @param size the number of colors in the color map + * @param cmap interleaved color components + * @param start the offset of the first color component in <code>cmap</code> + * @param hasAlpha <code>cmap</code> has alpha values + * @param trans the index of the transparent color + * @throws IllegalArgumentException if bits < 1, bits > 16, or size + * < 1. + * @throws NullPointerException if <code>cmap</code> is <code>null</code>. + */ + public IndexColorModel(int bits, int size, byte[] cmap, int start, + boolean hasAlpha, int trans) + { + super(bits, nArray(8, hasAlpha || (0 <= trans && trans < size) ? 4 : 3), + ColorSpace.getInstance(ColorSpace.CS_sRGB), + hasAlpha || (0 <= trans && trans < size), false, OPAQUE, + Buffers.smallestAppropriateTransferType(bits)); + if (bits < 1) + throw new IllegalArgumentException("bits < 1"); + if (bits > 16) + throw new IllegalArgumentException("bits > 16"); + if (size < 1) + throw new IllegalArgumentException("size < 1"); + map_size = size; + opaque = !hasAlpha; + + rgb = createColorMap(bits, size); + if (hasAlpha) + { + int alpha; + int alphaZero = 0x00; // use to detect all zeros + int alphaOne = 0xff; // use to detect all ones + for (int i = 0; i < size; i++) { + alpha = cmap[4 * i + 3 + start] & 0xff; + alphaZero = alphaZero | alpha; + alphaOne = alphaOne & alpha; + rgb[i] = + ( alpha << 24 + // red + | ((cmap[4 * i + start] & 0xff) << 16) + // green + | ((cmap[4 * i + 1 + start] & 0xff) << 8) + // blue + | (cmap[4 * i + 2 + start] & 0xff)); + } + if (alphaZero == 0) + transparency = BITMASK; + else if (alphaOne == 255) + transparency = (trans != -1 ? BITMASK : OPAQUE); + else + transparency = TRANSLUCENT; + } + else + { + for (int i = 0; i < size; i++) + rgb[i] = (0xff000000 + // red + | ((cmap[3 * i + start] & 0xff) << 16) + // green + | ((cmap[3 * i + 1 + start] & 0xff) << 8) + // blue + | (cmap[3 * i + 2 + start] & 0xff)); + if (trans != -1) + transparency = BITMASK; + } + + setTransparentPixel(trans); + + // Generate a bigint with 1's for every pixel + validBits = validBits.setBit(size).subtract(BigInteger.ONE); + } + + /** + * Construct an IndexColorModel from an array of <code>size</code> packed + * colors. Each int element contains 8-bit red, green, blue, and optional + * alpha values packed in order. If hasAlpha is false, then all the colors + * are opaque except for the transparent color. + * + * @param bits the number of bits needed to represent <code>size</code> + * colors + * @param size the number of colors in the color map + * @param cmap packed color components + * @param start the offset of the first color component in <code>cmap</code> + * @param hasAlpha <code>cmap</code> has alpha values + * @param trans the index of the transparent color + * @param transferType {@link DataBuffer#TYPE_BYTE} or + {@link DataBuffer#TYPE_USHORT}. + * @throws IllegalArgumentException if bits < 1, bits > 16, or size + * < 1. + * @throws IllegalArgumentException if <code>transferType</code> is something + * other than {@link DataBuffer#TYPE_BYTE} or + * {@link DataBuffer#TYPE_USHORT}. + */ + public IndexColorModel(int bits, int size, int[] cmap, int start, + boolean hasAlpha, int trans, int transferType) + { + super(bits, + nArray(8, 4), // bits for each channel + ColorSpace.getInstance(ColorSpace.CS_sRGB), // sRGB + true, // has alpha + false, // not premultiplied + TRANSLUCENT, transferType); + if (transferType != DataBuffer.TYPE_BYTE + && transferType != DataBuffer.TYPE_USHORT) + throw new IllegalArgumentException(); + if (bits > 16) + throw new IllegalArgumentException("bits > 16"); + if (size < 1) + throw new IllegalArgumentException("size < 1"); + map_size = size; + opaque = !hasAlpha; + rgb = createColorMap(bits, size); + if (!hasAlpha) + for (int i = 0; i < size; i++) + rgb[i] = cmap[i + start] | 0xff000000; + else + System.arraycopy(cmap, start, rgb, 0, size); + + setTransparentPixel(trans); + + // Generate a bigint with 1's for every pixel + validBits = validBits.setBit(size).subtract(BigInteger.ONE); + } + + /** + * Construct an IndexColorModel using a colormap with holes. + * <br><br> + * The IndexColorModel is built from the array of ints defining the + * colormap. Each element contains red, green, blue, and alpha + * components. The ColorSpace is sRGB. The transparency value is + * automatically determined. + * <br><br> + * This constructor permits indicating which colormap entries are valid, + * using the validBits argument. Each entry in cmap is valid if the + * corresponding bit in validBits is set. + * + * @param bits the number of bits needed to represent <code>size</code> + * colors. + * @param size the number of colors in the color map. + * @param cmap packed color components. + * @param start the offset of the first color component in <code>cmap</code>. + * @param transferType {@link DataBuffer#TYPE_BYTE} or + * {@link DataBuffer#TYPE_USHORT}. + * @param validBits a map of the valid entries in <code>cmap</code>. + * @throws IllegalArgumentException if bits < 1, bits > 16, or size + * < 1. + * @throws IllegalArgumentException if transferType is something other than + * {@link DataBuffer#TYPE_BYTE} or {@link DataBuffer#TYPE_USHORT}. + */ + public IndexColorModel(int bits, int size, int[] cmap, int start, + int transferType, BigInteger validBits) + { + super(bits, // total bits, sRGB, four channels + nArray(8, 4), // bits for each channel + ColorSpace.getInstance(ColorSpace.CS_sRGB), // sRGB + true, // has alpha + false, // not premultiplied + TRANSLUCENT, transferType); + if (transferType != DataBuffer.TYPE_BYTE + && transferType != DataBuffer.TYPE_USHORT) + throw new IllegalArgumentException(); + if (bits > 16) + throw new IllegalArgumentException("bits > 16"); + if (size < 1) + throw new IllegalArgumentException("size < 1"); + map_size = size; + opaque = false; + this.trans = -1; + this.validBits = validBits; + + rgb = createColorMap(bits, size); + if (!hasAlpha) + for (int i = 0; i < size; i++) + rgb[i] = cmap[i + start] | 0xff000000; + else + System.arraycopy(cmap, start, rgb, 0, size); + } + + /** + * Returns the size of the color lookup table. + * + * @return The size of the color lookup table. + */ + public final int getMapSize() + { + return map_size; + } + + /** + * Get the index of the transparent color in this color model. + * + * @return The index of the color that is considered transparent, or -1 if + * there is no transparent color. + */ + public final int getTransparentPixel() + { + return trans; + } + + /** + * Fills the supplied array with the red component of each color in the + * lookup table. + * + * @param r an array that is at least as large as {@link #getMapSize()}. + * @throws NullPointerException if <code>r</code> is <code>null</code>. + * @throws ArrayIndexOutOfBoundsException if <code>r</code> has less + * than {@link #getMapSize()} elements. + */ + public final void getReds(byte[] r) + { + int i; + for (i = 0; i < map_size; i++) + r[i] = (byte) ((0x00FF0000 & rgb[i]) >> 16); + } + + /** + * Fills the supplied array with the green component of each color in the + * lookup table. + * + * @param g an array that is at least as large as {@link #getMapSize()}. + * @throws NullPointerException if <code>g</code> is <code>null</code>. + * @throws ArrayIndexOutOfBoundsException if <code>g</code> has less + * than {@link #getMapSize()} elements. + */ + public final void getGreens(byte[] g) + { + int i; + for (i = 0; i < map_size; i++) + g[i] = (byte) ((0x0000FF00 & rgb[i]) >> 8); + } + + /** + * Fills the supplied array with the blue component of each color in the + * lookup table. + * + * @param b an array that is at least as large as {@link #getMapSize()}. + * @throws NullPointerException if <code>b</code> is <code>null</code>. + * @throws ArrayIndexOutOfBoundsException if <code>b</code> has less + * than {@link #getMapSize()} elements. + */ + public final void getBlues(byte[] b) + { + int i; + for (i = 0; i < map_size; i++) + b[i] = (byte) (0x000000FF & rgb[i]); + } + + /** + * Fills the supplied array with the alpha component of each color in the + * lookup table. If the model has a transparent pixel specified, the alpha + * for that pixel will be 0. + * + * @param a an array that is at least as large as {@link #getMapSize()}. + * @throws NullPointerException if <code>a</code> is <code>null</code>. + * @throws ArrayIndexOutOfBoundsException if <code>a</code> has less + * than {@link #getMapSize()} elements. + */ + public final void getAlphas(byte[] a) + { + int i; + for (i = 0; i < map_size; i++) + if (i == trans) + a[i] = (byte) 0; + else + a[i] = (byte) ((0xFF000000 & rgb[i]) >> 24); + } + + /** + * Returns the red component of the color in the lookup table for the + * given pixel value. + * + * @param pixel the pixel lookup value. + * + * @return The red component of the color in the lookup table. + * @throws ArrayIndexOutOfBoundsException if <code>pixel</code> is negative. + */ + public final int getRed(int pixel) + { + if (pixel < map_size) + return (0x00FF0000 & rgb[pixel]) >> 16; + + return 0; + } + + /** + * Returns the green component of the color in the lookup table for the + * given pixel value. + * + * @param pixel the pixel lookup value. + * + * @return The green component of the color in the lookup table. + * @throws ArrayIndexOutOfBoundsException if <code>pixel</code> is negative. + */ + public final int getGreen(int pixel) + { + if (pixel < map_size) + return (0x0000FF00 & rgb[pixel]) >> 8; + + return 0; + } + + /** + * Returns the blue component of the color in the lookup table for the + * given pixel value. + * + * @param pixel the pixel lookup value. + * + * @return The blue component of the color in the lookup table. + * @throws ArrayIndexOutOfBoundsException if <code>pixel</code> is negative. + */ + public final int getBlue(int pixel) + { + if (pixel < map_size) + return 0x000000FF & rgb[pixel]; + + return 0; + } + + /** + * Returns the alpha component of the color in the lookup table for the + * given pixel value. If no alpha channel was specified when the color model + * was created, then 255 is returned for all pixels except the transparent + * pixel (if one is defined - see {@link #getTransparentPixel()}) which + * returns an alpha of 0. + * + * @param pixel the pixel lookup value. + * + * @return The alpha component of the color in the lookup table (in the + * range 0 to 255). + * @throws ArrayIndexOutOfBoundsException if <code>pixel</code> is negative. + */ + public final int getAlpha(int pixel) + { + return (rgb[pixel] >> 24) & 0xFF; + } + + /** + * Get the RGB color value of the given pixel using the default + * RGB color model. + * + * @param pixel the pixel lookup value. + * @return The RGB color value. + * @throws ArrayIndexOutOfBoundsException if <code>pixel</code> is negative. + */ + public final int getRGB(int pixel) + { + if (pixel >= 0 && pixel < map_size) + return rgb[pixel]; + + return 0; + } + + /** + * Get the RGB color values of all pixels in the map using the default + * RGB color model. + * + * @param rgb The destination array. + */ + public final void getRGBs(int[] rgb) + { + System.arraycopy(this.rgb, 0, rgb, 0, map_size); + } + + /** + * Return <code>true</code> if the lookup table contains valid data for + * <code>pixel</code>, and <code>false</code> otherwise. + * + * @param pixel the pixel value used to index the color lookup table. + * @return <code>true</code> if <code>pixel</code> is valid, + * <code>false</code> otherwise. + */ + public boolean isValid(int pixel) + { + if (pixel >= 0) + return validBits.testBit(pixel); + return false; + } + + /** + * Return <code>true</code> if all pixels are valid, <code>false</code> + * otherwise. + * + * @return <code>true</code> if all pixels are valid, <code>false</code> + * otherwise. + */ + public boolean isValid() + { + // Generate a bigint with 1's for every pixel + BigInteger allbits = new BigInteger("0"); + allbits = allbits.setBit(map_size); + allbits = allbits.subtract(new BigInteger("1")); + return allbits.equals(validBits); + } + + /** + * Returns a binary value ({@link BigInteger}) where each bit represents an + * entry in the color lookup table. If the bit is on, the entry is valid. + * + * @return The binary value. + */ + public BigInteger getValidPixels() + { + return validBits; + } + + /** + * Construct a {@link BufferedImage} with rgb pixel values from a + * {@link Raster}. + * + * Constructs a new BufferedImage in which each pixel is an RGBA int from + * a Raster with index-valued pixels. If this model has no alpha component + * or transparent pixel, the type of the new BufferedImage is TYPE_INT_RGB. + * Otherwise the type is TYPE_INT_ARGB. If forceARGB is true, the type is + * forced to be TYPE_INT_ARGB no matter what. + * + * @param raster The source of pixel values. + * @param forceARGB True if type must be TYPE_INT_ARGB. + * @return New BufferedImage with RBGA int pixel values. + */ + public BufferedImage convertToIntDiscrete(Raster raster, boolean forceARGB) + { + int type = forceARGB ? BufferedImage.TYPE_INT_ARGB + : ((opaque && trans == -1) ? BufferedImage.TYPE_INT_RGB : + BufferedImage.TYPE_INT_ARGB); + + // FIXME: assuming that raster has only 1 band since pixels are supposed + // to be int indexes. + // FIXME: it would likely be more efficient to fetch a complete array, + // but it would take much more memory. + // FIXME: I'm not sure if transparent pixels or alpha values need special + // handling here. + BufferedImage im = new BufferedImage(raster.width, raster.height, type); + for (int x = raster.minX; x < raster.width + raster.minX; x++) + for (int y = raster.minY; y < raster.height + raster.minY; y++) + im.setRGB(x, y, rgb[raster.getSample(x, y, 0)]); + + return im; + } + + /** + * Creates a {@link SampleModel} that is compatible to this color model. + * This will be a {@link MultiPixelPackedSampleModel} for bits/pixel of + * 1, 2 or 4, or a {@link ComponentColorModel} for the other cases. + * + * @param w the width of the sample model to create + * @param h the height of the sample model to create + * + * @return a compatible sample model + */ + public SampleModel createCompatibleSampleModel(int w, int h) + { + SampleModel sm; + if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) + sm = new MultiPixelPackedSampleModel(transferType, w, h, pixel_bits); + else + sm = new ComponentSampleModel(transferType, w, h, 1, w, new int[]{0}); + return sm; + } + + /** + * Sets the transparent pixel. This is called by the various constructors. + * + * @param t the transparent pixel + */ + private void setTransparentPixel(int t) + { + if (t >= 0 && t < map_size) + { + rgb[t] &= 0xffffff; // Make the value transparent. + trans = t; + if (transparency == OPAQUE) + { + transparency = BITMASK; + hasAlpha = true; + } + } + } + + private int[] createColorMap(int bits, int size) + { + // According to a Mauve test, the RI allocates at least 256 entries here. + int realSize = Math.max(256, Math.max(1 << bits, size)); + return new int[realSize]; + } +} diff --git a/libjava/classpath/java/awt/image/Kernel.java b/libjava/classpath/java/awt/image/Kernel.java new file mode 100644 index 000000000..ae0ff1469 --- /dev/null +++ b/libjava/classpath/java/awt/image/Kernel.java @@ -0,0 +1,171 @@ +/* Kernel.java -- Java class for an image processing kernel + Copyright (C) 2004, 2005, 2006, Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +/** + * Kernel represents an image processing kernel. It gets used to hold + * convolution filters among other purposes. It stores an array of float + * values representing a 2-dimensional array in row-major order. + * + * @author Jerry Quinn (jlquinn@optonline.net) + */ +public class Kernel implements Cloneable +{ + /** The kernel width. */ + private final int width; + + /** The kernel height. */ + private final int height; + + /** Internal storage for the kernel's values. */ + private final float[] data; + + /** + * Creates a new <code>Kernel</code> instance with the specified dimensions + * and values. The first <code>width * height</code> values in the specified + * <code>data</code> array are copied to internal storage. + * + * @param width the kernel width. + * @param height the kernel height. + * @param data the source data array (<code>null</code> not permitted). + * + * @throws IllegalArgumentException if <code>data.length</code> is less than + * <code>width * height</code>. + * @throws IllegalArgumentException if <code>width</code> or + * <code>height</code> is less than zero. + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public Kernel(int width, int height, float[] data) + throws IllegalArgumentException + { + this.width = width; + this.height = height; + if (data.length < width * height || width < 0 || height < 0) + throw new IllegalArgumentException(); + this.data = new float[width * height]; + System.arraycopy(data, 0, this.data, 0, width * height); + } + + /** + * Returns the x-origin for the kernel, which is calculated as + * <code>(width - 1) / 2</code>. + * + * @return The x-origin for the kernel. + */ + public final int getXOrigin() + { + return (width - 1) / 2; + } + + /** + * Returns the y-origin for the kernel, which is calculated as + * <code>(height - 1) / 2</code>. + * + * @return The y-origin for the kernel. + */ + public final int getYOrigin() + { + return (height - 1) / 2; + } + + /** + * Returns the kernel width (as supplied to the constructor). + * + * @return The kernel width. + */ + public final int getWidth() + { + return width; + } + + /** + * Returns the kernel height (as supplied to the constructor). + * + * @return The kernel height. + */ + public final int getHeight() + { + return height; + } + + /** + * Returns an array containing a copy of the kernel data. If the + * <code>data</code> argument is non-<code>null</code>, the kernel values + * are copied into it and then <code>data</code> is returned as the result. + * If the <code>data</code> argument is <code>null</code>, this method + * allocates a new array then populates and returns it. + * + * @param data an array to copy the return values into (if + * <code>null</code>, a new array is allocated). + * + * @return The array with copied values. + * + * @throws IllegalArgumentException if <code>data.length</code> is less than + * the kernel's <code>width * height</code>. + */ + public final float[] getKernelData(float[] data) + throws IllegalArgumentException + { + if (data == null) + return (float[]) this.data.clone(); + + if (data.length < this.data.length) + throw new IllegalArgumentException(); + + System.arraycopy(this.data, 0, data, 0, this.data.length); + return data; + } + + /** + * Returns a clone of this kernel. + * + * @return a clone of this Kernel. + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // Impossible + } + } +} diff --git a/libjava/classpath/java/awt/image/LookupOp.java b/libjava/classpath/java/awt/image/LookupOp.java new file mode 100644 index 000000000..0bc79a00b --- /dev/null +++ b/libjava/classpath/java/awt/image/LookupOp.java @@ -0,0 +1,307 @@ +/* LookupOp.java -- Filter that converts each pixel using a lookup table. + Copyright (C) 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import java.awt.RenderingHints; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * LookupOp is a filter that converts each pixel using a lookup table. + * + * For filtering Rasters, the lookup table must have either one component + * that is applied to all bands, or one component for every band in the + * Rasters. + * + * For BufferedImages, the lookup table may apply to both color and alpha + * components. If the lookup table contains one component, or if there are + * the same number of components as color components in the source, the table + * applies to all color components. Otherwise the table applies to all + * components including alpha. Alpha premultiplication is ignored during the + * lookup filtering. + * + * After filtering, if color conversion is necessary, the conversion happens, + * taking alpha premultiplication into account. + * + * @author jlquinn + */ +public class LookupOp implements BufferedImageOp, RasterOp +{ + private LookupTable lut; + private RenderingHints hints; + + /** + * Construct a new LookupOp using the given LookupTable. + * + * @param lookup LookupTable to use. + * @param hints Rendering hints (can be null). + */ + public LookupOp(LookupTable lookup, RenderingHints hints) + { + lut = lookup; + this.hints = hints; + } + + /** + * Converts the source image using the lookup table specified in the + * constructor. The resulting image is stored in the destination image if one + * is provided; otherwise a new BufferedImage is created and returned. + * + * The source image cannot use an IndexColorModel, and the destination image + * (if one is provided) must have the same size. + * + * @param src The source image. + * @param dst The destination image. + * @throws IllegalArgumentException if the rasters and/or color spaces are + * incompatible. + * @throws ArrayIndexOutOfBoundsException if a pixel in the source is not + * contained in the LookupTable. + * @return The convolved image. + */ + public final BufferedImage filter(BufferedImage src, BufferedImage dst) + { + if (src.getColorModel() instanceof IndexColorModel) + throw new IllegalArgumentException("LookupOp.filter: IndexColorModel " + + "not allowed"); + + if (lut.getNumComponents() != 1 + && lut.getNumComponents() != src.getColorModel().getNumComponents() + && lut.getNumComponents() != src.getColorModel().getNumColorComponents()) + throw new IllegalArgumentException("LookupOp.filter: Incompatible " + + "lookup table and source image"); + + if (dst == null) + dst = createCompatibleDestImage(src, null); + + else if (src.getHeight() != dst.getHeight() || src.getWidth() != dst.getWidth()) + throw new IllegalArgumentException("Source and destination images are " + + "different sizes."); + + // Set up for potential colormodel mismatch + BufferedImage tgt; + if (dst.getColorModel().equals(src.getColorModel())) + tgt = dst; + else + tgt = createCompatibleDestImage(src, src.getColorModel()); + + Raster sr = src.getRaster(); + WritableRaster dr = tgt.getRaster(); + + if (src.getColorModel().hasAlpha() && + (lut.getNumComponents() == 1 || + lut.getNumComponents() == src.getColorModel().getNumColorComponents())) + { + // Need to ignore alpha for lookup + int[] dbuf = new int[src.getColorModel().getNumComponents()]; + int tmpBands = src.getColorModel().getNumColorComponents(); + int[] tmp = new int[tmpBands]; + + // Filter the pixels + for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) + for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) + { + // Filter only color components, but also copy alpha + sr.getPixel(x, y, dbuf); + System.arraycopy(dbuf, 0, tmp, 0, tmpBands); + dr.setPixel(x, y, lut.lookupPixel(tmp, dbuf)); + + /* The reference implementation does not use LookupTable.lookupPixel, + * but rather it seems to copy the table into a native array. The + * effect of this (a probable bug in their implementation) is that + * an out-of-bounds lookup on a ByteLookupTable will *not* throw an + * out of bounds exception, but will instead return random garbage. + * A bad lookup on a ShortLookupTable, however, will throw an + * exception. + * + * Instead of mimicing this behaviour, we always throw an + * ArrayOutofBoundsException by virtue of using + * LookupTable.lookupPixle. + */ + } + } + else + { + // No alpha to ignore + int[] dbuf = new int[src.getColorModel().getNumComponents()]; + + // Filter the pixels + for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) + for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) + dr.setPixel(x, y, lut.lookupPixel(sr.getPixel(x, y, dbuf), dbuf)); + } + + if (tgt != dst) + new ColorConvertOp(hints).filter(tgt, dst); + + return dst; + } + + /* (non-Javadoc) + * @see java.awt.image.BufferedImageOp#getBounds2D(java.awt.image.BufferedImage) + */ + public final Rectangle2D getBounds2D(BufferedImage src) + { + return src.getRaster().getBounds(); + } + + /* (non-Javadoc) + * @see java.awt.image.BufferedImageOp#createCompatibleDestImage(java.awt.image.BufferedImage, java.awt.image.ColorModel) + */ + public BufferedImage createCompatibleDestImage(BufferedImage src, + ColorModel dstCM) + { + if (dstCM != null) + return new BufferedImage(dstCM, + src.getRaster().createCompatibleWritableRaster(), + src.isAlphaPremultiplied(), null); + + // This is a strange exception, done for compatibility with the reference + // (as demonstrated by a mauve testcase) + int imgType = src.getType(); + if (imgType == BufferedImage.TYPE_USHORT_GRAY) + imgType = BufferedImage.TYPE_BYTE_GRAY; + + return new BufferedImage(src.getWidth(), src.getHeight(), imgType); + } + + /** + * Returns the corresponding destination point for a given source point. + * + * This Op will return the source point unchanged. + * + * @param src The source point. + * @param dst The destination point. + */ + public final Point2D getPoint2D(Point2D src, Point2D dst) + { + if (dst == null) + return (Point2D) src.clone(); + + dst.setLocation(src); + return dst; + } + + /** + * Return the LookupTable for this op. + * + * @return The lookup table. + */ + public final LookupTable getTable() + { + return lut; + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#getRenderingHints() + */ + public final RenderingHints getRenderingHints() + { + return hints; + } + + /** + * Filter a raster through a lookup table. + * + * Applies the lookup table for this Rasterop to each pixel of src and + * puts the results in dest. If dest is null, a new Raster is created and + * returned. + * + * @param src The source raster. + * @param dest The destination raster. + * @return The WritableRaster with the filtered pixels. + * @throws IllegalArgumentException if lookup table has more than one + * component but not the same as src and dest. + * @throws ArrayIndexOutOfBoundsException if a pixel in the source is not + * contained in the LookupTable. + */ + public final WritableRaster filter(Raster src, WritableRaster dest) + { + if (dest == null) + // Allocate a raster if needed + dest = createCompatibleDestRaster(src); + else + if (src.getNumBands() != dest.getNumBands()) + throw new IllegalArgumentException("Source and destination rasters " + + "are incompatible."); + + if (lut.getNumComponents() != 1 + && lut.getNumComponents() != src.getNumBands()) + throw new IllegalArgumentException("Lookup table is incompatible with " + + "this raster."); + + // Allocate pixel storage. + int[] tmp = new int[src.getNumBands()]; + + // Filter the pixels + for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) + for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) + dest.setPixel(x, y, lut.lookupPixel(src.getPixel(x, y, tmp), tmp)); + + /* The reference implementation does not use LookupTable.lookupPixel, + * but rather it seems to copy the table into a native array. The + * effect of this (a probable bug in their implementation) is that + * an out-of-bounds lookup on a ByteLookupTable will *not* throw an + * out of bounds exception, but will instead return random garbage. + * A bad lookup on a ShortLookupTable, however, will throw an + * exception. + * + * Instead of mimicing this behaviour, we always throw an + * ArrayOutofBoundsException by virtue of using + * LookupTable.lookupPixle. + */ + return dest; + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#getBounds2D(java.awt.image.Raster) + */ + public final Rectangle2D getBounds2D(Raster src) + { + return src.getBounds(); + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#createCompatibleDestRaster(java.awt.image.Raster) + */ + public WritableRaster createCompatibleDestRaster(Raster src) + { + return src.createCompatibleWritableRaster(); + } + +} diff --git a/libjava/classpath/java/awt/image/LookupTable.java b/libjava/classpath/java/awt/image/LookupTable.java new file mode 100644 index 000000000..d104b2fd5 --- /dev/null +++ b/libjava/classpath/java/awt/image/LookupTable.java @@ -0,0 +1,109 @@ +/* LookupTable.java -- Java class for a pixel translation table. + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +/** + * LookupTable represents translation arrays for pixel values. It wraps one + * or more data arrays for each layer (or component) in an image, such as + * Alpha, R, G, and B. When doing translation, the offset is subtracted from + * the pixel values to allow a subset of an array to be used. + * + * @see ByteLookupTable + * @see ShortLookupTable + * + * @author Jerry Quinn (jlquinn@optonline.net) + * @version 1.0 + */ +public abstract class LookupTable +{ + // Not protected since that's part of the public API. + int offset; + int numComponents; + + /** + * Creates a new <code>LookupTable</code> instance. + * + * If numComponents is 1, the same translation table is used for all pixel + * components. + * + * @param offset Offset to be subtracted. + * @param numComponents Number of image components. + * @exception IllegalArgumentException if offset < 0 or numComponents < 1. + */ + protected LookupTable(int offset, int numComponents) + throws IllegalArgumentException + { + if (offset < 0 || numComponents < 1) + throw new IllegalArgumentException(); + this.offset = offset; + this.numComponents = numComponents; + } + + /** Return the number of components. */ + public int getNumComponents() + { + return numComponents; + } + + /** Return the offset. */ + public int getOffset() + { + return offset; + } + + + /** + * Return translated values for a pixel. + * + * For each value in the pixel src, use the value minus offset as an index + * in the component array and copy the value there to the output for the + * component. If dest is null, the output is a new array, otherwise the + * translated values are written to dest. Dest can be the same array as + * src. + * + * For example, if the pixel src is [2, 4, 3], and offset is 1, the output + * is [comp1[1], comp2[3], comp3[2]], where comp1, comp2, and comp3 are the + * translation arrays. + * + * @param src Component values of a pixel. + * @param dest Destination array for values, or null. + * @return Translated values for the pixel. + */ + public abstract int[] lookupPixel(int[] src, int[] dest); +} diff --git a/libjava/classpath/java/awt/image/MemoryImageSource.java b/libjava/classpath/java/awt/image/MemoryImageSource.java new file mode 100644 index 000000000..e8780f6f5 --- /dev/null +++ b/libjava/classpath/java/awt/image/MemoryImageSource.java @@ -0,0 +1,429 @@ +/* MemoryImageSource.java -- Java class for providing image data + Copyright (C) 1999, 2004, 2006, Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import java.util.Hashtable; +import java.util.Vector; + +/** + * An image producer that delivers image data from an array. + */ +public class MemoryImageSource implements ImageProducer +{ + private boolean animated = false; + private boolean fullbuffers = false; + private int[] pixeli; + private int width; + private int height; + private int offset; + private int scansize; + private byte[] pixelb; + private ColorModel cm; + private Hashtable props = new Hashtable(); + private Vector consumers = new Vector(); + + /** + * Construct an image producer that reads image data from a byte + * array. + * + * @param w width of image + * @param h height of image + * @param cm the color model used to represent pixel values + * @param pix a byte array of pixel values + * @param off the offset into the array at which the first pixel is stored + * @param scan the number of array elements that represents a single pixel row + */ + public MemoryImageSource(int w, int h, ColorModel cm, byte[] pix, int off, + int scan) + { + this(w, h, cm, pix, off, scan, null); + } + + /** + * Constructs an ImageProducer from memory. + * + * @param w the image width. + * @param h the image height. + * @param cm the color model. + * @param pix the image data. + * @param off the offset to the first pixel in the array. + * @param scan the number of array elements from a pixel on one row to the + * corresponding pixel on the next row. + * @param props image properties (<code>null</code> permitted). + */ + public MemoryImageSource(int w, int h, ColorModel cm, byte[] pix, int off, + int scan, Hashtable<?,?> props) + { + width = w; + height = h; + this.cm = cm; + offset = off; + scansize = scan; + this.props = props; + int max = ((scansize > width) ? scansize : width); + pixelb = pix; + } + + /** + * Construct an image producer that reads image data from an + * integer array. + * + * @param w width of image + * @param h height of image + * @param cm the color model used to represent pixel values + * @param pix an integer array of pixel values + * @param off the offset into the array at which the first pixel is stored + * @param scan the number of array elements that represents a single pixel row + */ + public MemoryImageSource(int w, int h, ColorModel cm, int[] pix, int off, + int scan) + { + this(w, h, cm, pix, off, scan, null); + } + + /** + * Constructs an ImageProducer from memory + * + * @param w the image width. + * @param h the image height. + * @param cm the color model. + * @param pix the image data. + * @param off the offset to the first pixel in the array. + * @param scan the number of array elements from a pixel on one row to the + * corresponding pixel on the next row. + * @param props image properties (<code>null</code> permitted). + */ + public MemoryImageSource(int w, int h, ColorModel cm, int[] pix, int off, + int scan, Hashtable<?,?> props) + { + width = w; + height = h; + this.cm = cm; + offset = off; + scansize = scan; + this.props = props; + int max = ((scansize > width) ? scansize : width); + pixeli = pix; + } + + /** + * Constructs an ImageProducer from memory using the default RGB ColorModel. + * + * @param w the image width. + * @param h the image height. + * @param pix the image data. + * @param off the offset to the first pixel in the array. + * @param scan the number of array elements from a pixel on one row to the + * corresponding pixel on the next row. + * @param props image properties (<code>null</code> permitted). + + */ + public MemoryImageSource(int w, int h, int[] pix, int off, int scan, + Hashtable<?,?> props) + { + this(w, h, ColorModel.getRGBdefault(), pix, off, scan, props); + } + + /** + * Constructs an ImageProducer from memory using the default RGB ColorModel. + * + * @param w the image width. + * @param h the image height. + * @param pix the image data. + * @param off the offset to the first pixel in the array. + * @param scan the number of array elements from a pixel on one row to the + * corresponding pixel on the next row. + */ + public MemoryImageSource(int w, int h, int[] pix, int off, int scan) + { + this(w, h, ColorModel.getRGBdefault(), pix, off, scan, null); + } + + /** + * Used to register an <code>ImageConsumer</code> with this + * <code>ImageProducer</code>. + * + * @param ic the image consumer. + */ + public synchronized void addConsumer(ImageConsumer ic) + { + if (consumers.contains(ic)) + return; + + consumers.addElement(ic); + } + + /** + * Used to determine if the given <code>ImageConsumer</code> is + * already registered with this <code>ImageProducer</code>. + * + * @param ic the image consumer. + */ + public synchronized boolean isConsumer(ImageConsumer ic) + { + if (consumers.contains(ic)) + return true; + return false; + } + + /** + * Used to remove an <code>ImageConsumer</code> from the list of + * registered consumers for this <code>ImageProducer</code>. + * + * @param ic the image consumer. + */ + public synchronized void removeConsumer(ImageConsumer ic) + { + consumers.removeElement(ic); + } + + /** + * Used to register an <code>ImageConsumer</code> with this + * <code>ImageProducer</code> and then immediately start + * reconstruction of the image data to be delivered to all + * registered consumers. + */ + public void startProduction(ImageConsumer ic) + { + if (! (consumers.contains(ic))) + consumers.addElement(ic); + + Vector list = (Vector) consumers.clone(); + for (int i = 0; i < list.size(); i++) + { + ic = (ImageConsumer) list.elementAt(i); + sendPicture(ic); + if (animated) + ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE); + else + ic.imageComplete(ImageConsumer.STATICIMAGEDONE); + } + } + + /** + * Used to register an <code>ImageConsumer</code> with this + * <code>ImageProducer</code> and then request that this producer + * resend the image data in the order top-down, left-right. + * + * @param ic the image consumer. + */ + public void requestTopDownLeftRightResend(ImageConsumer ic) + { + startProduction(ic); + } + + /** + * Changes a flag to indicate whether this MemoryImageSource supports + * animations. + * + * @param animated A flag indicating whether this class supports animations + */ + public synchronized void setAnimated(boolean animated) + { + this.animated = animated; + } + + /** + * A flag to indicate whether or not to send full buffer updates when + * sending animation. If this flag is set then full buffers are sent + * in the newPixels methods instead of just regions. + * + * @param fullbuffers a flag indicating whether to send the full buffers + */ + public synchronized void setFullBufferUpdates(boolean fullbuffers) + { + this.fullbuffers = fullbuffers; + } + + /** + * Send an animation frame to the image consumers. + */ + public void newPixels() + { + if (animated == true) + { + ImageConsumer ic; + Vector list = (Vector) consumers.clone(); + for (int i = 0; i < list.size(); i++) + { + ic = (ImageConsumer) list.elementAt(i); + sendPicture(ic); + ic.imageComplete(ImageConsumer.SINGLEFRAME); + } + } + } + + private void sendPicture(ImageConsumer ic) + { + ic.setHints(ImageConsumer.TOPDOWNLEFTRIGHT); + if (props != null) + ic.setProperties(props); + ic.setDimensions(width, height); + ic.setColorModel(cm); + if (pixeli != null) + ic.setPixels(0, 0, width, height, cm, pixeli, offset, scansize); + else + ic.setPixels(0, 0, width, height, cm, pixelb, offset, scansize); + } + + /** + * Send an animation frame to the image consumers containing the specified + * pixels unless setFullBufferUpdates is set. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param w the width. + * @param h the height. + */ + public synchronized void newPixels(int x, int y, int w, int h) + { + if (animated == true) + { + if (fullbuffers) + newPixels(); + else + { + ImageConsumer ic; + Vector list = (Vector) consumers.clone(); + for (int i = 0; i < list.size(); i++) + { + ic = (ImageConsumer) list.elementAt(i); + ic.setHints(ImageConsumer.TOPDOWNLEFTRIGHT); + if (props != null) + ic.setProperties(props); + if (pixeli != null) + { + int[] pixelbuf = new int[w * h]; + for (int row = y; row < y + h; row++) + System.arraycopy(pixeli, row * scansize + x + offset, + pixelbuf, 0, w * h); + ic.setPixels(x, y, w, h, cm, pixelbuf, 0, w); + } + else + { + byte[] pixelbuf = new byte[w * h]; + for (int row = y; row < y + h; row++) + System.arraycopy(pixelb, row * scansize + x + offset, + pixelbuf, 0, w * h); + + ic.setPixels(x, y, w, h, cm, pixelbuf, 0, w); + } + ic.imageComplete(ImageConsumer.SINGLEFRAME); + } + } + } + } + + /** + * Send an animation frame to the image consumers containing the specified + * pixels unless setFullBufferUpdates is set. + * + * If framenotify is set then a notification is sent when the frame + * is sent otherwise no status is sent. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param w the width. + * @param h the height. + * @param framenotify send notification? + */ + public synchronized void newPixels(int x, int y, int w, int h, + boolean framenotify) + { + if (animated == true) + { + if (fullbuffers) + newPixels(); + else + { + ImageConsumer ic; + Vector list = (Vector) consumers.clone(); + for (int i = 0; i < list.size(); i++) + { + ic = (ImageConsumer) list.elementAt(i); + ic.setHints(ImageConsumer.TOPDOWNLEFTRIGHT); + if (props != null) + ic.setProperties(props); + if (pixeli != null) + { + int[] pixelbuf = new int[w * h]; + for (int row = y; row < y + h; row++) + System.arraycopy(pixeli, row * scansize + x + offset, + pixelbuf, 0, w * h); + ic.setPixels(x, y, w, h, cm, pixelbuf, 0, w); + } + else + { + byte[] pixelbuf = new byte[w * h]; + for (int row = y; row < y + h; row++) + System.arraycopy(pixelb, row * scansize + x + offset, + pixelbuf, 0, w * h); + ic.setPixels(x, y, w, h, cm, pixelbuf, 0, w); + } + if (framenotify == true) + ic.imageComplete(ImageConsumer.SINGLEFRAME); + } + } + } + } + + public synchronized void newPixels(byte[] newpix, ColorModel newmodel, + int offset, int scansize) + { + pixeli = null; + pixelb = newpix; + cm = newmodel; + this.offset = offset; + this.scansize = scansize; + if (animated == true) + newPixels(); + } + + public synchronized void newPixels(int[] newpix, ColorModel newmodel, + int offset, int scansize) + { + pixelb = null; + pixeli = newpix; + cm = newmodel; + this.offset = offset; + this.scansize = scansize; + if (animated == true) + newPixels(); + } +} diff --git a/libjava/classpath/java/awt/image/MultiPixelPackedSampleModel.java b/libjava/classpath/java/awt/image/MultiPixelPackedSampleModel.java new file mode 100644 index 000000000..592611cbb --- /dev/null +++ b/libjava/classpath/java/awt/image/MultiPixelPackedSampleModel.java @@ -0,0 +1,603 @@ +/* Copyright (C) 2004, 2006, Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +import gnu.java.awt.Buffers; +import gnu.java.lang.CPStringBuilder; + +/** + * MultiPixelPackedSampleModel provides a single band model that supports + * multiple pixels in a single unit. Pixels have 2^n bits and 2^k pixels fit + * per data element. + * + * @author Jerry Quinn (jlquinn@optonline.net) + */ +public class MultiPixelPackedSampleModel extends SampleModel +{ + private int scanlineStride; + private int[] bitMasks; + private int[] bitOffsets; + private int[] sampleSize; + private int dataBitOffset; + private int elemBits; + private int numberOfBits; + private int numElems; + + /** + * Creates a new <code>MultiPixelPackedSampleModel</code> with the specified + * data type, which should be one of: + * <ul> + * <li>{@link DataBuffer#TYPE_BYTE};</li> + * <li>{@link DataBuffer#TYPE_USHORT};</li> + * <li>{@link DataBuffer#TYPE_INT};</li> + * </ul> + * + * @param dataType the data type. + * @param w the width (in pixels). + * @param h the height (in pixels). + * @param numberOfBits the number of bits per pixel (must be a power of 2). + */ + public MultiPixelPackedSampleModel(int dataType, int w, int h, + int numberOfBits) + { + this(dataType, w, h, numberOfBits, 0, 0); + } + + /** + * Creates a new <code>MultiPixelPackedSampleModel</code> with the specified + * data type, which should be one of: + * <ul> + * <li>{@link DataBuffer#TYPE_BYTE};</li> + * <li>{@link DataBuffer#TYPE_USHORT};</li> + * <li>{@link DataBuffer#TYPE_INT};</li> + * </ul> + * + * @param dataType the data type. + * @param w the width (in pixels). + * @param h the height (in pixels). + * @param numberOfBits the number of bits per pixel (must be a power of 2). + * @param scanlineStride the number of data elements from a pixel on one + * row to the corresponding pixel in the next row. + * @param dataBitOffset the offset to the first data bit. + */ + public MultiPixelPackedSampleModel(int dataType, int w, int h, + int numberOfBits, int scanlineStride, + int dataBitOffset) + { + super(dataType, w, h, 1); + + switch (dataType) + { + case DataBuffer.TYPE_BYTE: + elemBits = 8; + break; + case DataBuffer.TYPE_USHORT: + elemBits = 16; + break; + case DataBuffer.TYPE_INT: + elemBits = 32; + break; + default: + throw new IllegalArgumentException("MultiPixelPackedSampleModel" + + " unsupported dataType"); + } + + this.dataBitOffset = dataBitOffset; + + this.numberOfBits = numberOfBits; + if (numberOfBits > elemBits) + throw new RasterFormatException("MultiPixelPackedSampleModel pixel size" + + " larger than dataType"); + switch (numberOfBits) + { + case 1: case 2: case 4: case 8: case 16: case 32: break; + default: + throw new RasterFormatException("MultiPixelPackedSampleModel pixel" + + " size not 2^n bits"); + } + numElems = elemBits / numberOfBits; + + // Compute scan line large enough for w pixels. + if (scanlineStride == 0) + scanlineStride = ((dataBitOffset + w * numberOfBits) - 1) / elemBits + 1; + this.scanlineStride = scanlineStride; + + + sampleSize = new int[1]; + sampleSize[0] = numberOfBits; + + bitMasks = new int[numElems]; + bitOffsets = new int[numElems]; + for (int i=0; i < numElems; i++) + { + bitOffsets[numElems - i- 1] = numberOfBits * i; + bitMasks[numElems - i - 1] = ((1 << numberOfBits) - 1) << + bitOffsets[numElems - i - 1]; + } + } + + /** + * Creates a new <code>MultiPixelPackedSample</code> model with the same + * data type and bits per pixel as this model, but with the specified + * dimensions. + * + * @param w the width (in pixels). + * @param h the height (in pixels). + * + * @return The new sample model. + */ + public SampleModel createCompatibleSampleModel(int w, int h) + { + /* FIXME: We can avoid recalculation of bit offsets and sample + sizes here by passing these from the current instance to a + special private constructor. */ + return new MultiPixelPackedSampleModel(dataType, w, h, numberOfBits); + } + + /** + * Creates a DataBuffer for holding pixel data in the format and + * layout described by this SampleModel. The returned buffer will + * consist of one single bank. + * + * @return A new data buffer. + */ + public DataBuffer createDataBuffer() + { + int size = scanlineStride * height; + if (dataBitOffset > 0) + size += (dataBitOffset - 1) / elemBits + 1; + return Buffers.createBuffer(getDataType(), size); + } + + /** + * Returns the number of data elements required to transfer a pixel in the + * get/setDataElements() methods. + * + * @return <code>1</code>. + */ + public int getNumDataElements() + { + return 1; + } + + /** + * Returns an array containing the size (in bits) of the samples in each + * band. The <code>MultiPixelPackedSampleModel</code> class supports only + * one band, so this method returns an array with length <code>1</code>. + * + * @return An array containing the size (in bits) of the samples in band zero. + * + * @see #getSampleSize(int) + */ + public int[] getSampleSize() + { + return (int[]) sampleSize.clone(); + } + + /** + * Returns the size of the samples in the specified band. Note that the + * <code>MultiPixelPackedSampleModel</code> supports only one band -- this + * method ignored the <code>band</code> argument, and always returns the size + * of band zero. + * + * @param band the band (this parameter is ignored). + * + * @return The size of the samples in band zero. + * + * @see #getSampleSize() + */ + public int getSampleSize(int band) + { + return sampleSize[0]; + } + + /** + * Returns the index in the data buffer that stores the pixel at (x, y). + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * + * @return The index in the data buffer that stores the pixel at (x, y). + * + * @see #getBitOffset(int) + */ + public int getOffset(int x, int y) + { + return scanlineStride * y + ((dataBitOffset + x * numberOfBits) / elemBits); + } + + /** + * The bit offset (within an element in the data buffer) of the pixels with + * the specified x-coordinate. + * + * @param x the x-coordinate. + * + * @return The bit offset. + */ + public int getBitOffset(int x) + { + return (dataBitOffset + x * numberOfBits) % elemBits; + } + + /** + * Returns the offset to the first data bit. + * + * @return The offset to the first data bit. + */ + public int getDataBitOffset() + { + return dataBitOffset; + } + + /** + * Returns the number of data elements from a pixel in one row to the + * corresponding pixel in the next row. + * + * @return The scanline stride. + */ + public int getScanlineStride() + { + return scanlineStride; + } + + /** + * Returns the number of bits per pixel. + * + * @return The number of bits per pixel. + */ + public int getPixelBitStride() + { + return numberOfBits; + } + + /** + * Returns the transfer type, which is one of the following (depending on + * the number of bits per sample for this model): + * <ul> + * <li>{@link DataBuffer#TYPE_BYTE};</li> + * <li>{@link DataBuffer#TYPE_USHORT};</li> + * <li>{@link DataBuffer#TYPE_INT};</li> + * </ul> + * + * @return The transfer type. + */ + public int getTransferType() + { + if (numberOfBits <= DataBuffer.getDataTypeSize(DataBuffer.TYPE_BYTE)) + return DataBuffer.TYPE_BYTE; + else if (numberOfBits <= DataBuffer.getDataTypeSize(DataBuffer.TYPE_USHORT)) + return DataBuffer.TYPE_USHORT; + return DataBuffer.TYPE_INT; + } + + /** + * Normally this method returns a sample model for accessing a subset of + * bands of image data, but since <code>MultiPixelPackedSampleModel</code> + * only supports a single band, this overridden implementation just returns + * a new instance of <code>MultiPixelPackedSampleModel</code>, with the same + * attributes as this instance. + * + * @param bands the bands to include in the subset (this is ignored, except + * that if it is non-<code>null</code> a check is made to ensure that the + * array length is equal to <code>1</code>). + * + * @throws RasterFormatException if <code>bands</code> is not + * <code>null</code> and <code>bands.length != 1</code>. + */ + public SampleModel createSubsetSampleModel(int[] bands) + { + if (bands != null && bands.length != 1) + throw new RasterFormatException("MultiPixelPackedSampleModel only" + + " supports one band"); + return new MultiPixelPackedSampleModel(dataType, width, height, + numberOfBits, scanlineStride, dataBitOffset); + } + + /** + * Extract one pixel and return in an array of transfer type. + * + * Extracts the pixel at x, y from data and stores into the 0th index of the + * array obj, since there is only one band. If obj is null, a new array of + * getTransferType() is created. + * + * @param x The x-coordinate of the pixel rectangle to store in + * <code>obj</code>. + * @param y The y-coordinate of the pixel rectangle to store in + * <code>obj</code>. + * @param obj The primitive array to store the pixels into or null to force + * creation. + * @param data The DataBuffer that is the source of the pixel data. + * @return The primitive array containing the pixel data. + * @see java.awt.image.SampleModel#getDataElements(int, int, Object, + * DataBuffer) + */ + public Object getDataElements(int x, int y, Object obj, DataBuffer data) + { + int pixel = getSample(x, y, 0, data); + switch (getTransferType()) + { + case DataBuffer.TYPE_BYTE: + if (obj == null) + obj = new byte[1]; + ((byte[]) obj)[0] = (byte) pixel; + return obj; + case DataBuffer.TYPE_USHORT: + if (obj == null) + obj = new short[1]; + ((short[]) obj)[0] = (short) pixel; + return obj; + case DataBuffer.TYPE_INT: + if (obj == null) + obj = new int[1]; + ((int[]) obj)[0] = pixel; + return obj; + default: + // Seems like the only sensible thing to do. + throw new ClassCastException(); + } + } + + /** + * Returns an array (of length 1) containing the sample for the pixel at + * (x, y) in the specified data buffer. If <code>iArray</code> is not + * <code>null</code>, it will be populated with the sample value and + * returned as the result of this function (this avoids allocating a new + * array instance). + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param iArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return An array containing the pixel sample value. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) + { + if (iArray == null) + iArray = new int[1]; + iArray[0] = getSample(x, y, 0, data); + return iArray; + } + + /** + * Returns the sample value for the pixel at (x, y) in the specified data + * buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample value. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public int getSample(int x, int y, int b, DataBuffer data) + { + int pos = + ((dataBitOffset + x * numberOfBits) % elemBits) / numberOfBits; + int offset = getOffset(x, y); + int samples = data.getElem(offset); + return (samples & bitMasks[pos]) >>> bitOffsets[pos]; + } + + /** + * Set the pixel at x, y to the value in the first element of the primitive + * array obj. + * + * @param x The x-coordinate of the data elements in <code>obj</code>. + * @param y The y-coordinate of the data elements in <code>obj</code>. + * @param obj The primitive array containing the data elements to set. + * @param data The DataBuffer to store the data elements into. + */ + public void setDataElements(int x, int y, Object obj, DataBuffer data) + { + int transferType = getTransferType(); + try + { + switch (transferType) + { + case DataBuffer.TYPE_BYTE: + { + byte[] in = (byte[]) obj; + setSample(x, y, 0, in[0] & 0xFF, data); + return; + } + case DataBuffer.TYPE_USHORT: + { + short[] in = (short[]) obj; + setSample(x, y, 0, in[0] & 0xFFFF, data); + return; + } + case DataBuffer.TYPE_INT: + { + int[] in = (int[]) obj; + setSample(x, y, 0, in[0], data); + return; + } + default: + throw new ClassCastException("Unsupported data type"); + } + } + catch (ArrayIndexOutOfBoundsException aioobe) + { + String msg = "While writing data elements" + + ", x=" + x + ", y=" + y + + ", width=" + width + ", height=" + height + + ", scanlineStride=" + scanlineStride + + ", offset=" + getOffset(x, y) + + ", data.getSize()=" + data.getSize() + + ", data.getOffset()=" + data.getOffset() + + ": " + aioobe; + throw new ArrayIndexOutOfBoundsException(msg); + } + } + + /** + * Sets the sample value for the pixel at (x, y) in the specified data + * buffer to the specified value. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param iArray the sample value (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>iArray</code> or + * <code>data</code> is <code>null</code>. + * + * @see #setSample(int, int, int, int, DataBuffer) + */ + public void setPixel(int x, int y, int[] iArray, DataBuffer data) + { + setSample(x, y, 0, iArray[0], data); + } + + /** + * Sets the sample value for a band for the pixel at (x, y) in the + * specified data buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param s the sample value. + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public void setSample(int x, int y, int b, int s, DataBuffer data) + { + int bitpos = + ((dataBitOffset + x * numberOfBits) % elemBits) / numberOfBits; + int offset = getOffset(x, y); + + s = s << bitOffsets[bitpos]; + s = s & bitMasks[bitpos]; + + int sample = data.getElem(offset); + sample |= s; + data.setElem(offset, sample); + } + + /** + * Tests this sample model for equality with an arbitrary object. This + * method returns <code>true</code> if and only if: + * <ul> + * <li><code>obj</code> is not <code>null</code>; + * <li><code>obj</code> is an instance of + * <code>MultiPixelPackedSampleModel</code>; + * <li>both models have the same: + * <ul> + * <li><code>dataType</code>; + * <li><code>width</code>; + * <li><code>height</code>; + * <li><code>numberOfBits</code>; + * <li><code>scanlineStride</code>; + * <li><code>dataBitOffsets</code>. + * </ul> + * </li> + * </ul> + * + * @param obj the object (<code>null</code> permitted) + * + * @return <code>true</code> if this model is equal to <code>obj</code>, and + * <code>false</code> otherwise. + */ + public boolean equals(Object obj) + { + if (this == obj) + return true; + if (! (obj instanceof MultiPixelPackedSampleModel)) + return false; + MultiPixelPackedSampleModel that = (MultiPixelPackedSampleModel) obj; + if (this.dataType != that.dataType) + return false; + if (this.width != that.width) + return false; + if (this.height != that.height) + return false; + if (this.numberOfBits != that.numberOfBits) + return false; + if (this.scanlineStride != that.scanlineStride) + return false; + if (this.dataBitOffset != that.dataBitOffset) + return false; + return true; + } + + /** + * Returns a hash code for this <code>MultiPixelPackedSampleModel</code>. + * + * @return A hash code. + */ + public int hashCode() + { + // this hash code won't match Sun's, but that shouldn't matter... + int result = 193; + result = 37 * result + dataType; + result = 37 * result + width; + result = 37 * result + height; + result = 37 * result + numberOfBits; + result = 37 * result + scanlineStride; + result = 37 * result + dataBitOffset; + return result; + } + + /** + * Creates a String with some information about this SampleModel. + * @return A String describing this SampleModel. + * @see java.lang.Object#toString() + */ + public String toString() + { + CPStringBuilder result = new CPStringBuilder(); + result.append(getClass().getName()); + result.append("["); + result.append("scanlineStride=").append(scanlineStride); + for(int i=0; i < bitMasks.length; i+=1) + { + result.append(", mask[").append(i).append("]=0x").append(Integer.toHexString(bitMasks[i])); + } + + result.append("]"); + return result.toString(); + } +} diff --git a/libjava/classpath/java/awt/image/PackedColorModel.java b/libjava/classpath/java/awt/image/PackedColorModel.java new file mode 100644 index 000000000..a89d73b8c --- /dev/null +++ b/libjava/classpath/java/awt/image/PackedColorModel.java @@ -0,0 +1,188 @@ +/* Copyright (C) 2000, 2002, 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import gnu.java.awt.BitMaskExtent; + +import java.awt.Point; +import java.awt.color.ColorSpace; + +/** + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public abstract class PackedColorModel extends ColorModel +{ + private int masks[]; + + /* Package accessibility, the DirectColorModel needs this array */ + int shifts[]; + + public PackedColorModel(ColorSpace cspace, int pixelBits, + int[] colorMaskArray, int alphaMask, + boolean isAlphaPremultiplied, + int transparency, + int transferType) + { + super(pixelBits, calcBitsPerComponent(colorMaskArray, alphaMask), + cspace, (alphaMask != 0), isAlphaPremultiplied, transparency, + transferType); + initMasks(colorMaskArray, alphaMask); + if ((pixelBits<1) || (pixelBits>32)) { + throw new IllegalArgumentException("pixels per bits must be " + + "in the range [1, 32]"); + } + } + + private static int[] calcBitsPerComponent(int[] colorMaskArray, + int alphaMask) + { + int numComponents = colorMaskArray.length; + if (alphaMask != 0) numComponents++; + + int[] bitsPerComponent = new int[numComponents]; + + BitMaskExtent extent = new BitMaskExtent(); + for (int b=0; b<colorMaskArray.length; b++) + { + extent.setMask(colorMaskArray[b]); + bitsPerComponent[b] = extent.bitWidth; + } + if (alphaMask != 0) + { + extent.setMask(alphaMask); + bitsPerComponent[numComponents-1] = extent.bitWidth; + } + return bitsPerComponent; + } + + /** Initializes the masks. */ + private void initMasks(int[] colorMaskArray, int alphaMask) + { + int numComponents = colorMaskArray.length; + if (alphaMask == 0) + { + masks = colorMaskArray; + } + else + { + masks = new int[numComponents+1]; + System.arraycopy(colorMaskArray, 0, + masks, 0, + numComponents); + masks[numComponents++] = alphaMask; + } + + shifts = new int[numComponents]; + + // Bit field handling have been moved to a utility class + BitMaskExtent extent = new BitMaskExtent(); + for (int b=0; b<numComponents; b++) + { + extent.setMask(masks[b]); + shifts[b] = extent.leastSignificantBit; + } + } + + public PackedColorModel(ColorSpace cspace, int pixelBits, + int rmask, int gmask, int bmask, + int amask, boolean isAlphaPremultiplied, + int transparency, + int transferType) + { + this(cspace, pixelBits, makeColorMaskArray(rmask, gmask, bmask), + amask, isAlphaPremultiplied, transparency, transferType); + } + + /* TODO: If there is a alpha mask, it is inefficient to create a + color mask array that will be discarded when the alpha mask is + appended. We should probably create a private constructor that + takes a complete array of masks (color+alpha) as an + argument. */ + + private static int[] makeColorMaskArray(int rmask, int gmask, int bmask) + { + int[] colorMaskArray = { rmask, gmask, bmask }; + return colorMaskArray; + } + + public final int getMask(int index) + { + return masks[index]; + } + + public final int[] getMasks() + { + return masks; + } + + public SampleModel createCompatibleSampleModel(int w, int h) + { + return new SinglePixelPackedSampleModel(transferType, w, h, masks); + } + + public boolean isCompatibleSampleModel(SampleModel sm) + { + if (!super.isCompatibleSampleModel(sm)) return false; + if (!(sm instanceof SinglePixelPackedSampleModel)) return false; + + SinglePixelPackedSampleModel sppsm = + (SinglePixelPackedSampleModel) sm; + return java.util.Arrays.equals(sppsm.getBitMasks(), masks); + } + + public WritableRaster getAlphaRaster(WritableRaster raster) { + if (!hasAlpha()) return null; + + SampleModel sm = raster.getSampleModel(); + int[] alphaBand = { sm.getNumBands() - 1 }; + SampleModel alphaModel = sm.createSubsetSampleModel(alphaBand); + DataBuffer buffer = raster.getDataBuffer(); + Point origin = new Point(0, 0); + return Raster.createWritableRaster(alphaModel, buffer, origin); + } + + public boolean equals(Object obj) + { + if (!super.equals(obj)) return false; + if (!(obj instanceof PackedColorModel)) return false; + + PackedColorModel other = (PackedColorModel) obj; + + return java.util.Arrays.equals(masks, other.masks); + } +} diff --git a/libjava/classpath/java/awt/image/PixelGrabber.java b/libjava/classpath/java/awt/image/PixelGrabber.java new file mode 100644 index 000000000..b83fab571 --- /dev/null +++ b/libjava/classpath/java/awt/image/PixelGrabber.java @@ -0,0 +1,631 @@ +/* PixelGrabber.java -- retrieve a subset of an image's data + Copyright (C) 1999, 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import java.awt.Image; +import java.util.Hashtable; + +/** + * PixelGrabber is an ImageConsumer that extracts a rectangular region + * of pixels from an Image. + */ +public class PixelGrabber implements ImageConsumer +{ + int x, y, offset; + int width = -1; + int height = -1; + int scansize = -1; + boolean forceRGB = true; + + ColorModel model = ColorModel.getRGBdefault(); + int hints; + Hashtable<?,?> props; + + int int_pixel_buffer[]; + boolean ints_delivered = false; + byte byte_pixel_buffer[]; + boolean bytes_delivered = false; + + ImageProducer ip; + int observerStatus; + int consumerStatus; + + private Thread grabberThread; + boolean grabbing = false; + + /** + * Construct a PixelGrabber that will retrieve RGB data from a given + * Image. + * + * The RGB data will be retrieved from a rectangular region + * <code>(x, y, w, h)</code> within the image. The data will be + * stored in the provided <code>pix</code> array, which must have + * been initialized to a size of at least <code>w * h</code>. The + * data for a pixel (m, n) in the grab rectangle will be stored at + * <code>pix[(n - y) * scansize + (m - x) + off]</code>. + * + * @param img the Image from which to grab pixels + * @param x the x coordinate, relative to <code>img</code>'s + * top-left corner, of the grab rectangle's top-left pixel + * @param y the y coordinate, relative to <code>img</code>'s + * top-left corner, of the grab rectangle's top-left pixel + * @param w the width of the grab rectangle, in pixels + * @param h the height of the grab rectangle, in pixels + * @param pix the array in which to store grabbed RGB pixel data + * @param off the offset into the <code>pix</code> array at which to + * start storing RGB data + * @param scansize a set of <code>scansize</code> consecutive + * elements in the <code>pix</code> array represents one row of + * pixels in the grab rectangle + */ + public PixelGrabber(Image img, int x, int y, int w, int h, + int pix[], int off, int scansize) + { + this (img.getSource(), x, y, w, h, pix, off, scansize); + } + + /** + * Construct a PixelGrabber that will retrieve RGB data from a given + * ImageProducer. + * + * The RGB data will be retrieved from a rectangular region + * <code>(x, y, w, h)</code> within the image produced by + * <code>ip</code>. The data will be stored in the provided + * <code>pix</code> array, which must have been initialized to a + * size of at least <code>w * h</code>. The data for a pixel (m, n) + * in the grab rectangle will be stored at + * <code>pix[(n - y) * scansize + (m - x) + off]</code>. + * + * @param ip the ImageProducer from which to grab pixels. This can + * be null. + * @param x the x coordinate of the grab rectangle's top-left pixel, + * specified relative to the top-left corner of the image produced + * by <code>ip</code> + * @param y the y coordinate of the grab rectangle's top-left pixel, + * specified relative to the top-left corner of the image produced + * by <code>ip</code> + * @param w the width of the grab rectangle, in pixels + * @param h the height of the grab rectangle, in pixels + * @param pix the array in which to store grabbed RGB pixel data + * @param off the offset into the <code>pix</code> array at which to + * start storing RGB data + * @param scansize a set of <code>scansize</code> consecutive + * elements in the <code>pix</code> array represents one row of + * pixels in the grab rectangle + */ + public PixelGrabber(ImageProducer ip, int x, int y, int w, int h, + int pix[], int off, int scansize) + { + this.ip = ip; + this.x = x; + this.y = y; + this.width = w; + this.height = h; + this.offset = off; + this.scansize = scansize; + + int_pixel_buffer = pix; + // Initialize the byte array in case ip sends us byte-formatted + // pixel data. + byte_pixel_buffer = new byte[pix.length * 4]; + } + + /** + * Construct a PixelGrabber that will retrieve data from a given + * Image. + * + * The RGB data will be retrieved from a rectangular region + * <code>(x, y, w, h)</code> within the image. The data will be + * stored in an internal array which can be accessed by calling + * <code>getPixels</code>. The data for a pixel (m, n) in the grab + * rectangle will be stored in the returned array at index + * <code>(n - y) * scansize + (m - x) + off</code>. + * If forceRGB is false, then the returned data will be not be + * converted to RGB from its format in <code>img</code>. + * + * If <code>w</code> is negative, the width of the grab region will + * be from x to the right edge of the image. Likewise, if + * <code>h</code> is negative, the height of the grab region will be + * from y to the bottom edge of the image. + * + * @param img the Image from which to grab pixels + * @param x the x coordinate, relative to <code>img</code>'s + * top-left corner, of the grab rectangle's top-left pixel + * @param y the y coordinate, relative to <code>img</code>'s + * top-left corner, of the grab rectangle's top-left pixel + * @param w the width of the grab rectangle, in pixels + * @param h the height of the grab rectangle, in pixels + * @param forceRGB true to force conversion of the rectangular + * region's pixel data to RGB + */ + public PixelGrabber(Image img, + int x, int y, + int w, int h, + boolean forceRGB) + { + this.ip = img.getSource(); + + if (this.ip == null) + throw new NullPointerException("The ImageProducer must not be null."); + + this.x = x; + this.y = y; + width = w; + height = h; + // If width or height is negative, postpone pixel buffer + // initialization until setDimensions is called back by ip. + if (width >= 0 && height >= 0) + { + int_pixel_buffer = new int[width * height]; + byte_pixel_buffer = new byte[width * height]; + } + this.forceRGB = forceRGB; + } + + /** + * Start grabbing pixels. + * + * Spawns an image production thread that calls back to this + * PixelGrabber's ImageConsumer methods. + */ + public synchronized void startGrabbing() + { + // Make sure we're not already grabbing. + if (grabbing == false) + { + grabbing = true; + grabberThread = new Thread () + { + public void run () + { + try + { + ip.startProduction (PixelGrabber.this); + } + catch (Exception ex) + { + imageComplete(ImageConsumer.IMAGEABORTED); + } + } + }; + grabberThread.start (); + } + } + + /** + * Abort pixel grabbing. + */ + public synchronized void abortGrabbing() + { + if (grabbing) + { + // Interrupt the grabbing thread. + Thread moribund = grabberThread; + grabberThread = null; + moribund.interrupt(); + + imageComplete (ImageConsumer.IMAGEABORTED); + } + } + + /** + * Have our Image or ImageProducer start sending us pixels via our + * ImageConsumer methods and wait for all pixels in the grab + * rectangle to be delivered. + * + * @return true if successful, false on abort or error + * + * @throws InterruptedException if interrupted by another thread. + */ + public synchronized boolean grabPixels() throws InterruptedException + { + return grabPixels(0); + } + + /** + * grabPixels's behavior depends on the value of <code>ms</code>. + * + * If ms < 0, return true if all pixels from the source image have + * been delivered, false otherwise. Do not wait. + * + * If ms >= 0 then we request that our Image or ImageProducer start + * delivering pixels to us via our ImageConsumer methods. + * + * If ms > 0, wait at most <code>ms</code> milliseconds for + * delivery of all pixels within the grab rectangle. + * + * If ms == 0, wait until all pixels have been delivered. + * + * @return true if all pixels from the source image have been + * delivered, false otherwise + * + * @throws InterruptedException if this thread is interrupted while + * we are waiting for pixels to be delivered + */ + public synchronized boolean grabPixels(long ms) throws InterruptedException + { + if (ms < 0) + return ((observerStatus & (ImageObserver.FRAMEBITS + | ImageObserver.ALLBITS)) != 0); + + // Spawn a new ImageProducer thread to send us the image data via + // our ImageConsumer methods. + startGrabbing(); + + if (ms > 0) + { + long stop_time = System.currentTimeMillis() + ms; + long time_remaining; + while (grabbing) + { + time_remaining = stop_time - System.currentTimeMillis(); + if (time_remaining <= 0) + break; + wait (time_remaining); + } + abortGrabbing (); + } + else + wait (); + + // If consumerStatus is non-zero then the image is done loading or + // an error has occurred. + if (consumerStatus != 0) + return setObserverStatus (); + + return ((observerStatus & (ImageObserver.FRAMEBITS + | ImageObserver.ALLBITS)) != 0); + } + + // Set observer status flags based on the current consumer status + // flags. Return true if the consumer flags indicate that the + // image was loaded successfully, or false otherwise. + private synchronized boolean setObserverStatus () + { + boolean retval = false; + + if ((consumerStatus & IMAGEERROR) != 0) + observerStatus |= ImageObserver.ERROR; + + if ((consumerStatus & IMAGEABORTED) != 0) + observerStatus |= ImageObserver.ABORT; + + if ((consumerStatus & STATICIMAGEDONE) != 0) + { + observerStatus |= ImageObserver.ALLBITS; + retval = true; + } + + if ((consumerStatus & SINGLEFRAMEDONE) != 0) + { + observerStatus |= ImageObserver.FRAMEBITS; + retval = true; + } + + return retval; + } + + /** + * @return the status of the pixel grabbing thread, represented by a + * bitwise OR of ImageObserver flags + */ + public synchronized int getStatus() + { + return observerStatus; + } + + /** + * @return the width of the grab rectangle in pixels, or a negative + * number if the ImageProducer has not yet called our setDimensions + * method + */ + public synchronized int getWidth() + { + return width; + } + + /** + * @return the height of the grab rectangle in pixels, or a negative + * number if the ImageProducer has not yet called our setDimensions + * method + */ + public synchronized int getHeight() + { + return height; + } + + /** + * @return a byte array of pixel data if ImageProducer delivered + * pixel data using the byte[] variant of setPixels, or an int array + * otherwise + */ + public synchronized Object getPixels() + { + if (ints_delivered) + return int_pixel_buffer; + else if (bytes_delivered) + return byte_pixel_buffer; + else + return null; + } + + /** + * @return the ColorModel currently being used for the majority of + * pixel data conversions + */ + public synchronized ColorModel getColorModel() + { + return model; + } + + /** + * Our <code>ImageProducer</code> calls this method to indicate the + * size of the image being produced. + * + * setDimensions is an ImageConsumer method. None of PixelGrabber's + * ImageConsumer methods should be called by code that instantiates + * a PixelGrabber. They are only made public so they can be called + * by the PixelGrabber's ImageProducer. + * + * @param width the width of the image + * @param height the height of the image + */ + public synchronized void setDimensions(int width, int height) + { + // Our width wasn't set when we were constructed. Set our width + // so that the grab region includes all pixels from x to the right + // edge of the source image. + if (this.width < 0) + this.width = width - x; + + // Our height wasn't set when we were constructed. Set our height + // so that the grab region includes all pixels from y to the + // bottom edge of the source image. + if (this.height < 0) + this.height = height - y; + + if (scansize < 0) + scansize = this.width; + + if (int_pixel_buffer == null) + int_pixel_buffer = new int[this.width * this.height]; + + if (byte_pixel_buffer == null) + byte_pixel_buffer = new byte[this.width * this.height]; + } + + /** + * Our <code>ImageProducer</code> may call this method to send us a + * list of its image's properties. + * + * setProperties is an ImageConsumer method. None of PixelGrabber's + * ImageConsumer methods should be called by code that instantiates + * a PixelGrabber. They are only made public so they can be called + * by the PixelGrabber's ImageProducer. + * + * @param props a list of properties associated with the image being + * produced + */ + public synchronized void setProperties(Hashtable<?,?> props) + { + this.props = props; + } + + /** + * Our ImageProducer will call <code>setColorModel</code> to + * indicate the model used by the majority of calls to + * <code>setPixels</code>. Each call to <code>setPixels</code> + * could however indicate a different <code>ColorModel</code>. + * + * setColorModel is an ImageConsumer method. None of PixelGrabber's + * ImageConsumer methods should be called by code that instantiates + * a PixelGrabber. They are only made public so they can be called + * by the PixelGrabber's ImageProducer. + * + * @param model the color model to be used most often by setPixels + * + * @see ColorModel + */ + public synchronized void setColorModel(ColorModel model) + { + this.model = model; + } + + /** + * Our <code>ImageProducer</code> may call this method with a + * bit mask of hints from any of <code>RANDOMPIXELORDER</code>, + * <code>TOPDOWNLEFTRIGHT</code>, <code>COMPLETESCANLINES</code>, + * <code>SINGLEPASS</code>, <code>SINGLEFRAME</code>. + * + * setHints is an ImageConsumer method. None of PixelGrabber's + * ImageConsumer methods should be called by code that instantiates + * a PixelGrabber. They are only made public so they can be called + * by the PixelGrabber's ImageProducer. + * + * @param flags a bit mask of hints + */ + public synchronized void setHints(int flags) + { + hints = flags; + } + + /** + * Our ImageProducer calls setPixels to deliver a subset of its + * pixels. + * + * Each element of the pixels array represents one pixel. The + * pixel data is formatted according to the color model model. + * The x and y parameters are the coordinates of the rectangular + * region of pixels being delivered to this ImageConsumer, + * specified relative to the top left corner of the image being + * produced. Likewise, w and h are the pixel region's dimensions. + * + * @param x x coordinate of pixel block + * @param y y coordinate of pixel block + * @param w width of pixel block + * @param h height of pixel block + * @param model color model used to interpret pixel data + * @param pixels pixel block data + * @param offset offset into pixels array + * @param scansize width of one row in the pixel block + */ + public synchronized void setPixels(int x, int y, int w, int h, + ColorModel model, byte[] pixels, + int offset, int scansize) + { + ColorModel currentModel; + if (model != null) + currentModel = model; + else + currentModel = this.model; + + for(int yp = y; yp < (y + h); yp++) + { + for(int xp = x; xp < (x + w); xp++) + { + // Check if the coordinates (xp, yp) are within the + // pixel block that we are grabbing. + if(xp >= this.x + && yp >= this.y + && xp < (this.x + this.width) + && yp < (this.y + this.height)) + { + int i = (yp - this.y) * this.scansize + (xp - this.x) + this.offset; + int p = (yp - y) * scansize + (xp - x) + offset; + if (forceRGB) + { + ints_delivered = true; + + int_pixel_buffer[i] = currentModel.getRGB (pixels[p] & 0xFF); + } + else + { + bytes_delivered = true; + + byte_pixel_buffer[i] = pixels[p]; + } + } + } + } + } + + /** + * Our ImageProducer calls setPixels to deliver a subset of its + * pixels. + * + * Each element of the pixels array represents one pixel. The + * pixel data is formatted according to the color model model. + * The x and y parameters are the coordinates of the rectangular + * region of pixels being delivered to this ImageConsumer, + * specified relative to the top left corner of the image being + * produced. Likewise, w and h are the pixel region's dimensions. + * + * @param x x coordinate of pixel block + * @param y y coordinate of pixel block + * @param w width of pixel block + * @param h height of pixel block + * @param model color model used to interpret pixel data + * @param pixels pixel block data + * @param offset offset into pixels array + * @param scansize width of one row in the pixel block + */ + public synchronized void setPixels(int x, int y, int w, int h, + ColorModel model, int[] pixels, + int offset, int scansize) + { + ColorModel currentModel; + if (model != null) + currentModel = model; + else + currentModel = this.model; + + ints_delivered = true; + + for(int yp = y; yp < (y + h); yp++) + { + for(int xp = x; xp < (x + w); xp++) + { + // Check if the coordinates (xp, yp) are within the + // pixel block that we are grabbing. + if(xp >= this.x + && yp >= this.y + && xp < (this.x + this.width) + && yp < (this.y + this.height)) + { + int i = (yp - this.y) * this.scansize + (xp - this.x) + this.offset; + int p = (yp - y) * scansize + (xp - x) + offset; + if (forceRGB) + int_pixel_buffer[i] = currentModel.getRGB (pixels[p]); + else + int_pixel_buffer[i] = pixels[p]; + } + } + } + } + + /** + * Our <code>ImageProducer</code> calls this method to inform us + * that a single frame or the entire image is complete. The method + * is also used to inform us of an error in loading or producing the + * image. + * + * @param status the status of image production, represented by a + * bitwise OR of ImageConsumer flags + */ + public synchronized void imageComplete(int status) + { + consumerStatus = status; + setObserverStatus (); + grabbing = false; + if (ip != null) + ip.removeConsumer (this); + + notifyAll (); + } + + /** + * @return the return value of getStatus + * + * @specnote The newer getStatus should be used in place of status. + */ + public synchronized int status() + { + return getStatus(); + } +} diff --git a/libjava/classpath/java/awt/image/PixelInterleavedSampleModel.java b/libjava/classpath/java/awt/image/PixelInterleavedSampleModel.java new file mode 100644 index 000000000..13134b413 --- /dev/null +++ b/libjava/classpath/java/awt/image/PixelInterleavedSampleModel.java @@ -0,0 +1,123 @@ +/* PixelInterleavedSampleModel.java + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + + +/** + * A <code>SampleModel</code> that uses exactly one element of the + * raster’s {@link DataBuffer} per pixel, holds all bands in a + * single bank, and stores band data in pixel-interleaved manner. + * + * @since 1.2 + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class PixelInterleavedSampleModel + extends ComponentSampleModel +{ + public PixelInterleavedSampleModel(int dataType, int width, int height, + int pixelStride, int scanlineStride, + int[] bandOffsets) + { + super(dataType, width, height, pixelStride, scanlineStride, + bandOffsets); + } + + + /** + * Creates a new <code>SampleModel</code> that is like this one, but + * uses the specified width and height. + * + * @param width the number of pixels in the horizontal direction. + * + * @param height the number of pixels in the vertical direction. + */ + public SampleModel createCompatibleSampleModel(int width, int height) + { + // Find minimum band offset. + int minBandoff = bandOffsets[0]; + int numBands = bandOffsets.length; + for (int i = 1; i < numBands; i++) + { + if (bandOffsets[i] < minBandoff) + { + minBandoff = bandOffsets[i]; + } + } + // Adjust band offsets so that minimum offset is at 0. + int[] bandOff; + if (minBandoff > 0) + { + bandOff = new int[numBands]; + for (int i = 0; i < numBands; i++) + { + bandOff[i] = bandOffsets[i] - minBandoff; + } + } + else + { + bandOff = bandOffsets; + } + // Adjust scanline stride for new width. + return new PixelInterleavedSampleModel(dataType, width, height, + pixelStride, pixelStride * width, + bandOff); + } + + + /** + * Creates a new <code>SampleModel</code> that is like this one, but + * uses only a subset of its bands. + * + * @param bands an array whose elements indicate which bands shall + * be part of the subset. For example, <code>[0, 2, 3]</code> would + * create a SampleModel containing bands #0, #2 and #3. + */ + public SampleModel createSubsetSampleModel(int[] bands) + { + int[] subOffsets; + + subOffsets = new int[bands.length]; + for (int i = 0; i < bands.length; i++) + subOffsets[i] = bandOffsets[bands[i]]; + + return new PixelInterleavedSampleModel(dataType, width, height, + pixelStride, scanlineStride, + subOffsets); + } +} diff --git a/libjava/classpath/java/awt/image/RGBImageFilter.java b/libjava/classpath/java/awt/image/RGBImageFilter.java new file mode 100644 index 000000000..1354c3a80 --- /dev/null +++ b/libjava/classpath/java/awt/image/RGBImageFilter.java @@ -0,0 +1,265 @@ +/* RGBImageFilter.java -- Java class for filtering Pixels by RGB values + Copyright (C) 1999, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +/** + * A filter designed to filter images in the default RGBColorModel regardless of + * the ImageProducer's ColorModel. + * + * @author Mark Benvenuto (mcb54@columbia.edu) + */ +public abstract class RGBImageFilter extends ImageFilter +{ + protected ColorModel origmodel; + + protected ColorModel newmodel; + + /** + * Specifies whether to apply the filter to the index entries of the + * IndexColorModel. Subclasses should set this to true if the filter + * does not depend on the pixel's coordinate. + */ + protected boolean canFilterIndexColorModel = false; + + /** + * Construct new RGBImageFilter. + */ + public RGBImageFilter() + { + } + + /** + * Sets the ColorModel used to filter with. If the specified ColorModel is + * IndexColorModel and canFilterIndexColorModel is true, we subsitute the + * ColorModel for a filtered one here and in setPixels whenever the original + * one appears. Otherwise overrides the default ColorModel of ImageProducer + * and specifies the default RGBColorModel + * + * @param model the color model to be used most often by setPixels + * + * @see ColorModel + */ + public void setColorModel(ColorModel model) + { + if ((model instanceof IndexColorModel) && canFilterIndexColorModel) + { + ColorModel newCM = filterIndexColorModel((IndexColorModel) model); + substituteColorModel(model, newCM); + consumer.setColorModel(newmodel); + } + else + { + consumer.setColorModel(ColorModel.getRGBdefault()); + } + } + + /** + * Registers a new ColorModel to subsitute for the old ColorModel when + * setPixels encounters the a pixel with the old ColorModel. The pixel + * remains unchanged except for a new ColorModel. + * + * @param oldcm the old ColorModel + * @param newcm the new ColorModel + */ + public void substituteColorModel(ColorModel oldcm, ColorModel newcm) + { + origmodel = oldcm; + newmodel = newcm; + } + + /** + * Filters an IndexColorModel through the filterRGB function. Uses + * coordinates of -1 to indicate its filtering an index and not a pixel. + * + * @param icm an IndexColorModel to filter + */ + public IndexColorModel filterIndexColorModel(IndexColorModel icm) + { + int len = icm.getMapSize(); + byte[] reds = new byte[len]; + byte[] greens = new byte[len]; + byte[] blues = new byte[len]; + byte[] alphas = new byte[len]; + + icm.getAlphas( alphas ); + icm.getReds( reds ); + icm.getGreens( greens ); + icm.getBlues( blues ); + + int transparent = icm.getTransparentPixel(); + boolean needAlpha = false; + for( int i = 0; i < len; i++ ) + { + int rgb = filterRGB(-1, -1, icm.getRGB(i)); + alphas[i] = (byte) (rgb >> 24); + if (alphas[i] != ((byte) 0xff) && i != transparent) + needAlpha = true; + reds[i] = (byte) (rgb >> 16); + greens[i] = (byte) (rgb >> 8); + blues[i] = (byte) (rgb); + } + IndexColorModel newIcm; + if (needAlpha) + newIcm = new IndexColorModel(icm.getPixelSize(), len, reds, greens, + blues, alphas); + else + newIcm = new IndexColorModel(icm.getPixelSize(), len, reds, greens, + blues, transparent); + return newIcm; + } + + /** + * This functions filters a set of RGB pixels through filterRGB. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the + * <code>pixels</code> array + * @param scansize the width to use in extracting pixels from the + * <code>pixels</code> array + */ + public void filterRGBPixels(int x, int y, int w, int h, int[] pixels, + int offset, int scansize) + { + int index = offset; + for (int yp = 0; yp < h; yp++) + { + for (int xp = 0; xp < w; xp++) + { + pixels[index] = filterRGB(xp + x, yp + y, pixels[index]); + index++; + } + index += scansize - w; + } + consumer.setPixels(x, y, w, h, ColorModel.getRGBdefault(), pixels, offset, + scansize); + } + + /** + * If the ColorModel is the same ColorModel which as already converted + * then it converts it the converted ColorModel. Otherwise it passes the + * array of pixels through filterRGBpixels. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the <code>ColorModel</code> used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the <code>pixels</code> + * array + * @param scansize the width to use in extracting pixels from the + * <code>pixels</code> array + */ + public void setPixels(int x, int y, int w, int h, ColorModel model, + byte[] pixels, int offset, int scansize) + { + if (model == origmodel) + { + consumer.setPixels(x, y, w, h, newmodel, pixels, offset, scansize); + } + else + { + int[] filtered = new int[w]; + int index = offset; + for (int yp = 0; yp < h; yp++) + { + for (int xp = 0; xp < w; xp++) + { + filtered[xp] = model.getRGB((pixels[index] & 0xff)); + index++; + } + index += scansize - w; + filterRGBPixels(x, y + yp, w, 1, filtered, 0, w); + } + } + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as an <code>int</code> at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the <code>ColorModel</code> used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the <code>pixels</code> + * array + * @param scansize the width to use in extracting pixels from the + * <code>pixels</code> array + */ + public void setPixels(int x, int y, int w, int h, ColorModel model, + int[] pixels, int offset, int scansize) + { + if (model == origmodel) + { + consumer.setPixels(x, y, w, h, newmodel, pixels, offset, scansize); + } + else + { + int[] filtered = new int[w]; + int index = offset; + for (int yp = 0; yp < h; yp++) + { + for (int xp = 0; xp < w; xp++) + { + filtered[xp] = model.getRGB((pixels[index])); + index++; + } + index += scansize - w; + filterRGBPixels(x, y + yp, w, 1, filtered, 0, w); + } + } + } + + /** + * Filters a single pixel from the default ColorModel. + * + * @param x x-coordinate + * @param y y-coordinate + * @param rgb color + */ + public abstract int filterRGB(int x, int y, int rgb); +} diff --git a/libjava/classpath/java/awt/image/Raster.java b/libjava/classpath/java/awt/image/Raster.java new file mode 100644 index 000000000..6d99c3683 --- /dev/null +++ b/libjava/classpath/java/awt/image/Raster.java @@ -0,0 +1,973 @@ +/* Copyright (C) 2000, 2002, 2003, 2006, Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import gnu.java.lang.CPStringBuilder; + +import java.awt.Point; +import java.awt.Rectangle; + +/** + * A rectangular collection of pixels composed from a {@link DataBuffer} which + * stores the pixel values, and a {@link SampleModel} which is used to retrieve + * the pixel values. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public class Raster +{ + /** The sample model used to access the pixel values. */ + protected SampleModel sampleModel; + + /** The data buffer used to store the pixel values. */ + protected DataBuffer dataBuffer; + + /** The x-coordinate of the top left corner of the raster. */ + protected int minX; + + /** The y-coordinate of the top left corner of the raster. */ + protected int minY; + + /** The width of the raster. */ + protected int width; + + /** The height of the raster. */ + protected int height; + + protected int sampleModelTranslateX; + + protected int sampleModelTranslateY; + + /** The number of bands. */ + protected int numBands; + + protected int numDataElements; + + /** The raster's parent. */ + protected Raster parent; + + /** + * Creates a new raster. + * + * @param sampleModel the sample model. + * @param origin the origin. + */ + protected Raster(SampleModel sampleModel, Point origin) + { + this(sampleModel, sampleModel.createDataBuffer(), origin); + } + + /** + * Creates a new raster. + * + * @param sampleModel the sample model. + * @param dataBuffer the data buffer. + * @param origin the origin. + */ + protected Raster(SampleModel sampleModel, DataBuffer dataBuffer, + Point origin) + { + this(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y, + sampleModel.getWidth(), sampleModel.getHeight()), origin, null); + } + + /** + * Creates a new raster. + * + * @param sampleModel the sample model. + * @param dataBuffer the data buffer. + * @param aRegion the raster's bounds. + * @param sampleModelTranslate the translation (<code>null</code> permitted). + * @param parent the raster's parent. + */ + protected Raster(SampleModel sampleModel, DataBuffer dataBuffer, + Rectangle aRegion, Point sampleModelTranslate, Raster parent) + { + this.sampleModel = sampleModel; + this.dataBuffer = dataBuffer; + this.minX = aRegion.x; + this.minY = aRegion.y; + this.width = aRegion.width; + this.height = aRegion.height; + + // If sampleModelTranslate is null, use (0,0). Methods such as + // Raster.createRaster are specified to allow for a null argument. + if (sampleModelTranslate != null) + { + this.sampleModelTranslateX = sampleModelTranslate.x; + this.sampleModelTranslateY = sampleModelTranslate.y; + } + + this.numBands = sampleModel.getNumBands(); + this.numDataElements = sampleModel.getNumDataElements(); + this.parent = parent; + } + + /** + * Creates an interleaved raster using the specified data type. + * + * @param dataType the data type. + * @param w the width. + * @param h the height. + * @param bands the number of bands. + * @param location + * + * @return The new raster. + */ + public static WritableRaster createInterleavedRaster(int dataType, + int w, int h, int bands, Point location) + { + int[] bandOffsets = new int[bands]; + // TODO: Maybe not generate this every time. + for (int b = 0; b < bands; b++) + bandOffsets[b] = b; + + int scanlineStride = bands * w; + return createInterleavedRaster(dataType, w, h, scanlineStride, bands, + bandOffsets, location); + } + + /** + * Creates an interleaved raster. + * + * @param dataType the data type. + * @param w the width. + * @param h the height. + * @param scanlineStride the number of data elements from a sample on one + * row to the corresponding sample on the next row. + * @param pixelStride the number of elements from a sample in one pixel to + * the corresponding sample in the next pixel. + * @param bandOffsets the band offsets. + * @param location + * + * @return The new raster. + */ + public static WritableRaster createInterleavedRaster(int dataType, + int w, int h, int scanlineStride, int pixelStride, int[] bandOffsets, + Point location) + { + SampleModel sm = new ComponentSampleModel(dataType, w, h, pixelStride, + scanlineStride, bandOffsets); + return createWritableRaster(sm, location); + } + + /** + * Creates a new banded raster. + * + * @param dataType the data type. + * @param w the width. + * @param h the height. + * @param bands the number of bands. + * @param location + * + * @return The new raster. + */ + public static WritableRaster createBandedRaster(int dataType, int w, int h, + int bands, Point location) + { + SampleModel sm = new BandedSampleModel(dataType, w, h, bands); + return createWritableRaster(sm, location); + } + + /** + * Creates a new banded raster. + * + * @param dataType the data type. + * @param w the width. + * @param h the height. + * @param scanlineStride the number of data elements from a sample on one + * row to the corresponding sample on the next row. + * @param bankIndices the index for each bank. + * @param bandOffsets the offset for each band. + * @param location + * + * @return The new raster. + */ + public static WritableRaster createBandedRaster(int dataType, int w, int h, + int scanlineStride, int[] bankIndices, int[] bandOffsets, Point location) + { + SampleModel sm = new BandedSampleModel(dataType, w, h, scanlineStride, + bankIndices, bandOffsets); + return createWritableRaster(sm, location); + } + + /** + * Creates a new packed raster. + * + * @param dataType the data type. + * @param w the width. + * @param h the height. + * @param bandMasks the bit mask for each band. + * @param location + * + * @return The new raster. + */ + public static WritableRaster createPackedRaster(int dataType, int w, int h, + int[] bandMasks, Point location) + { + SampleModel sm = new SinglePixelPackedSampleModel(dataType, w, h, + bandMasks); + return createWritableRaster(sm, location); + } + + /** + * Creates a new raster. + * + * @param dataType the data type. + * @param w the width. + * @param h the height. + * @param bands the number of bands. + * @param bitsPerBand the number of bits per band. + * @param location + * + * @return The new raster. + */ + public static WritableRaster createPackedRaster(int dataType, + int w, int h, int bands, int bitsPerBand, Point location) + { + if (bands <= 0 || (bands * bitsPerBand > getTypeBits(dataType))) + throw new IllegalArgumentException(); + + SampleModel sm; + + if (bands == 1) + sm = new MultiPixelPackedSampleModel(dataType, w, h, bitsPerBand); + else + { + int[] bandMasks = new int[bands]; + int mask = 0x1; + for (int bits = bitsPerBand; --bits != 0;) + mask = (mask << 1) | 0x1; + for (int i = 0; i < bands; i++) + { + bandMasks[i] = mask; + mask <<= bitsPerBand; + } + + sm = new SinglePixelPackedSampleModel(dataType, w, h, bandMasks); + } + return createWritableRaster(sm, location); + } + + /** + * Creates a new interleaved raster. + * + * @param dataBuffer the data buffer. + * @param w the width. + * @param h the height. + * @param scanlineStride the number of data elements from a sample on one + * row to the corresponding sample on the next row. + * @param pixelStride the number of elements from a sample in one pixel to + * the corresponding sample in the next pixel. + * @param bandOffsets the offset for each band. + * @param location + * + * @return The new raster. + */ + public static WritableRaster createInterleavedRaster(DataBuffer dataBuffer, + int w, int h, int scanlineStride, int pixelStride, int[] bandOffsets, + Point location) + { + SampleModel sm = new ComponentSampleModel(dataBuffer.getDataType(), + w, h, pixelStride, scanlineStride, bandOffsets); + return createWritableRaster(sm, dataBuffer, location); + } + + /** + * Creates a new banded raster. + * + * @param dataBuffer the data buffer. + * @param w the width. + * @param h the height. + * @param scanlineStride the number of data elements from a sample on one + * row to the corresponding sample on the next row. + * @param bankIndices the index for each bank. + * @param bandOffsets the band offsets. + * @param location + * + * @return The new raster. + */ + public static WritableRaster createBandedRaster(DataBuffer dataBuffer, + int w, int h, int scanlineStride, int[] bankIndices, int[] bandOffsets, + Point location) + { + SampleModel sm = new BandedSampleModel(dataBuffer.getDataType(), + w, h, scanlineStride, bankIndices, bandOffsets); + return createWritableRaster(sm, dataBuffer, location); + } + + /** + * Creates a new packed raster. + * + * @param dataBuffer the data buffer. + * @param w the width. + * @param h the height. + * @param scanlineStride the number of data elements from a sample on one + * row to the corresponding sample on the next row. + * @param bandMasks the bit mask for each band. + * @param location + * + * @return The new raster. + */ + public static WritableRaster createPackedRaster(DataBuffer dataBuffer, + int w, int h, int scanlineStride, int[] bandMasks, Point location) + { + SampleModel sm = new SinglePixelPackedSampleModel(dataBuffer.getDataType(), + w, h, scanlineStride, bandMasks); + return createWritableRaster(sm, dataBuffer, location); + } + + /** + * Creates a new packed raster. + * + * @param dataBuffer the data buffer. + * @param w the width. + * @param h the height. + * @param bitsPerPixel the number of bits per pixel. + * @param location + * + * @return The new raster. + */ + public static WritableRaster createPackedRaster(DataBuffer dataBuffer, + int w, int h, int bitsPerPixel, Point location) + { + SampleModel sm = new MultiPixelPackedSampleModel(dataBuffer.getDataType(), + w, h, bitsPerPixel); + return createWritableRaster(sm, dataBuffer, location); + } + + /** + * Creates a new raster. + * + * @param sm the sample model. + * @param db the data buffer. + * @param location + * + * @return The new raster. + */ + public static Raster createRaster(SampleModel sm, DataBuffer db, + Point location) + { + return new Raster(sm, db, location); + } + + /** + * Creates a new writable raster. + * + * @param sm the sample model. + * @param location + * + * @return The new writable raster. + */ + public static WritableRaster createWritableRaster(SampleModel sm, + Point location) + { + return new WritableRaster(sm, location); + } + + /** + * Creates a new writable raster. + * + * @param sm the sample model. + * @param db the data buffer. + * @param location + * + * @return The new writable raster. + */ + public static WritableRaster createWritableRaster(SampleModel sm, + DataBuffer db, Point location) + { + return new WritableRaster(sm, db, location); + } + + /** + * Returns the raster's parent. + * + * @return The raster's parent. + */ + public Raster getParent() + { + return parent; + } + + /** + * Returns the x-translation. + * + * @return The x-translation. + */ + public final int getSampleModelTranslateX() + { + return sampleModelTranslateX; + } + + /** + * Returns the y-translation. + * + * @return The y-translation. + */ + public final int getSampleModelTranslateY() + { + return sampleModelTranslateY; + } + + /** + * Creates a new writable raster that is compatible with this raster. + * + * @return A new writable raster. + */ + public WritableRaster createCompatibleWritableRaster() + { + return new WritableRaster(getSampleModel(), new Point(minX, minY)); + } + + /** + * Creates a new writable raster that is compatible with this raster. + * + * @param w the width. + * @param h the height. + * + * @return A new writable raster. + */ + public WritableRaster createCompatibleWritableRaster(int w, int h) + { + return createCompatibleWritableRaster(minX, minY, w, h); + } + + /** + * Creates a new writable raster that is compatible with this raster, with + * the specified bounds. + * + * @param rect the raster bounds. + * + * @return A new writable raster. + */ + public WritableRaster createCompatibleWritableRaster(Rectangle rect) + { + return createCompatibleWritableRaster(rect.x, rect.y, + rect.width, rect.height); + } + + /** + * Creates a new writable raster that is compatible with this raster, with + * the specified bounds. + * + * @param x the x-coordinate of the top-left corner of the raster. + * @param y the y-coordinate of the top-left corner of the raster. + * @param w the raster width. + * @param h the raster height. + * + * @return A new writable raster. + */ + public WritableRaster createCompatibleWritableRaster(int x, int y, + int w, int h) + { + SampleModel sm = getSampleModel().createCompatibleSampleModel(w, h); + return new WritableRaster(sm, sm.createDataBuffer(), new Point(x, y)); + } + + public Raster createTranslatedChild(int childMinX, int childMinY) { + int tcx = sampleModelTranslateX - minX + childMinX; + int tcy = sampleModelTranslateY - minY + childMinY; + + return new Raster(sampleModel, dataBuffer, + new Rectangle(childMinX, childMinY, width, height), + new Point(tcx, tcy), this); + } + + public Raster createChild(int parentX, int parentY, int width, + int height, int childMinX, int childMinY, + int[] bandList) + { + if (parentX < minX || parentX + width > minX + this.width + || parentY < minY || parentY + height > minY + this.height) + throw new RasterFormatException("Child raster extends beyond parent"); + + SampleModel sm = (bandList == null) ? + sampleModel : + sampleModel.createSubsetSampleModel(bandList); + + /* + data origin + / + +------------------------- + |\. __ parent trans + | \`. + | \ `. parent origin + | \ `. / + | /\ +-------- - - + |trans\ /<\-- deltaTrans + |child +-+-\---- - - + | /|`| \__ parent [x, y] + |child | |`. \ + |origin| : `.\ + | | / `\ + | : / + + | child [x, y] + + parent_xy - parent_trans = child_xy - child_trans + + child_trans = parent_trans + child_xy - parent_xy + */ + + return new Raster(sm, dataBuffer, + new Rectangle(childMinX, childMinY, width, height), + new Point(sampleModelTranslateX + childMinX - parentX, + sampleModelTranslateY + childMinY - parentY), + this); + } + + /** + * Returns a new rectangle containing the bounds of this raster. + * + * @return A new rectangle containing the bounds of this raster. + */ + public Rectangle getBounds() + { + return new Rectangle(minX, minY, width, height); + } + + /** + * Returns the x-coordinate of the top left corner of the raster. + * + * @return The x-coordinate of the top left corner of the raster. + */ + public final int getMinX() + { + return minX; + } + + /** + * Returns the t-coordinate of the top left corner of the raster. + * + * @return The t-coordinate of the top left corner of the raster. + */ + public final int getMinY() + { + return minY; + } + + /** + * Returns the width of the raster. + * + * @return The width of the raster. + */ + public final int getWidth() + { + return width; + } + + /** + * Returns the height of the raster. + * + * @return The height of the raster. + */ + public final int getHeight() + { + return height; + } + + /** + * Returns the number of bands for this raster. + * + * @return The number of bands. + */ + public final int getNumBands() + { + return numBands; + } + + public final int getNumDataElements() + { + return numDataElements; + } + + /** + * Returns the transfer type for the raster (this is determined by the + * raster's sample model). + * + * @return The transfer type. + */ + public final int getTransferType() + { + return sampleModel.getTransferType(); + } + + /** + * Returns the data buffer that stores the pixel data for this raster. + * + * @return The data buffer. + */ + public DataBuffer getDataBuffer() + { + return dataBuffer; + } + + /** + * Returns the sample model that accesses the data buffer (to extract pixel + * data) for this raster. + * + * @return The sample model. + */ + public SampleModel getSampleModel() + { + return sampleModel; + } + + public Object getDataElements(int x, int y, Object outData) + { + return sampleModel.getDataElements(x - sampleModelTranslateX, + y - sampleModelTranslateY, outData, dataBuffer); + } + + public Object getDataElements(int x, int y, int w, int h, Object outData) + { + return sampleModel.getDataElements(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, outData, dataBuffer); + } + + /** + * Returns an array containing the samples for the pixel at (x, y) in the + * raster. If <code>iArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of + * this function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param iArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * + * @return The pixel sample values. + */ + public int[] getPixel(int x, int y, int[] iArray) + { + return sampleModel.getPixel(x - sampleModelTranslateX, + y - sampleModelTranslateY, iArray, dataBuffer); + } + + /** + * Returns an array containing the samples for the pixel at (x, y) in the + * raster. If <code>fArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of + * this function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param fArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * + * @return The pixel sample values. + */ + public float[] getPixel(int x, int y, float[] fArray) + { + return sampleModel.getPixel(x - sampleModelTranslateX, + y - sampleModelTranslateY, fArray, dataBuffer); + } + + /** + * Returns an array containing the samples for the pixel at (x, y) in the + * raster. If <code>dArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of + * this function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param dArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * + * @return The pixel sample values. + */ + public double[] getPixel(int x, int y, double[] dArray) + { + return sampleModel.getPixel(x - sampleModelTranslateX, + y - sampleModelTranslateY, dArray, dataBuffer); + } + + /** + * Returns an array containing the samples for the pixels in the region + * specified by (x, y, w, h) in the raster. The array is ordered by pixels + * (that is, all the samples for the first pixel are grouped together, + * followed by all the samples for the second pixel, and so on). + * If <code>iArray</code> is not <code>null</code>, it will be populated + * with the sample values and returned as the result of this function (this + * avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param iArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * + * @return The pixel sample values. + */ + public int[] getPixels(int x, int y, int w, int h, int[] iArray) + { + return sampleModel.getPixels(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, iArray, dataBuffer); + } + + /** + * Returns an array containing the samples for the pixels in the region + * specified by (x, y, w, h) in the raster. The array is ordered by pixels + * (that is, all the samples for the first pixel are grouped together, + * followed by all the samples for the second pixel, and so on). + * If <code>fArray</code> is not <code>null</code>, it will be populated + * with the sample values and returned as the result of this function (this + * avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param fArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * + * @return The pixel sample values. + */ + public float[] getPixels(int x, int y, int w, int h, float[] fArray) + { + return sampleModel.getPixels(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, fArray, dataBuffer); + } + + /** + * Returns an array containing the samples for the pixels in the region + * specified by (x, y, w, h) in the raster. The array is ordered by pixels + * (that is, all the samples for the first pixel are grouped together, + * followed by all the samples for the second pixel, and so on). + * If <code>dArray</code> is not <code>null</code>, it will be populated + * with the sample values and returned as the result of this function (this + * avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param dArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * + * @return The pixel sample values. + */ + public double[] getPixels(int x, int y, int w, int h, double[] dArray) + { + return sampleModel.getPixels(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, dArray, dataBuffer); + } + + /** + * Returns the sample value for the pixel at (x, y) in the raster. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * + * @return The sample value. + */ + public int getSample(int x, int y, int b) + { + return sampleModel.getSample(x - sampleModelTranslateX, + y - sampleModelTranslateY, b, dataBuffer); + } + + /** + * Returns the sample value for the pixel at (x, y) in the raster. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * + * @return The sample value. + * + * @see #getSample(int, int, int) + */ + public float getSampleFloat(int x, int y, int b) + { + return sampleModel.getSampleFloat(x - sampleModelTranslateX, + y - sampleModelTranslateY, b, dataBuffer); + } + + /** + * Returns the sample value for the pixel at (x, y) in the raster. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * + * @return The sample value. + * + * @see #getSample(int, int, int) + */ + public double getSampleDouble(int x, int y, int b) + { + return sampleModel.getSampleDouble(x - sampleModelTranslateX, + y - sampleModelTranslateY, b, dataBuffer); + } + + /** + * Returns an array containing the samples from one band for the pixels in + * the region specified by (x, y, w, h) in the raster. If + * <code>iArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of this + * function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param iArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * + * @return The sample values. + */ + public int[] getSamples(int x, int y, int w, int h, int b, + int[] iArray) + { + return sampleModel.getSamples(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, b, iArray, dataBuffer); + } + + /** + * Returns an array containing the samples from one band for the pixels in + * the region specified by (x, y, w, h) in the raster. If + * <code>fArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of this + * function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param fArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * + * @return The sample values. + */ + public float[] getSamples(int x, int y, int w, int h, int b, float[] fArray) + { + return sampleModel.getSamples(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, b, fArray, dataBuffer); + } + + /** + * Returns an array containing the samples from one band for the pixels in + * the region specified by (x, y, w, h) in the raster. If + * <code>dArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of this + * function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param dArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * + * @return The sample values. + */ + public double[] getSamples(int x, int y, int w, int h, int b, + double[] dArray) + { + return sampleModel.getSamples(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, b, dArray, dataBuffer); + } + + /** + * Create a String representing the state of this Raster. + * + * @return A String representing the stat of this Raster. + */ + public String toString() + { + CPStringBuilder result = new CPStringBuilder(); + + result.append(getClass().getName()); + result.append("[("); + result.append(minX).append(",").append(minY).append("), "); + result.append(width).append(" x ").append(height).append(","); + result.append(sampleModel).append(","); + result.append(dataBuffer); + result.append("]"); + + return result.toString(); + } + + /** + * Returns the number of bits used to represent the specified data type. + * Valid types are: + * <ul> + * <li>{@link DataBuffer#TYPE_BYTE};</li> + * <li>{@link DataBuffer#TYPE_USHORT};</li> + * <li>{@link DataBuffer#TYPE_SHORT};</li> + * <li>{@link DataBuffer#TYPE_INT};</li> + * <li>{@link DataBuffer#TYPE_FLOAT};</li> + * <li>{@link DataBuffer#TYPE_DOUBLE};</li> + * </ul> + * This method returns 0 for invalid data types. + * + * @param dataType the data type. + * + * @return The number of bits used to represent the specified data type. + */ + private static int getTypeBits(int dataType) + { + switch (dataType) + { + case DataBuffer.TYPE_BYTE: + return 8; + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_SHORT: + return 16; + case DataBuffer.TYPE_INT: + case DataBuffer.TYPE_FLOAT: + return 32; + case DataBuffer.TYPE_DOUBLE: + return 64; + default: + return 0; + } + } +} diff --git a/libjava/classpath/java/awt/image/RasterFormatException.java b/libjava/classpath/java/awt/image/RasterFormatException.java new file mode 100644 index 000000000..582c2ae5a --- /dev/null +++ b/libjava/classpath/java/awt/image/RasterFormatException.java @@ -0,0 +1,65 @@ +/* RasterFormatException.java -- indicates invalid layout in Raster + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +/** + * This exception is thrown when there is invalid layout information in + * <code>Raster</code> + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see Raster + * @status updated to 1.4 + */ +public class RasterFormatException extends RuntimeException +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 96598996116164315L; + + /** + * Create a new instance with a descriptive error message. + * + * @param message the descriptive error message + */ + public RasterFormatException(String message) + { + super(message); + } +} // class RasterFormatException diff --git a/libjava/classpath/java/awt/image/RasterOp.java b/libjava/classpath/java/awt/image/RasterOp.java new file mode 100644 index 000000000..2b2c0731f --- /dev/null +++ b/libjava/classpath/java/awt/image/RasterOp.java @@ -0,0 +1,104 @@ +/* RasterOp.java -- + Copyright (C) 2000, 2002, 2004, 2005, 2006, Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import java.awt.RenderingHints; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * An operation that is performed on one raster (the source) producing a new + * raster (the destination). + */ +public interface RasterOp +{ + /** + * Performs an operation on the source raster, returning the result in a + * writable raster. If <code>dest</code> is <code>null</code>, a new + * <code>WritableRaster</code> will be created by calling the + * {@link #createCompatibleDestRaster(Raster)} method. If <code>dest</code> + * is not <code>null</code>, the result is written to <code>dest</code> then + * returned (this avoids creating a new <code>WritableRaster</code> each + * time this method is called). + * + * @param src the source raster. + * @param dest the destination raster (<code>null</code> permitted). + * + * @return The filtered raster. + */ + WritableRaster filter(Raster src, WritableRaster dest); + + /** + * Returns the bounds of the destination raster on the basis of this + * <code>RasterOp</code> being applied to the specified source raster. + * + * @param src the source raster. + * + * @return The destination bounds. + */ + Rectangle2D getBounds2D(Raster src); + + /** + * Returns a raster that can be used by this <code>RasterOp</code> as the + * destination raster when operating on the specified source raster. + * + * @param src the source raster. + * + * @return A new writable raster that can be used as the destination raster. + */ + WritableRaster createCompatibleDestRaster(Raster src); + + /** + * Returns the point on the destination raster that corresponds to the given + * point on the source raster. + * + * @param srcPoint the source point. + * @param destPoint the destination point (<code>null</code> permitted). + * + * @return The destination point. + */ + Point2D getPoint2D(Point2D srcPoint, Point2D destPoint); + + /** + * Returns the rendering hints for this operation. + * + * @return The rendering hints. + */ + RenderingHints getRenderingHints(); +} diff --git a/libjava/classpath/java/awt/image/RenderedImage.java b/libjava/classpath/java/awt/image/RenderedImage.java new file mode 100644 index 000000000..fd18871a9 --- /dev/null +++ b/libjava/classpath/java/awt/image/RenderedImage.java @@ -0,0 +1,70 @@ +/* RenderedImage.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import java.awt.Rectangle; +import java.util.Vector; + +/** + * NEEDS DOCUMENTATION + */ +public interface RenderedImage +{ + Vector<RenderedImage> getSources(); + Object getProperty(String name); + String[] getPropertyNames(); + ColorModel getColorModel(); + SampleModel getSampleModel(); + int getWidth(); + int getHeight(); + int getMinX(); + int getMinY(); + int getNumXTiles(); + int getNumYTiles(); + int getMinTileX(); + int getMinTileY(); + int getTileWidth(); + int getTileHeight(); + int getTileGridXOffset(); + int getTileGridYOffset(); + Raster getTile(int x, int y); + Raster getData(); + Raster getData(Rectangle r); + WritableRaster copyData(WritableRaster raster); +} // interface RenderedImage diff --git a/libjava/classpath/java/awt/image/ReplicateScaleFilter.java b/libjava/classpath/java/awt/image/ReplicateScaleFilter.java new file mode 100644 index 000000000..94aad85dd --- /dev/null +++ b/libjava/classpath/java/awt/image/ReplicateScaleFilter.java @@ -0,0 +1,257 @@ +/* ReplicateScaleFilter.java -- Java class for filtering images + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import java.util.Hashtable; + +/** + * This filter should be used for fast scaling of images where the result + * does not need to ensure straight lines are still straight, etc. The + * exact method is not defined by Sun but some sort of fast Box filter should + * probably be correct. + * <br> + * Currently this filter does nothing and needs to be implemented. + * + * @author C. Brian Jones (cbj@gnu.org) + */ +public class ReplicateScaleFilter extends ImageFilter +{ + public ReplicateScaleFilter(int width, int height) { + destHeight = height; + destWidth = width; + } + + /** + * The height of the destination image. + */ + protected int destHeight; + + /** + * The width of the destination image. + */ + protected int destWidth; + + /** + * The height of the source image. + */ + protected int srcHeight; + + /** + * The width of the source image. + */ + protected int srcWidth; + + /** + * + */ + protected int srcrows[]; + + /** + * + */ + protected int srccols[]; + + /** + * + */ + protected Object outpixbuf; + + /** + * An <code>ImageProducer</code> indicates the size of the image + * being produced using this method. A filter can override this + * method to intercept these calls from the producer in order to + * change either the width or the height before in turn calling + * the consumer's <code>setDimensions</code> method. + * + * @param width the width of the image + * @param height the height of the image + */ + public void setDimensions(int width, int height) + { + srcWidth = width; + srcHeight = height; + + /* If either destHeight or destWidth is < 0, the image should + maintain its original aspect ratio. When both are < 0, + just maintain the original width and height. */ + if (destWidth < 0 && destHeight < 0) + { + destWidth = width; + destHeight = height; + } + else if (destWidth < 0) + { + destWidth = width * destHeight / srcHeight; + } + else if (destHeight < 0) + { + destHeight = height * destWidth / srcWidth; + } + + if (consumer != null) + consumer.setDimensions(destWidth, destHeight); + } + + /** + * An <code>ImageProducer</code> can set a list of properties + * associated with this image by using this method. + * + * @param props the list of properties associated with this image + */ + public void setProperties(Hashtable<?, ?> props) + { + Hashtable<Object, Object> prop2 = (Hashtable<Object, Object>) props; + prop2.put("filters", "ReplicateScaleFilter"); + if (consumer != null) + consumer.setProperties(prop2); + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as a <code>byte</code> at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the <code>ColorModel</code> used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the <code>pixels</code> array + * @param scansize the width to use in extracting pixels from the <code>pixels</code> array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, byte[] pixels, int offset, int scansize) + { + if (srcrows == null || srccols == null) + setupSources(); + int dx1 = (2 * x * destWidth + srcWidth - 1) / (2 * destWidth); + int dy1 = (2 * y * destHeight + srcHeight - 1) / (2 * destHeight); + byte[] pix; + if (outpixbuf != null && outpixbuf instanceof byte[]) + { + pix = (byte[]) outpixbuf; + } + else + { + pix = new byte[destWidth]; + outpixbuf = pix; + } + int sy, sx; + for (int yy = dy1; (sy = srcrows[yy]) < y + h; yy++) + { + int offs = offset + scansize * (sy - y); + int xx; + for (xx = dx1; (sx = srccols[xx]) < x + w; xx++) + { + pix[xx] = pixels[offs + sx - x]; + } + if (xx > dx1) + { + consumer.setPixels(dx1, yy, xx - dx1, 1, model, pix, dx1, + destWidth); + } + } + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as an <code>int</code> at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the <code>ColorModel</code> used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the <code>pixels</code> array + * @param scansize the width to use in extracting pixels from the <code>pixels</code> array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, int[] pixels, int offset, int scansize) + { + if (srcrows == null || srccols == null) + setupSources(); + int dx1 = (2 * x * destWidth + srcWidth - 1) / (2 * destWidth); + int dy1 = (2 * y * destHeight + srcHeight - 1) / (2 * destHeight); + int[] pix; + if (outpixbuf != null && outpixbuf instanceof int[]) + { + pix = (int[]) outpixbuf; + } + else + { + pix = new int[destWidth]; + outpixbuf = pix; + } + int sy, sx; + for (int yy = dy1; (sy = srcrows[yy]) < y + h; yy++) + { + int offs = offset + scansize * (sy - y); + int xx; + for (xx = dx1; (sx = srccols[xx]) < x + w; xx++) + { + pix[xx] = pixels[offs + sx - x]; + } + if (xx > dx1) + { + consumer.setPixels(dx1, yy, xx - dx1, 1, model, pix, dx1, + destWidth); + } + } + } + + /** + * Sets up the srcrows and srccols arrays. + */ + private void setupSources() + { + srcrows = new int[destHeight + 1]; + for (int y = 0; y <= destHeight; y++) + { + srcrows[y] = (2 * y * srcHeight + srcHeight) / (2 * destHeight); + } + srccols = new int[destWidth + 1]; + for (int x = 0; x <= destWidth; x++) + { + srccols[x] = (2 * x * srcWidth + srcWidth) / (2 * destWidth); + } + } +} diff --git a/libjava/classpath/java/awt/image/RescaleOp.java b/libjava/classpath/java/awt/image/RescaleOp.java new file mode 100644 index 000000000..efab40b7e --- /dev/null +++ b/libjava/classpath/java/awt/image/RescaleOp.java @@ -0,0 +1,385 @@ +/* Copyright (C) 2004, 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import java.awt.RenderingHints; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.Arrays; + +/** + * RescaleOp is a filter that changes each pixel by a scaling factor and offset. + * + * For filtering Rasters, either one scaling factor and offset can be specified, + * which will be applied to all bands; or a scaling factor and offset can be + * specified for each band. + * + * For BufferedImages, the scaling may apply to both color and alpha components. + * If only one scaling factor is provided, or if the number of factors provided + * equals the number of color components, the scaling is performed on all color + * components. Otherwise, the scaling is performed on all components including + * alpha. Alpha premultiplication is ignored. + * + * After filtering, if color conversion is necessary, the conversion happens, + * taking alpha premultiplication into account. + * + * @author Jerry Quinn (jlquinn@optonline.net) + * @author Francis Kung (fkung@redhat.com) + */ +public class RescaleOp implements BufferedImageOp, RasterOp +{ + private float[] scale; + private float[] offsets; + private RenderingHints hints = null; + + /** + * Create a new RescaleOp object using the given scale factors and offsets. + * + * The length of the arrays must be equal to the number of bands (or number of + * data or color components) of the raster/image that this Op will be used on, + * otherwise an IllegalArgumentException will be thrown when calling the + * filter method. + * + * @param scaleFactors an array of scale factors. + * @param offsets an array of offsets. + * @param hints any rendering hints to use (can be null). + * @throws NullPointerException if the scaleFactors or offsets array is null. + */ + public RescaleOp(float[] scaleFactors, + float[] offsets, + RenderingHints hints) + { + int length = Math.min(scaleFactors.length, offsets.length); + + scale = new float[length]; + System.arraycopy(scaleFactors, 0, this.scale, 0, length); + + this.offsets = new float[length]; + System.arraycopy(offsets, 0, this.offsets, 0, length); + + this.hints = hints; + } + + /** + * Create a new RescaleOp object using the given scale factor and offset. + * + * The same scale factor and offset will be used on all bands/components. + * + * @param scaleFactor the scale factor to use. + * @param offset the offset to use. + * @param hints any rendering hints to use (can be null). + */ + public RescaleOp(float scaleFactor, + float offset, + RenderingHints hints) + { + scale = new float[]{ scaleFactor }; + offsets = new float[]{offset}; + this.hints = hints; + } + + /** + * Returns the scaling factors. This method accepts an optional array, which + * will be used to store the factors if not null (this avoids allocating a + * new array). If this array is too small to hold all the scaling factors, + * the array will be filled and the remaining factors discarded. + * + * @param scaleFactors array to store the scaling factors in (can be null). + * @return an array of scaling factors. + */ + public final float[] getScaleFactors(float[] scaleFactors) + { + if (scaleFactors == null) + scaleFactors = new float[scale.length]; + System.arraycopy(scale, 0, scaleFactors, 0, Math.min(scale.length, + scaleFactors.length)); + return scaleFactors; + } + + /** + * Returns the offsets. This method accepts an optional array, which + * will be used to store the offsets if not null (this avoids allocating a + * new array). If this array is too small to hold all the offsets, the array + * will be filled and the remaining factors discarded. + * + * @param offsets array to store the offsets in (can be null). + * @return an array of offsets. + */ + public final float[] getOffsets(float[] offsets) + { + if (offsets == null) + offsets = new float[this.offsets.length]; + System.arraycopy(this.offsets, 0, offsets, 0, Math.min(this.offsets.length, + offsets.length)); + return offsets; + } + + /** + * Returns the number of scaling factors / offsets. + * + * @return the number of scaling factors / offsets. + */ + public final int getNumFactors() + { + return scale.length; + } + + /* (non-Javadoc) + * @see java.awt.image.BufferedImageOp#getRenderingHints() + */ + public final RenderingHints getRenderingHints() + { + return hints; + } + + /** + * Converts the source image using the scale factors and offsets specified in + * the constructor. The resulting image is stored in the destination image if + * one is provided; otherwise a new BufferedImage is created and returned. + * + * The source image cannot use an IndexColorModel, and the destination image + * (if one is provided) must have the same size. + * + * If the final value of a sample is beyond the range of the color model, it + * will be clipped to the appropriate maximum / minimum. + * + * @param src The source image. + * @param dst The destination image. + * @throws IllegalArgumentException if the rasters and/or color spaces are + * incompatible. + * @return The rescaled image. + */ + public final BufferedImage filter(BufferedImage src, BufferedImage dst) + { + // Initial checks + if (scale.length != 1 + && scale.length != src.getColorModel().getNumComponents() + && (scale.length != src.getColorModel().getNumColorComponents())) + throw new IllegalArgumentException("Source image has wrong number of " + + "bands for these scaling factors."); + + if (dst == null) + dst = createCompatibleDestImage(src, null); + else if (src.getHeight() != dst.getHeight() + || src.getWidth() != dst.getWidth()) + throw new IllegalArgumentException("Source and destination images are " + + "different sizes."); + + // Prepare for possible colorspace conversion + BufferedImage dst2 = dst; + if (dst.getColorModel().getColorSpace().getType() != src.getColorModel().getColorSpace().getType()) + dst2 = createCompatibleDestImage(src, src.getColorModel()); + + // Figure out how many bands to scale + int numBands = scale.length; + if (scale.length == 1) + numBands = src.getColorModel().getNumColorComponents(); + boolean[] bands = new boolean[numBands]; + // this assumes the alpha, if present, is the last band + Arrays.fill(bands, true); + + // Perform rescaling + filter(src.getRaster(), dst2.getRaster(), bands); + + // Copy alpha band if needed (ie if it exists and wasn't scaled) + // NOTE: This assumes the alpha component is the last band! + if (src.getColorModel().hasAlpha() + && numBands == src.getColorModel().getNumColorComponents()) + { + + dst2.getRaster().setSamples(0, 0, src.getWidth(), src.getHeight(), + numBands, + src.getRaster().getSamples(0, 0, + src.getWidth(), + src.getHeight(), + numBands, + (int[]) null)); + } + + // Perform colorspace conversion if needed + if (dst != dst2) + new ColorConvertOp(hints).filter(dst2, dst); + + return dst; + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#filter(java.awt.image.Raster, java.awt.image.WritableRaster) + */ + public final WritableRaster filter(Raster src, WritableRaster dest) + { + // Required sanity checks + if (scale.length != 1 && scale.length != src.numBands) + throw new IllegalArgumentException("Number of rasters is incompatible " + + "with the number of scaling " + + "factors provided."); + + if (dest == null) + dest = src.createCompatibleWritableRaster(); + else if (src.getHeight() != dest.getHeight() + || src.getWidth() != dest.getWidth()) + throw new IllegalArgumentException("Source and destination rasters are " + + "different sizes."); + else if (src.numBands != dest.numBands) + throw new IllegalArgumentException("Source and destination rasters " + + "are incompatible."); + + // Filter all bands + boolean[] bands = new boolean[src.getNumBands()]; + Arrays.fill(bands, true); + return filter(src, dest, bands); + } + + /** + * Perform raster-based filtering on a selected number of bands. + * + * The length of the bands array should equal the number of bands; a true + * element indicates filtering should happen on the corresponding band, while + * a false element will skip the band. + * + * The rasters are assumed to be compatible and non-null. + * + * @param src the source raster. + * @param dest the destination raster. + * @param bands an array indicating which bands to filter. + * @throws NullPointerException if any parameter is null. + * @throws ArrayIndexOutOfBoundsException if the bands array is too small. + * @return the destination raster. + */ + private WritableRaster filter(Raster src, WritableRaster dest, boolean[] bands) + { + int[] values = new int[src.getHeight() * src.getWidth()]; + float scaleFactor, offset; + + // Find max sample value, to be used for clipping later + int[] maxValue = src.getSampleModel().getSampleSize(); + for (int i = 0; i < maxValue.length; i++) + maxValue[i] = (int)Math.pow(2, maxValue[i]) - 1; + + // TODO: can this be optimized further? + // Filter all samples of all requested bands + for (int band = 0; band < bands.length; band++) + if (bands[band]) + { + values = src.getSamples(src.getMinX(), src.getMinY(), src.getWidth(), + src.getHeight(), band, values); + + if (scale.length == 1) + { + scaleFactor = scale[0]; + offset = offsets[0]; + } + else + { + scaleFactor = scale[band]; + offset = offsets[band]; + } + + for (int i = 0; i < values.length; i++) + { + values[i] = (int) (values[i] * scaleFactor + offset); + + // Clip if needed + if (values[i] < 0) + values[i] = 0; + if (values[i] > maxValue[band]) + values[i] = maxValue[band]; + } + + dest.setSamples(dest.getMinX(), dest.getMinY(), dest.getWidth(), + dest.getHeight(), band, values); + } + + return dest; + } + + /* + * (non-Javadoc) + * + * @see java.awt.image.BufferedImageOp#createCompatibleDestImage(java.awt.image.BufferedImage, + * java.awt.image.ColorModel) + */ + public BufferedImage createCompatibleDestImage(BufferedImage src, + ColorModel dstCM) + { + if (dstCM == null) + return new BufferedImage(src.getWidth(), src.getHeight(), src.getType()); + + return new BufferedImage(dstCM, + src.getRaster().createCompatibleWritableRaster(), + src.isAlphaPremultiplied(), null); + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#createCompatibleDestRaster(java.awt.image.Raster) + */ + public WritableRaster createCompatibleDestRaster(Raster src) + { + return src.createCompatibleWritableRaster(); + } + + /* (non-Javadoc) + * @see java.awt.image.BufferedImageOp#getBounds2D(java.awt.image.BufferedImage) + */ + public final Rectangle2D getBounds2D(BufferedImage src) + { + return src.getRaster().getBounds(); + } + + /* (non-Javadoc) + * @see java.awt.image.RasterOp#getBounds2D(java.awt.image.Raster) + */ + public final Rectangle2D getBounds2D(Raster src) + { + return src.getBounds(); + } + + /* (non-Javadoc) + * @see java.awt.image.BufferedImageOp#getPoint2D(java.awt.geom.Point2D, java.awt.geom.Point2D) + */ + public final Point2D getPoint2D(Point2D src, Point2D dst) + { + if (dst == null) + dst = (Point2D) src.clone(); + else + dst.setLocation(src); + + return dst; + } + +} diff --git a/libjava/classpath/java/awt/image/SampleModel.java b/libjava/classpath/java/awt/image/SampleModel.java new file mode 100644 index 000000000..7e0b18c55 --- /dev/null +++ b/libjava/classpath/java/awt/image/SampleModel.java @@ -0,0 +1,974 @@ +/* Copyright (C) 2000, 2001, 2002, 2005, 2006, Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +/** + * A <code>SampleModel</code> is used to access pixel data from a + * {@link DataBuffer}. This is used by the {@link Raster} class. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public abstract class SampleModel +{ + /** Width of image described. */ + protected int width; + + /** Height of image described. */ + protected int height; + + /** Number of bands in the image described. Package-private here, + shadowed by ComponentSampleModel. */ + protected int numBands; + + /** + * The DataBuffer type that is used to store the data of the image + * described. + */ + protected int dataType; + + /** + * Creates a new sample model with the specified attributes. + * + * @param dataType the data type (one of {@link DataBuffer#TYPE_BYTE}, + * {@link DataBuffer#TYPE_USHORT}, {@link DataBuffer#TYPE_SHORT}, + * {@link DataBuffer#TYPE_INT}, {@link DataBuffer#TYPE_FLOAT}, + * {@link DataBuffer#TYPE_DOUBLE} or {@link DataBuffer#TYPE_UNDEFINED}). + * @param w the width in pixels (must be greater than zero). + * @param h the height in pixels (must be greater than zero). + * @param numBands the number of bands (must be greater than zero). + * + * @throws IllegalArgumentException if <code>dataType</code> is not one of + * the listed values. + * @throws IllegalArgumentException if <code>w</code> is less than or equal + * to zero. + * @throws IllegalArgumentException if <code>h</code> is less than or equal + * to zero. + * @throws IllegalArgumentException if <code>w * h</code> is greater than + * {@link Integer#MAX_VALUE}. + */ + public SampleModel(int dataType, int w, int h, int numBands) + { + if (dataType != DataBuffer.TYPE_UNDEFINED) + if (dataType < DataBuffer.TYPE_BYTE || dataType > DataBuffer.TYPE_DOUBLE) + throw new IllegalArgumentException("Unrecognised 'dataType' argument."); + + if ((w <= 0) || (h <= 0)) + throw new IllegalArgumentException((w <= 0 ? " width<=0" : " width is ok") + + (h <= 0 ? " height<=0" : " height is ok")); + + long area = (long) w * (long) h; + if (area > Integer.MAX_VALUE) + throw new IllegalArgumentException("w * h exceeds Integer.MAX_VALUE."); + + if (numBands <= 0) + throw new IllegalArgumentException("Requires numBands > 0."); + + this.dataType = dataType; + this.width = w; + this.height = h; + this.numBands = numBands; + } + + /** + * Returns the width of the pixel data accessible via this + * <code>SampleModel</code>. + * + * @return The width. + * + * @see #getHeight() + */ + public final int getWidth() + { + return width; + } + + /** + * Returns the height of the pixel data accessible via this + * <code>SampleModel</code>. + * + * @return The height. + * + * @see #getWidth() + */ + public final int getHeight() + { + return height; + } + + /** + * Returns the number of bands for this <code>SampleModel</code>. + * + * @return The number of bands. + */ + public final int getNumBands() + { + return numBands; + } + + public abstract int getNumDataElements(); + + /** + * Returns the type of the {@link DataBuffer} that this + * <code>SampleModel</code> accesses. + * + * @return The data buffer type. + */ + public final int getDataType() + { + return dataType; + } + + public int getTransferType() + { + // FIXME: Is this a reasonable default implementation? + return dataType; + } + + /** + * Returns an array containing the samples for the pixel at (x, y) in the + * specified data buffer. If <code>iArray</code> is not <code>null</code>, + * it will be populated with the sample values and returned as the result of + * this function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param iArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The pixel sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) + { + if (iArray == null) + iArray = new int[numBands]; + for (int b = 0; b < numBands; b++) + iArray[b] = getSample(x, y, b, data); + return iArray; + } + + /** + * + * This method is provided as a faster alternative to getPixel(), + * that can be used when there is no need to decode the pixel into + * separate sample values. + * + * @param obj An array to return the pixel data in. If null, an + * array of the right type and size will be created. + * + * @return A single pixel as an array object of a primitive type, + * based on the transfer type. Eg. if transfer type is + * DataBuffer.TYPE_USHORT, then a short[] object is returned. + */ + public abstract Object getDataElements(int x, int y, Object obj, + DataBuffer data); + + + public Object getDataElements(int x, int y, int w, int h, Object obj, + DataBuffer data) + { + int size = w * h; + int numDataElements = getNumDataElements(); + int dataSize = numDataElements * size; + + if (obj == null) + { + switch (getTransferType()) + { + case DataBuffer.TYPE_BYTE: + obj = new byte[dataSize]; + break; + case DataBuffer.TYPE_USHORT: + obj = new short[dataSize]; + break; + case DataBuffer.TYPE_INT: + obj = new int[dataSize]; + break; + default: + // Seems like the only sensible thing to do. + throw new ClassCastException(); + } + } + Object pixelData = null; + int outOffset = 0; + for (int yy = y; yy < (y + h); yy++) + { + for (int xx = x; xx < (x + w); xx++) + { + pixelData = getDataElements(xx, yy, pixelData, data); + System.arraycopy(pixelData, 0, obj, outOffset, + numDataElements); + outOffset += numDataElements; + } + } + return obj; + } + + public abstract void setDataElements(int x, int y, Object obj, + DataBuffer data); + + public void setDataElements(int x, int y, int w, int h, + Object obj, DataBuffer data) + { + int numDataElements = getNumDataElements(); + + Object pixelData; + switch (getTransferType()) + { + case DataBuffer.TYPE_BYTE: + pixelData = new byte[numDataElements]; + break; + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_SHORT: + pixelData = new short[numDataElements]; + break; + case DataBuffer.TYPE_INT: + pixelData = new int[numDataElements]; + break; + case DataBuffer.TYPE_FLOAT: + pixelData = new float[numDataElements]; + break; + case DataBuffer.TYPE_DOUBLE: + pixelData = new double[numDataElements]; + break; + default: + // The RI silently igores invalid types. + pixelData = null; + } + + int inOffset = 0; + if (pixelData != null) + { + for (int yy=y; yy<(y+h); yy++) + { + for (int xx=x; xx<(x+w); xx++) + { + System.arraycopy(obj, inOffset, pixelData, 0, numDataElements); + setDataElements(xx, yy, pixelData, data); + inOffset += numDataElements; + } + } + } + } + + /** + * Returns an array containing the samples for the pixel at (x, y) in the + * specified data buffer. If <code>fArray</code> is not <code>null</code>, + * it will be populated with the sample values and returned as the result of + * this function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param fArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The pixel sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public float[] getPixel(int x, int y, float[] fArray, DataBuffer data) + { + if (fArray == null) + fArray = new float[numBands]; + + for (int b = 0; b < numBands; b++) + { + fArray[b] = getSampleFloat(x, y, b, data); + } + return fArray; + } + + /** + * Returns an array containing the samples for the pixel at (x, y) in the + * specified data buffer. If <code>dArray</code> is not <code>null</code>, + * it will be populated with the sample values and returned as the result of + * this function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param dArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The pixel sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public double[] getPixel(int x, int y, double[] dArray, DataBuffer data) { + if (dArray == null) + dArray = new double[numBands]; + for (int b = 0; b < numBands; b++) + { + dArray[b] = getSampleDouble(x, y, b, data); + } + return dArray; + } + + /** + * Returns an array containing the samples for the pixels in the region + * specified by (x, y, w, h) in the specified data buffer. The array is + * ordered by pixels (that is, all the samples for the first pixel are + * grouped together, followed by all the samples for the second pixel, and so + * on). If <code>iArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of this + * function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param iArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The pixel sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public int[] getPixels(int x, int y, int w, int h, int[] iArray, + DataBuffer data) + { + int size = w * h; + int outOffset = 0; + int[] pixel = null; + if (iArray == null) + iArray = new int[w * h * numBands]; + for (int yy = y; yy < (y + h); yy++) + { + for (int xx = x; xx < (x + w); xx++) + { + pixel = getPixel(xx, yy, pixel, data); + System.arraycopy(pixel, 0, iArray, outOffset, numBands); + outOffset += numBands; + } + } + return iArray; + } + + /** + * Returns an array containing the samples for the pixels in the region + * specified by (x, y, w, h) in the specified data buffer. The array is + * ordered by pixels (that is, all the samples for the first pixel are + * grouped together, followed by all the samples for the second pixel, and so + * on). If <code>fArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of this + * function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param fArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The pixel sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public float[] getPixels(int x, int y, int w, int h, float[] fArray, + DataBuffer data) + { + int size = w * h; + int outOffset = 0; + float[] pixel = null; + if (fArray == null) fArray = new float[w * h * numBands]; + for (int yy = y; yy < (y + h); yy++) + { + for (int xx = x; xx < (x + w); xx++) + { + pixel = getPixel(xx, yy, pixel, data); + System.arraycopy(pixel, 0, fArray, outOffset, numBands); + outOffset += numBands; + } + } + return fArray; + } + + /** + * Returns an array containing the samples for the pixels in the region + * specified by (x, y, w, h) in the specified data buffer. The array is + * ordered by pixels (that is, all the samples for the first pixel are + * grouped together, followed by all the samples for the second pixel, and so + * on). If <code>dArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of this + * function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param dArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The pixel sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public double[] getPixels(int x, int y, int w, int h, double[] dArray, + DataBuffer data) + { + int size = w * h; + int outOffset = 0; + double[] pixel = null; + if (dArray == null) + dArray = new double[w * h * numBands]; + for (int yy = y; yy < (y + h); yy++) + { + for (int xx = x; xx < (x + w); xx++) + { + pixel = getPixel(xx, yy, pixel, data); + System.arraycopy(pixel, 0, dArray, outOffset, numBands); + outOffset += numBands; + } + } + return dArray; + } + + /** + * Returns the sample value for the pixel at (x, y) in the specified data + * buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample value. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public abstract int getSample(int x, int y, int b, DataBuffer data); + + /** + * Returns the sample value for the pixel at (x, y) in the specified data + * buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample value. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + * + * @see #getSample(int, int, int, DataBuffer) + */ + public float getSampleFloat(int x, int y, int b, DataBuffer data) + { + return getSample(x, y, b, data); + } + + /** + * Returns the sample value for the pixel at (x, y) in the specified data + * buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample value. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + * + * @see #getSample(int, int, int, DataBuffer) + */ + public double getSampleDouble(int x, int y, int b, DataBuffer data) + { + return getSampleFloat(x, y, b, data); + } + + /** + * Returns an array containing the samples from one band for the pixels in + * the region specified by (x, y, w, h) in the specified data buffer. If + * <code>iArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of this + * function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param iArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public int[] getSamples(int x, int y, int w, int h, int b, + int[] iArray, DataBuffer data) + { + int size = w * h; + int outOffset = 0; + if (iArray == null) + iArray = new int[size]; + for (int yy = y; yy < (y + h); yy++) + { + for (int xx = x; xx < (x + w); xx++) + { + iArray[outOffset++] = getSample(xx, yy, b, data); + } + } + return iArray; + } + + /** + * Returns an array containing the samples from one band for the pixels in + * the region specified by (x, y, w, h) in the specified data buffer. If + * <code>fArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of this + * function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param fArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public float[] getSamples(int x, int y, int w, int h, int b, + float[] fArray, DataBuffer data) + { + int size = w * h; + int outOffset = 0; + if (fArray == null) + fArray = new float[size]; + for (int yy = y; yy < (y + h); yy++) + { + for (int xx = x; xx < (x + w); xx++) + { + fArray[outOffset++] = getSampleFloat(xx, yy, b, data); + } + } + return fArray; + } + + /** + * Returns an array containing the samples from one band for the pixels in + * the region specified by (x, y, w, h) in the specified data buffer. If + * <code>dArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of this + * function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param dArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public double[] getSamples(int x, int y, int w, int h, int b, + double[] dArray, DataBuffer data) + { + int size = w * h; + int outOffset = 0; + if (dArray == null) + dArray = new double[size]; + for (int yy = y; yy < (y + h); yy++) + { + for (int xx = x; xx < (x + w); xx++) + { + dArray[outOffset++] = getSampleDouble(xx, yy, b, data); + } + } + return dArray; + } + + /** + * Sets the samples for the pixel at (x, y) in the specified data buffer to + * the specified values. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param iArray the sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>iArray</code> or + * <code>data</code> is <code>null</code>. + */ + public void setPixel(int x, int y, int[] iArray, DataBuffer data) + { + for (int b = 0; b < numBands; b++) + setSample(x, y, b, iArray[b], data); + } + + /** + * Sets the samples for the pixel at (x, y) in the specified data buffer to + * the specified values. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param fArray the sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>fArray</code> or + * <code>data</code> is <code>null</code>. + */ + public void setPixel(int x, int y, float[] fArray, DataBuffer data) + { + for (int b = 0; b < numBands; b++) + setSample(x, y, b, fArray[b], data); + } + + /** + * Sets the samples for the pixel at (x, y) in the specified data buffer to + * the specified values. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param dArray the sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>dArray</code> or + * <code>data</code> is <code>null</code>. + */ + public void setPixel(int x, int y, double[] dArray, DataBuffer data) + { + for (int b = 0; b < numBands; b++) + setSample(x, y, b, dArray[b], data); + } + + /** + * Sets the sample values for the pixels in the region specified by + * (x, y, w, h) in the specified data buffer. The array is + * ordered by pixels (that is, all the samples for the first pixel are + * grouped together, followed by all the samples for the second pixel, and so + * on). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param iArray the pixel sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>iArray</code> or + * <code>data</code> is <code>null</code>. + */ + public void setPixels(int x, int y, int w, int h, int[] iArray, + DataBuffer data) + { + int inOffset = 0; + int[] pixel = new int[numBands]; + for (int yy = y; yy < (y + h); yy++) + { + for (int xx = x; xx < (x + w); xx++) + { + System.arraycopy(iArray, inOffset, pixel, 0, numBands); + setPixel(xx, yy, pixel, data); + inOffset += numBands; + } + } + } + + /** + * Sets the sample values for the pixels in the region specified by + * (x, y, w, h) in the specified data buffer. The array is + * ordered by pixels (that is, all the samples for the first pixel are + * grouped together, followed by all the samples for the second pixel, and so + * on). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param fArray the pixel sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>fArray</code> or + * <code>data</code> is <code>null</code>. + */ + public void setPixels(int x, int y, int w, int h, float[] fArray, + DataBuffer data) + { + int inOffset = 0; + float[] pixel = new float[numBands]; + for (int yy = y; yy < (y + h); yy++) + { + for (int xx = x; xx < (x + w); xx++) + { + System.arraycopy(fArray, inOffset, pixel, 0, numBands); + setPixel(xx, yy, pixel, data); + inOffset += numBands; + } + } + } + + /** + * Sets the sample values for the pixels in the region specified by + * (x, y, w, h) in the specified data buffer. The array is + * ordered by pixels (that is, all the samples for the first pixel are + * grouped together, followed by all the samples for the second pixel, and so + * on). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param dArray the pixel sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>dArray</code> or + * <code>data</code> is <code>null</code>. + */ + public void setPixels(int x, int y, int w, int h, double[] dArray, + DataBuffer data) + { + int inOffset = 0; + double[] pixel = new double[numBands]; + for (int yy = y; yy < (y + h); yy++) + { + for (int xx = x; xx < (x + w); xx++) + { + System.arraycopy(dArray, inOffset, pixel, 0, numBands); + setPixel(xx, yy, pixel, data); + inOffset += numBands; + } + } + } + + /** + * Sets the sample value for a band for the pixel at (x, y) in the + * specified data buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param s the sample value. + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public abstract void setSample(int x, int y, int b, int s, + DataBuffer data); + + /** + * Sets the sample value for a band for the pixel at (x, y) in the + * specified data buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param s the sample value. + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public void setSample(int x, int y, int b, float s, + DataBuffer data) + { + setSample(x, y, b, (int) s, data); + } + + /** + * Sets the sample value for a band for the pixel at (x, y) in the + * specified data buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param s the sample value. + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public void setSample(int x, int y, int b, double s, + DataBuffer data) + { + setSample(x, y, b, (float) s, data); + } + + /** + * Sets the sample values for one band for the pixels in the region + * specified by (x, y, w, h) in the specified data buffer. + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param iArray the sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>iArray</code> or + * <code>data</code> is <code>null</code>. + */ + public void setSamples(int x, int y, int w, int h, int b, + int[] iArray, DataBuffer data) + { + int size = w * h; + int inOffset = 0; + for (int yy = y; yy < (y + h); yy++) + for (int xx = x; xx < (x + w); xx++) + setSample(xx, yy, b, iArray[inOffset++], data); + } + + /** + * Sets the sample values for one band for the pixels in the region + * specified by (x, y, w, h) in the specified data buffer. + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param fArray the sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>iArray</code> or + * <code>data</code> is <code>null</code>. + */ + public void setSamples(int x, int y, int w, int h, int b, + float[] fArray, DataBuffer data) + { + int size = w * h; + int inOffset = 0; + for (int yy = y; yy < (y + h); yy++) + for (int xx = x; xx < (x + w); xx++) + setSample(xx, yy, b, fArray[inOffset++], data); + + } + + /** + * Sets the sample values for one band for the pixels in the region + * specified by (x, y, w, h) in the specified data buffer. + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param dArray the sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>iArray</code> or + * <code>data</code> is <code>null</code>. + */ + public void setSamples(int x, int y, int w, int h, int b, + double[] dArray, DataBuffer data) { + int size = w * h; + int inOffset = 0; + for (int yy = y; yy < (y + h); yy++) + for (int xx = x; xx < (x + w); xx++) + setSample(xx, yy, b, dArray[inOffset++], data); + } + + /** + * Creates a new <code>SampleModel</code> that is compatible with this + * model and has the specified width and height. + * + * @param w the width (in pixels). + * @param h the height (in pixels). + * + * @return The new sample model. + */ + public abstract SampleModel createCompatibleSampleModel(int w, int h); + + /** + * Return a SampleModel with a subset of the bands in this model. + * + * Selects bands.length bands from this sample model. The bands chosen + * are specified in the indices of bands[]. This also permits permuting + * the bands as well as taking a subset. Thus, giving an array with + * 1, 2, 3, ..., numbands, will give an identical sample model. + * + * @param bands Array with band indices to include. + * @return A new sample model + */ + public abstract SampleModel createSubsetSampleModel(int[] bands); + + /** + * Creates a new {@link DataBuffer} of the correct type and size for this + * <code>SampleModel</code>. + * + * @return The data buffer. + */ + public abstract DataBuffer createDataBuffer(); + + /** + * Returns an array containing the size (in bits) for each band accessed by + * the <code>SampleModel</code>. + * + * @return An array. + * + * @see #getSampleSize(int) + */ + public abstract int[] getSampleSize(); + + /** + * Returns the size (in bits) of the samples for the specified band. + * + * @param band the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * + * @return The sample size (in bits). + */ + public abstract int getSampleSize(int band); +} diff --git a/libjava/classpath/java/awt/image/ShortLookupTable.java b/libjava/classpath/java/awt/image/ShortLookupTable.java new file mode 100644 index 000000000..3e276fe9f --- /dev/null +++ b/libjava/classpath/java/awt/image/ShortLookupTable.java @@ -0,0 +1,177 @@ +/* ShortLookupTable.java -- Java class for a pixel translation table. + Copyright (C) 2004, 2005, 2006, Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +/** + * ShortLookupTable represents translation arrays for pixel values. It wraps + * one or more data arrays for each layer (or component) in an image, such as + * Alpha, R, G, and B. When doing translation, the offset is subtracted from + * the pixel values to allow a subset of an array to be used. + * + * @author Jerry Quinn (jlquinn@optonline.net) + * @version 1.0 + */ +public class ShortLookupTable extends LookupTable +{ + // Array of translation tables. + private short data[][]; + + /** + * Creates a new <code>ShortLookupTable</code> instance. + * + * Offset is subtracted from pixel values when looking up in the translation + * tables. If data.length is one, the same table is applied to all pixel + * components. + * + * @param offset Offset to be subtracted. + * @param data Array of lookup tables. + * @exception IllegalArgumentException if offset < 0 or data.length < 1. + */ + public ShortLookupTable(int offset, short[][] data) + throws IllegalArgumentException + { + super(offset, data.length); + + // tests show that Sun's implementation creates a new array to store the + // references from the incoming 'data' array - not sure why, but we'll + // match that behaviour just in case it matters... + this.data = new short[data.length][]; + for (int i = 0; i < data.length; i++) + this.data[i] = data[i]; + } + + /** + * Creates a new <code>ShortLookupTable</code> instance. + * + * Offset is subtracted from pixel values when looking up in the translation + * table. The same table is applied to all pixel components. + * + * @param offset Offset to be subtracted. + * @param data Lookup table for all components (<code>null</code> not + * permitted). + * @exception IllegalArgumentException if offset < 0. + */ + public ShortLookupTable(int offset, short[] data) + throws IllegalArgumentException + { + super(offset, 1); + if (data == null) + throw new NullPointerException("Null 'data' argument."); + this.data = new short[][] {data}; + } + + /** + * Return the lookup tables. This is a reference to the actual table, so + * modifying the contents of the returned array will modify the lookup table. + * + * @return The lookup table. + */ + public final short[][] getTable() + { + return data; + } + + /** + * Return translated values for a pixel. + * + * For each value in the pixel src, use the value minus offset as an index + * in the component array and copy the value there to the output for the + * component. If dest is null, the output is a new array, otherwise the + * translated values are written to dest. Dest can be the same array as + * src. + * + * For example, if the pixel src is [2, 4, 3], and offset is 1, the output + * is [comp1[1], comp2[3], comp3[2]], where comp1, comp2, and comp3 are the + * translation arrays. + * + * @param src Component values of a pixel. + * @param dst Destination array for values, or null. + * @return Translated values for the pixel. + */ + public int[] lookupPixel(int[] src, int[] dst) + throws ArrayIndexOutOfBoundsException + { + if (dst == null) + dst = new int[src.length]; + + if (data.length == 1) + for (int i = 0; i < src.length; i++) + dst[i] = data[0][src[i] - offset]; + else + for (int i = 0; i < src.length; i++) + dst[i] = data[i][src[i] - offset]; + + return dst; + } + + /** + * Return translated values for a pixel. + * + * For each value in the pixel src, use the value minus offset as an index + * in the component array and copy the value there to the output for the + * component. If dest is null, the output is a new array, otherwise the + * translated values are written to dest. Dest can be the same array as + * src. + * + * For example, if the pixel src is [2, 4, 3], and offset is 1, the output + * is [comp1[1], comp2[3], comp3[2]], where comp1, comp2, and comp3 are the + * translation arrays. + * + * @param src Component values of a pixel. + * @param dst Destination array for values, or null. + * @return Translated values for the pixel. + * + */ + public short[] lookupPixel(short[] src, short[] dst) + throws ArrayIndexOutOfBoundsException + { + if (dst == null) + dst = new short[src.length]; + + if (data.length == 1) + for (int i = 0; i < src.length; i++) + dst[i] = data[0][((int) src[i]) - offset]; + else + for (int i = 0; i < src.length; i++) + dst[i] = data[i][((int) src[i]) - offset]; + + return dst; + + } +} diff --git a/libjava/classpath/java/awt/image/SinglePixelPackedSampleModel.java b/libjava/classpath/java/awt/image/SinglePixelPackedSampleModel.java new file mode 100644 index 000000000..143581db9 --- /dev/null +++ b/libjava/classpath/java/awt/image/SinglePixelPackedSampleModel.java @@ -0,0 +1,586 @@ +/* Copyright (C) 2000, 2002, 2003, 2004, 2006, Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +import java.util.Arrays; + +import gnu.java.awt.BitMaskExtent; +import gnu.java.lang.CPStringBuilder; + +/** + * A <code>SampleModel</code> used when all samples are stored in a single + * data element in the {@link DataBuffer}, and each data element contains + * samples for one pixel only. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public class SinglePixelPackedSampleModel extends SampleModel +{ + private int scanlineStride; + private int[] bitMasks; + private int[] bitOffsets; + private int[] sampleSize; + + /** + * Creates a new <code>SinglePixelPackedSampleModel</code>. + * + * @param dataType the data buffer type. + * @param w the width (in pixels). + * @param h the height (in pixels). + * @param bitMasks an array containing the bit mask used to extract the + * sample value for each band. + */ + public SinglePixelPackedSampleModel(int dataType, int w, int h, + int[] bitMasks) + { + this(dataType, w, h, w, bitMasks); + } + + /** + * Creates a new <code>SinglePixelPackedSampleModel</code>. + * + * @param dataType the data buffer type. + * @param w the width (in pixels). + * @param h the height (in pixels). + * @param scanlineStride the number of data elements between a pixel on one + * row and the corresponding pixel on the next row. + * @param bitMasks an array containing the bit mask used to extract the + * sample value for each band. + */ + public SinglePixelPackedSampleModel(int dataType, int w, int h, + int scanlineStride, int[] bitMasks) + { + super(dataType, w, h, bitMasks.length); + + switch (dataType) + { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + break; + default: + throw new IllegalArgumentException( + "SinglePixelPackedSampleModel unsupported dataType"); + } + + this.scanlineStride = scanlineStride; + this.bitMasks = bitMasks; + + bitOffsets = new int[numBands]; + sampleSize = new int[numBands]; + + BitMaskExtent extent = new BitMaskExtent(); + for (int b = 0; b < numBands; b++) + { + // the mask is an unsigned integer + long mask = bitMasks[b] & 0xFFFFFFFFL; + extent.setMask(mask); + sampleSize[b] = extent.bitWidth; + bitOffsets[b] = extent.leastSignificantBit; + } + } + + /** + * Returns the number of data elements. + * + * @return <code>1</code>. + */ + public int getNumDataElements() + { + return 1; + } + + /** + * Creates a new <code>SampleModel</code> that is compatible with this + * model and has the specified width and height. + * + * @param w the width (in pixels). + * @param h the height (in pixels). + * + * @return The new sample model. + */ + public SampleModel createCompatibleSampleModel(int w, int h) + { + /* FIXME: We can avoid recalculation of bit offsets and sample + sizes here by passing these from the current instance to a + special private constructor. */ + return new SinglePixelPackedSampleModel(dataType, w, h, bitMasks); + } + + + /** + * Creates a DataBuffer for holding pixel data in the format and + * layout described by this SampleModel. The returned buffer will + * consist of one single bank. + * + * @return The data buffer. + */ + public DataBuffer createDataBuffer() + { + // We can save (scanlineStride - width) pixels at the very end of + // the buffer. The Sun reference implementation (J2SE 1.3.1 and + // 1.4.1_01) seems to do this; tested with Mauve test code. + int size = scanlineStride * (height - 1) + width; + + DataBuffer buffer = null; + switch (getTransferType()) + { + case DataBuffer.TYPE_BYTE: + buffer = new DataBufferByte(size); + break; + case DataBuffer.TYPE_USHORT: + buffer = new DataBufferUShort(size); + break; + case DataBuffer.TYPE_INT: + buffer = new DataBufferInt(size); + break; + } + return buffer; + } + + /** + * Returns an array containing the size (in bits) for each band accessed by + * the <code>SampleModel</code>. + * + * @return An array. + * + * @see #getSampleSize(int) + */ + public int[] getSampleSize() + { + return (int[]) sampleSize.clone(); + } + + /** + * Returns the size (in bits) of the samples for the specified band. + * + * @param band the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * + * @return The sample size (in bits). + */ + public int getSampleSize(int band) + { + return sampleSize[band]; + } + + /** + * Returns the index in the data buffer that stores the pixel at (x, y). + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * + * @return The index in the data buffer that stores the pixel at (x, y). + */ + public int getOffset(int x, int y) + { + return scanlineStride*y + x; + } + + public int[] getBitOffsets() + { + return bitOffsets; + } + + public int[] getBitMasks() + { + return bitMasks; + } + + /** + * Returns the number of data elements from a pixel in one row to the + * corresponding pixel in the next row. + * + * @return The scanline stride. + */ + public int getScanlineStride() + { + return scanlineStride; + } + + /** + * Creates a new <code>SinglePixelPackedSampleModel</code> that accesses + * the specified subset of bands. + * + * @param bands an array containing band indices (<code>null</code> not + * permitted). + * + * @return A new sample model. + * + * @throws NullPointerException if <code>bands</code> is <code>null</code>. + * @throws RasterFormatException if <code>bands.length</code> is greater + * than the number of bands in this model. + */ + public SampleModel createSubsetSampleModel(int[] bands) + { + if (bands.length > numBands) + throw new RasterFormatException("Too many bands."); + + int numBands = bands.length; + + int[] bitMasks = new int[numBands]; + + for (int b = 0; b < numBands; b++) + bitMasks[b] = this.bitMasks[bands[b]]; + + return new SinglePixelPackedSampleModel(dataType, width, height, + scanlineStride, bitMasks); + } + + public Object getDataElements(int x, int y, Object obj, + DataBuffer data) + { + int type = getTransferType(); + Object ret = null; + switch (type) + { + case DataBuffer.TYPE_BYTE: + { + byte[] in = (byte[]) obj; + if (in == null) + in = new byte[1]; + in[0] = (byte) data.getElem(x + y * scanlineStride); + ret = in; + } + break; + case DataBuffer.TYPE_USHORT: + { + short[] in = (short[]) obj; + if (in == null) + in = new short[1]; + in[0] = (short) data.getElem(x + y * scanlineStride); + ret = in; + } + break; + case DataBuffer.TYPE_INT: + { + int[] in = (int[]) obj; + if (in == null) + in = new int[1]; + in[0] = data.getElem(x + y * scanlineStride); + ret = in; + } + break; + } + return ret; + } + + /** + * Returns an array containing the samples for the pixel at (x, y) in the + * specified data buffer. If <code>iArray</code> is not <code>null</code>, + * it will be populated with the sample values and returned as the result of + * this function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param iArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The pixel sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) + { + int offset = scanlineStride*y + x; + if (iArray == null) iArray = new int[numBands]; + int samples = data.getElem(offset); + + for (int b = 0; b < numBands; b++) + iArray[b] = (samples & bitMasks[b]) >>> bitOffsets[b]; + + return iArray; + } + + /** + * Returns an array containing the samples for the pixels in the region + * specified by (x, y, w, h) in the specified data buffer. The array is + * ordered by pixels (that is, all the samples for the first pixel are + * grouped together, followed by all the samples for the second pixel, and so + * on). If <code>iArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of this + * function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param iArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The pixel sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public int[] getPixels(int x, int y, int w, int h, int[] iArray, + DataBuffer data) + { + int offset = scanlineStride*y + x; + if (iArray == null) iArray = new int[numBands*w*h]; + int outOffset = 0; + for (y = 0; y < h; y++) + { + int lineOffset = offset; + for (x = 0; x < w; x++) + { + int samples = data.getElem(lineOffset++); + for (int b = 0; b < numBands; b++) + iArray[outOffset++] = (samples & bitMasks[b]) >>> bitOffsets[b]; + } + offset += scanlineStride; + } + return iArray; + } + + /** + * Returns the sample value for the pixel at (x, y) in the specified data + * buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample value. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public int getSample(int x, int y, int b, DataBuffer data) + { + int offset = scanlineStride*y + x; + int samples = data.getElem(offset); + return (samples & bitMasks[b]) >>> bitOffsets[b]; + } + + public void setDataElements(int x, int y, Object obj, DataBuffer data) + { + int transferType = getTransferType(); + switch (transferType) + { + case DataBuffer.TYPE_BYTE: + { + byte[] in = (byte[]) obj; + data.setElem(y * scanlineStride + x, ((int) in[0]) & 0xff); + } + break; + case DataBuffer.TYPE_USHORT: + { + short[] in = (short[]) obj; + data.setElem(y * scanlineStride + x, ((int) in[0]) & 0xffff); + } + break; + case DataBuffer.TYPE_INT: + { + int[] in = (int[]) obj; + data.setElem(y * scanlineStride + x, in[0]); + break; + } + } + } + + /** + * Sets the samples for the pixel at (x, y) in the specified data buffer to + * the specified values. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param iArray the sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>iArray</code> or + * <code>data</code> is <code>null</code>. + */ + public void setPixel(int x, int y, int[] iArray, DataBuffer data) + { + int offset = scanlineStride*y + x; + + int samples = 0; + for (int b = 0; b < numBands; b++) + samples |= (iArray[b] << bitOffsets[b]) & bitMasks[b]; + + data.setElem(offset, samples); + } + + /** + * This method implements a more efficient way to set pixels than the default + * implementation of the super class. It copies the pixel components directly + * from the input array instead of creating a intermediate buffer. + * @param x The x-coordinate of the pixel rectangle in <code>obj</code>. + * @param y The y-coordinate of the pixel rectangle in <code>obj</code>. + * @param w The width of the pixel rectangle in <code>obj</code>. + * @param h The height of the pixel rectangle in <code>obj</code>. + * @param iArray The primitive array containing the pixels to set. + * @param data The DataBuffer to store the pixels into. + * @see java.awt.image.SampleModel#setPixels(int, int, int, int, int[], + * java.awt.image.DataBuffer) + */ + public void setPixels(int x, int y, int w, int h, int[] iArray, + DataBuffer data) + { + int inOffset = 0; + for (int yy=y; yy<(y+h); yy++) + { + int offset = scanlineStride*yy + x; + for (int xx=x; xx<(x+w); xx++) + { + int samples = 0; + for (int b = 0; b < numBands; b++) + samples |= (iArray[inOffset+b] << bitOffsets[b]) & bitMasks[b]; + data.setElem(0, offset, samples); + inOffset += numBands; + offset += 1; + } + } + } + + /** + * Sets the sample value for a band for the pixel at (x, y) in the + * specified data buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param s the sample value. + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ + public void setSample(int x, int y, int b, int s, DataBuffer data) + { + int offset = scanlineStride*y + x; + int samples = data.getElem(offset); + int bitMask = bitMasks[b]; + samples &= ~bitMask; + samples |= (s << bitOffsets[b]) & bitMask; + data.setElem(offset, samples); + } + + /** + * Tests this sample model for equality with an arbitrary object. This + * method returns <code>true</code> if and only if: + * <ul> + * <li><code>obj</code> is not <code>null</code>; + * <li><code>obj</code> is an instance of + * <code>SinglePixelPackedSampleModel</code>; + * <li>both models have the same: + * <ul> + * <li><code>dataType</code>; + * <li><code>width</code>; + * <li><code>height</code>; + * <li><code>numBands</code>; + * <li><code>scanlineStride</code>; + * <li><code>bitMasks</code>; + * <li><code>bitOffsets</code>. + * </ul> + * </li> + * </ul> + * + * @param obj the object (<code>null</code> permitted) + * + * @return <code>true</code> if this model is equal to <code>obj</code>, and + * <code>false</code> otherwise. + */ + public boolean equals(Object obj) + { + if (this == obj) + return true; + if (! (obj instanceof SinglePixelPackedSampleModel)) + return false; + SinglePixelPackedSampleModel that = (SinglePixelPackedSampleModel) obj; + if (this.dataType != that.dataType) + return false; + if (this.width != that.width) + return false; + if (this.height != that.height) + return false; + if (this.numBands != that.numBands) + return false; + if (this.scanlineStride != that.scanlineStride) + return false; + if (!Arrays.equals(this.bitMasks, that.bitMasks)) + return false; + if (!Arrays.equals(this.bitOffsets, that.bitOffsets)) + return false; + return true; + } + + /** + * Returns a hash code for this <code>SinglePixelPackedSampleModel</code>. + * + * @return A hash code. + */ + public int hashCode() + { + // this hash code won't match Sun's, but that shouldn't matter... + int result = 193; + result = 37 * result + dataType; + result = 37 * result + width; + result = 37 * result + height; + result = 37 * result + numBands; + result = 37 * result + scanlineStride; + for (int i = 0; i < bitMasks.length; i++) + result = 37 * result + bitMasks[i]; + for (int i = 0; i < bitOffsets.length; i++) + result = 37 * result + bitOffsets[i]; + return result; + } + + /** + * Creates a String with some information about this SampleModel. + * @return A String describing this SampleModel. + * @see java.lang.Object#toString() + */ + public String toString() + { + CPStringBuilder result = new CPStringBuilder(); + result.append(getClass().getName()); + result.append("["); + result.append("scanlineStride=").append(scanlineStride); + for(int i = 0; i < bitMasks.length; i+=1) + { + result.append(", mask[").append(i).append("]=0x").append( + Integer.toHexString(bitMasks[i])); + } + + result.append("]"); + return result.toString(); + } +} diff --git a/libjava/classpath/java/awt/image/TileObserver.java b/libjava/classpath/java/awt/image/TileObserver.java new file mode 100644 index 000000000..769888e40 --- /dev/null +++ b/libjava/classpath/java/awt/image/TileObserver.java @@ -0,0 +1,47 @@ +/* TileObserver.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +/** + * NEEDS DOCUMENTATION + */ +public interface TileObserver +{ + void tileUpdate(WritableRenderedImage src, int x, int y, boolean writable); +} // interface TileObserver diff --git a/libjava/classpath/java/awt/image/VolatileImage.java b/libjava/classpath/java/awt/image/VolatileImage.java new file mode 100644 index 000000000..308654162 --- /dev/null +++ b/libjava/classpath/java/awt/image/VolatileImage.java @@ -0,0 +1,253 @@ +/* VolatileImage.java -- a hardware-accelerated image buffer + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Transparency; +import java.awt.ImageCapabilities; + +/** + * VolatileImage represents a hardware-accelerated graphics buffer. + * The native graphics system may free or damage the resources + * occupied by a VolatileImage at any time. As such, one must + * frequently check the "validity" of the image buffer's resources. + * + * A volatile image's "validity" depends on multiple factors. Its + * resources may have become unavailble in which case you must + * reallocate them. If you move the image from one output device to + * another, you may need to recreate the image's resources if the new + * output device's capabilities don't match the old one's. Finally, + * if the contents of the image's buffer have been damaged you must + * re-render the image. + * + * VolatileImages should always be created using either + * Component.createVolatileImage or + * GraphicsConfiguration.createCompatibleVolatileImage. + */ +public abstract class VolatileImage extends Image + implements Transparency +{ + /** + * One of validate's possible return values. Indicates that the + * image buffer matches its graphics configuration's capabilities + * and that its resources are initialized and ready to be drawn + * into. Also implies that any existing image rendered to the + * buffer is intact and need not be re-rendered. + */ + public static final int IMAGE_OK = 0; + + /** + * One of validate's possible return values. Indicates that the + * image buffer has been restored, meaning that it is valid and + * ready-to-use but that its previous contents have been lost. This + * return value implies that the image needs to be re-rendered. + */ + public static final int IMAGE_RESTORED = 1; + + /** + * One of validate's possible return values. Indicates that the + * image buffer type is unsupported by the current graphics + * configuration. The graphics configuration may have changed, for + * example if the image moved from one output device to another. + * This return value implies that the image buffer's resources + * should be re-acquired. + */ + public static final int IMAGE_INCOMPATIBLE = 2; + + /** + * This image's transparency type. One of Transparency.BITMASK, + * Transparency.OPAQUE or Transparency.TRANSLUCENT. + * + * @since 1.5 + */ + protected int transparency; + + /** + * Default constructor. VolatileImages should not be created + * directly. Rather, you should use Component.createVolatileImage + * or GraphicsConfiguration.createCompatibleVolatileImage. + */ + public VolatileImage() + { + } + + /** + * Returns an image representing the current state of the volatile + * image buffer. The returned image is static meaning that it is + * not updated after being created. It is a snapshot of the + * volatile image buffer at the time getSnapshot is called. + * + * This method, which reads pixels from the volatile image buffer, + * may be less-performant than methods that write pixels since + * VolatileImages are typically optimized for writing. + * + * @return a BufferedImage representing this VolatileImage + */ + public abstract BufferedImage getSnapshot(); + + /** + * Returns the width of this image buffer. + * + * @return the width of this VolatileImage + */ + public abstract int getWidth(); + + /** + * Returns the height of this image buffer. + * + * @return the height of this VolatileImage + */ + public abstract int getHeight(); + + /** + * Calling this method is equivalent to calling + * getSnapshot().getSource(). The ImageProducer produces pixels + * from the BufferedImage snapshot and not from the VolatileImage + * itself. Thus, changes to the VolatileImage that occur after this + * ImageProducer has been retrieved will not be reflected in the + * produced pixels. + * + * This method, which reads pixels from the volatile image buffer, + * may be less-performant than methods that write pixels since + * VolatileImages are typically optimized for writing. + * + * @return an ImageProducer for a static BufferedImage snapshot of + * this image buffer + */ + public ImageProducer getSource() + { + return getSnapshot().getSource(); + } + + /** + * Releases the system resources taken by this image. + */ + public void flush() + { + } + + /** + * Returns a Graphics2D object that can be used to draw onto this + * image. This method is present for backwards-compatibility. It + * simply returns the result of createGraphics. + * + * @return a Graphics2D object that can be used to draw onto this + * image + */ + public Graphics getGraphics() + { + return createGraphics(); + } + + /** + * Returns a Graphics2D object that can be used to draw onto this + * image. + * + * @return a Graphics2D object that can be used to draw onto this + * image + */ + public abstract Graphics2D createGraphics(); + + /** + * Validates and restores this image. If the image buffer has + * become unavailable for further use since the last call to + * validate, validate will allocate a new image buffer. The image + * is also "validated" against the GraphicsConfiguration parameter. + * + * "Validating" the image means checking that the capabilities it + * requires of the output device are indeed supported by the given + * output device. If the image's characteristics, which can be + * highly output device-specific, are not supported by the graphics + * configuration, then IMAGE_INCOMPATIBLE will be returned. This + * can happen, for example, if this image was created on one output + * device, then validated against a different output device with + * different capabilities. Calling validate with a NULL gc argument + * causes validate to skip the validation test. + * + * @param gc graphics configuration against which to validate or + * NULL + * + * @return a code indicating the result of validation. One of: + * <ul> + * <li><code>IMAGE_OK</code> if the image did not need to be + * validated and didn't need to be restored</li> + * <li><code>IMAGE_RESTORED</code> if the image may need to be + * re-rendered.</li> + * <li><code>IMAGE_INCOMPATIBLE</code> if this image's + * requirements are not fulfilled by the graphics configuration + * parameter. This implies that you need to create a new + * VolatileImage for the different GraphicsConfiguration or + * Component. This return value implies nothing about whether the + * image is valid or needs to be re-rendered.</li> + * </ul> + */ + public abstract int validate(GraphicsConfiguration gc); + + /** + * Returns true if the contents of the image buffer have been + * damaged or if the image buffer's resources have been reclaimed by + * the graphics system. You should call this method after a series + * of rendering operations to or from the image, to see if the image + * buffer needs to be revalidated or the image re-rendered. + * + * @return true if the validate should be called, false otherwise + */ + public abstract boolean contentsLost(); + + /** + * Returns the capabilities of this image buffer. + * + * @return the capabilities of this image buffer + */ + public abstract ImageCapabilities getCapabilities(); + + /** + * Returns the transparency type of this image. + * + * @return Transparency.OPAQUE, Transparency.BITMASK or + * Transparency.TRANSLUCENT + */ + public int getTransparency() + { + return transparency; + } +} diff --git a/libjava/classpath/java/awt/image/WritableRaster.java b/libjava/classpath/java/awt/image/WritableRaster.java new file mode 100644 index 000000000..68774f785 --- /dev/null +++ b/libjava/classpath/java/awt/image/WritableRaster.java @@ -0,0 +1,448 @@ +/* Copyright (C) 2000, 2002, 2003, 2006, Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import java.awt.Point; +import java.awt.Rectangle; + +/** + * A raster with methods to support updating pixel values. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public class WritableRaster extends Raster +{ + /** + * Creates a new <code>WritableRaster</code>. + * + * @param sampleModel the sample model. + * @param origin the origin. + */ + protected WritableRaster(SampleModel sampleModel, Point origin) + { + this(sampleModel, sampleModel.createDataBuffer(), origin); + } + + /** + * Creates a new <code>WritableRaster</code> instance. + * + * @param sampleModel the sample model. + * @param dataBuffer the data buffer. + * @param origin the origin. + */ + protected WritableRaster(SampleModel sampleModel, DataBuffer dataBuffer, + Point origin) + { + this(sampleModel, dataBuffer, + new Rectangle(origin != null ? origin.x : 0, + origin != null ? origin.y : 0, + sampleModel.getWidth(), sampleModel.getHeight()), + origin, null); + } + + /** + * Creates a new <code>WritableRaster</code> instance. + * + * @param sampleModel the sample model. + * @param dataBuffer the data buffer. + * @param aRegion the raster's bounds. + * @param sampleModelTranslate the translation. + * @param parent the parent. + */ + protected WritableRaster(SampleModel sampleModel, + DataBuffer dataBuffer, + Rectangle aRegion, + Point sampleModelTranslate, + WritableRaster parent) + { + super(sampleModel, dataBuffer, aRegion, sampleModelTranslate, parent); + } + + /** + * Returns the raster's parent, cast as a {@link WritableRaster}. + * + * @return The raster's parent. + */ + public WritableRaster getWritableParent() + { + return (WritableRaster) getParent(); + } + + /** + * @param childMinX + * @param childMinY + * @return + */ + public WritableRaster createWritableTranslatedChild(int childMinX, + int childMinY) + { + return createWritableChild(minX, minY, width, height, + childMinX, childMinY, null); + } + + /** + * + * @param parentX + * @param parentY + * @param w + * @param h + * @param childMinX + * @param childMinY + * @param bandList + * @return + */ + public WritableRaster createWritableChild(int parentX, int parentY, + int w, int h, int childMinX, int childMinY, int[] bandList) + { + // This mirrors the code from the super class + + if (parentX < minX || parentX + w > minX + width + || parentY < minY || parentY + h > minY + height) + throw new RasterFormatException("Child raster extends beyond parent"); + + SampleModel sm = (bandList == null) ? + sampleModel : + sampleModel.createSubsetSampleModel(bandList); + + return new WritableRaster(sm, getDataBuffer(), + new Rectangle(childMinX, childMinY, w, h), + new Point(sampleModelTranslateX + childMinX - + parentX, + sampleModelTranslateY + childMinY - + parentY), + this); + } + + public Raster createChild(int parentX, int parentY, int width, + int height, int childMinX, int childMinY, + int[] bandList) + { + if (parentX < minX || parentX + width > minX + this.width + || parentY < minY || parentY + height > minY + this.height) + throw new RasterFormatException("Child raster extends beyond parent"); + + SampleModel sm = (bandList == null) ? + sampleModel : + sampleModel.createSubsetSampleModel(bandList); + + return new WritableRaster(sm, dataBuffer, + new Rectangle(childMinX, childMinY, width, height), + new Point(sampleModelTranslateX + childMinX - parentX, + sampleModelTranslateY + childMinY - parentY), + this); + } + + public void setDataElements(int x, int y, Object inData) + { + sampleModel.setDataElements(x - sampleModelTranslateX, + y - sampleModelTranslateY, inData, dataBuffer); + } + + public void setDataElements(int x, int y, Raster inRaster) + { + Object dataElements = getDataElements(0, 0, inRaster.getWidth(), + inRaster.getHeight(), null); + setDataElements(x, y, dataElements); + } + + public void setDataElements(int x, int y, int w, int h, Object inData) + { + sampleModel.setDataElements(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, inData, dataBuffer); + } + + /** + * + * @param srcRaster + */ + public void setRect(Raster srcRaster) + { + setRect(0, 0, srcRaster); + } + + /** + * + * @param dx + * @param dy + * @param srcRaster + */ + public void setRect(int dx, int dy, Raster srcRaster) + { + Rectangle targetUnclipped = new Rectangle(srcRaster.getMinX() + dx, + srcRaster.getMinY() + dy, srcRaster.getWidth(), srcRaster.getHeight()); + + Rectangle target = getBounds().intersection(targetUnclipped); + + if (target.isEmpty()) return; + + int sx = target.x - dx; + int sy = target.y - dy; + + // FIXME: Do tests on rasters and use get/set data instead. + + /* The JDK documentation seems to imply this implementation. + (the trucation of higher bits), but an implementation using + get/setDataElements would be more efficient. None of the + implementations would do anything sensible when the sample + models don't match. + + But this is probably not the place to consider such + optimizations.*/ + + int[] pixels = srcRaster.getPixels(sx, sy, target.width, target.height, + (int[]) null); + + setPixels(target.x, target.y, target.width, target.height, pixels); + } + + /** + * Sets the samples for the pixel at (x, y) in the raster to the specified + * values. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param iArray the sample values (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>iArray</code> is <code>null</code>. + */ + public void setPixel(int x, int y, int[] iArray) + { + sampleModel.setPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, + iArray, dataBuffer); + } + + /** + * Sets the samples for the pixel at (x, y) in the raster to the specified + * values. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param fArray the sample values (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>fArray</code> is <code>null</code>. + */ + public void setPixel(int x, int y, float[] fArray) + { + sampleModel.setPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, + fArray, dataBuffer); + } + + /** + * Sets the samples for the pixel at (x, y) in the raster to the specified + * values. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param dArray the sample values (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>dArray</code> is <code>null</code>. + */ + public void setPixel(int x, int y, double[] dArray) + { + sampleModel.setPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, + dArray, dataBuffer); + } + + /** + * Sets the sample values for the pixels in the region specified by + * (x, y, w, h) in the raster. The array is ordered by pixels (that is, all + * the samples for the first pixel are grouped together, followed by all the + * samples for the second pixel, and so on). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param iArray the pixel sample values (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>iArray</code> is <code>null</code>. + */ + public void setPixels(int x, int y, int w, int h, int[] iArray) + { + sampleModel.setPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, + w, h, iArray, dataBuffer); + } + + /** + * Sets the sample values for the pixels in the region specified by + * (x, y, w, h) in the raster. The array is ordered by pixels (that is, all + * the samples for the first pixel are grouped together, followed by all the + * samples for the second pixel, and so on). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param fArray the pixel sample values (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>fArray</code> is <code>null</code>. + */ + public void setPixels(int x, int y, int w, int h, float[] fArray) + { + sampleModel.setPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, + w, h, fArray, dataBuffer); + } + + /** + * Sets the sample values for the pixels in the region specified by + * (x, y, w, h) in the raster. The array is ordered by pixels (that is, all + * the samples for the first pixel are grouped together, followed by all the + * samples for the second pixel, and so on). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param dArray the pixel sample values (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>dArray</code> is <code>null</code>. + */ + public void setPixels(int x, int y, int w, int h, double[] dArray) + { + sampleModel.setPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, + w, h, dArray, dataBuffer); + } + + /** + * Sets the sample value for a band for the pixel at (x, y) in the raster. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param s the sample value. + */ + public void setSample(int x, int y, int b, int s) + { + sampleModel.setSample(x - sampleModelTranslateX, y - sampleModelTranslateY, + b, s, dataBuffer); + } + + /** + * Sets the sample value for a band for the pixel at (x, y) in the raster. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param s the sample value. + */ + public void setSample(int x, int y, int b, float s) + { + sampleModel.setSample(x - sampleModelTranslateX, y - sampleModelTranslateY, + b, s, dataBuffer); + } + + /** + * Sets the sample value for a band for the pixel at (x, y) in the raster. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param s the sample value. + */ + public void setSample(int x, int y, int b, double s) + { + sampleModel.setSample(x - sampleModelTranslateX, y - sampleModelTranslateY, + b, s, dataBuffer); + } + + /** + * Sets the sample values for one band for the pixels in the region + * specified by (x, y, w, h) in the raster. + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param iArray the sample values (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>iArray</code> is <code>null</code>. + */ + public void setSamples(int x, int y, int w, int h, int b, + int[] iArray) + { + sampleModel.setSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, + w, h, b, iArray, dataBuffer); + } + + /** + * Sets the sample values for one band for the pixels in the region + * specified by (x, y, w, h) in the raster. + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param fArray the sample values (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>fArray</code> is <code>null</code>. + */ + public void setSamples(int x, int y, int w, int h, int b, + float[] fArray) + { + sampleModel.setSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, + w, h, b, fArray, dataBuffer); + } + + /** + * Sets the sample values for one band for the pixels in the region + * specified by (x, y, w, h) in the raster. + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param dArray the sample values (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>dArray</code> is <code>null</code>. + */ + public void setSamples(int x, int y, int w, int h, int b, + double[] dArray) + { + sampleModel.setSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, + w, h, b, dArray, dataBuffer); + } +} diff --git a/libjava/classpath/java/awt/image/WritableRenderedImage.java b/libjava/classpath/java/awt/image/WritableRenderedImage.java new file mode 100644 index 000000000..9142fe004 --- /dev/null +++ b/libjava/classpath/java/awt/image/WritableRenderedImage.java @@ -0,0 +1,56 @@ +/* WritableRenderedImage.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image; + +import java.awt.Point; + +/** + * NEEDS DOCUMENTATION + */ +public interface WritableRenderedImage extends RenderedImage +{ + void addTileObserver(TileObserver to); + void removeTileObserver(TileObserver to); + WritableRaster getWritableTile(int x, int y); + void releaseWritableTile(int x, int y); + boolean isTileWritable(int x, int y); + Point[] getWritableTileIndices(); + boolean hasTileWriters(); + void setData(Raster r); +} // interface WritableRenderedImage diff --git a/libjava/classpath/java/awt/image/package.html b/libjava/classpath/java/awt/image/package.html new file mode 100644 index 000000000..50fa99d13 --- /dev/null +++ b/libjava/classpath/java/awt/image/package.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in java.awt.image package. + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - java.awt.image</title></head> + +<body> +<p>Image consumers, producers and filters.</p> + +</body> +</html> diff --git a/libjava/classpath/java/awt/image/renderable/ContextualRenderedImageFactory.java b/libjava/classpath/java/awt/image/renderable/ContextualRenderedImageFactory.java new file mode 100644 index 000000000..8852bef1c --- /dev/null +++ b/libjava/classpath/java/awt/image/renderable/ContextualRenderedImageFactory.java @@ -0,0 +1,56 @@ +/* ContextualRenderedImageFactory.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image.renderable; + +import java.awt.geom.Rectangle2D; +import java.awt.image.RenderedImage; + +/** + * STUBBED + */ +public interface ContextualRenderedImageFactory extends RenderedImageFactory +{ + RenderContext mapRenderContext(int i, RenderContext context, + ParameterBlock block, RenderableImage image); + RenderedImage create(RenderContext context, ParameterBlock block); + Rectangle2D getBounds2D(ParameterBlock block); + Object getProperty(ParameterBlock block, String name); + String[] getPropertyNames(); + boolean isDynamic(); +} // interface ContextualRenderedImageFactory diff --git a/libjava/classpath/java/awt/image/renderable/ParameterBlock.java b/libjava/classpath/java/awt/image/renderable/ParameterBlock.java new file mode 100644 index 000000000..f38077816 --- /dev/null +++ b/libjava/classpath/java/awt/image/renderable/ParameterBlock.java @@ -0,0 +1,308 @@ +/* ParameterBlock.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image.renderable; + +import java.awt.image.RenderedImage; +import java.io.Serializable; +import java.util.Vector; + +public class ParameterBlock implements Cloneable, Serializable +{ + private static final long serialVersionUID = -7577115551785240750L; + protected Vector<Object> sources; + protected Vector<Object> parameters; + + public ParameterBlock() + { + this(new Vector<Object>(), new Vector<Object>()); + } + + public ParameterBlock(Vector<Object> sources) + { + this(sources, new Vector<Object>()); + } + + public ParameterBlock(Vector<Object> sources, Vector<Object> parameters) + { + this.sources = sources; + this.parameters = parameters; + } + + public Object shallowClone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // impossible + } + } + + public Object clone() + { + ParameterBlock pb = (ParameterBlock) shallowClone(); + if (sources != null) + pb.sources = (Vector<Object>) sources.clone(); + if (parameters != null) + pb.parameters = (Vector<Object>) parameters.clone(); + return pb; + } + + public ParameterBlock addSource(Object source) + { + sources.add(source); + return this; + } + + public Object getSource(int index) + { + return sources.get(index); + } + + public ParameterBlock setSource(Object source, int index) + { + sources.ensureCapacity(index); + sources.set(index, source); + return this; + } + + public RenderedImage getRenderedSource(int index) + { + return (RenderedImage) sources.get(index); + } + + public RenderableImage getRenderableSource(int index) + { + return (RenderableImage) sources.get(index); + } + + public int getNumSources() + { + return sources.size(); + } + + public Vector<Object> getSources() + { + return sources; + } + + public void setSources(Vector<Object> sources) + { + this.sources = sources; + } + + public void removeSources() + { + if (sources != null) + sources.clear(); + } + + public int getNumParameters() + { + return parameters.size(); + } + + public Vector<Object> getParameters() + { + return parameters; + } + + public void setParameters(Vector<Object> parameters) + { + this.parameters = parameters; + } + + public void removeParameters() + { + if (parameters != null) + parameters.clear(); + } + + public ParameterBlock add(Object o) + { + parameters.add(o); + return this; + } + + public ParameterBlock add(byte b) + { + return add(new Byte(b)); + } + + public ParameterBlock add(char c) + { + return add(new Character(c)); + } + + public ParameterBlock add(short s) + { + return add(new Short(s)); + } + + public ParameterBlock add(int i) + { + return add(new Integer(i)); + } + + public ParameterBlock add(long l) + { + return add(new Long(l)); + } + + public ParameterBlock add(float f) + { + return add(new Float(f)); + } + + public ParameterBlock add(double d) + { + return add(new Double(d)); + } + + public ParameterBlock set(Object o, int index) + { + parameters.ensureCapacity(index); + parameters.set(index, o); + return this; + } + + public ParameterBlock set(byte b, int index) + { + return set(new Byte(b), index); + } + + public ParameterBlock set(char c, int index) + { + return set(new Character(c), index); + } + + public ParameterBlock set(short s, int index) + { + return set(new Short(s), index); + } + + public ParameterBlock set(int i, int index) + { + return set(new Integer(i), index); + } + + public ParameterBlock set(long l, int index) + { + return set(new Long(l), index); + } + + public ParameterBlock set(float f, int index) + { + return set(new Float(f), index); + } + + public ParameterBlock set(double d, int index) + { + return set(new Double(d), index); + } + + public Object getObjectParameter(int index) + { + return parameters.get(index); + } + + public byte getByteParameter(int index) + { + return ((Byte) parameters.get(index)).byteValue(); + } + + public char getCharParameter(int index) + { + return ((Character) parameters.get(index)).charValue(); + } + + public short getShortParameter(int index) + { + return ((Short) parameters.get(index)).shortValue(); + } + + public int getIntParameter(int index) + { + return ((Integer) parameters.get(index)).intValue(); + } + + public long getLongParameter(int index) + { + return ((Long) parameters.get(index)).longValue(); + } + + public float getFloatParameter(int index) + { + return ((Float) parameters.get(index)).floatValue(); + } + + public double getDoubleParameter(int index) + { + return ((Double) parameters.get(index)).doubleValue(); + } + + public Class[] getParamClasses() + { + int i = parameters.size(); + Class[] result = new Class[i]; + while (--i >= 0) + { + Class c = parameters.get(i).getClass(); + if (c == Byte.class) + result[i] = byte.class; + else if (c == Character.class) + result[i] = char.class; + else if (c == Short.class) + result[i] = short.class; + else if (c == Integer.class) + result[i] = int.class; + else if (c == Long.class) + result[i] = long.class; + else if (c == Float.class) + result[i] = float.class; + else if (c == Double.class) + result[i] = double.class; + else + result[i] = c; + } + return result; + } +} // class ParameterBlock diff --git a/libjava/classpath/java/awt/image/renderable/RenderContext.java b/libjava/classpath/java/awt/image/renderable/RenderContext.java new file mode 100644 index 000000000..8017c1acf --- /dev/null +++ b/libjava/classpath/java/awt/image/renderable/RenderContext.java @@ -0,0 +1,141 @@ +/* RenderContext.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image.renderable; + +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.geom.AffineTransform; + +public class RenderContext implements Cloneable +{ + private AffineTransform xform; + private Shape aoi; + private RenderingHints hints; + + public RenderContext(AffineTransform xform, Shape aoi, RenderingHints hints) + { + this.xform = xform; + this.aoi = aoi; + this.hints = hints; + } + + public RenderContext(AffineTransform xform) + { + this(xform, null, null); + } + + public RenderContext(AffineTransform xform, RenderingHints hints) + { + this(xform, null, hints); + } + + public RenderContext(AffineTransform xform, Shape aoi) + { + this(xform, aoi, null); + } + + public RenderingHints getRenderingHints() + { + return hints; + } + + public void setRenderingHints(RenderingHints hints) + { + this.hints = hints; + } + + public void setTransform(AffineTransform xform) + { + this.xform = xform; + } + + public void preConcatenateTransform(AffineTransform pre) + { + preConcetenateTransform (pre); + } + + /** @deprecated */ + public void preConcetenateTransform(AffineTransform pre) + { + xform.preConcatenate (pre); + } + + public void concatenateTransform(AffineTransform post) + { + concetenateTransform (post); + } + + /** @deprecated */ + public void concetenateTransform(AffineTransform post) + { + xform.concatenate (post); + } + + public AffineTransform getTransform() + { + return xform; + } + + public void setAreaOfInterest(Shape aoi) + { + this.aoi = aoi; + } + + public Shape getAreaOfInterest() + { + return aoi; + } + + public Object clone() + { + try + { + RenderContext copy = (RenderContext) super.clone(); + if (xform != null) + copy.xform = (AffineTransform) xform.clone(); + if (hints != null) + copy.hints = (RenderingHints) hints.clone(); + return copy; + } + catch (CloneNotSupportedException e) + { + throw (Error) new InternalError().initCause(e); // impossible + } + } +} // class RenderContext diff --git a/libjava/classpath/java/awt/image/renderable/RenderableImage.java b/libjava/classpath/java/awt/image/renderable/RenderableImage.java new file mode 100644 index 000000000..31767af2c --- /dev/null +++ b/libjava/classpath/java/awt/image/renderable/RenderableImage.java @@ -0,0 +1,61 @@ +/* RenderableImage.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image.renderable; + +import java.awt.RenderingHints; +import java.awt.image.RenderedImage; +import java.util.Vector; + +public interface RenderableImage +{ + String HINTS_OBSERVED = "HINTS_OBSERVED"; + + Vector<RenderableImage> getSources(); + Object getProperty(String name); + String[] getPropertyNames(); + boolean isDynamic(); + float getWidth(); + float getHeight(); + float getMinX(); + float getMinY(); + RenderedImage createScaledRendering(int w, int h, RenderingHints hints); + RenderedImage createDefaultRendering(); + RenderedImage createRendering(RenderContext context); + +} // interface RenderableImage diff --git a/libjava/classpath/java/awt/image/renderable/RenderableImageOp.java b/libjava/classpath/java/awt/image/renderable/RenderableImageOp.java new file mode 100644 index 000000000..81e537cd5 --- /dev/null +++ b/libjava/classpath/java/awt/image/renderable/RenderableImageOp.java @@ -0,0 +1,157 @@ +/* RenderableImageOp.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image.renderable; + +import java.awt.RenderingHints; +import java.awt.geom.AffineTransform; +import java.awt.image.RenderedImage; +import java.util.Vector; + +public class RenderableImageOp implements RenderableImage +{ + private final ContextualRenderedImageFactory crif; + private ParameterBlock block; + + public RenderableImageOp(ContextualRenderedImageFactory crif, + ParameterBlock block) + { + this.crif = crif; + this.block = (ParameterBlock) block.clone(); + } + + public Vector<RenderableImage> getSources() + { + if (block.sources == null) + return null; + int size = block.sources.size(); + Vector v = new Vector(); + for (int i = 0; i < size; i++) + { + Object o = block.sources.get(i); + if (o instanceof RenderableImage) + v.add(o); + } + return v; + } + + public Object getProperty(String name) + { + return crif.getProperty(block, name); + } + + public String[] getPropertyNames() + { + return crif.getPropertyNames(); + } + + public boolean isDynamic() + { + return crif.isDynamic(); + } + + public float getWidth() + { + return (float) crif.getBounds2D(block).getWidth(); + } + + public float getHeight() + { + return (float) crif.getBounds2D(block).getHeight(); + } + + public float getMinX() + { + return (float) crif.getBounds2D(block).getX(); + } + + public float getMinY() + { + return (float) crif.getBounds2D(block).getY(); + } + + public ParameterBlock setParameterBlock(ParameterBlock block) + { + ParameterBlock result = this.block; + this.block = (ParameterBlock) block.clone(); + return result; + } + + public ParameterBlock getParameterBlock() + { + return block; + } + + public RenderedImage createScaledRendering(int w, int h, + RenderingHints hints) + { + if (w == 0) + if (h == 0) + throw new IllegalArgumentException(); + else + w = Math.round(h * getWidth() / getHeight()); + if (h == 0) + h = Math.round(w * getHeight() / getWidth()); + AffineTransform xform = AffineTransform.getScaleInstance(w * getWidth(), + h * getHeight()); + return createRendering(new RenderContext(xform, hints)); + } + + public RenderedImage createDefaultRendering() + { + return createRendering(new RenderContext(new AffineTransform())); + } + + public RenderedImage createRendering(RenderContext context) + { + ParameterBlock copy = (ParameterBlock) block.clone(); + int i = block.sources.size(); + while (--i >= 0) + { + Object o = block.sources.get(i); + if (o instanceof RenderableImage) + { + RenderableImage ri = (RenderableImage) o; + RenderContext rc = crif.mapRenderContext(i, context, block, ri); + copy.sources.set(i, ri.createRendering(rc)); + } + } + // Now copy.sources should be only RenderedImages. + return crif.create(context, copy); + } +} // class RenderableImageOp diff --git a/libjava/classpath/java/awt/image/renderable/RenderableImageProducer.java b/libjava/classpath/java/awt/image/renderable/RenderableImageProducer.java new file mode 100644 index 000000000..bd3b507cb --- /dev/null +++ b/libjava/classpath/java/awt/image/renderable/RenderableImageProducer.java @@ -0,0 +1,166 @@ +/* RenderableImageProducer.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image.renderable; + +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.ImageConsumer; +import java.awt.image.ImageProducer; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.SampleModel; +import java.util.ArrayList; +import java.util.Iterator; + +public class RenderableImageProducer implements ImageProducer, Runnable +{ + private RenderableImage image; + private RenderContext context; + private ArrayList consumers = new ArrayList(); + + public RenderableImageProducer(RenderableImage image, RenderContext context) + { + this.image = image; + this.context = context; + } + + public void setRenderContext(RenderContext context) + { + this.context = context; + } + + public void addConsumer(ImageConsumer consumer) + { + synchronized (consumers) + { + if (! consumers.contains(consumer)) + consumers.add(consumer); + } + } + + public boolean isConsumer(ImageConsumer consumer) + { + synchronized (consumers) + { + return consumers.contains(consumer); + } + } + + public void removeConsumer(ImageConsumer consumer) + { + synchronized (consumers) + { + consumers.remove(consumer); + } + } + + public void startProduction(ImageConsumer consumer) + { + addConsumer(consumer); + Thread t = new Thread(this, "RenderableImageProducerWorker"); + t.start(); + } + + public void requestTopDownLeftRightResend(ImageConsumer consumer) + { + // Do nothing. The contract says we can ignore this call, so we do. + } + + public void run() + { + // This isn't ideal but it avoids fail-fast problems. + // Alternatively, we could clone 'consumers' here. + synchronized (consumers) + { + RenderedImage newImage; + if (context == null) + newImage = image.createDefaultRendering(); + else + newImage = image.createRendering(context); + Raster newData = newImage.getData(); + ColorModel colorModel = newImage.getColorModel(); + if (colorModel == null) + colorModel = ColorModel.getRGBdefault(); + SampleModel sampleModel = newData.getSampleModel(); + DataBuffer dataBuffer = newData.getDataBuffer(); + int width = newData.getWidth(); + int height = newData.getHeight(); + + // Initialize the consumers. + Iterator it = consumers.iterator(); + while (it.hasNext()) + { + ImageConsumer target = (ImageConsumer) it.next(); + target.setHints(ImageConsumer.COMPLETESCANLINES + | ImageConsumer.SINGLEFRAME + | ImageConsumer.SINGLEPASS + | ImageConsumer.TOPDOWNLEFTRIGHT); + target.setDimensions(width, height); + } + + // Work in scan-line order. + int[] newLine = new int[width]; + int[] bands = new int[sampleModel.getNumBands()]; + for (int y = 0; y < height; ++y) + { + for (int x = 0; x < width; ++x) + { + sampleModel.getPixel(x, y, bands, dataBuffer); + newLine[x] = colorModel.getDataElement(bands, 0); + } + + // Tell the consumers about the new scan line. + it = consumers.iterator(); + while (it.hasNext()) + { + ImageConsumer target = (ImageConsumer) it.next(); + target.setPixels(0, y, width, 1, colorModel, newLine, 0, width); + } + } + + // Tell the consumers that we're done. + it = consumers.iterator(); + while (it.hasNext()) + { + ImageConsumer target = (ImageConsumer) it.next(); + target.imageComplete(ImageConsumer.STATICIMAGEDONE); + } + } + } +} // class RenderableImageProducer diff --git a/libjava/classpath/java/awt/image/renderable/RenderedImageFactory.java b/libjava/classpath/java/awt/image/renderable/RenderedImageFactory.java new file mode 100644 index 000000000..ea2bd69f7 --- /dev/null +++ b/libjava/classpath/java/awt/image/renderable/RenderedImageFactory.java @@ -0,0 +1,47 @@ +/* RenderedImageFactory.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.image.renderable; + +import java.awt.RenderingHints; +import java.awt.image.RenderedImage; + +public interface RenderedImageFactory +{ + RenderedImage create(ParameterBlock block, RenderingHints hints); +} // interface RenderedImageFactory diff --git a/libjava/classpath/java/awt/image/renderable/package.html b/libjava/classpath/java/awt/image/renderable/package.html new file mode 100644 index 000000000..a24237e72 --- /dev/null +++ b/libjava/classpath/java/awt/image/renderable/package.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in java.awt.image.renderable package. + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - java.awt.image.renderable</title></head> + +<body> +<p></p> + +</body> +</html> diff --git a/libjava/classpath/java/awt/package.html b/libjava/classpath/java/awt/package.html new file mode 100644 index 000000000..c5ff9881a --- /dev/null +++ b/libjava/classpath/java/awt/package.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in java.awt package. + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - java.awt</title></head> + +<body> +<p>Abstract Window Toolkit classes.</p> + +</body> +</html> diff --git a/libjava/classpath/java/awt/peer/ButtonPeer.java b/libjava/classpath/java/awt/peer/ButtonPeer.java new file mode 100644 index 000000000..6e2510ff5 --- /dev/null +++ b/libjava/classpath/java/awt/peer/ButtonPeer.java @@ -0,0 +1,45 @@ +/* ButtonPeer.java -- Peer interface for buttons + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +public interface ButtonPeer extends ComponentPeer +{ + void setLabel (String label); + +} // interface ButtonPeer diff --git a/libjava/classpath/java/awt/peer/CanvasPeer.java b/libjava/classpath/java/awt/peer/CanvasPeer.java new file mode 100644 index 000000000..241a0e4e3 --- /dev/null +++ b/libjava/classpath/java/awt/peer/CanvasPeer.java @@ -0,0 +1,44 @@ +/* CanvasPeer.java -- Peer interface for a canvas + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +public interface CanvasPeer extends ComponentPeer +{ + +} // interface CanvasPeer diff --git a/libjava/classpath/java/awt/peer/CheckboxMenuItemPeer.java b/libjava/classpath/java/awt/peer/CheckboxMenuItemPeer.java new file mode 100644 index 000000000..3cc8f72a6 --- /dev/null +++ b/libjava/classpath/java/awt/peer/CheckboxMenuItemPeer.java @@ -0,0 +1,45 @@ +/* CheckboxMenuItemPeer.java -- Peer interface for checkbox menu items + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +public interface CheckboxMenuItemPeer extends MenuItemPeer +{ + void setState (boolean state); + +} // interface CheckboxMenuItemPeer diff --git a/libjava/classpath/java/awt/peer/CheckboxPeer.java b/libjava/classpath/java/awt/peer/CheckboxPeer.java new file mode 100644 index 000000000..639614891 --- /dev/null +++ b/libjava/classpath/java/awt/peer/CheckboxPeer.java @@ -0,0 +1,51 @@ +/* CheckboxPeer.java -- Interface for checkbox peer + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +import java.awt.CheckboxGroup; + +public interface CheckboxPeer extends ComponentPeer +{ + void setCheckboxGroup (CheckboxGroup group); + + void setLabel (String label); + + void setState (boolean state); + +} // interface CheckboxPeer diff --git a/libjava/classpath/java/awt/peer/ChoicePeer.java b/libjava/classpath/java/awt/peer/ChoicePeer.java new file mode 100644 index 000000000..3605a97ef --- /dev/null +++ b/libjava/classpath/java/awt/peer/ChoicePeer.java @@ -0,0 +1,53 @@ +/* ChoicePeer.java -- Peer for choice box + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +public interface ChoicePeer extends ComponentPeer +{ + void add (String item, int index); + + void addItem (String item, int index); + + void remove (int index); + + void removeAll(); + + void select (int index); + +} // interface ChoicePeer diff --git a/libjava/classpath/java/awt/peer/ComponentPeer.java b/libjava/classpath/java/awt/peer/ComponentPeer.java new file mode 100644 index 000000000..736cdf376 --- /dev/null +++ b/libjava/classpath/java/awt/peer/ComponentPeer.java @@ -0,0 +1,532 @@ +/* ComponentPeer.java -- Toplevel component peer + Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +import java.awt.AWTEvent; +import java.awt.AWTException; +import java.awt.BufferCapabilities; +import java.awt.Color; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.event.PaintEvent; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.VolatileImage; + +import sun.awt.CausedFocusEvent; + +/** + * Defines the methods that a component peer is required to implement. + */ +public interface ComponentPeer +{ + /** + * Returns the construction status of the specified image. This is called + * by {@link Component#checkImage(Image, int, int, ImageObserver)}. + * + * @param img the image + * @param width the width of the image + * @param height the height of the image + * @param ob the image observer to be notified of updates of the status + * + * @return a bitwise ORed set of ImageObserver flags + */ + int checkImage(Image img, int width, int height, + ImageObserver ob); + + /** + * Creates an image by starting the specified image producer. This is called + * by {@link Component#createImage(ImageProducer)}. + * + * @param prod the image producer to be used to create the image + * + * @return the created image + */ + Image createImage(ImageProducer prod); + + /** + * Creates an empty image with the specified <code>width</code> and + * <code>height</code>. + * + * @param width the width of the image to be created + * @param height the height of the image to be created + * + * @return the created image + */ + Image createImage(int width, int height); + + /** + * Disables the component. This is called by {@link Component#disable()}. + */ + void disable(); + + /** + * Disposes the component peer. This should release all resources held by the + * peer. This is called when the component is no longer in use. + */ + void dispose(); + + /** + * Enables the component. This is called by {@link Component#enable()}. + */ + void enable(); + + /** + * Returns the color model of the component. This is currently not used. + * + * @return the color model of the component + */ + ColorModel getColorModel(); + + /** + * Returns the font metrics for the specified font. This is called by + * {@link Component#getFontMetrics(Font)}. + * + * @param f the font for which to query the font metrics + * + * @return the font metrics for the specified font + */ + FontMetrics getFontMetrics(Font f); + + /** + * Returns a {@link Graphics} object suitable for drawing on this component. + * This is called by {@link Component#getGraphics()}. + * + * @return a graphics object suitable for drawing on this component + */ + Graphics getGraphics(); + + /** + * Returns the location of this component in screen coordinates. This is + * called by {@link Component#getLocationOnScreen()}. + * + * @return the location of this component in screen coordinates + */ + Point getLocationOnScreen(); + + /** + * Returns the minimum size for the component. This is called by + * {@link Component#getMinimumSize()}. + * + * @return the minimum size for the component + * + * @specnote Presumably this method got added to replace minimumSize(). + * However, testing shows that this is never called in the RI + * (tested with JDK5), but instead minimumSize() is called + * directly. It is advisable to implement this method to delegate + * to minimumSize() and put the real implementation in there. + */ + Dimension getMinimumSize(); + + /** + * Returns the preferred size for the component. This is called by + * {@link Component#getPreferredSize()}. + * + * @return the preferred size for the component + * + * @specnote Presumably this method got added to replace preferredSize(). + * However, testing shows that this is never called in the RI + * (tested with JDK5), but instead preferredSize() is called + * directly. It is advisable to implement this method to delegate + * to preferredSize() and put the real implementation in there. + */ + Dimension getPreferredSize(); + + /** + * Returns the toolkit that created this peer. + * + * @return the toolkit that created this peer + */ + Toolkit getToolkit(); + + /** + * Handles the given event. This is called from + * {@link Component#dispatchEvent(AWTEvent)} to give the peer a chance to + * react to events for the component. + * + * @param e the event + */ + void handleEvent(AWTEvent e); + + /** + * Makes the component invisible. This is called from + * {@link Component#hide()}. + */ + void hide(); + + /** + * Returns <code>true</code> if the component can receive keyboard input + * focus. This is called from {@link Component#isFocusTraversable()}. + * + * @specnote Part of the earlier 1.1 API, replaced by isFocusable(). + */ + boolean isFocusTraversable(); + + /** + * Returns <code>true</code> if the component can receive keyboard input + * focus. This is called from {@link Component#isFocusable()}. + */ + boolean isFocusable(); + + /** + * Returns the minimum size for the component. This is called by + * {@link Component#minimumSize()}. + * + * @return the minimum size for the component + */ + Dimension minimumSize(); + + /** + * Returns the preferred size for the component. This is called by + * {@link Component#getPreferredSize()}. + * + * @return the preferred size for the component + */ + Dimension preferredSize(); + + void paint(Graphics graphics); + + /** + * Prepares an image for rendering on this component. This is called by + * {@link Component#prepareImage(Image, int, int, ImageObserver)}. + * + * @param img the image to prepare + * @param width the desired width of the rendered image + * @param height the desired height of the rendered image + * @param ob the image observer to be notified of updates in the preparation + * process + * + * @return <code>true</code> if the image has been fully prepared, + * <code>false</code> otherwise (in which case the image observer + * receives updates) + */ + boolean prepareImage(Image img, int width, int height, + ImageObserver ob); + + void print(Graphics graphics); + + /** + * Repaints the specified rectangle of this component. This is called from + * {@link Component#repaint(long, int, int, int, int)}. + * + * @param tm number of milliseconds to wait with repainting + * @param x the X coordinate of the upper left corner of the damaged rectangle + * @param y the Y coordinate of the upper left corner of the damaged rectangle + * @param width the width of the damaged rectangle + * @param height the height of the damaged rectangle + */ + void repaint(long tm, int x, int y, int width, int height); + + /** + * Requests that this component receives the focus. This is called from + * {@link Component#requestFocus()}. + * + * @specnote Part of the earlier 1.1 API, apparently replaced by argument + * form of the same method. + */ + void requestFocus(); + + /** + * Requests that this component receives the focus. This is called from + * {@link Component#requestFocus()}. + * + * This method is only called for heavyweight component's peers. Lightweight + * components ask their nearest heavyweight component to request focus. + * It's up to the heavyweight peer to decide if any of it's lightweight + * descendants are allowed to receive keyboard input focus or not. If the + * focus request is finally approved, then the peer must post a FOCUS_GAINED + * event for the requested component. + * + * @param request the component for which the focus is requested + * @param temporary indicates if the focus change is temporary (true) or + * permanent (false) + * @param allowWindowFocus indicates if it's allowed to change window focus + * @param time the timestamp + */ + boolean requestFocus(Component request, boolean temporary, + boolean allowWindowFocus, long time); + + /** + * Notifies the peer that the bounds of this component have changed. This + * is called by {@link Component#reshape(int, int, int, int)}. + * + * @param x the X coordinate of the upper left corner of the component + * @param y the Y coordinate of the upper left corner of the component + * @param width the width of the component + * @param height the height of the component + */ + void reshape(int x, int y, int width, int height); + + /** + * Sets the background color of the component. This is called by + * {@link Component#setBackground(Color)}. + * + * @param color the background color to set + */ + void setBackground(Color color); + + /** + * Notifies the peer that the bounds of this component have changed. This + * is called by {@link Component#setBounds(int, int, int, int)}. + * + * @param x the X coordinate of the upper left corner of the component + * @param y the Y coordinate of the upper left corner of the component + * @param width the width of the component + * @param height the height of the component + */ + void setBounds(int x, int y, int width, int height); + + /** + * Sets the cursor of the component. This is called by + * {@link Component#setCursor(Cursor)}. + * + * @specnote Part of the earlier 1.1 API, apparently no longer needed. + */ + void setCursor(Cursor cursor); + + /** + * Sets the enabled/disabled state of this component. This is called by + * {@link Component#setEnabled(boolean)}. + * + * @param enabled <code>true</code> to enable the component, + * <code>false</code> to disable it + */ + void setEnabled(boolean enabled); + + /** + * Sets the font of the component. This is called by + * {@link Component#setFont(Font)}. + * + * @param font the font to set + */ + void setFont(Font font); + + /** + * Sets the foreground color of the component. This is called by + * {@link Component#setForeground(Color)}. + * + * @param color the foreground color to set + */ + void setForeground(Color color); + + /** + * Sets the visibility state of the component. This is called by + * {@link Component#setVisible(boolean)}. + * + * @param visible <code>true</code> to make the component visible, + * <code>false</code> to make it invisible + */ + void setVisible(boolean visible); + + /** + * Makes the component visible. This is called by {@link Component#show()}. + */ + void show(); + + /** + * Get the graphics configuration of the component. The color model + * of the component can be derived from the configuration. + * + * @return the graphics configuration of the component + */ + GraphicsConfiguration getGraphicsConfiguration(); + + /** + * Part of an older API, no longer needed. + */ + void setEventMask(long mask); + + /** + * Returns <code>true</code> if this component has been obscured, + * <code>false</code> otherwise. This will only work if + * {@link #canDetermineObscurity()} also returns <code>true</code>. + * + * @return <code>true</code> if this component has been obscured, + * <code>false</code> otherwise. + */ + boolean isObscured(); + + /** + * Returns <code>true</code> if this component peer can determine if the + * component has been obscured, <code>false</code> otherwise. + * + * @return <code>true</code> if this component peer can determine if the + * component has been obscured, <code>false</code> otherwise + */ + boolean canDetermineObscurity(); + + /** + * Coalesces the specified paint event. + * + * @param e the paint event + */ + void coalescePaintEvent(PaintEvent e); + + /** + * Updates the cursor. + */ + void updateCursorImmediately(); + + /** + * Returns true, if this component can handle wheel scrolling, + * <code>false</code> otherwise. + * + * @return true, if this component can handle wheel scrolling, + * <code>false</code> otherwise + */ + boolean handlesWheelScrolling(); + + /** + * A convenience method that creates a volatile image. The volatile + * image is created on the screen device on which this component is + * displayed, in the device's current graphics configuration. + * + * @param width width of the image + * @param height height of the image + * + * @see VolatileImage + * + * @since 1.2 + */ + VolatileImage createVolatileImage(int width, int height); + + /** + * Create a number of image buffers that implement a buffering + * strategy according to the given capabilities. + * + * @param numBuffers the number of buffers + * @param caps the buffering capabilities + * + * @throws AWTException if the specified buffering strategy is not + * implemented + * + * @since 1.2 + */ + void createBuffers(int numBuffers, BufferCapabilities caps) + throws AWTException; + + /** + * Return the back buffer of this component. + * + * @return the back buffer of this component. + * + * @since 1.2 + */ + Image getBackBuffer(); + + /** + * Perform a page flip, leaving the contents of the back buffer in + * the specified state. + * + * @param contents the state in which to leave the back buffer + * + * @since 1.2 + */ + void flip(BufferCapabilities.FlipContents contents); + + /** + * Destroy the resources created by createBuffers. + * + * @since 1.2 + */ + void destroyBuffers(); + + /** + * Get the bounds of this component peer. + * + * @return component peer bounds + * @since 1.5 + */ + Rectangle getBounds(); + + /** + * Reparent this component under another container. + * + * @param parent + * @since 1.5 + */ + void reparent(ContainerPeer parent); + + /** + * Set the bounds of this component peer. + * + * @param x the new x co-ordinate + * @param y the new y co-ordinate + * @param width the new width + * @param height the new height + * @param z the new stacking level + * @since 1.5 + */ + void setBounds (int x, int y, int width, int height, int z); + + /** + * Check if this component supports being reparented. + * + * @return true if this component can be reparented, + * false otherwise. + * @since 1.5 + */ + boolean isReparentSupported(); + + /** + * Layout this component peer. + * + * @since 1.5 + */ + void layout(); + + + /** + * Requests the focus on the component. + */ + boolean requestFocus(Component lightweightChild, boolean temporary, + boolean focusedWindowChangeAllowed, long time, + CausedFocusEvent.Cause cause); + +} diff --git a/libjava/classpath/java/awt/peer/ContainerPeer.java b/libjava/classpath/java/awt/peer/ContainerPeer.java new file mode 100644 index 000000000..497abdc32 --- /dev/null +++ b/libjava/classpath/java/awt/peer/ContainerPeer.java @@ -0,0 +1,83 @@ +/* ContainerPeer.java -- Interface for container peers + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.peer; + +import java.awt.Insets; + +public interface ContainerPeer extends ComponentPeer +{ + Insets insets(); + + Insets getInsets(); + + void beginValidate(); + + void endValidate(); + + void beginLayout(); + + void endLayout(); + + boolean isPaintPending(); + + /** + * Check if this container peer can be restacked. + * + * @return true if this container peer supports being restacked, false otherwise + * @since 1.5 + */ + boolean isRestackSupported(); + + /** + * Cancel a pending paint event on a region of this container. + * + * @param x the x co-ordinate of the region + * @param y the y co-ordinate of the region + * @param width the width of the region + * @param height the height of the region + * @since 1.5 + */ + void cancelPendingPaint(int x, int y, int width, int height); + + /** + * Restack the component peers in this container peer. + * + * @since 1.5 + */ + void restack(); +} // interface ContainerPeer diff --git a/libjava/classpath/java/awt/peer/DesktopPeer.java b/libjava/classpath/java/awt/peer/DesktopPeer.java new file mode 100644 index 000000000..626ea840e --- /dev/null +++ b/libjava/classpath/java/awt/peer/DesktopPeer.java @@ -0,0 +1,64 @@ +/* DesktopPeer.java -- Interface to enable access to common applications + Copyright (C) 2006, 2007 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + +package java.awt.peer; + +import java.awt.Desktop.Action; +import java.io.File; +import java.io.IOException; +import java.net.URI; + +/** + * @author Mario Torre <neugens@limasoftware.net> + * + */ +public interface DesktopPeer +{ + public void browse(URI url) throws IOException; + + public void edit(File file) throws IOException; + + public boolean isSupported(Action action); + + public void mail(URI mailtoURL) throws IOException; + + public void mail() throws IOException; + + public void open(File file) throws IOException; + + public void print(File file) throws IOException; +} diff --git a/libjava/classpath/java/awt/peer/DialogPeer.java b/libjava/classpath/java/awt/peer/DialogPeer.java new file mode 100644 index 000000000..b0963eceb --- /dev/null +++ b/libjava/classpath/java/awt/peer/DialogPeer.java @@ -0,0 +1,47 @@ +/* DialogPeer.java -- Interface for dialog box peer + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +public interface DialogPeer extends WindowPeer +{ + void setResizable (boolean resizeable); + + void setTitle (String title); + +} // interface DialogPeer diff --git a/libjava/classpath/java/awt/peer/FileDialogPeer.java b/libjava/classpath/java/awt/peer/FileDialogPeer.java new file mode 100644 index 000000000..608b9c5d6 --- /dev/null +++ b/libjava/classpath/java/awt/peer/FileDialogPeer.java @@ -0,0 +1,51 @@ +/* FileDialogPeer.java -- Interface for file selection dialog box peer + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +import java.io.FilenameFilter; + +public interface FileDialogPeer extends DialogPeer +{ + void setFile (String file); + + void setDirectory (String dir); + + void setFilenameFilter (FilenameFilter ff); + +} // interface FileDialogPeer diff --git a/libjava/classpath/java/awt/peer/FontPeer.java b/libjava/classpath/java/awt/peer/FontPeer.java new file mode 100644 index 000000000..388e56175 --- /dev/null +++ b/libjava/classpath/java/awt/peer/FontPeer.java @@ -0,0 +1,44 @@ +/* FontPeer.java -- Interface for font peers + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +public interface FontPeer +{ + +} // interface FontPeer diff --git a/libjava/classpath/java/awt/peer/FramePeer.java b/libjava/classpath/java/awt/peer/FramePeer.java new file mode 100644 index 000000000..f00236819 --- /dev/null +++ b/libjava/classpath/java/awt/peer/FramePeer.java @@ -0,0 +1,77 @@ +/* FramePeer.java -- Interface for frame peers + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +import java.awt.Image; +import java.awt.MenuBar; +import java.awt.Rectangle; + +public interface FramePeer extends WindowPeer +{ + void setIconImage(Image image); + void setMenuBar(MenuBar mb); + void setResizable(boolean resizable); + void setTitle(String title); + int getState(); + void setState(int state); + void setMaximizedBounds(Rectangle r); + + /** + * Check if this frame peer supports being restacked. + * + * @return true if this frame peer can be restacked, + * false otherwise + * @since 1.5 + */ + boolean isRestackSupported(); + + /** + * Sets the bounds of this frame peer. + * + * @param x the new x co-ordinate + * @param y the new y co-ordinate + * @param width the new width + * @param height the new height + * @since 1.5 + */ + void setBoundsPrivate(int x, int y, int width, int height); + + Rectangle getBoundsPrivate(); + +} // interface FramePeer diff --git a/libjava/classpath/java/awt/peer/LabelPeer.java b/libjava/classpath/java/awt/peer/LabelPeer.java new file mode 100644 index 000000000..b0c5c346d --- /dev/null +++ b/libjava/classpath/java/awt/peer/LabelPeer.java @@ -0,0 +1,45 @@ +/* LabelPeer.java -- Interface for simple text lable peer + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +public interface LabelPeer extends ComponentPeer +{ + void setAlignment(int alignment); + void setText(String text); +} // interface LabelPeer diff --git a/libjava/classpath/java/awt/peer/LightweightPeer.java b/libjava/classpath/java/awt/peer/LightweightPeer.java new file mode 100644 index 000000000..38333b0aa --- /dev/null +++ b/libjava/classpath/java/awt/peer/LightweightPeer.java @@ -0,0 +1,44 @@ +/* LightweightPeer.java -- Interface for lightweight peers + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +public interface LightweightPeer extends ComponentPeer +{ + +} // interface LightweightPeer diff --git a/libjava/classpath/java/awt/peer/ListPeer.java b/libjava/classpath/java/awt/peer/ListPeer.java new file mode 100644 index 000000000..55ff92913 --- /dev/null +++ b/libjava/classpath/java/awt/peer/ListPeer.java @@ -0,0 +1,60 @@ +/* ListPeer.java -- Interface for list box peer + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +import java.awt.Dimension; + +public interface ListPeer extends ComponentPeer +{ + void add(String item, int index); + void addItem(String item, int index); + void clear(); + void delItems(int start_index, int end_index); + void deselect(int index); + int[] getSelectedIndexes(); + void makeVisible(int index); + Dimension minimumSize(int s); + Dimension preferredSize(int s); + void removeAll(); + void select(int index); + void setMultipleMode(boolean multi); + void setMultipleSelections(boolean multi); + Dimension getPreferredSize(int s); + Dimension getMinimumSize(int s); +} // interface ListPeer diff --git a/libjava/classpath/java/awt/peer/MenuBarPeer.java b/libjava/classpath/java/awt/peer/MenuBarPeer.java new file mode 100644 index 000000000..ae43af3cc --- /dev/null +++ b/libjava/classpath/java/awt/peer/MenuBarPeer.java @@ -0,0 +1,48 @@ +/* MenuBarPeer.java -- Interface for menu bar peer + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +import java.awt.Menu; + +public interface MenuBarPeer extends MenuComponentPeer +{ + void addMenu(Menu m); + void addHelpMenu(Menu menu); + void delMenu(int index); +} // interface MenuBarPeer diff --git a/libjava/classpath/java/awt/peer/MenuComponentPeer.java b/libjava/classpath/java/awt/peer/MenuComponentPeer.java new file mode 100644 index 000000000..7369aa52e --- /dev/null +++ b/libjava/classpath/java/awt/peer/MenuComponentPeer.java @@ -0,0 +1,54 @@ +/* MenuComponentPeer.java -- + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +import java.awt.Font; + +public interface MenuComponentPeer +{ + void dispose(); + + /** + * Set the font on this menu component peer. + * + * @param font the new font + * @since 1.5 + */ + void setFont (Font font); +} // interface MenuComponentPeer diff --git a/libjava/classpath/java/awt/peer/MenuItemPeer.java b/libjava/classpath/java/awt/peer/MenuItemPeer.java new file mode 100644 index 000000000..bedbd9f9e --- /dev/null +++ b/libjava/classpath/java/awt/peer/MenuItemPeer.java @@ -0,0 +1,47 @@ +/* MenuItemPeer.java -- Interface for menu item peers + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +public interface MenuItemPeer extends MenuComponentPeer +{ + void disable(); + void enable(); + void setEnabled(boolean enabled); + void setLabel(String text); +} // interface MenuItemPeer diff --git a/libjava/classpath/java/awt/peer/MenuPeer.java b/libjava/classpath/java/awt/peer/MenuPeer.java new file mode 100644 index 000000000..e1f7a90e2 --- /dev/null +++ b/libjava/classpath/java/awt/peer/MenuPeer.java @@ -0,0 +1,48 @@ +/* MenuPeer.java -- Interface for menu peers + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +import java.awt.MenuItem; + +public interface MenuPeer extends MenuItemPeer +{ + void addItem (MenuItem item); + void addSeparator (); + void delItem (int index); +} diff --git a/libjava/classpath/java/awt/peer/MouseInfoPeer.java b/libjava/classpath/java/awt/peer/MouseInfoPeer.java new file mode 100644 index 000000000..71d294157 --- /dev/null +++ b/libjava/classpath/java/awt/peer/MouseInfoPeer.java @@ -0,0 +1,61 @@ +/* MouseInfoPeer.java -- peer interface for MouseInfo + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.peer; + +import java.awt.Point; +import java.awt.Window; + +/** + * MouseInfoPeer is the peer interface java.awt.MouseInfo. + * + * @author Sven de Marothy + * @since 1.5 + */ +public interface MouseInfoPeer +{ + /** + * Get the mouse pointer coordinates and store them in p (obviously non-null) + * returns the index of the current screen device of the mouse. + */ + public int fillPointWithCoords(Point p); + + /** + * Returns whether a given Window is under the mouse. + */ + public boolean isWindowUnderMouse(Window w); +} diff --git a/libjava/classpath/java/awt/peer/PanelPeer.java b/libjava/classpath/java/awt/peer/PanelPeer.java new file mode 100644 index 000000000..a72b16cac --- /dev/null +++ b/libjava/classpath/java/awt/peer/PanelPeer.java @@ -0,0 +1,44 @@ +/* PanelPeer.java -- Interface for panel peers + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +public interface PanelPeer extends ContainerPeer +{ + +} // interface PanelPeer diff --git a/libjava/classpath/java/awt/peer/PopupMenuPeer.java b/libjava/classpath/java/awt/peer/PopupMenuPeer.java new file mode 100644 index 000000000..e747a4de7 --- /dev/null +++ b/libjava/classpath/java/awt/peer/PopupMenuPeer.java @@ -0,0 +1,52 @@ +/* PopupMenuPeer.java -- Interface for popup menu peers + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +import java.awt.Component; +import java.awt.Event; + +public interface PopupMenuPeer extends MenuPeer +{ + /** + * Part of the older API, replaced by event version instead. + */ + void show (Component origin, int x, int y); + + void show (Event e); +} // interface PopupMenuPeer diff --git a/libjava/classpath/java/awt/peer/RobotPeer.java b/libjava/classpath/java/awt/peer/RobotPeer.java new file mode 100644 index 000000000..46c0086dc --- /dev/null +++ b/libjava/classpath/java/awt/peer/RobotPeer.java @@ -0,0 +1,55 @@ +/* RobotPeer.java -- Interface for programatically driving GUI + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +import java.awt.Rectangle; + +public interface RobotPeer +{ + void mouseMove (int x, int y); + void mousePress (int buttons); + void mouseRelease (int buttons); + void mouseWheel (int wheelAmt); + void keyPress (int keycode); + void keyRelease (int keycode); + int getRGBPixel (int x, int y); + int[] getRGBPixels (Rectangle screen); + void dispose(); + +} // interface RobotPeer diff --git a/libjava/classpath/java/awt/peer/ScrollPanePeer.java b/libjava/classpath/java/awt/peer/ScrollPanePeer.java new file mode 100644 index 000000000..afbd2f861 --- /dev/null +++ b/libjava/classpath/java/awt/peer/ScrollPanePeer.java @@ -0,0 +1,51 @@ +/* ScrollPanePeer.java -- Interface for scrollable panes + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +import java.awt.Adjustable; + +public interface ScrollPanePeer extends ContainerPeer +{ + int getHScrollbarHeight(); + int getVScrollbarWidth(); + void setScrollPosition(int h, int v); + void childResized(int width, int height); + void setUnitIncrement(Adjustable item, int inc); + void setValue(Adjustable item, int value); +} // interface ScollPanePeer diff --git a/libjava/classpath/java/awt/peer/ScrollbarPeer.java b/libjava/classpath/java/awt/peer/ScrollbarPeer.java new file mode 100644 index 000000000..4191a39b7 --- /dev/null +++ b/libjava/classpath/java/awt/peer/ScrollbarPeer.java @@ -0,0 +1,46 @@ +/* ScrollbarPeer.java -- Interface for scrollbar peers + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +public interface ScrollbarPeer extends ComponentPeer +{ + void setLineIncrement(int inc); + void setPageIncrement(int inc); + void setValues(int value, int visible, int min, int max); +} // interface ScrollbarPeer diff --git a/libjava/classpath/java/awt/peer/TextAreaPeer.java b/libjava/classpath/java/awt/peer/TextAreaPeer.java new file mode 100644 index 000000000..354e46d9c --- /dev/null +++ b/libjava/classpath/java/awt/peer/TextAreaPeer.java @@ -0,0 +1,53 @@ +/* TextAreaPeer.java -- Interface for text area peers + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +import java.awt.Dimension; + +public interface TextAreaPeer extends TextComponentPeer +{ + void insert(String text, int pos); + void insertText(String text, int pos); + Dimension minimumSize(int rows, int cols); + Dimension getMinimumSize(int rows, int cols); + Dimension preferredSize(int rows, int cols); + Dimension getPreferredSize(int rows, int cols); + void replaceRange(String text, int start_pos, int end_pos); + void replaceText(String text, int start_pos, int end_pos); +} // interface TextAreaPeer diff --git a/libjava/classpath/java/awt/peer/TextComponentPeer.java b/libjava/classpath/java/awt/peer/TextComponentPeer.java new file mode 100644 index 000000000..57f0fd2eb --- /dev/null +++ b/libjava/classpath/java/awt/peer/TextComponentPeer.java @@ -0,0 +1,65 @@ +/* TextComponentPeer.java -- Superclass interface for text components + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +import java.awt.Rectangle; +import java.awt.im.InputMethodRequests; + +public interface TextComponentPeer extends ComponentPeer +{ + int getSelectionEnd(); + int getSelectionStart(); + String getText(); + void setText(String text); + void select(int start_pos, int end_pos); + void setEditable(boolean editable); + int getCaretPosition(); + void setCaretPosition(int pos); + int getIndexAtPoint(int x, int y); + Rectangle getCharacterBounds(int pos); + long filterEvents(long filter); + + /** + * Retrieve this text component peer's input method requests. + * + * @return the input method requests made by this text component peer + * @since 1.5 + */ + InputMethodRequests getInputMethodRequests(); +} // interface TextComponentPeer diff --git a/libjava/classpath/java/awt/peer/TextFieldPeer.java b/libjava/classpath/java/awt/peer/TextFieldPeer.java new file mode 100644 index 000000000..55c673a2d --- /dev/null +++ b/libjava/classpath/java/awt/peer/TextFieldPeer.java @@ -0,0 +1,51 @@ +/* TextFieldPeer.java -- Interface for text field peers + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +import java.awt.Dimension; + +public interface TextFieldPeer extends TextComponentPeer +{ + Dimension minimumSize(int len); + Dimension preferredSize(int len); + Dimension getMinimumSize(int len); + Dimension getPreferredSize(int len); + void setEchoChar(char echo_char); + void setEchoCharacter(char echo_char); +} // interface TextFieldPeer diff --git a/libjava/classpath/java/awt/peer/WindowPeer.java b/libjava/classpath/java/awt/peer/WindowPeer.java new file mode 100644 index 000000000..3ca13a20f --- /dev/null +++ b/libjava/classpath/java/awt/peer/WindowPeer.java @@ -0,0 +1,69 @@ +/* WindowPeer.java -- Interface for window peers + Copyright (C) 1999, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.peer; + +import java.awt.Dialog; + +public interface WindowPeer extends ContainerPeer +{ + void toBack(); + void toFront(); + + /** + * Update the always-on-top status of the Window. + * + * @since 1.5 + */ + void updateAlwaysOnTop(); + + /** + * Request that this window peer be given the window focus. + * + * @return true if the window received focus, false otherwise + * @since 1.5 + */ + boolean requestWindowFocus(); + + void setAlwaysOnTop(boolean alwaysOnTop); + void updateFocusableWindowState(); + void setModalBlocked(Dialog blocker, boolean blocked); + void updateMinimumSize(); + void updateIconImages(); + +} // interface WindowPeer diff --git a/libjava/classpath/java/awt/peer/package.html b/libjava/classpath/java/awt/peer/package.html new file mode 100644 index 000000000..7a7458c17 --- /dev/null +++ b/libjava/classpath/java/awt/peer/package.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in java.awt.peer package. + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - java.awt.peer</title></head> + +<body> +<p>Interfaces for using native interface components.</p> + +</body> +</html> diff --git a/libjava/classpath/java/awt/print/Book.java b/libjava/classpath/java/awt/print/Book.java new file mode 100644 index 000000000..8b040b2d1 --- /dev/null +++ b/libjava/classpath/java/awt/print/Book.java @@ -0,0 +1,159 @@ +/* Book.java -- A mixed group of pages to print. + Copyright (C) 1999, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.print; + +import java.util.Vector; + +/** + * This class allows documents to be created with different paper types, + * page formatters, and painters. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class Book implements Pageable +{ + /** + * Painter objects for the book. + */ + Vector printables = new Vector(); + + /** + * Page formats for the book. + */ + Vector page_formats = new Vector(); + + /** + * Initializes a new instance of <code>Book</code> that is empty. + */ + public Book() + { + } + + /** + * Returns the number of pages in this book. + * + * @return The number of pages in this book. + */ + public int getNumberOfPages() + { + return printables.size(); + } + + /** + * This method returns the <code>PageFormat</code> object for the + * specified page. + * + * @param page_number The number of the page to get information for, where + * page numbers start at 0. + * + * @return The <code>PageFormat</code> object for the specified page. + * + * @exception IndexOutOfBoundsException If the page number is not valid. + */ + public PageFormat getPageFormat(int page_number) + { + return (PageFormat) page_formats.elementAt(page_number); + } + + /** + * This method returns the <code>Printable</code> object for the + * specified page. + * + * @param page_number The number of the page to get information for, where + * page numbers start at 0. + * + * @return The <code>Printable</code> object for the specified page. + * + * @exception IndexOutOfBoundsException If the page number is not valid. + */ + public Printable getPrintable(int page_number) + { + return (Printable) printables.elementAt(page_number); + } + + /** + * This method appends a page to the end of the book. + * + * @param printable The <code>Printable</code> for this page. + * @param page_format The <code>PageFormat</code> for this page. + * + * @exception NullPointerException If either argument is <code>null</code>. + */ + public void append(Printable printable, PageFormat page_format) + { + append(printable, page_format, 1); + } + + /** + * This method appends the specified number of pages to the end of the book. + * Each one will be associated with the specified <code>Printable</code> + * and <code>PageFormat</code>. + * + * @param printable The <code>Printable</code> for this page. + * @param page_format The <code>PageFormat</code> for this page. + * @param num_pages The number of pages to append. + * + * @exception NullPointerException If any argument is <code>null</code>. + */ + public void append(Printable printable, PageFormat page_format, int num_pages) + { + for (int i = 0; i < num_pages; i++) + { + printables.addElement(printable); + page_formats.addElement(page_format); + } + } + + /** + * This method changes the <code>Printable</code> and <code>PageFormat</code> + * for the specified page. The page must already exist or an exception + * will be thrown. + * + * @param page_num The page number to alter. + * @param printable The new <code>Printable</code> for the page. + * @param page_format The new <code>PageFormat</code> for the page. + * + * @throws IndexOutOfBoundsException If the specified page does not exist. + */ + public void setPage(int page_num, Printable printable, PageFormat page_format) + { + printables.setElementAt(printable, page_num); + page_formats.setElementAt(page_format, page_num); + } +} diff --git a/libjava/classpath/java/awt/print/NoPrinterJob.java b/libjava/classpath/java/awt/print/NoPrinterJob.java new file mode 100644 index 000000000..e9659a147 --- /dev/null +++ b/libjava/classpath/java/awt/print/NoPrinterJob.java @@ -0,0 +1,124 @@ +/* NoPrinterJob.java -- Fake PrinterJob that just signals no print service. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.print; + +/** + * Fake PrinterJob that just signals no print service. This is only + * here so applications can call + * <code>PrintJob.getPrinterJob().getPrinterJob()</code> and check + * that it returns <code>null</code> which indicates no actual + * printing support is available. + */ +class NoPrinterJob extends PrinterJob +{ + public int getCopies() + { + return 0; + } + + public void setCopies(int copies) + { + // Do nothing. + } + + public String getJobName() + { + return "NoPrinterJob"; + } + + public void setJobName(String job_name) + { + // Do nothing. + } + + public String getUserName() + { + return "NoUser"; + } + + public void cancel() + { + // Do nothing. + } + + public boolean isCancelled() + { + return true; + } + + public PageFormat defaultPage(PageFormat page_format) + { + return page_format; + } + + public PageFormat pageDialog(PageFormat page_format) + { + return page_format; + } + + public void print() throws PrinterException + { + throw new PrinterException("No printer"); + } + + public boolean printDialog() + { + return false; + } + + public void setPageable(Pageable pageable) + { + // Do nothing. + } + + public void setPrintable(Printable printable) + { + // Do nothing. + } + + public void setPrintable(Printable printable, PageFormat page_format) + { + // Do nothing. + } + + public PageFormat validatePage(PageFormat page_format) + { + return page_format; + } +} diff --git a/libjava/classpath/java/awt/print/PageFormat.java b/libjava/classpath/java/awt/print/PageFormat.java new file mode 100644 index 000000000..86d8ba210 --- /dev/null +++ b/libjava/classpath/java/awt/print/PageFormat.java @@ -0,0 +1,233 @@ +/* PageFormat.java -- Information about the page format + Copyright (C) 1999, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.print; + +/** + * This class contains information about the desired page format to use for + * printing a particular set of pages. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class PageFormat + implements Cloneable +{ + /** + * A constant for a landscaped page orientation. Used by + * <code>getOrientation</code> and <code>setOrientation</code>. + */ + public static final int LANDSCAPE = 0; + + /** + * A constant for a portrait page orientation. Used by + * <code>getOrientation</code> and <code>setOrientation</code>. + */ + public static final int PORTRAIT = 1; + + /** + * A constant for a reversed landscaped page orientation. This is the + * orientation used by Macintosh's for landscape. The origin is in the + * upper right hand corner instead of the upper left. The X and Y axes + * are reversed. Used by <code>getOrientation</code> and + * <code>setOrientation</code>. + */ + public static final int REVERSE_LANDSCAPE = 2; + + // The page orientation + private int orientation; + + // The paper type + private Paper paper; + + /** + * This method creates a default page layout, which will be in portrait + * format. + */ + public PageFormat() + { + this.paper = new Paper(); + this.orientation = PORTRAIT; + } + + /** + * This method returns the width of the page, in 1/72nd's of an inch. The + * "width" measured depends on orientation. + * + * @return The width of the page. + */ + public double getWidth() + { + return paper.getWidth(); + } + + /** + * This method returns the height of the page, in 1/72nd's of an inch. The + * "height" measured depends on the orientation. + * + * @return The height of the page. + */ + public double getHeight() + { + return paper.getHeight(); + } + + /** + * This method returns the X coordinate value of the upper leftmost drawable + * area of the paper. + * + * @return The upper leftmost imageable X coordinate. + */ + public double getImageableX() + { + return paper.getImageableX(); + } + + /** + * This method returns the Y coordinate value of the upper leftmost drawable + * area of the paper. + * + * @return The upper leftmost imageable Y coordinate. + */ + public double getImageableY() + { + return paper.getImageableY(); + } + + /** + * This method returns the imageable width of the paper, in 1/72nd's of an + * inch. + * + * @return The imageable width of the paper. + */ + public double getImageableWidth() + { + return paper.getImageableWidth(); + } + + /** + * This method returns the imageable height of the paper, in 1/72nd's of an + * inch. + * + * @return The imageable height of the paper. + */ + public double getImageableHeight() + { + return paper.getImageableHeight(); + } + + /** + * Returns a copy of the <code>paper</code> object being used for this page + * format. + * + * @return A copy of the <code>Paper</code> object for this format. + */ + public Paper getPaper() + { + return (Paper) paper.clone(); + } + + /** + * Sets the <code>Paper</code> object to be used by this page format. + * + * @param paper The new <code>Paper</code> object for this page format. + */ + public void setPaper(Paper paper) + { + this.paper = paper; + } + + /** + * This method returns the current page orientation. The value returned will + * be one of the page orientation constants from this class. + * + * @return The current page orientation. + */ + public int getOrientation() + { + return orientation; + } + + /** + * This method sets the page orientation for this format to the specified + * value. It must be one of the page orientation constants from this class + * or an exception will be thrown. + * + * @param orientation The new page orientation. + * @exception IllegalArgumentException If the specified page orientation + * value is not one of the constants from this class. + */ + public void setOrientation(int orientation) throws IllegalArgumentException + { + if ((orientation != PORTRAIT) && (orientation != LANDSCAPE) + && (orientation != REVERSE_LANDSCAPE)) + throw new IllegalArgumentException("Bad page orientation value: " + + orientation); + + this.orientation = orientation; + } + + /** + * This method returns a matrix used for transforming user space coordinates + * to page coordinates. The value returned will be six doubles as described + * in <code>java.awt.geom.AffineTransform</code>. + * + * @return The transformation matrix for this page format. + */ + public double[] getMatrix() + { + throw new RuntimeException("Not implemented since I don't know what to do"); + } + + /** + * This method returns a copy of this object. + * + * @return A copy of this object. + */ + public Object clone() + { + try + { + return (super.clone()); + } + catch (CloneNotSupportedException e) + { + return (null); + } + } + +} diff --git a/libjava/classpath/java/awt/print/Pageable.java b/libjava/classpath/java/awt/print/Pageable.java new file mode 100644 index 000000000..58e0885fb --- /dev/null +++ b/libjava/classpath/java/awt/print/Pageable.java @@ -0,0 +1,90 @@ +/* Pageable.java -- Pages to be printed + Copyright (C) 1999, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.print; + +/** + * This interface represents pages that are to be printed. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface Pageable +{ + /** + * This constant is returned when <code>getNumberOfPages()</code> cannot + * determine the number of pages available for printing. + */ + int UNKNOWN_NUMBER_OF_PAGES = - 1; + + /** + * This method returns the number of pages this object contains, or + * <code>UNKNOWN_NUMBER_OF_PAGES</code> if it cannot determine the number + * of pages to be printed. + * + * @return The number of pages to be printed, or + * <code>UNKNOWN_NUMBER_OF_PAGES</code> if this is unknown. + */ + int getNumberOfPages(); + + /** + * This method returns the <code>PageFormat</code> instance for the + * specified page. Page numbers start at zero. An exception is thrown if the + * requested page does not exist. + * + * @param pageIndex The index of the page to return the + * <code>PageFormat</code> for. + * @return The <code>PageFormat</code> for the requested page. + * @exception IndexOutOfBoundsException If the requested page number does + * not exist. + */ + PageFormat getPageFormat(int pageIndex) throws IndexOutOfBoundsException; + + /** + * This method returns the <code>Printable</code> instance for the specified + * page. Page numbers start at zero. An exception is thrown if the requested + * page does not exist. + * + * @param pageIndex The index of the page to return the + * <code>Printable</code> for. + * @return The <code>Printable</code> for the requested page. + * @exception IndexOutOfBoundsException If the requested page number does + * not exist. + */ + Printable getPrintable(int pageIndex) throws IndexOutOfBoundsException; + +} diff --git a/libjava/classpath/java/awt/print/Paper.java b/libjava/classpath/java/awt/print/Paper.java new file mode 100644 index 000000000..a80da2fea --- /dev/null +++ b/libjava/classpath/java/awt/print/Paper.java @@ -0,0 +1,197 @@ +/* Paper.java -- Information about a paper type. + Copyright (C) 1999, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.print; + +/** + * This class describes a particular type of paper. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class Paper + implements Cloneable +{ + // Height of the paper + private double height; + + // Width of the paper + private double width; + + // Upper left imageable X coordinate + private double imageableX; + + // Upper left imageable Y coordinate + private double imageableY; + + // Imageable width of the page + private double imageableWidth; + + // Imageable height of the page + private double imageableHeight; + + /** + * This method creates a letter sized paper with one inch margins + */ + public Paper() + { + width = 8.5 * 72; + height = 11 * 72; + imageableX = 72; + imageableY = 72; + imageableWidth = width - (2 * 72); + imageableHeight = height - (2 * 72); + } + + /** + * This method returns the height of the paper in 1/72nds of an inch. + * + * @return The height of the paper in 1/72nds of an inch. + */ + public double getHeight() + { + return height; + } + + /** + * Returns the width of the paper in 1/72nds of an inch. + * + * @return The width of the paper in 1/72nds of an inch. + */ + public double getWidth() + { + return width; + } + + /** + * This method returns the X coordinate of the upper left hand corner of the + * imageable area of the paper. + * + * @return The X coordinate of the upper left hand corner of the imageable + * area of the paper. + */ + public double getImageableX() + { + return imageableX; + } + + /** + * This method returns the Y coordinate of the upper left hand corner of the + * imageable area of the paper. + * + * @return The Y coordinate of the upper left hand corner of the imageable + * area of the paper. + */ + public double getImageableY() + { + return imageableY; + } + + /** + * Returns the width of the imageable area of the paper. + * + * @return The width of the imageable area of the paper. + */ + public double getImageableWidth() + { + return imageableWidth; + } + + /** + * Returns the height of the imageable area of the paper. + * + * @return The height of the imageable area of the paper. + */ + public double getImageableHeight() + { + return imageableHeight; + } + + /** + * This method sets the size of the paper to the specified width and height, + * which are specified in 1/72nds of an inch. + * + * @param width The width of the paper in 1/72nds of an inch. + * @param height The height of the paper in 1/72nds of an inch. + */ + public void setSize(double width, double height) + { + this.width = width; + this.height = height; + } + + /** + * This method sets the imageable area of the paper by specifying the + * coordinates of the upper left hand corner of that area, and its length + * and height. All values are in 1/72nds of an inch. + * + * @param imageableX The X coordinate of the upper left hand corner of the + * imageable area, in 1/72nds of an inch. + * @param imageableY The Y coordinate of the upper left hand corner of the + * imageable area, in 1/72nds of an inch. + * @param imageableWidth The width of the imageable area of the paper, in + * 1/72nds of an inch. + * @param imageableHeight The heigth of the imageable area of the paper, in + * 1/72nds of an inch. + */ + public void setImageableArea(double imageableX, double imageableY, + double imageableWidth, double imageableHeight) + { + this.imageableX = imageableX; + this.imageableY = imageableY; + this.imageableWidth = imageableWidth; + this.imageableHeight = imageableHeight; + } + + /** + * This method creates a copy of this object. + * + * @return A copy of this object. + */ + public Object clone() + { + try + { + return (super.clone()); + } + catch (CloneNotSupportedException e) + { + return (null); + } + } + +} diff --git a/libjava/classpath/java/awt/print/Printable.java b/libjava/classpath/java/awt/print/Printable.java new file mode 100644 index 000000000..775167e66 --- /dev/null +++ b/libjava/classpath/java/awt/print/Printable.java @@ -0,0 +1,80 @@ +/* Printable.java -- Renders a page to the print device + Copyright (C) 1999, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.print; + +import java.awt.Graphics; + + +/** + * This interface provides a mechanism for the actual printing of pages to the + * printer. The object implementing this interface performs the page + * rendering. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface Printable +{ + /** + * This value is returned by the <code>print()</code> method to indicate + * that the requested page exists and has been printed. + */ + int PAGE_EXISTS = 0; + + /** + * This value is returned by the <code>print()</code> method to indicate + * that the requested page number does not exist. + */ + int NO_SUCH_PAGE = 1; + + /** + * This method prints the specified page to the specified graphics + * context in the specified format. The pages are numbered starting + * from zero. + * + * @param graphics The graphics context to render the pages on. + * @param format The format in which to print the page. + * @param page_number The page number to print, where numbers start at zero. + * + * @return <code>PAGE_EXISTS</code> if the requested page exists and was + * successfully printed, <code>NO_SUCH_PAGE</code> otherwise. + * + * @exception PrinterException If an error occurs during printing. + */ + int print(Graphics graphics, PageFormat format, int page_number) + throws PrinterException; +} diff --git a/libjava/classpath/java/awt/print/PrinterAbortException.java b/libjava/classpath/java/awt/print/PrinterAbortException.java new file mode 100644 index 000000000..458063079 --- /dev/null +++ b/libjava/classpath/java/awt/print/PrinterAbortException.java @@ -0,0 +1,71 @@ +/* PrinterAbortException.java -- Indicates the print job was aborted + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.print; + +/** + * This exception is thrown when the print job is aborted, either by the + * user or by the application. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @status updated to 1.4 + */ +public class PrinterAbortException extends PrinterException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 4725169026278854136L; + + /** + * Create a new instance with no detailed error message. + */ + public PrinterAbortException() + { + } + + /** + * Create a new instance with a descriptive error message. + * + * @param message the descriptive error message + */ + public PrinterAbortException(String message) + { + super(message); + } +} // class PrinterAbortException diff --git a/libjava/classpath/java/awt/print/PrinterException.java b/libjava/classpath/java/awt/print/PrinterException.java new file mode 100644 index 000000000..c105f549d --- /dev/null +++ b/libjava/classpath/java/awt/print/PrinterException.java @@ -0,0 +1,71 @@ +/* PrinterException.java -- generic problem in the printing subsystem + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.print; + +/** + * This is the generic toplevel exception for printing errors. Subclasses + * provide more detailed descriptions of the problem. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @status updated to 1.4 + */ +public class PrinterException extends Exception +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = -3757589981158265819L; + + /** + * Create a new instance with no detailed error message. + */ + public PrinterException() + { + } + + /** + * Create a new instance with a descriptive error message. + * + * @param message the descriptive error message + */ + public PrinterException(String message) + { + super(message); + } +} // class PrinterException diff --git a/libjava/classpath/java/awt/print/PrinterGraphics.java b/libjava/classpath/java/awt/print/PrinterGraphics.java new file mode 100644 index 000000000..c1f199c65 --- /dev/null +++ b/libjava/classpath/java/awt/print/PrinterGraphics.java @@ -0,0 +1,58 @@ +/* PrinterGraphics.java -- Hook to return print job controller. + Copyright (C) 1999, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.print; + +/** + * This interface is implemented by the <code>Graphics</code> instance that is + * used for rendering pages. It provides a hook to return the object that is + * controlling the print job. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface PrinterGraphics +{ + /** + * This method returns the instance of <code>PrinterJob</code> that is + * controlling this print job. + * + * @return The <code>PrinterJob</code> that is controlling this print job. + */ + PrinterJob getPrinterJob(); + +} diff --git a/libjava/classpath/java/awt/print/PrinterIOException.java b/libjava/classpath/java/awt/print/PrinterIOException.java new file mode 100644 index 000000000..2089af59e --- /dev/null +++ b/libjava/classpath/java/awt/print/PrinterIOException.java @@ -0,0 +1,97 @@ +/* PrinterIOException.java -- The print job encountered an I/O error + Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.print; + +import java.io.IOException; + +/** + * This exception is thrown when the print job encounters an I/O problem + * of some kind. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @status updated to 1.4 + */ +public class PrinterIOException extends PrinterException +{ + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 5850870712125932846L; + + /** + * The exception that caused this (duplicates Throwable). + * + * @serial the I/O exception that terminated the job + */ + private final IOException mException; + + /** + * Initializes a new instance with the given cause. + * + * @param mException the cause + */ + public PrinterIOException(IOException mException) + { + super(mException == null ? null : mException.toString()); + initCause(mException); + this.mException = mException; + } + + /** + * Gets the underlying <code>IOException</code> that caused this exception. + * This legacy method has been replaced by {@link #getCause()}. + * + * @return the cause + */ + public IOException getIOException() + { + return mException; + } + + /** + * Gets the cause. + * + * @return the cause + */ + public Throwable getCause() + { + return mException; + } +} // class PrinterIOException diff --git a/libjava/classpath/java/awt/print/PrinterJob.java b/libjava/classpath/java/awt/print/PrinterJob.java new file mode 100644 index 000000000..1a4b8c8e2 --- /dev/null +++ b/libjava/classpath/java/awt/print/PrinterJob.java @@ -0,0 +1,300 @@ +/* PrinterJob.java -- This job is the printer control class + Copyright (C) 1999, 2004, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.print; + +import gnu.java.awt.print.JavaPrinterJob; + +import java.awt.HeadlessException; +import javax.print.PrintService; +import javax.print.PrintServiceLookup; +import javax.print.DocFlavor; +import javax.print.StreamPrintServiceFactory; +import javax.print.attribute.PrintRequestAttributeSet; + +/** + * This class controls printing. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public abstract class PrinterJob +{ + // The print service associated with this job + private PrintService printer = null; + + /** + * Creates a new print job. + * + * @return A <code>PrinterJob</code> object for the newly created print job. + */ + public static PrinterJob getPrinterJob() + { + return new JavaPrinterJob(); + } + + /** + * Initializes a new instance of <code>PrinterJob</code>. + */ + public PrinterJob() + { + } + + /** + * Returns the number of copies to be printed. + * + * @return The number of copies to be printed. + */ + public abstract int getCopies(); + + /** + * Sets the number of copies to be printed. + * + * @param copies The number of copies to be printed. + */ + public abstract void setCopies(int copies); + + /** + * Returns the name of the print job. + * + * @return The name of the print job. + */ + public abstract String getJobName(); + + /** + * Sets the name of the print job. + * + * @param job_name The name of the print job. + */ + public abstract void setJobName(String job_name); + + /** + * Returns the printing user name. + * + * @return The printing username. + */ + public abstract String getUserName(); + + /** + * Cancels an in progress print job. + */ + public abstract void cancel(); + + /** + * Tests whether or not this job has been cancelled. + * + * @return <code>true</code> if this job has been cancelled, <code>false</code> + * otherwise. + */ + public abstract boolean isCancelled(); + + /** + * Returns an instance of the default page which will have the default + * paper and orientation. + * + * @return A default instance of <code>PageFormat</code>. + */ + public PageFormat defaultPage() + { + return new PageFormat(); + } + + /** + * Clones the specified <code>PageFormat</code> object then alters the + * clone so that it represents the default page format. + * + * @param page_format The <code>PageFormat</code> to clone. + * + * @return A new default page format. + */ + public abstract PageFormat defaultPage(PageFormat page_format); + + /** + * Displays a dialog box to the user which allows the page format + * attributes to be modified. + * + * @param page_format The <code>PageFormat</code> object to modify. + * + * @return The modified <code>PageFormat</code>. + */ + public abstract PageFormat pageDialog(PageFormat page_format) + throws HeadlessException; + + /** + * @since 1.4 + */ + public PageFormat pageDialog(PrintRequestAttributeSet attributes) + throws HeadlessException + { + // FIXME: Implement this for real. + return pageDialog((PageFormat) null); + } + + /** + * Prints the pages. + */ + public abstract void print () throws PrinterException; + + /** + * Prints the page with given attributes. + */ + public void print (PrintRequestAttributeSet attributes) + throws PrinterException + { + print (); + } + + /** + * Displays a dialog box to the user which allows the print job + * attributes to be modified. + * + * @return <code>false</code> if the user cancels the dialog box, + * <code>true</code> otherwise. + */ + public abstract boolean printDialog() + throws HeadlessException; + + /** + * Displays a dialog box to the user which allows the print job + * attributes to be modified. + * + * @return <code>false</code> if the user cancels the dialog box, + * <code>true</code> otherwise. + */ + public boolean printDialog(PrintRequestAttributeSet attributes) + throws HeadlessException + { + // FIXME: Implement this for real. + return printDialog(); + } + + /** + * This sets the pages that are to be printed. + * + * @param pageable The pages to be printed, which may not be <code>null</code>. + */ + public abstract void setPageable(Pageable pageable); + + /** + * Sets this specified <code>Printable</code> as the one to use for + * rendering the pages on the print device. + * + * @param printable The <code>Printable</code> for the print job. + */ + public abstract void setPrintable(Printable printable); + + /** + * Sets the <code>Printable</code> and the page format for the pages + * to be printed. + * + * @param printable The <code>Printable</code> for the print job. + * @param page_format The <code>PageFormat</code> for the print job. + */ + public abstract void setPrintable(Printable printable, PageFormat page_format); + + /** + * Makes any alterations to the specified <code>PageFormat</code> + * necessary to make it work with the current printer. The alterations + * are made to a clone of the input object, which is then returned. + * + * @param page_format The <code>PageFormat</code> to validate. + * + * @return The validated <code>PageFormat</code>. + */ + public abstract PageFormat validatePage(PageFormat page_format); + + /** + * Find and return 2D image print services. + * + * This is the same as calling PrintServiceLookup.lookupPrintServices() + * with Pageable service-specified DocFlavor. + * @return Array of PrintService objects, could be empty. + * @since 1.4 + */ + public static PrintService[] lookupPrintServices() + { + return PrintServiceLookup.lookupPrintServices + ( + new DocFlavor("application/x-java-jvm-local-objectref", + "java.awt.print.Pageable"), + null); + } + + /** + * Find and return 2D image stream print services. + * + * This is the same as calling + * StreamPrintServiceFactory.lookupStreamPrintServices() + * with Pageable service-specified DocFlavor. + * @param mimeType The output format mime type, or null for any type. + * @return Array of stream print services, could be empty. + * @since 1.4 + */ + public static StreamPrintServiceFactory[] + lookupStreamPrintServices(String mimeType) + { + return StreamPrintServiceFactory.lookupStreamPrintServiceFactories( + DocFlavor.SERVICE_FORMATTED.PAGEABLE, mimeType); + } + + /** + * Return the printer for this job. If print services aren't supported by + * the subclass, returns null. + * + * @return The associated PrintService. + * @since 1.4 + */ + public PrintService getPrintService() + { + return printer; + } + + /** + * Change the printer for this print job to service. Subclasses that + * support setting the print service override this method. Throws + * PrinterException when the class doesn't support setting the printer, + * the service doesn't support Pageable or Printable interfaces for 2D + * print output. + * @param service The new printer to use. + * @throws PrinterException if service is not valid. + */ + public void setPrintService(PrintService service) + throws PrinterException + { + printer = service; + } +} diff --git a/libjava/classpath/java/awt/print/package.html b/libjava/classpath/java/awt/print/package.html new file mode 100644 index 000000000..50abcbfad --- /dev/null +++ b/libjava/classpath/java/awt/print/package.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in java.awt.print package. + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - java.awt.print</title></head> + +<body> +<p>Classes for printer jobs, pages, paper sizes, graphics and formats.</p> + +</body> +</html> |