summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
authorAndrew John Hughes <gnu_andrew@member.fsf.org>2006-10-05 02:44:18 +0000
committerAndrew John Hughes <gnu_andrew@member.fsf.org>2006-10-05 02:44:18 +0000
commit2799793789d5b66c90efbd1a3eb56e0c1ec57f88 (patch)
tree9157197f502b6830af9cafe029fd3d47628a7ed6 /java
parent7516107c5abe26f7a4378017344eb9e449ebc28e (diff)
downloadclasspath-2799793789d5b66c90efbd1a3eb56e0c1ec57f88.tar.gz
2006-10-05 Andrew John Hughes <gnu_andrew@member.fsf.org>
* Merge of HEAD-->generics for 2006/09/03-2006/10/04.
Diffstat (limited to 'java')
-rw-r--r--java/awt/AWTEvent.java5
-rw-r--r--java/awt/Choice.java4
-rw-r--r--java/awt/Component.java438
-rw-r--r--java/awt/Container.java215
-rw-r--r--java/awt/EventQueue.java324
-rw-r--r--java/awt/Frame.java17
-rw-r--r--java/awt/GridLayout.java2
-rw-r--r--java/awt/LightweightDispatcher.java382
-rw-r--r--java/awt/List.java1745
-rw-r--r--java/awt/Menu.java641
-rw-r--r--java/awt/Rectangle.java22
-rw-r--r--java/awt/Window.java54
-rw-r--r--java/awt/geom/RoundRectangle2D.java415
-rw-r--r--java/awt/image/AffineTransformOp.java314
-rw-r--r--java/awt/image/BandCombineOp.java26
-rw-r--r--java/awt/image/BufferedImage.java1
-rw-r--r--java/awt/image/ColorModel.java40
-rw-r--r--java/awt/image/ComponentColorModel.java9
-rw-r--r--java/awt/image/ConvolveOp.java15
-rw-r--r--java/awt/image/DirectColorModel.java16
-rw-r--r--java/awt/image/IndexColorModel.java17
-rw-r--r--java/awt/image/LookupOp.java141
-rw-r--r--java/awt/image/MemoryImageSource.java70
-rw-r--r--java/awt/image/RescaleOp.java293
-rw-r--r--java/io/FileDescriptor.java2
-rw-r--r--java/io/FileInputStream.java20
-rw-r--r--java/io/FileOutputStream.java26
-rw-r--r--java/io/InputStreamReader.java2
-rw-r--r--java/io/ObjectStreamClass.java4
-rw-r--r--java/io/PipedInputStream.java4
-rw-r--r--java/io/PipedReader.java4
-rw-r--r--java/io/RandomAccessFile.java17
-rw-r--r--java/net/DatagramSocket.java37
-rw-r--r--java/net/Inet4Address.java68
-rw-r--r--java/net/Inet6Address.java9
-rw-r--r--java/net/InetAddress.java379
-rw-r--r--java/net/NetworkInterface.java148
-rw-r--r--java/net/ResolverCache.java269
-rw-r--r--java/net/ServerSocket.java81
-rw-r--r--java/net/Socket.java87
-rw-r--r--java/net/SocketPermission.java171
-rw-r--r--java/nio/channels/spi/AbstractSelectableChannel.java15
-rw-r--r--java/text/AttributedCharacterIterator.java24
-rw-r--r--java/text/AttributedString.java76
-rw-r--r--java/text/AttributedStringIterator.java27
-rw-r--r--java/util/IdentityHashMap.java230
-rw-r--r--java/util/Locale.java36
-rw-r--r--java/util/logging/LogManager.java33
48 files changed, 3994 insertions, 2981 deletions
diff --git a/java/awt/AWTEvent.java b/java/awt/AWTEvent.java
index a6151b424..3f4027c2c 100644
--- a/java/awt/AWTEvent.java
+++ b/java/awt/AWTEvent.java
@@ -97,6 +97,11 @@ public abstract class AWTEvent extends EventObject
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.
diff --git a/java/awt/Choice.java b/java/awt/Choice.java
index 3113c599c..ae89b9e99 100644
--- a/java/awt/Choice.java
+++ b/java/awt/Choice.java
@@ -255,8 +255,8 @@ public class Choice extends Component
/**
* Adds the specified item to this choice box.
*
- * This method is oboslete since Java 2 platform 1.1. Please use @see add
- * instead.
+ * This method is oboslete since Java 2 platform 1.1. Please use
+ * {@link #add(String)} instead.
*
* @param item The item to add.
*
diff --git a/java/awt/Component.java b/java/awt/Component.java
index 26ba605b5..7688e2618 100644
--- a/java/awt/Component.java
+++ b/java/awt/Component.java
@@ -971,14 +971,14 @@ public abstract class Component
// case lightweight components are not initially painted --
// Container.paint first calls isShowing () before painting itself
// and its children.
- if(!isVisible())
+ 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;
+ ComponentPeer currentPeer = peer;
if (currentPeer != null)
{
currentPeer.show();
@@ -990,7 +990,7 @@ public abstract class Component
// The JDK repaints the component before invalidating the parent.
// So do we.
- if (isLightweight())
+ if (peer instanceof LightweightPeer)
repaint();
}
@@ -1037,7 +1037,7 @@ public abstract class Component
*/
public void hide()
{
- if (isVisible())
+ if (visible)
{
// Need to lock the tree here to avoid races and inconsistencies.
synchronized (getTreeLock())
@@ -1180,31 +1180,78 @@ public abstract class Component
*/
public Font getFont()
{
- Font f = font;
- if (f != null)
- return f;
+ Font f;
+ synchronized (getTreeLock())
+ {
+ f = getFontImpl();
+ }
+ return f;
+ }
- Component p = parent;
- if (p != null)
- return p.getFont();
- return null;
+ /**
+ * Implementation of getFont(). This is pulled out of getFont() to prevent
+ * client programs from overriding this. This method is executed within
+ * a tree lock, so we can assume that the hierarchy doesn't change in
+ * between.
+ *
+ * @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();
+ }
+ return f;
}
/**
* Sets the font for this component to the specified font. This is a bound
* property.
*
- * @param newFont the new font for this component
+ * @param f the new font for this component
*
* @see #getFont()
*/
- public void setFont(Font newFont)
+ public void setFont(Font f)
{
- Font oldFont = font;
- font = newFont;
- if (peer != null)
- peer.setFont(font);
+ 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();
}
@@ -2036,7 +2083,32 @@ public abstract class Component
*/
public void validate()
{
- valid = true;
+ 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;
+ }
}
/**
@@ -2078,27 +2150,26 @@ public abstract class Component
{
// Only heavyweight peers can handle this.
ComponentPeer p = peer;
- Component comp = this;
- int offsX = 0;
- int offsY = 0;
- while (p instanceof LightweightPeer)
+ Graphics g = null;
+ if (p instanceof LightweightPeer)
{
- offsX += comp.x;
- offsY += comp.y;
- comp = comp.parent;
- p = comp == null ? null : comp.peer;
+ if (parent != null)
+ {
+ g = parent.getGraphics();
+ if (g != null)
+ {
+ g.translate(x, y);
+ g.setClip(0, 0, width, height);
+ g.setFont(getFont());
+ }
+ }
}
-
- Graphics gfx = null;
- if (p != null)
+ else
{
- assert ! (p instanceof LightweightPeer);
- gfx = p.getGraphics();
- gfx.translate(offsX, offsY);
- gfx.clipRect(0, 0, width, height);
- gfx.setFont(font);
+ if (p != null)
+ g = p.getGraphics();
}
- return gfx;
+ return g;
}
/**
@@ -2229,9 +2300,14 @@ public abstract class Component
*/
public void paintAll(Graphics g)
{
- if (! visible)
- return;
- paint(g);
+ if (isShowing())
+ {
+ validate();
+ if (peer instanceof LightweightPeer)
+ paint(g);
+ else
+ peer.paint(g);
+ }
}
/**
@@ -2302,36 +2378,32 @@ public abstract class Component
// Let the nearest heavyweight parent handle repainting for lightweight
// components.
- // This goes up the hierarchy until we hit
- // a heavyweight component that handles this and translates the
- // rectangle while doing so.
-
- // We perform some boundary checking to restrict the paint
- // region to this component.
- int px = (x < 0 ? 0 : x);
- int py = (y < 0 ? 0 : y);
- int pw = width;
- int ph = height;
- Component par = this;
- while (par != null && p instanceof LightweightPeer)
+ // 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)
{
- px += par.x;
- py += par.y;
// We perform some boundary checking to restrict the paint
// region to this component.
- pw = Math.min(pw, par.width);
- ph = Math.min(ph, par.height);
- par = par.parent;
- p = par == null ? null : par.peer;
+ 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);
+ }
}
-
- // Now send an UPDATE event to the heavyweight component that we've found.
- if (par != null && par.isVisible() && p != null && pw > 0 && ph > 0)
+ else
{
- assert ! (p instanceof LightweightPeer);
- PaintEvent pe = new PaintEvent(par, PaintEvent.UPDATE,
- new Rectangle(px, py, pw, ph));
- getToolkit().getSystemEventQueue().postEvent(pe);
+ // 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);
+ }
}
}
@@ -2459,7 +2531,8 @@ public abstract class Component
p = comp == null ? null : comp.peer;
}
- returnValue = p.createImage(width, height);
+ if (p != null)
+ returnValue = p.createImage(width, height);
}
return returnValue;
}
@@ -2756,14 +2829,6 @@ public abstract class Component
*/
public final void dispatchEvent(AWTEvent e)
{
- Event oldEvent = translateEvent(e);
- if (oldEvent != null)
- postEvent (oldEvent);
-
- // Give toolkit a chance to dispatch the event
- // to globally registered listeners.
- Toolkit.getDefaultToolkit().globalDispatchEvent(e);
-
// Some subclasses in the AWT package need to override this behavior,
// hence the use of dispatchEventImpl().
dispatchEventImpl(e);
@@ -2814,9 +2879,12 @@ public abstract class Component
*/
public synchronized void addComponentListener(ComponentListener listener)
{
- componentListener = AWTEventMulticaster.add(componentListener, listener);
- if (componentListener != null)
- enableEvents(AWTEvent.COMPONENT_EVENT_MASK);
+ if (listener != null)
+ {
+ componentListener = AWTEventMulticaster.add(componentListener,
+ listener);
+ newEventsOnly = true;
+ }
}
/**
@@ -2862,9 +2930,11 @@ public abstract class Component
*/
public synchronized void addFocusListener(FocusListener listener)
{
- focusListener = AWTEventMulticaster.add(focusListener, listener);
- if (focusListener != null)
- enableEvents(AWTEvent.FOCUS_EVENT_MASK);
+ if (listener != null)
+ {
+ focusListener = AWTEventMulticaster.add(focusListener, listener);
+ newEventsOnly = true;
+ }
}
/**
@@ -2909,16 +2979,19 @@ public abstract class Component
*/
public synchronized void addHierarchyListener(HierarchyListener listener)
{
- hierarchyListener = AWTEventMulticaster.add(hierarchyListener, listener);
- if (hierarchyListener != null)
- enableEvents(AWTEvent.HIERARCHY_EVENT_MASK);
-
- // Need to lock the tree, otherwise we might end up inconsistent.
- synchronized (getTreeLock())
+ if (listener != null)
{
- numHierarchyListeners++;
- if (parent != null)
- parent.updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK, 1);
+ 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);
+ }
}
}
@@ -2975,19 +3048,20 @@ public abstract class Component
public synchronized void
addHierarchyBoundsListener(HierarchyBoundsListener listener)
{
- hierarchyBoundsListener =
- AWTEventMulticaster.add(hierarchyBoundsListener, listener);
- if (hierarchyBoundsListener != null)
- enableEvents(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK);
-
- // Need to lock the tree, otherwise we might end up inconsistent.
- synchronized (getTreeLock())
+ if (listener != null)
{
- numHierarchyBoundsListeners++;
- if (parent != null)
- parent.updateHierarchyListenerCount
- (AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
- 1);
+ 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);
+ }
}
}
@@ -3080,9 +3154,11 @@ public abstract class Component
*/
public synchronized void addKeyListener(KeyListener listener)
{
- keyListener = AWTEventMulticaster.add(keyListener, listener);
- if (keyListener != null)
- enableEvents(AWTEvent.KEY_EVENT_MASK);
+ if (listener != null)
+ {
+ keyListener = AWTEventMulticaster.add(keyListener, listener);
+ newEventsOnly = true;
+ }
}
/**
@@ -3127,9 +3203,11 @@ public abstract class Component
*/
public synchronized void addMouseListener(MouseListener listener)
{
- mouseListener = AWTEventMulticaster.add(mouseListener, listener);
- if (mouseListener != null)
- enableEvents(AWTEvent.MOUSE_EVENT_MASK);
+ if (listener != null)
+ {
+ mouseListener = AWTEventMulticaster.add(mouseListener, listener);
+ newEventsOnly = true;
+ }
}
/**
@@ -3174,9 +3252,12 @@ public abstract class Component
*/
public synchronized void addMouseMotionListener(MouseMotionListener listener)
{
- mouseMotionListener = AWTEventMulticaster.add(mouseMotionListener, listener);
- if (mouseMotionListener != null)
- enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
+ if (listener != null)
+ {
+ mouseMotionListener = AWTEventMulticaster.add(mouseMotionListener,
+ listener);
+ newEventsOnly = true;
+ }
}
/**
@@ -3223,9 +3304,12 @@ public abstract class Component
*/
public synchronized void addMouseWheelListener(MouseWheelListener listener)
{
- mouseWheelListener = AWTEventMulticaster.add(mouseWheelListener, listener);
- if (mouseWheelListener != null)
- enableEvents(AWTEvent.MOUSE_WHEEL_EVENT_MASK);
+ if (listener != null)
+ {
+ mouseWheelListener = AWTEventMulticaster.add(mouseWheelListener,
+ listener);
+ newEventsOnly = true;
+ }
}
/**
@@ -3273,9 +3357,12 @@ public abstract class Component
*/
public synchronized void addInputMethodListener(InputMethodListener listener)
{
- inputMethodListener = AWTEventMulticaster.add(inputMethodListener, listener);
- if (inputMethodListener != null)
- enableEvents(AWTEvent.INPUT_METHOD_EVENT_MASK);
+ if (listener != null)
+ {
+ inputMethodListener = AWTEventMulticaster.add(inputMethodListener,
+ listener);
+ newEventsOnly = true;
+ }
}
/**
@@ -3430,6 +3517,7 @@ public abstract class Component
}
eventMask |= eventsToEnable;
+ newEventsOnly = true;
// Only heavyweight peers handle this.
ComponentPeer p = peer;
@@ -3512,19 +3600,36 @@ public abstract class Component
*/
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.
- return newEvent;
+ MouseEvent me1 = (MouseEvent) existingEvent;
+ MouseEvent me2 = (MouseEvent) newEvent;
+ if (me1.getModifiers() == me2.getModifiers())
+ coalesced = newEvent;
+ break;
case PaintEvent.PAINT:
case PaintEvent.UPDATE:
- return coalescePaintEvents((PaintEvent) existingEvent,
- (PaintEvent) newEvent);
+ // 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;
+ }
+ break;
default:
- return null;
+ coalesced = null;
}
+ return coalesced;
}
/**
@@ -4046,23 +4151,29 @@ public abstract class Component
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. */
+ // 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 do not invalidate here, but rather leave that job up to
- the peer. For efficiency, the peer can choose not to
- invalidate if it is happy with the current dimensions,
- etc. */
- if (dropTarget != null)
- dropTarget.addNotify(peer);
-
- // Notify hierarchy listeners.
- long flags = HierarchyEvent.DISPLAYABILITY_CHANGED;
- if (isHierarchyVisible())
- flags |= HierarchyEvent.SHOWING_CHANGED;
- fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, this, parent,
- flags);
+
+ // 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);
}
}
@@ -4087,6 +4198,7 @@ public abstract class Component
ComponentPeer tmp = peer;
peer = null;
+ peerFont = null;
if (tmp != null)
{
tmp.hide();
@@ -5542,7 +5654,7 @@ p * <li>the set of backward traversal keys
oldKey = Event.UP;
break;
default:
- oldKey = (int) ((KeyEvent) e).getKeyChar();
+ oldKey = ((KeyEvent) e).getKeyChar();
}
translated = new Event (target, when, oldID,
@@ -5585,7 +5697,6 @@ p * <li>the set of backward traversal keys
*
* @param e the event to dispatch
*/
-
void dispatchEventImpl(AWTEvent e)
{
// Retarget focus events before dispatching it to the KeyboardFocusManager
@@ -5600,11 +5711,21 @@ p * <li>the set of backward traversal keys
if (! dispatched)
{
- if (eventTypeEnabled (e.id))
+ // Give toolkit a chance to dispatch the event
+ // to globally registered listeners.
+ Toolkit.getDefaultToolkit().globalDispatchEvent(e);
+
+ if (newEventsOnly)
{
- if (e.id != PaintEvent.PAINT && e.id != PaintEvent.UPDATE)
+ if (eventTypeEnabled(e.id))
processEvent(e);
}
+ else
+ {
+ Event oldEvent = translateEvent(e);
+ if (oldEvent != null)
+ postEvent (oldEvent);
+ }
if (peer != null)
peer.handleEvent(e);
}
@@ -5697,45 +5818,6 @@ p * <li>the set of backward traversal keys
}
/**
- * Coalesce paint events. Current heuristic is: Merge if the union of
- * areas is less than twice that of the sum of the areas. The X server
- * tend to create a lot of paint events that are adjacent but not
- * overlapping.
- *
- * <pre>
- * +------+
- * | +-----+ ...will be merged
- * | | |
- * | | |
- * +------+ |
- * +-----+
- *
- * +---------------+--+
- * | | | ...will not be merged
- * +---------------+ |
- * | |
- * | |
- * | |
- * | |
- * | |
- * +--+
- * </pre>
- *
- * @param queuedEvent the first paint event
- * @param newEvent the second paint event
- * @return the combined paint event, or null
- */
- private PaintEvent coalescePaintEvents(PaintEvent queuedEvent,
- PaintEvent newEvent)
- {
- Rectangle r1 = queuedEvent.getUpdateRect();
- Rectangle r2 = newEvent.getUpdateRect();
- Rectangle union = r1.union(r2);
- newEvent.setUpdateRect(union);
- return newEvent;
- }
-
- /**
* 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.
@@ -5875,7 +5957,7 @@ p * <li>the set of backward traversal keys
*/
public void componentHidden(ComponentEvent event)
{
- if (!isShowing())
+ if (isShowing())
peer.hide();
}
}
diff --git a/java/awt/Container.java b/java/awt/Container.java
index 17ca3e0ad..3d460baaf 100644
--- a/java/awt/Container.java
+++ b/java/awt/Container.java
@@ -39,7 +39,6 @@ exception statement from your version. */
package java.awt;
-import java.awt.event.ComponentListener;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.awt.event.HierarchyEvent;
@@ -325,23 +324,6 @@ public class Container extends Component
// we are.
if (comp.parent != null)
comp.parent.remove(comp);
- comp.parent = this;
-
- if (peer != null)
- {
- // Notify the component that it has a new parent.
- comp.addNotify();
-
- if (comp.isLightweight ())
- {
- enableEvents (comp.eventMask);
- if (!isLightweight ())
- enableEvents (AWTEvent.PAINT_EVENT_MASK);
- }
- }
-
- // Invalidate the layout of the added component and its ancestors.
- comp.invalidate();
if (component == null)
component = new Component[4]; // FIXME, better initial size?
@@ -366,6 +348,9 @@ public class Container extends Component
++ncomponents;
}
+ // Give the new component a parent.
+ comp.parent = this;
+
// Update the counter for Hierarchy(Bounds)Listeners.
int childHierarchyListeners = comp.numHierarchyListeners;
if (childHierarchyListeners > 0)
@@ -376,6 +361,18 @@ public class Container extends Component
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)
{
@@ -395,13 +392,15 @@ public class Container extends Component
// 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.
- ContainerEvent ce = new ContainerEvent(this,
- ContainerEvent.COMPONENT_ADDED,
- comp);
- ContainerListener[] listeners = getContainerListeners();
- for (int i = 0; i < listeners.length; i++)
- listeners[i].componentAdded(ce);
+ // 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,
@@ -418,17 +417,15 @@ public class Container extends Component
{
synchronized (getTreeLock ())
{
- Component r = component[index];
+ if (index < 0 || index >= ncomponents)
+ throw new ArrayIndexOutOfBoundsException();
- ComponentListener[] list = r.getComponentListeners();
- for (int j = 0; j < list.length; j++)
- r.removeComponentListener(list[j]);
-
- r.removeNotify();
+ Component r = component[index];
+ if (peer != null)
+ r.removeNotify();
- System.arraycopy(component, index + 1, component, index,
- ncomponents - index - 1);
- component[--ncomponents] = null;
+ if (layoutMgr != null)
+ layoutMgr.removeLayoutComponent(r);
// Update the counter for Hierarchy(Bounds)Listeners.
int childHierarchyListeners = r.numHierarchyListeners;
@@ -440,20 +437,23 @@ public class Container extends Component
updateHierarchyListenerCount(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
-childHierarchyListeners);
- invalidate();
+ r.parent = null;
- if (layoutMgr != null)
- layoutMgr.removeLayoutComponent(r);
+ System.arraycopy(component, index + 1, component, index,
+ ncomponents - index - 1);
+ component[--ncomponents] = null;
- r.parent = null;
+ if (valid)
+ invalidate();
- if (isShowing ())
+ 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);
- getToolkit().getSystemEventQueue().postEvent(ce);
+ ContainerEvent.COMPONENT_REMOVED,
+ r);
+ dispatchEvent(ce);
}
// Notify hierarchy listeners.
@@ -497,25 +497,14 @@ public class Container extends Component
// super.removeAll() ).
// By doing it this way, user code cannot prevent the correct
// removal of components.
- for ( int index = 0; index < ncomponents; index++)
+ while (ncomponents > 0)
{
- Component r = component[index];
-
- ComponentListener[] list = r.getComponentListeners();
- for (int j = 0; j < list.length; j++)
- r.removeComponentListener(list[j]);
-
- r.removeNotify();
+ ncomponents--;
+ Component r = component[ncomponents];
+ component[ncomponents] = null;
- // 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);
+ if (peer != null)
+ r.removeNotify();
if (layoutMgr != null)
layoutMgr.removeLayoutComponent(r);
@@ -534,6 +523,17 @@ public class Container extends Component
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);
@@ -542,8 +542,6 @@ public class Container extends Component
if (valid)
invalidate();
-
- ncomponents = 0;
}
}
@@ -620,24 +618,20 @@ public class Container extends Component
/**
* Recursively invalidates the container tree.
*/
- void invalidateTree()
+ private final void invalidateTree()
{
synchronized (getTreeLock())
{
- super.invalidate(); // Clean cached layout state.
for (int i = 0; i < ncomponents; i++)
{
Component comp = component[i];
- comp.invalidate();
if (comp instanceof Container)
((Container) comp).invalidateTree();
+ else if (comp.valid)
+ comp.invalidate();
}
-
- if (layoutMgr != null && layoutMgr instanceof LayoutManager2)
- {
- LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
- lm2.invalidateLayout(this);
- }
+ if (valid)
+ invalidate();
}
}
@@ -688,13 +682,11 @@ public class Container extends Component
public void setFont(Font f)
{
- if( (f != null && (font == null || !font.equals(f)))
- || f == null)
+ Font oldFont = getFont();
+ super.setFont(f);
+ Font newFont = getFont();
+ if (newFont != oldFont && (oldFont == null || ! oldFont.equals(newFont)))
{
- super.setFont(f);
- // FIXME: Although it might make more sense to invalidate only
- // those children whose font == null, Sun invalidates all children.
- // So we'll do the same.
invalidateTree();
}
}
@@ -796,8 +788,9 @@ public class Container extends Component
LayoutManager l = layoutMgr;
if (l instanceof LayoutManager2)
maxSize = ((LayoutManager2) l).maximumLayoutSize(this);
- else
+ else {
maxSize = super.maximumSizeImpl();
+ }
size = maxSize;
}
}
@@ -932,8 +925,8 @@ public class Container extends Component
*/
public void paintComponents(Graphics g)
{
- paint(g);
- visitChildren(g, GfxPaintAllVisitor.INSTANCE, true);
+ if (isShowing())
+ visitChildren(g, GfxPaintAllVisitor.INSTANCE, false);
}
/**
@@ -955,7 +948,12 @@ public class Container extends Component
*/
public synchronized void addContainerListener(ContainerListener listener)
{
- containerListener = AWTEventMulticaster.add(containerListener, listener);
+ if (listener != null)
+ {
+ containerListener = AWTEventMulticaster.add(containerListener,
+ listener);
+ newEventsOnly = true;
+ }
}
/**
@@ -1259,8 +1257,14 @@ public class Container extends Component
{
synchronized (getTreeLock ())
{
- for (int i = 0; i < ncomponents; ++i)
- component[i].removeNotify();
+ 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();
}
}
@@ -1880,6 +1884,7 @@ public class Container extends Component
bounds.height);
try
{
+ g2.setFont(comp.getFont());
visitor.visit(comp, g2);
}
finally
@@ -1888,20 +1893,40 @@ public class Container extends Component
}
}
+ /**
+ * Overridden to dispatch events to lightweight descendents.
+ *
+ * @param e the event to dispatch.
+ */
void dispatchEventImpl(AWTEvent e)
{
- boolean dispatched =
- LightweightDispatcher.getInstance().dispatchEvent(e);
- if (! dispatched)
+ LightweightDispatcher dispatcher = LightweightDispatcher.getInstance();
+ if (! isLightweight() && dispatcher.dispatchEvent(e))
{
- if ((e.id <= ContainerEvent.CONTAINER_LAST
- && e.id >= ContainerEvent.CONTAINER_FIRST)
- && (containerListener != null
- || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0))
- processEvent(e);
- else
- super.dispatchEventImpl(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);
}
/**
@@ -2062,12 +2087,6 @@ public class Container extends Component
for (int i = ncomponents; --i >= 0; )
{
component[i].addNotify();
- if (component[i].isLightweight ())
- {
- enableEvents(component[i].eventMask);
- if (peer != null && !isLightweight ())
- enableEvents (AWTEvent.PAINT_EVENT_MASK);
- }
}
}
}
diff --git a/java/awt/EventQueue.java b/java/awt/EventQueue.java
index 235ad2ac1..e1f109098 100644
--- a/java/awt/EventQueue.java
+++ b/java/awt/EventQueue.java
@@ -38,10 +38,15 @@ exception statement from your version. */
package java.awt;
+import gnu.java.awt.LowPriorityEvent;
+
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;
@@ -61,11 +66,47 @@ import java.util.EmptyStackException;
*/
public class EventQueue
{
- private static final int INITIAL_QUEUE_DEPTH = 8;
- private AWTEvent[] queue = new AWTEvent[INITIAL_QUEUE_DEPTH];
+ /**
+ * 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;
+ }
- private int next_in = 0; // Index where next event will be added to queue
- private int next_out = 0; // Index of next event to be removed from queue
+ /**
+ * The three internal event queues.
+ *
+ * @see Queue
+ */
+ private Queue[] queues;
private EventQueue next;
private EventQueue prev;
@@ -105,6 +146,9 @@ public class EventQueue
*/
public EventQueue()
{
+ queues = new Queue[2];
+ queues[NORM_PRIORITY] = new Queue();
+ queues[LOW_PRIORITY] = new Queue();
}
/**
@@ -122,7 +166,8 @@ public class EventQueue
if (next != null)
return next.getNextEvent();
- while (next_in == next_out)
+ AWTEvent res = getNextEventImpl(true);
+ while (res == null)
{
// We are not allowed to return null from this method, yet it
// is possible that we actually have run out of native events
@@ -137,16 +182,47 @@ public class EventQueue
throw new InterruptedException();
wait();
+ res = getNextEventImpl(true);
}
- AWTEvent res = queue[next_out];
-
- if (++next_out == queue.length)
- next_out = 0;
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.
@@ -160,10 +236,7 @@ public class EventQueue
if (next != null)
return next.peekEvent();
- if (next_in != next_out)
- return queue[next_out];
- else
- return null;
+ return getNextEventImpl(false);
}
/**
@@ -184,14 +257,18 @@ public class EventQueue
if (next != null)
return next.peekEvent(id);
- int i = next_out;
- while (i != next_in)
+ AWTEvent evt = null;
+ for (int i = 0; i < queues.length && evt == null; i++)
{
- AWTEvent qevt = queue[i];
- if (qevt.id == id)
- return qevt;
+ 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 null;
+ return evt;
}
/**
@@ -201,7 +278,36 @@ public class EventQueue
*
* @exception NullPointerException If event is null.
*/
- public synchronized void postEvent(AWTEvent evt)
+ 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.
+ 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();
@@ -212,52 +318,71 @@ public class EventQueue
return;
}
- /* Check for any events already on the queue with the same source
- and ID. */
- int i = next_out;
- while (i != next_in)
+ Object source = evt.getSource();
+
+ Queue q = queues[priority];
+ if (source instanceof Component)
{
- AWTEvent qevt = queue[i];
- Object src;
- if (qevt.id == evt.id
- && (src = qevt.getSource()) == evt.getSource()
- && src 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)
{
- /* If there are, call coalesceEvents on the source component
- to see if they can be combined. */
- Component srccmp = (Component) src;
- AWTEvent coalesced_evt = srccmp.coalesceEvents(qevt, evt);
- if (coalesced_evt != null)
+ Object src = qevt.getSource();
+ if (qevt.id == evt.id && src == comp)
{
- /* Yes. Replace the existing event with the combined event. */
- queue[i] = coalesced_evt;
- return;
+ // 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;
+ }
}
- break;
+ previous = qevt;
}
- if (++i == queue.length)
- i = 0;
}
- queue[next_in] = evt;
- if (++next_in == queue.length)
- next_in = 0;
-
- if (next_in == next_out)
+ if (q.queueHead == null)
{
- /* Queue is full. Extend it. */
- AWTEvent[] oldQueue = queue;
- queue = new AWTEvent[queue.length * 2];
-
- int len = oldQueue.length - next_out;
- System.arraycopy(oldQueue, next_out, queue, 0, len);
- if (next_out != 0)
- System.arraycopy(oldQueue, 0, queue, len, next_out);
-
- next_out = 0;
- next_in = oldQueue.length;
+ // 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);
@@ -287,15 +412,15 @@ public class EventQueue
throw new Error("Can't call invokeAndWait from event dispatch thread");
EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
- Thread current = Thread.currentThread();
+ Object notifyObject = new Object();
- InvocationEvent ie =
- new InvocationEvent(eq, runnable, current, true);
+ InvocationEvent ie =
+ new InvocationEvent(eq, runnable, notifyObject, true);
- synchronized (current)
+ synchronized (notifyObject)
{
eq.postEvent(ie);
- current.wait();
+ notifyObject.wait();
}
Exception exception;
@@ -387,17 +512,26 @@ public class EventQueue
if (dispatchThread == null)
dispatchThread = new EventDispatchThread(this);
- int i = next_out;
- while (i != next_in)
+ synchronized (newEventQueue)
{
- newEventQueue.postEvent(queue[i]);
- next_out = i;
- if (++i == queue.length)
- i = 0;
+ // 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;
- newEventQueue.prev = this;
}
/** Transfer any pending events from this queue back to the parent queue that
@@ -408,36 +542,46 @@ public class EventQueue
*/
protected void pop() throws EmptyStackException
{
- if (prev == null)
- throw new 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. */
- synchronized (prev)
+ EventQueue previous = prev;
+ if (previous == null)
+ throw new EmptyStackException();
+ synchronized (previous)
{
- prev.next = next;
- if (next != null)
- next.prev = prev;
-
synchronized (this)
{
- int i = next_out;
- while (i != next_in)
+ EventQueue nextQueue = next;
+ if (nextQueue != null)
{
- prev.postEvent(queue[i]);
- next_out = i;
- if (++i == queue.length)
- i = 0;
+ 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;
+ setShutdown(true);
+ dispatchThread = null;
+ this.notifyAll();
}
- // Empty the queue so it can be reused
- next_in = 0;
- next_out = 0;
-
- setShutdown(true);
- dispatchThread = null;
- this.notifyAll();
}
}
}
diff --git a/java/awt/Frame.java b/java/awt/Frame.java
index 542013671..e0c0d1ff3 100644
--- a/java/awt/Frame.java
+++ b/java/awt/Frame.java
@@ -340,13 +340,16 @@ public class Frame extends Window implements MenuContainer
parent.remove(menuBar);
menuBar.setParent(this);
- if (peer != null)
- {
- if (menuBar != null)
- menuBar.addNotify();
- invalidateTree();
- ((FramePeer) peer).setMenuBar(menuBar);
- }
+ // Create local copy for thread safety.
+ FramePeer p = (FramePeer) peer;
+ if (p != null)
+ {
+ if (menuBar != null)
+ menuBar.addNotify();
+ if (valid)
+ invalidate();
+ p.setMenuBar(menuBar);
+ }
}
}
diff --git a/java/awt/GridLayout.java b/java/awt/GridLayout.java
index a6836681d..65e09aa59 100644
--- a/java/awt/GridLayout.java
+++ b/java/awt/GridLayout.java
@@ -289,7 +289,7 @@ public class GridLayout implements LayoutManager, Serializable
public String toString ()
{
return (getClass ().getName () + "["
- + ",hgap=" + hgap + ",vgap=" + vgap
+ + "hgap=" + hgap + ",vgap=" + vgap
+ ",rows=" + rows + ",cols=" + cols
+ "]");
}
diff --git a/java/awt/LightweightDispatcher.java b/java/awt/LightweightDispatcher.java
index 3ea3f90a6..4360f592d 100644
--- a/java/awt/LightweightDispatcher.java
+++ b/java/awt/LightweightDispatcher.java
@@ -38,7 +38,10 @@ 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;
/**
@@ -49,7 +52,7 @@ import java.util.WeakHashMap;
*
* @author Roman Kennke (kennke@aicas.com)
*/
-class LightweightDispatcher
+final class LightweightDispatcher
{
/**
@@ -60,26 +63,17 @@ class LightweightDispatcher
private static WeakHashMap instances = new WeakHashMap();
/**
- * The component that is the start of a mouse dragging. All MOUSE_DRAGGED
- * events that follow the initial press must have the source set to this,
- * as well as the MOUSE_RELEASED event following the dragging.
- */
- private Component dragTarget;
-
- /**
- * Stores the button number which started the drag operation. This is needed
- * because we want to handle only one drag operation and only the button that
- * started the dragging should be able to stop it (by a button release).
- */
- private int dragButton;
-
- /**
* 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.
*
@@ -113,9 +107,9 @@ class LightweightDispatcher
*
* @param event the event
*/
- public boolean dispatchEvent(AWTEvent event)
+ public boolean dispatchEvent(final AWTEvent event)
{
- if (event instanceof MouseEvent && event.getSource() instanceof Window)
+ if (event instanceof MouseEvent)
{
MouseEvent mouseEvent = (MouseEvent) event;
return handleMouseEvent(mouseEvent);
@@ -130,151 +124,47 @@ class LightweightDispatcher
* @param ev the mouse event
* @return whether or not we found a lightweight that handled the event.
*/
- private boolean handleMouseEvent(MouseEvent ev)
+ private boolean handleMouseEvent(final MouseEvent ev)
{
- Window window = (Window) ev.getSource();
- // Find the target for the mouse event. We first seach the deepest
- // component at the specified location. The we go up to its parent and
- // try to find a neighbor of the deepest component that is suitable as
- // mouse event target (it must be showing, at that location and have either
- // a MouseListener or MouseMotionListener installed). If no such component
- // is found, then we walk up the container hierarchy and find the next
- // container that has a MouseListener or MouseMotionListener installed.
- Component deepest = window.findComponentAt(ev.getX(), ev.getY());
- if (deepest == null)
- return false;
- Container parent = deepest.getParent();
- Point loc = ev.getPoint();
- loc = convertPointToChild(window, loc, parent);
- Component target = null;
- if (parent != null)
- {
- target = findTarget(parent, loc);
- while (target == null && parent != null)
- {
- if (parent.mouseListener != null
- || parent.mouseMotionListener != null
- || (parent.eventMask
- & (AWTEvent.MOUSE_EVENT_MASK
- | AWTEvent.MOUSE_MOTION_EVENT_MASK)) != 0)
- {
- target = parent;
- }
- else
- parent = parent.getParent();
- }
- }
- if (target == null || target.isLightweight())
+ 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)
{
- // Dispatch additional MOUSE_EXITED and MOUSE_ENTERED if event target
- // is different from the last event target.
- if (target != lastTarget)
+ switch (id)
{
- if (lastTarget != null)
- {
- Point p1 = convertPointToChild(window, ev.getPoint(),
- lastTarget);
- MouseEvent mouseExited =
- new MouseEvent(lastTarget, MouseEvent.MOUSE_EXITED,
- ev.getWhen(), ev.getModifiers(), p1.x, p1.y,
- ev.getClickCount(), ev.isPopupTrigger());
- //System.err.println("event: " + mouseExited);
- lastTarget.dispatchEvent(mouseExited);
- }
-
- // If a target exists dispatch the MOUSE_ENTERED event.
- // Experimenting shows that the MOUSE_ENTERED is also dispatched
- // when the mouse is dragging.
- if (target != null)
- {
- Point p = convertPointToChild(window, ev.getPoint(), target);
- MouseEvent mouseEntered =
- new MouseEvent(target,
- MouseEvent.MOUSE_ENTERED, ev.getWhen(),
- ev.getModifiers(), p.x, p.y, ev.getClickCount(),
- ev.isPopupTrigger());
- //System.err.println("event: " + mouseEntered);
- target.dispatchEvent(mouseEntered);
- }
- }
-
- switch (ev.getID())
- {
- case MouseEvent.MOUSE_PRESSED:
- // Handle the start of a drag operation or discard the event if
- // one is already in progress. This prevents focus changes with the
- // other mouse buttons when one is used for dragging.
- if (dragTarget == null)
- {
- lastTarget = dragTarget = target;
-
- // Save the button that started the drag operation.
- dragButton = ev.getButton();
- }
- else
- return false;
-
+ case MouseEvent.MOUSE_ENTERED:
+ case MouseEvent.MOUSE_EXITED:
+ // This is already handled in trackEnterExit().
break;
+ case MouseEvent.MOUSE_PRESSED:
case MouseEvent.MOUSE_RELEASED:
- // Stop the drag operation only when the button that started
- // it was released.
- if (dragTarget != null && dragButton == ev.getButton())
- {
- // Only post MOUSE_RELEASED to dragTarget (set in
- // MOUSE_PRESSED) when the dragTarget is actually visible.
- // Otherwise post the event to the normal target.
- if (dragTarget.isVisible())
- target = dragTarget;
- dragTarget = null;
- }
-
- lastTarget = target;
+ case MouseEvent.MOUSE_MOVED:
+ redispatch(ev, mouseEventTarget, id);
break;
case MouseEvent.MOUSE_CLICKED:
- // When we receive a MOUSE_CLICKED, we set the target to the
- // previous target, which must have been a MOUSE_RELEASED event.
- // This is necessary for the case when the MOUSE_RELEASED has
- // caused the original target (like an internal component) go
- // away.
- // This line is the reason why it is not possible to move the
- // 'lastTarget = target' assignment before the switch-statement.
- target = lastTarget;
+ // MOUSE_CLICKED must be dispatched to the original target of
+ // MOUSE_PRESSED.
+ if (target == mouseEventTarget)
+ redispatch(ev, mouseEventTarget, id);
break;
case MouseEvent.MOUSE_DRAGGED:
- // We consider only dragTarget for redispatching the event still
- // we have to act in a way that the newly found target component
- // was handled.
- lastTarget = target;
- target = dragTarget;
+ if (isDragging(ev))
+ redispatch(ev, mouseEventTarget, id);
break;
- default:
- // Only declare current target as the old value in all other
- // cases.
- lastTarget = target;
- break;
- }
-
- if (target != null)
- {
- Point targetCoordinates = convertPointToChild(window,
- ev.getPoint(),
- target);
- int dx = targetCoordinates.x - ev.getX();
- int dy = targetCoordinates.y - ev.getY();
- ev.translatePoint(dx, dy);
- ev.setSource(target);
- target.dispatchEvent(ev);
-
- // We reset the event, so that the normal event dispatching is not
- // influenced by this modified event.
- ev.setSource(window);
- ev.translatePoint(-dx, -dy);
}
-
- return true;
+ ev.consume();
}
- else
- return false;
+
+ return ev.isConsumed();
}
/**
@@ -290,58 +180,180 @@ class LightweightDispatcher
* @return the actual receiver of the mouse event, or null, if no such
* component has been found
*/
- private Component findTarget(Container c, Point loc)
+ private Component findTarget(final Container c, final int x, final int y)
{
- int numComponents = c.getComponentCount();
Component target = null;
- if (c != 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++)
{
- for (int i = 0; i < numComponents; 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))
{
- Component child = c.getComponent(i);
- if (child.isShowing())
+ // Check if there's a deeper possible target.
+ if (child instanceof Container)
{
- if (child.contains(loc.x - child.getX(), loc.y - child.getY())
- && (child.mouseListener != null
- || child.mouseMotionListener != null
- || (child.eventMask
- & (AWTEvent.MOUSE_EVENT_MASK
- | AWTEvent.MOUSE_MOTION_EVENT_MASK)) != 0))
- {
- target = child;
- break;
- }
+ 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;
}
/**
- * Converts a point in the parent's coordinate system to a child coordinate
- * system. The resulting point is stored in the same Point object and
- * returned.
+ * 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 parent the parent component
- * @param p the point
- * @param child the child component
+ * @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();
+ if (target != null)
+ {
+ // 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());
+ }
+
+ 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 the translated point
+ * @return <code>true</code> if we are in the middle of a drag operation,
+ * <code>false</code> otherwise
*/
- private Point convertPointToChild(Component parent, Point p,
- Component child)
+ private boolean isDragging(MouseEvent ev)
{
- int offX = 0;
- int offY = 0;
- Component comp = child;
- while (comp != null && comp != parent)
+ int mods = ev.getModifiersEx();
+ int id = ev.getID();
+ if (id == MouseEvent.MOUSE_PRESSED || id == MouseEvent.MOUSE_RELEASED)
{
- offX += comp.getX();
- offY += comp.getY();
- comp = comp.getParent();
+ 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;
+ }
}
- p.x -= offX;
- p.y -= offY;
- return p;
+ return (mods & (InputEvent.BUTTON1_DOWN_MASK
+ | InputEvent.BUTTON2_DOWN_MASK
+ | InputEvent.BUTTON3_DOWN_MASK)) != 0;
}
}
diff --git a/java/awt/List.java b/java/awt/List.java
index 7b6524171..df8bffa19 100644
--- a/java/awt/List.java
+++ b/java/awt/List.java
@@ -1,5 +1,5 @@
/* List.java -- A listbox widget
- Copyright (C) 1999, 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2002, 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -54,826 +54,718 @@ import javax.accessibility.AccessibleState;
import javax.accessibility.AccessibleStateSet;
/**
- * Class that implements a listbox widget
- *
- * @author Aaron M. Renn (arenn@urbanophile.com)
- */
+ * Class that implements a listbox widget
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
public class List extends Component
implements ItemSelectable, Accessible
{
-/*
- * Static Variables
- */
-
-/**
- * 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;
-
-/*************************************************************************/
-
-/*
- * Instance Variables
- */
-
-// FIXME: Need read/writeObject
-
-/**
- * @serial The items in the list.
- */
-private Vector items = new Vector();
+ /**
+ * The number used to generate the name returned by getName.
+ */
+ private static transient long next_list_number;
-/**
- * @serial Indicates whether or not multiple items can be selected
- * simultaneously.
- */
-private boolean multipleMode;
+ // Serialization constant
+ private static final long serialVersionUID = -3304312411574666869L;
-/**
- * @serial The number of rows in the list. This is set on creation
- * only and cannot be modified.
- */
-private int rows;
+ // FIXME: Need read/writeObject
-/**
- * @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;
+ /**
+ * @serial The items in the list.
+ */
+ private Vector items = new Vector();
-// The list of ItemListeners for this object.
-private ItemListener item_listeners;
+ /**
+ * @serial Indicates whether or not multiple items can be selected
+ * simultaneously.
+ */
+ private boolean multipleMode;
-// The list of ActionListeners for this object.
-private ActionListener action_listeners;
+ /**
+ * @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;
-/*
- * Constructors
- */
+ /**
+ * @serial An index value used by <code>makeVisible()</code> and
+ * <code>getVisibleIndex</code>.
+ */
+ private int visibleIndex = -1;
-/**
- * Initializes a new instance of <code>List</code> with no visible lines
- * and multi-select disabled.
- *
- * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true.
- */
-public
-List()
-{
- this(4, false);
-}
+ // 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 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 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;
+ /**
+ * 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];
+ this.multipleMode = multipleMode;
+ selected = new int[0];
- if (GraphicsEnvironment.isHeadless())
- throw new HeadlessException ();
+ if (GraphicsEnvironment.isHeadless())
+ throw new HeadlessException();
-}
-
-/*************************************************************************/
-
-/*
- * Instance Variables
- */
-
-/**
- * Returns the number of items in this list.
- *
- * @return The number of items in this list.
- */
-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 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.
- */
-public synchronized String[]
-getItems()
-{
- String[] l_items = new String[getItemCount()];
+ /**
+ * 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);
-}
-
-/*************************************************************************/
+ items.copyInto(l_items);
+ return(l_items);
+ }
-/**
- * Tests whether or not multi-select mode is enabled.
- *
- * @return <code>true</code> if multi-select mode is enabled,
- * <code>false</code> otherwise.
- */
-public boolean
-isMultipleMode()
-{
- return allowsMultipleSelections ();
-}
+ /**
+ * 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.
- *
- * @deprecated This method is deprecated in favor of
- * <code>isMultipleMode()</code>.
- */
-public boolean
-allowsMultipleSelections()
-{
- return multipleMode;
-}
+ /**
+ * 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.
- */
-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.
+ *
+ * @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;
-/**
- * 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);
+ ListPeer peer = (ListPeer) getPeer();
+ if (peer != null)
+ peer.setMultipleMode(multipleMode);
-}
-
-/*************************************************************************/
-
-/**
- * Returns the minimum size of this component.
- *
- * @return The minimum size of this component.
- */
-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.
- */
-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.
- */
-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 minimum size of this component.
+ *
+ * @return The minimum size of this component.
+ *
+ * @since 1.1
+ */
+ public Dimension getMinimumSize()
+ {
+ return getMinimumSize(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.
- */
-public Dimension
-getPreferredSize(int rows)
-{
- return preferredSize (rows);
-}
+ /**
+ * 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 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();
-}
+ /**
+ * 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());
+ }
-/**
- * This method adds the specified item to the end of the list.
- *
- * @param item The item to add to the list.
- */
-public void
-add(String item)
-{
- add (item, -1);
-}
+ /**
+ * 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);
+ }
-/**
- * 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);
-}
+ /**
+ * 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);
+ }
-/**
- * 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.
- */
-public void
-add(String item, int index)
-{
- addItem (item, index);
-}
+ /**
+ * 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 = "";
+ /**
+ * 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 = -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);
-}
-
-/*************************************************************************/
+ 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);
- }
+ /**
+ * 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);
+ 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
- */
-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);
- }
-}
+ if (selected)
+ select(index);
-/*************************************************************************/
+ ListPeer peer = (ListPeer) getPeer();
+ if (peer != null)
+ peer.delItems (index, index);
+ }
-/**
- * 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.
- */
-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");
+ /**
+ * 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);
+ }
- remove(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");
-/**
- * Deletes all of the items from the list.
- */
-public synchronized void
-removeAll()
-{
- clear ();
-}
+ 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();
+ /**
+ * 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 ();
+ 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;
+ selected = new int[0];
+ }
- /* We add first and then remove so that the selected
- item remains the same */
- l.add (item, index + 1);
- l.delItems (index, index);
- }
-}
+ /**
+ * 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);
-/**
- * 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 (peer != null)
+ {
+ ListPeer l = (ListPeer) peer;
- if (selected == null || selected.length != 1)
- return -1;
-
- return selected[0];
-}
+ /* 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 ();
+ }
-/**
- * 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 ();
- }
+ if (selected == null || selected.length != 1)
+ return -1;
- 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);
-}
+ 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 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]);
+ /**
+ * 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);
- 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((String) items.elementAt(index));
+ }
- return(retvals);
-}
+ /**
+ * 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]);
-/**
- * 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.
- */
-public boolean
-isIndexSelected(int index)
-{
- return isSelected (index);
-}
+ 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]);
-/**
- * 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 ();
+ Object[] retvals = new Object[indexes.length];
+ if (retvals.length > 0)
+ for (int i = 0 ; i < retvals.length; i++)
+ retvals[i] = items.elementAt(indexes[i]);
- for (int i = 0; i < indexes.length; i++)
- if (indexes[i] == index)
- return true;
+ return(retvals);
+ }
- return false;
-}
+ /**
+ * 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();
-/**
- * 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);
- }
-}
+ for (int i = 0; i < indexes.length; i++)
+ if (indexes[i] == index)
+ return true;
-/*************************************************************************/
+ return false;
+ }
-/**
- * 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);
-}
+ /**
+ * 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.
- */
+ /**
+ * 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();
@@ -900,213 +792,194 @@ getVisibleIndex()
temp[selected.length] = index;
selected = temp;
}
- } else
- {
- selected = new int[1];
- selected[0] = index;
- }
+ }
+ 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.
- */
-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.
- */
-public synchronized void
-removeActionListener(ActionListener listener)
-{
- action_listeners = AWTEventMulticaster.remove(action_listeners, listener);
-}
-
-/*************************************************************************/
+ /**
+ * 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;
+ }
+ }
-/**
- * Adds the specified <code>ItemListener</code> 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);
-}
+ /**
+ * 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();
+ }
-/**
- * Removes the specified <code>ItemListener</code> from the list of
- * registers listeners for this object.
- *
- * @param listener The listener to remove.
- */
-public synchronized void
-removeItemListener(ItemListener listener)
-{
- item_listeners = AWTEventMulticaster.remove(item_listeners, listener);
-}
+ /**
+ * 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);
+ }
-/**
- * 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.
- */
-protected void
-processEvent(AWTEvent event)
-{
- if (event instanceof ActionEvent)
- processActionEvent((ActionEvent)event);
- else if (event instanceof ItemEvent)
- processItemEvent((ItemEvent)event);
- else
- super.processEvent(event);
-}
+ /**
+ * 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);
+ }
-/**
- * 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.
- */
-protected void
-processActionEvent(ActionEvent event)
-{
- if (action_listeners != null)
- action_listeners.actionPerformed(event);
-}
+ /**
+ * 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.
- */
-protected void
-processItemEvent(ItemEvent event)
-{
- if (item_listeners != null)
- item_listeners.itemStateChanged(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
+ 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);
-}
-
-/*************************************************************************/
+ || (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 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
@@ -1115,6 +988,8 @@ paramString()
*
* @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)
{
@@ -1129,6 +1004,8 @@ paramString()
/**
* Returns all action listeners registered to this object.
+ *
+ * @since 1.4
*/
public ActionListener[] getActionListeners ()
{
@@ -1137,6 +1014,8 @@ paramString()
/**
* Returns all action listeners registered to this object.
+ *
+ * @since 1.4
*/
public ItemListener[] getItemListeners ()
{
diff --git a/java/awt/Menu.java b/java/awt/Menu.java
index f900d9295..cef04a38e 100644
--- a/java/awt/Menu.java
+++ b/java/awt/Menu.java
@@ -54,38 +54,28 @@ import javax.accessibility.AccessibleRole;
public class Menu extends MenuItem implements MenuContainer, Serializable
{
-/*
- * Static Variables
- */
-
-/**
- * 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;
-
-/*************************************************************************/
+ /**
+ * The number used to generate the name returned by getName.
+ */
+ private static transient long next_menu_number;
-/*
- * Instance Variables
- */
+ // Serialization Constant
+ private static final long serialVersionUID = -8809584163345499784L;
-/**
- * @serial The actual items in the menu
- */
-private Vector items = new Vector();
+ /**
+ * @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 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 Indicates whether or not this is a help menu.
+ */
+ private boolean isHelpMenu;
/*
* @serial Unused in this implementation, but present in Sun's
@@ -93,371 +83,316 @@ private boolean isHelpMenu;
*/
private int menuSerializedDataVersion = 1;
-static final transient String separatorLabel = "-";
-
-/*************************************************************************/
-
-/*
- * Constructors
- */
-
-/**
- * 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);
+ static final transient String separatorLabel = "-";
- tearOff = isTearOff;
+ /**
+ * 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()
+ {
+ }
- if (label.equals("Help"))
- isHelpMenu = true;
+ /**
+ * 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);
+ }
- if (GraphicsEnvironment.isHeadless())
- throw new HeadlessException ();
-}
+ /**
+ * 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;
-/*
- * Instance Methods
- */
+ if (label.equals("Help"))
+ isHelpMenu = true;
-/**
- * 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);
-}
+ 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.
+ */
+ 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 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.
- *
- * @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);
+ /**
+ * 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));
+ }
- if (peer != null)
- {
- item.addNotify();
- MenuPeer mp = (MenuPeer) peer;
- mp.addItem(item);
- }
+ /**
+ * 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);
- return item;
-}
+ items.addElement(item);
+ item.setParent(this);
-/*************************************************************************/
+ if (peer != null)
+ {
+ item.addNotify();
+ MenuPeer mp = (MenuPeer) peer;
+ mp.addItem(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.
- *
- * @param item The menu item to add.
- * @param index The index of the menu item.
- *
- * @exception IllegalArgumentException If the index is less than zero.
- * @exception ArrayIndexOutOfBoundsException If the index is otherwise invalid.
- */
-public void
-insert(MenuItem item, int index)
-{
- if (index < 0)
- throw new IllegalArgumentException("Index is less than zero");
+ return item;
+ }
- int count = getItemCount ();
+ /**
+ * 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));
+ }
- if (index >= count)
- add(item);
- else
- {
- MenuContainer parent = item.getParent();
- if (parent != null)
- parent.remove(item);
+ /**
+ * 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;
+ items.insertElementAt(item, index);
+ item.setParent(this);
- for (int i = count - 1; i >= index; i--)
- peer.delItem(i);
+ MenuPeer peer = (MenuPeer) getPeer();
+ if (peer == null)
+ return;
- item.addNotify();
- peer.addItem(item);
+ for (int i = count - 1; i >= index; i--)
+ peer.delItem(i);
- for (int i = index; i < count; i++)
- peer.addItem((MenuItem) items.elementAt (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.
- *
- * @param label The label of the item to add.
- * @param index The index of the menu item.
- *
- * @exception IllegalArgumentException If the index is less than zero.
- * @exception ArrayIndexOutOfBoundsException If the index is otherwise invalid.
- */
-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);
-}
+ }
-/*************************************************************************/
+ /**
+ * 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);
+ }
-/**
- * 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);
+ /**
+ * Adds a separator bar at the current menu location.
+ */
+ public void addSeparator()
+ {
+ add(new MenuItem(separatorLabel));
+ }
- MenuPeer mp = (MenuPeer) getPeer();
- if (mp != null)
- {
- mp.delItem(index);
- item.removeNotify();
- }
- item.setParent(null);
-}
+ /**
+ * 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;
+ /**
+ * 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);
-}
+ 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);
+ }
+ }
-/**
- * Removes all the elements from this menu.
- */
-public synchronized void
-removeAll()
-{
- int count = getItemCount();
- for(int i = 0; i < count; i++)
+ /**
+ * 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())
{
- // We must always remove item 0.
- remove(0);
+ MenuItem mi = (MenuItem)e.nextElement();
+ mi.addNotify();
+ peer.addItem(mi);
}
-}
-/*************************************************************************/
+ super.addNotify();
+ }
-/**
- * Creates the native peer for this object.
- */
-public void
-addNotify()
-{
- MenuPeer peer = (MenuPeer) getPeer();
- if (peer == null)
+ /**
+ * Destroys the native peer for this object.
+ */
+ public void removeNotify()
+ {
+ Enumeration e = items.elements();
+ while (e.hasMoreElements())
{
- peer = getToolkit().createMenu(this);
- setPeer(peer);
+ MenuItem mi = (MenuItem) e.nextElement();
+ mi.removeNotify();
}
-
- Enumeration e = items.elements();
- while (e.hasMoreElements())
- {
- MenuItem mi = (MenuItem)e.nextElement();
- mi.addNotify();
- peer.addItem(mi);
+ super.removeNotify();
}
- super.addNotify ();
-}
-
-/*************************************************************************/
-
-/**
- * Destroys the native peer for this object.
- */
-public void
-removeNotify()
-{
- Enumeration e = items.elements();
- while (e.hasMoreElements())
+ /**
+ * Returns a debugging string for this menu.
+ *
+ * @return A debugging string for this menu.
+ */
+ public String paramString()
{
- MenuItem mi = (MenuItem) e.nextElement();
- mi.removeNotify();
+ return (",tearOff=" + tearOff + ",isHelpMenu=" + isHelpMenu
+ + super.paramString());
}
- 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
diff --git a/java/awt/Rectangle.java b/java/awt/Rectangle.java
index c4ba6ba14..ac2494ee0 100644
--- a/java/awt/Rectangle.java
+++ b/java/awt/Rectangle.java
@@ -1,5 +1,5 @@
/* Rectangle.java -- represents a graphics rectangle
- Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation
+ Copyright (C) 1999, 2000, 2001, 2002, 2006, Free Software Foundation
This file is part of GNU Classpath.
@@ -119,7 +119,6 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable
* coordinates of the specified rectangle.
*
* @param r the rectangle to copy from
- * @throws NullPointerException if r is null
* @since 1.1
*/
public Rectangle(Rectangle r)
@@ -168,7 +167,6 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable
*
* @param p the upper left corner of the rectangle
* @param d the width and height of the rectangle
- * @throws NullPointerException if p or d is null
*/
public Rectangle(Point p, Dimension d)
{
@@ -185,7 +183,7 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable
* @param p the upper left corner of the rectangle
*/
public Rectangle(Point p)
- {
+ {
x = p.x;
y = p.y;
}
@@ -198,7 +196,7 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable
* @param d the width and height of the rectangle
*/
public Rectangle(Dimension d)
- {
+ {
width = d.width;
height = d.height;
}
@@ -299,8 +297,10 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable
}
/**
- * Updates this rectangle to have the specified dimensions, as rounded to
- * integers.
+ * 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
@@ -310,10 +310,10 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable
*/
public void setRect(double x, double y, double width, double height)
{
- this.x = (int) x;
- this.y = (int) y;
- this.width = (int) width;
- this.height = (int) 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;
}
/**
diff --git a/java/awt/Window.java b/java/awt/Window.java
index 322fbdeb0..7a3092f81 100644
--- a/java/awt/Window.java
+++ b/java/awt/Window.java
@@ -140,7 +140,7 @@ public class Window extends Container implements Accessible
this();
graphicsConfiguration = gc;
}
-
+
/**
* Initializes a new instance of <code>Window</code> with the specified
* parent. The window will initially be invisible.
@@ -257,8 +257,6 @@ public class Window extends Container implements Accessible
{
synchronized (getTreeLock())
{
- if (parent != null && ! parent.isDisplayable())
- parent.addNotify();
if (peer == null)
addNotify();
@@ -300,6 +298,15 @@ public class Window extends Container implements Accessible
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;
}
}
@@ -355,9 +362,15 @@ public class Window extends Container implements Accessible
component[i].removeNotify();
this.removeNotify();
- // Post a WINDOW_CLOSED event.
- WindowEvent we = new WindowEvent(this, WindowEvent.WINDOW_CLOSED);
- getToolkit().getSystemEventQueue().postEvent(we);
+ // Post WINDOW_CLOSED 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);
+ }
}
}
@@ -592,33 +605,12 @@ public class Window extends Container implements Accessible
void dispatchEventImpl(AWTEvent e)
{
- // Make use of event id's in order to avoid multiple instanceof tests.
- if (e.id <= WindowEvent.WINDOW_LAST
- && e.id >= WindowEvent.WINDOW_FIRST
- && (windowListener != null
- || windowFocusListener != null
- || windowStateListener != null
- || (eventMask & AWTEvent.WINDOW_EVENT_MASK) != 0))
- processEvent(e);
- else
+ if (e.getID() == ComponentEvent.COMPONENT_RESIZED)
{
- if (peer != null && (e.id == ComponentEvent.COMPONENT_RESIZED
- || e.id == ComponentEvent.COMPONENT_MOVED))
- {
- Rectangle bounds = peer.getBounds();
- x = bounds.x;
- y = bounds.y;
- height = bounds.height;
- width = bounds.width;
-
- if (e.id == ComponentEvent.COMPONENT_RESIZED)
- {
- invalidate();
- validate();
- }
- }
- super.dispatchEventImpl(e);
+ invalidate();
+ validate();
}
+ super.dispatchEventImpl(e);
}
/**
diff --git a/java/awt/geom/RoundRectangle2D.java b/java/awt/geom/RoundRectangle2D.java
index ac0e6f812..ac4d89fff 100644
--- a/java/awt/geom/RoundRectangle2D.java
+++ b/java/awt/geom/RoundRectangle2D.java
@@ -1,5 +1,5 @@
/* RoundRectangle2D.java -- represents a rectangle with rounded corners
- Copyright (C) 2000, 2002, 2003, 2004 Free Software Foundation
+ Copyright (C) 2000, 2002, 2003, 2004, 2006, Free Software Foundation
This file is part of GNU Classpath.
@@ -37,7 +37,6 @@ exception statement from your version. */
package java.awt.geom;
-import java.util.NoSuchElementException;
/** This class implements a rectangle with rounded corners.
@@ -46,13 +45,29 @@ import java.util.NoSuchElementException;
*/
public abstract class RoundRectangle2D extends RectangularShape
{
- /** Return the arc height of this round rectangle. */
+ /**
+ * 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. */
+ /**
+ * 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
+ /**
+ * Set the values of this round rectangle.
+ *
* @param x The x coordinate
* @param y The y coordinate
* @param w The width
@@ -63,14 +78,16 @@ public abstract class RoundRectangle2D extends RectangularShape
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
+ /**
+ * 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.
+ /**
+ * Return true if this object contains the specified point.
* @param x The x coordinate
* @param y The y coordinate
*/
@@ -106,7 +123,8 @@ public abstract class RoundRectangle2D extends RectangularShape
return dx * dx + dy * dy <= 1.0;
}
- /** Return true if this object contains the specified rectangle
+ /**
+ * Return true if this object contains the specified rectangle
* @param x The x coordinate
* @param y The y coordinate
* @param w The width
@@ -120,176 +138,185 @@ public abstract class RoundRectangle2D extends RectangularShape
&& contains(x + w, y));
}
- /** Return a new path iterator which iterates over this rectangle.
+ /**
+ * 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)
+ public PathIterator getPathIterator(final AffineTransform at)
{
- final double minx = getX();
- final double miny = getY();
- final double maxx = minx + getWidth();
- final double maxy = miny + getHeight();
- final double arcwidth = getArcWidth();
- final double archeight = getArcHeight();
- return new PathIterator()
+ 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()
{
- /** We iterate counterclockwise around the rectangle, starting in the
- * upper right. This variable tracks our current point, which
- * can be on either side of a given corner. */
- private int current = 0;
-
- /** Child path iterator, used for corners. */
- private PathIterator corner;
-
- /** This is used when rendering the corners. We re-use the arc
- * for each corner. */
- private Arc2D arc = new Arc2D.Double();
-
- /** Temporary array used by getPoint. */
- private double[] temp = new double[2];
-
- public int getWindingRule()
- {
- return WIND_NON_ZERO;
- }
-
- public boolean isDone()
- {
- return current > 9;
- }
-
- private void getPoint(int val)
- {
- switch (val)
- {
- case 0:
- case 8:
- temp[0] = maxx;
- temp[1] = miny + archeight;
- break;
- case 7:
- temp[0] = maxx;
- temp[1] = maxy - archeight;
- break;
- case 6:
- temp[0] = maxx - arcwidth;
- temp[1] = maxy;
- break;
- case 5:
- temp[0] = minx + arcwidth;
- temp[1] = maxy;
- break;
- case 4:
- temp[0] = minx;
- temp[1] = maxy - archeight;
- break;
- case 3:
- temp[0] = minx;
- temp[1] = miny + archeight;
- break;
- case 2:
- temp[0] = minx + arcwidth;
- temp[1] = miny;
- break;
- case 1:
- temp[0] = maxx - arcwidth;
- temp[1] = miny;
- break;
- }
- }
-
- public void next()
- {
- if (current >= 8)
- ++current;
- else if (corner != null)
- {
- // We're iterating through the corner. Work on the child
- // iterator; if it finishes, reset and move to the next
- // point along the rectangle.
- corner.next();
- if (corner.isDone())
- {
- corner = null;
- ++current;
- }
- }
- else
- {
- // Make an arc between this point on the rectangle and
- // the next one, and then iterate over this arc.
- getPoint(current);
- double x1 = temp[0];
- double y1 = temp[1];
- getPoint(current + 1);
- Rectangle2D.Double r = new Rectangle2D.Double(Math.min(x1,
- temp[0]),
- Math.min(y1,
- temp[1]),
- Math.abs(x1
- - temp[0]),
- Math.abs(y1
- - temp[1]));
- arc.setArc(r, (current >> 1) * 90.0, 90.0, Arc2D.OPEN);
- corner = arc.getPathIterator(at);
- }
- }
-
- public int currentSegment(float[] coords)
- {
- if (corner != null)
- {
- int r = corner.currentSegment(coords);
- if (r == SEG_MOVETO)
- r = SEG_LINETO;
- return r;
- }
-
- if (current < 9)
- {
- getPoint(current);
- coords[0] = (float) temp[0];
- coords[1] = (float) temp[1];
- }
- else if (current == 9)
- return SEG_CLOSE;
- else
- 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)
- {
- if (corner != null)
- {
- int r = corner.currentSegment(coords);
- if (r == SEG_MOVETO)
- r = SEG_LINETO;
- return r;
- }
-
- if (current < 9)
- {
- getPoint(current);
- coords[0] = temp[0];
- coords[1] = temp[1];
- }
- else if (current == 9)
- return SEG_CLOSE;
- else
- 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;
- }
- };
+ 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.
+ /**
+ * Return true if the given rectangle intersects this shape.
* @param x The x coordinate
* @param y The y coordinate
* @param w The width
@@ -302,7 +329,8 @@ public abstract class RoundRectangle2D extends RectangularShape
|| contains(x + w, y));
}
- /** Set the boundary of this round rectangle.
+ /**
+ * Set the boundary of this round rectangle.
* @param x The x coordinate
* @param y The y coordinate
* @param w The width
@@ -314,7 +342,8 @@ public abstract class RoundRectangle2D extends RectangularShape
setRoundRect(x, y, w, h, getArcWidth(), getArcHeight());
}
- /** Set the values of this round rectangle to be the same as those
+ /**
+ * Set the values of this round rectangle to be the same as those
* of the argument.
* @param rr The round rectangle to copy
*/
@@ -324,8 +353,10 @@ public abstract class RoundRectangle2D extends RectangularShape
rr.getArcWidth(), rr.getArcHeight());
}
- /** A subclass of RoundRectangle which keeps its parameters as
- * doubles. */
+ /**
+ * A subclass of RoundRectangle which keeps its parameters as
+ * doubles.
+ */
public static class Double extends RoundRectangle2D
{
/** The height of the corner arc. */
@@ -346,12 +377,15 @@ public abstract class RoundRectangle2D extends RectangularShape
/** The height of this object. */
public double height;
- /** Construct a new instance, with all parameters set to 0. */
+ /**
+ * Construct a new instance, with all parameters set to 0.
+ */
public Double()
{
}
- /** Construct a new instance with the given arguments.
+ /**
+ * Construct a new instance with the given arguments.
* @param x The x coordinate
* @param y The y coordinate
* @param w The width
@@ -422,8 +456,10 @@ public abstract class RoundRectangle2D extends RectangularShape
}
} // class Double
- /** A subclass of RoundRectangle which keeps its parameters as
- * floats. */
+ /**
+ * A subclass of RoundRectangle which keeps its parameters as
+ * floats.
+ */
public static class Float extends RoundRectangle2D
{
/** The height of the corner arc. */
@@ -444,12 +480,15 @@ public abstract class RoundRectangle2D extends RectangularShape
/** The height of this object. */
public float height;
- /** Construct a new instance, with all parameters set to 0. */
+ /**
+ * Construct a new instance, with all parameters set to 0.
+ */
public Float()
{
}
- /** Construct a new instance with the given arguments.
+ /**
+ * Construct a new instance with the given arguments.
* @param x The x coordinate
* @param y The y coordinate
* @param w The width
@@ -508,6 +547,18 @@ public abstract class RoundRectangle2D extends RectangularShape
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)
{
diff --git a/java/awt/image/AffineTransformOp.java b/java/awt/image/AffineTransformOp.java
index 7820684d2..849c5b050 100644
--- a/java/awt/image/AffineTransformOp.java
+++ b/java/awt/image/AffineTransformOp.java
@@ -39,6 +39,7 @@ 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;
@@ -48,8 +49,11 @@ import java.awt.geom.Rectangle2D;
import java.util.Arrays;
/**
- * This class performs affine transformation between two images or
- * rasters in 2 dimensions.
+ * 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)
@@ -115,14 +119,14 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
}
/**
- * Creates empty BufferedImage with the size equal to that of the
- * transformed image and correct number of bands. The newly created
+ * 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 the ColorModel is equal to null, an appropriate ColorModel is used.
+ * If a ColorModel is not specified, an appropriate ColorModel is used.
*
- * @param src source image
- * @param destCM color model for the destination image
- * @return new compatible destination image
+ * @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)
@@ -145,21 +149,18 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
}
/**
- * Creates empty WritableRaster with the size equal to the transformed
- * source raster and correct number of bands
+ * Creates a new WritableRaster with the size equal to the transformed
+ * source raster and correct number of bands .
*
- * @param src source raster
- * @throws RasterFormatException if resulting width or height of raster is 0
- * @return new compatible raster
+ * @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);
- // throw RasterFormatException if resulting width or height of the
- // transformed raster is 0
-
- if (rect.getWidth () == 0 || rect.getHeight () == 0)
+ if (rect.getWidth() == 0 || rect.getHeight() == 0)
throw new RasterFormatException("width or height is 0");
return src.createCompatibleWritableRaster((int) rect.getWidth(),
@@ -175,24 +176,22 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
* @param dst destination image
* @throws IllegalArgumentException if the source and destination image are
* the same
- * @return transformed source image
+ * @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");
+ 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 the destination image is null, then use a compatible BufferedImage
if (dst == null)
dst = createCompatibleDestImage(src, null);
- Graphics2D gr = (Graphics2D) dst.createGraphics ();
- gr.setRenderingHints (hints);
- gr.drawImage (src, transform, null);
+ Graphics2D gr = (Graphics2D) dst.createGraphics();
+ gr.setRenderingHints(hints);
+ gr.drawImage(src, transform, null);
return dst;
-
}
/**
@@ -204,21 +203,40 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
* @param dst destination raster
* @throws IllegalArgumentException if the source and destination are not
* compatible
- * @return transformed raster
+ * @return transformed raster.
*/
- public final WritableRaster filter (Raster src, WritableRaster dst)
+ 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");
+ + " 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");
+ + " 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];
@@ -287,7 +305,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
}
/**
- * Returns interpolation type used during transformations
+ * Returns interpolation type used during transformations.
*
* @return interpolation type
*/
@@ -319,7 +337,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
/**
* Returns rendering hints that are used during transformation.
*
- * @return rendering hints
+ * @return the rendering hints used in this Op.
*/
public final RenderingHints getRenderingHints ()
{
@@ -330,7 +348,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
* Returns transform used in transformation between source and destination
* image.
*
- * @return transform
+ * @return the transform used in this Op.
*/
public final AffineTransform getTransform ()
{
@@ -377,6 +395,18 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
{
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)
@@ -400,22 +430,65 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
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;
-
- // Run the interpolation for each band
+
+ // 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++)
{
- double result = (src.getSampleDouble(x, y, j) * (1 - xdiff)
- + src.getSampleDouble(x + 1, y, j) * xdiff)
- * (1 - ydiff)
- + (src.getSampleDouble(x, y + 1, j)
- * (1 - xdiff)
- + src.getSampleDouble(x + 1, y + 1, j)
- * xdiff)
- * ydiff;
- dst.setSample((int) dpts[i] + dst.getMinX(),
- (int) dpts[i + 1] + dst.getMinY(),
- j, result);
+ // 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);
}
}
}
@@ -434,10 +507,11 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
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
- double[] result = new double[src.getNumBands()];
for (int i = 0; i < dpts.length; i += 2)
{
if (srcbounds.contains((int) Math.round(pts[i]) + src.getMinX(),
@@ -450,76 +524,84 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
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;
- if (rx > 0)
- 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
- for (int j = 0; j < result.length; j++)
- result[j] += src.getSample(srcX, srcY, j) * r1 * r2;
- }
- }
+ 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
- for (int j = 0; j < result.length; j++)
- dst.setSample((int) dpts[i] + dst.getMinX(),
- (int) dpts[i + 1] + dst.getMinY(),
- j, result[j]);
+ dst.setPixel((int)dpts[i] + dst.getMinX(),
+ (int)dpts[i+1] + dst.getMinY(),
+ result);
}
}
}
diff --git a/java/awt/image/BandCombineOp.java b/java/awt/image/BandCombineOp.java
index c4e2d5810..d9ce16fad 100644
--- a/java/awt/image/BandCombineOp.java
+++ b/java/awt/image/BandCombineOp.java
@@ -40,6 +40,7 @@ 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.
@@ -53,6 +54,9 @@ import java.awt.geom.Rectangle2D;
* 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
@@ -109,19 +113,27 @@ public class BandCombineOp implements RasterOp
throw new IllegalArgumentException("Destination raster is incompatible with source raster");
// Filter the pixels
- float[] spix = new float[matrix[0].length - 1];
- float[] dpix = new float[matrix.length];
+ 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.0f;
+ spix[spix.length - 1] = 1;
src.getPixel(x, y, spix);
- for (int i = 0; i < matrix.length; i++)
+
+ // Do not re-calculate if pixel is identical to the last one
+ // (ie, blocks of the same colour)
+ if (!Arrays.equals(spix, spix2))
{
- dpix[i] = 0;
- for (int j = 0; j < matrix[0].length - 1; j++)
- dpix[i] += spix[j] * matrix[i][j];
+ 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);
}
diff --git a/java/awt/image/BufferedImage.java b/java/awt/image/BufferedImage.java
index 1e94ad66d..0a78bf223 100644
--- a/java/awt/image/BufferedImage.java
+++ b/java/awt/image/BufferedImage.java
@@ -347,6 +347,7 @@ public class BufferedImage extends Image
public void coerceData(boolean premultiplied)
{
colorModel = colorModel.coerceData(raster, premultiplied);
+ isPremultiplied = premultiplied;
}
public WritableRaster copyData(WritableRaster dest)
diff --git a/java/awt/image/ColorModel.java b/java/awt/image/ColorModel.java
index fc413d0b4..ea3d1b64c 100644
--- a/java/awt/image/ColorModel.java
+++ b/java/awt/image/ColorModel.java
@@ -624,40 +624,36 @@ public abstract class ColorModel implements Transparency
return cspace;
}
- // Typically overridden
- public ColorModel coerceData(WritableRaster raster,
- boolean isAlphaPremultiplied)
- {
- if (this.isAlphaPremultiplied == isAlphaPremultiplied || ! hasAlpha)
- return this;
+ public abstract ColorModel coerceData(WritableRaster raster,
+ boolean isAlphaPremultiplied);
+ protected 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 size = w * h;
int numColors = getNumColorComponents();
int numComponents = getNumComponents();
- int alphaScale = (1<<getComponentSize(numColors)) - 1;
+ int alphaScale = (1 << getComponentSize(numColors)) - 1;
double[] pixels = raster.getPixels(x, y, w, h, (double[]) null);
- for (int i=0; i<size; i++)
+ 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] = pixels[offset]/alpha;
- else
- pixels[offset] = pixels[offset]*alpha;
- }
+ 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);
- // FIXME: what can we return?
- return null;
+ raster.setPixels(0, 0, w, h, pixels);
}
/**
diff --git a/java/awt/image/ComponentColorModel.java b/java/awt/image/ComponentColorModel.java
index f3f3e374b..2096800b2 100644
--- a/java/awt/image/ComponentColorModel.java
+++ b/java/awt/image/ComponentColorModel.java
@@ -306,17 +306,16 @@ public class ComponentColorModel extends ColorModel
public ColorModel coerceData(WritableRaster raster,
boolean isAlphaPremultiplied) {
- if (this.isAlphaPremultiplied == 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. */
- super.coerceData(raster, isAlphaPremultiplied);
+ super.coerceDataWorker(raster, isAlphaPremultiplied);
- return new ComponentColorModel(cspace, bits, hasAlpha(),
- isAlphaPremultiplied, // argument
- transparency, transferType);
+ return new ComponentColorModel(cspace, hasAlpha, isAlphaPremultiplied,
+ transparency, transferType);
}
public boolean isCompatibleRaster(Raster raster)
diff --git a/java/awt/image/ConvolveOp.java b/java/awt/image/ConvolveOp.java
index cd3b01131..cf30e7625 100644
--- a/java/awt/image/ConvolveOp.java
+++ b/java/awt/image/ConvolveOp.java
@@ -249,6 +249,11 @@ public class ConvolveOp implements BufferedImageOp, RasterOp
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;
@@ -270,12 +275,10 @@ public class ConvolveOp implements BufferedImageOp, RasterOp
// the samples array to make the tests pass. I haven't worked
// out why this is necessary.
- // This clipping is pretty strange, and seems to be hard-coded
- // at 255 (regardless of the raster's datatype or transfertype).
- // But it's what the reference does.
- if (v > 255)
- v = 255;
- if (v < 0)
+ // 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(),
diff --git a/java/awt/image/DirectColorModel.java b/java/awt/image/DirectColorModel.java
index 579dc97df..dab15319f 100644
--- a/java/awt/image/DirectColorModel.java
+++ b/java/awt/image/DirectColorModel.java
@@ -393,20 +393,20 @@ public class DirectColorModel extends PackedColorModel
return Buffers.getData(buffer);
}
- public final ColorModel coerceData (WritableRaster raster,
- boolean isAlphaPremultiplied)
+ public ColorModel coerceData (WritableRaster raster,
+ boolean isAlphaPremultiplied)
{
- if (this.isAlphaPremultiplied == 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. */
- super.coerceData(raster, isAlphaPremultiplied);
-
- return new ComponentColorModel(cspace, bits, hasAlpha(),
- isAlphaPremultiplied, // argument
- transparency, transferType);
+ super.coerceDataWorker(raster, isAlphaPremultiplied);
+
+ return new DirectColorModel(cspace, pixel_bits, getRedMask(),
+ getGreenMask(), getBlueMask(), getAlphaMask(),
+ isAlphaPremultiplied, transferType);
}
public boolean isCompatibleRaster(Raster raster)
diff --git a/java/awt/image/IndexColorModel.java b/java/awt/image/IndexColorModel.java
index 299b4dc0d..701362d53 100644
--- a/java/awt/image/IndexColorModel.java
+++ b/java/awt/image/IndexColorModel.java
@@ -694,4 +694,21 @@ public class IndexColorModel extends ColorModel
return im;
}
+
+ 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. */
+ super.coerceDataWorker(raster, isAlphaPremultiplied);
+
+ ColorModel cm = new IndexColorModel(pixel_bits, map_size, rgb, 0, hasAlpha, trans,
+ transferType);
+ cm.isAlphaPremultiplied = !(cm.isAlphaPremultiplied);
+ return cm;
+ }
}
diff --git a/java/awt/image/LookupOp.java b/java/awt/image/LookupOp.java
index 46e72fe61..5b0cf7831 100644
--- a/java/awt/image/LookupOp.java
+++ b/java/awt/image/LookupOp.java
@@ -38,7 +38,6 @@ exception statement from your version. */
package java.awt.image;
-import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
@@ -67,7 +66,8 @@ public class LookupOp implements BufferedImageOp, RasterOp
private LookupTable lut;
private RenderingHints hints;
- /** Construct a new LookupOp.
+ /**
+ * Construct a new LookupOp using the given LookupTable.
*
* @param lookup LookupTable to use.
* @param hints Rendering hints (can be null).
@@ -78,16 +78,40 @@ public class LookupOp implements BufferedImageOp, RasterOp
this.hints = hints;
}
- /* (non-Javadoc)
- * @see java.awt.image.BufferedImageOp#filter(java.awt.image.BufferedImage, java.awt.image.BufferedImage)
+ /**
+ * 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, src.getColorModel());
+ 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;
@@ -116,33 +140,35 @@ public class LookupOp implements BufferedImageOp, RasterOp
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 if (lut.getNumComponents() != 1
- &&
- lut.getNumComponents() != src.getColorModel().getNumComponents())
- throw new IllegalArgumentException("LookupOp.filter: "
- + "Incompatible lookup "
- + "table and source image");
-
- // 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)
+ else
{
- // Convert between color models.
- // TODO Check that premultiplied alpha is handled correctly here.
- Graphics2D gg = dst.createGraphics();
- gg.setRenderingHints(hints);
- gg.drawImage(tgt, 0, 0, null);
- gg.dispose();
+ // 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;
}
@@ -160,18 +186,27 @@ public class LookupOp implements BufferedImageOp, RasterOp
public BufferedImage createCompatibleDestImage(BufferedImage src,
ColorModel dstCM)
{
- // FIXME: set properties to those in src
- return new BufferedImage(dstCM,
- src.getRaster().createCompatibleWritableRaster(),
- src.isPremultiplied, null);
+ 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);
}
- /** Return corresponding destination point for source point.
+ /**
+ * Returns the corresponding destination point for a given source point.
+ *
+ * This Op will return the source point unchanged.
*
- * LookupOp will return the value of src unchanged.
* @param src The source point.
* @param 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)
{
@@ -182,7 +217,11 @@ public class LookupOp implements BufferedImageOp, RasterOp
return dst;
}
- /** Return the LookupTable for this op. */
+ /**
+ * Return the LookupTable for this op.
+ *
+ * @return The lookup table.
+ */
public final LookupTable getTable()
{
return lut;
@@ -196,7 +235,8 @@ public class LookupOp implements BufferedImageOp, RasterOp
return hints;
}
- /** Filter a raster through a lookup table.
+ /**
+ * 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
@@ -206,8 +246,9 @@ public class LookupOp implements BufferedImageOp, RasterOp
* @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.
- * @see java.awt.image.RasterOp#filter(java.awt.image.Raster, java.awt.image.WritableRaster)
+ * 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)
{
@@ -216,12 +257,13 @@ public class LookupOp implements BufferedImageOp, RasterOp
dest = createCompatibleDestRaster(src);
else
if (src.getNumBands() != dest.getNumBands())
- throw new IllegalArgumentException();
-
- if (lut.getNumComponents() != 1
- && lut.getNumComponents() != src.getNumBands())
- throw new IllegalArgumentException();
+ 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()];
@@ -230,6 +272,19 @@ public class LookupOp implements BufferedImageOp, RasterOp
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;
}
diff --git a/java/awt/image/MemoryImageSource.java b/java/awt/image/MemoryImageSource.java
index cb3526f6e..83a03ca44 100644
--- a/java/awt/image/MemoryImageSource.java
+++ b/java/awt/image/MemoryImageSource.java
@@ -1,5 +1,5 @@
/* MemoryImageSource.java -- Java class for providing image data
- Copyright (C) 1999, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -41,6 +41,9 @@ 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;
@@ -73,7 +76,16 @@ public class MemoryImageSource implements ImageProducer
}
/**
- * Constructs an ImageProducer from memory
+ * 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)
@@ -106,8 +118,17 @@ public class MemoryImageSource implements ImageProducer
}
/**
- Constructs an ImageProducer from memory
- */
+ * 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)
{
@@ -122,7 +143,16 @@ public class MemoryImageSource implements ImageProducer
}
/**
- * Constructs an ImageProducer from memory using the default RGB ColorModel
+ * 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)
@@ -131,7 +161,14 @@ public class MemoryImageSource implements ImageProducer
}
/**
- * Constructs an ImageProducer from memory using the default RGB ColorModel
+ * 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)
{
@@ -141,6 +178,8 @@ public class MemoryImageSource implements ImageProducer
/**
* Used to register an <code>ImageConsumer</code> with this
* <code>ImageProducer</code>.
+ *
+ * @param ic the image consumer.
*/
public synchronized void addConsumer(ImageConsumer ic)
{
@@ -153,6 +192,8 @@ public class MemoryImageSource implements ImageProducer
/**
* 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)
{
@@ -164,6 +205,8 @@ public class MemoryImageSource implements ImageProducer
/**
* 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)
{
@@ -197,6 +240,8 @@ public class MemoryImageSource implements ImageProducer
* 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)
{
@@ -219,7 +264,7 @@ public class MemoryImageSource implements ImageProducer
* 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
+ * @param fullbuffers a flag indicating whether to send the full buffers
*/
public synchronized void setFullBufferUpdates(boolean fullbuffers)
{
@@ -260,6 +305,11 @@ public class MemoryImageSource implements ImageProducer
/**
* 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)
{
@@ -306,6 +356,12 @@ public class MemoryImageSource implements ImageProducer
*
* 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)
diff --git a/java/awt/image/RescaleOp.java b/java/awt/image/RescaleOp.java
index d5b29693c..d56b12cb9 100644
--- a/java/awt/image/RescaleOp.java
+++ b/java/awt/image/RescaleOp.java
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004 Free Software Foundation
+/* Copyright (C) 2004, 2006 Free Software Foundation
This file is part of GNU Classpath.
@@ -43,7 +43,23 @@ 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
{
@@ -51,15 +67,43 @@ public class RescaleOp implements BufferedImageOp, RasterOp
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)
{
- this.scale = scaleFactors;
- this.offsets = offsets;
+ 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)
@@ -69,22 +113,47 @@ public class RescaleOp implements BufferedImageOp, RasterOp
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, 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, 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;
@@ -98,36 +167,74 @@ public class RescaleOp implements BufferedImageOp, RasterOp
return hints;
}
- /* (non-Javadoc)
- * @see java.awt.image.BufferedImageOp#filter(java.awt.image.BufferedImage, java.awt.image.BufferedImage)
+ /**
+ * 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)
{
- // TODO Make sure premultiplied alpha is handled correctly.
- // TODO See that color conversion is handled.
- // TODO figure out how to use rendering hints.
- if (scale.length != offsets.length)
- throw new IllegalArgumentException();
+ // 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.");
- ColorModel scm = src.getColorModel();
- if (dst == null) dst = createCompatibleDestImage(src, null);
+ 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.");
- WritableRaster wsrc = src.getRaster();
- WritableRaster wdst = dst.getRaster();
-
- // Share constant across colors except alpha
- if (scale.length == 1 || scale.length == scm.getNumColorComponents())
+ // 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())
{
- // Construct a raster that doesn't include an alpha band.
- int[] subbands = new int[scm.getNumColorComponents()];
- for (int i=0; i < subbands.length; i++) subbands[i] = i;
- wsrc =
- wsrc.createWritableChild(wsrc.minX, wsrc.minY, wsrc.width, wsrc.height,
- wsrc.minX, wsrc.minY, subbands);
+
+ dst2.getRaster().setSamples(0, 0, src.getWidth(), src.getHeight(),
+ numBands,
+ src.getRaster().getSamples(0, 0,
+ src.getWidth(),
+ src.getHeight(),
+ numBands,
+ (int[]) null));
}
- // else all color bands
- filter(wsrc, wdst);
+ // Perform colorspace conversion if needed
+ if (dst != dst2)
+ new ColorConvertOp(hints).filter(dst2, dst);
+
return dst;
}
@@ -136,50 +243,106 @@ public class RescaleOp implements BufferedImageOp, RasterOp
*/
public final WritableRaster filter(Raster src, WritableRaster dest)
{
- if (dest == null) dest = src.createCompatibleWritableRaster();
-
// Required sanity checks
- if (src.numBands != dest.numBands || scale.length != offsets.length)
- throw new IllegalArgumentException();
if (scale.length != 1 && scale.length != src.numBands)
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException("Number of rasters is incompatible "
+ + "with the number of scaling "
+ + "factors provided.");
- // Create scaling arrays if needed
- float[] lscale = scale;
- float[] loff = offsets;
- if (scale.length == 1)
- {
- lscale = new float[src.numBands];
- Arrays.fill(lscale, scale[0]);
- loff = new float[src.numBands];
- Arrays.fill(loff, offsets[0]);
- }
+ 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);
- // TODO The efficiency here can be improved for various data storage
- // patterns, aka SampleModels.
- float[] pixel = new float[src.numBands];
- for (int y = src.minY; y < src.height + src.minY; y++)
- for (int x = src.minX; x < src.width + src.minX; x++)
- {
- src.getPixel(x, y, pixel);
- for (int b = 0; b < src.numBands; b++)
- pixel[b] = pixel[b] * lscale[b] + loff[b];
- dest.setPixel(x, y, pixel);
- }
+ 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)
+ /*
+ * (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) dstCM = src.getColorModel();
- WritableRaster wr = src.getRaster().createCompatibleWritableRaster();
- BufferedImage image
- = new BufferedImage(dstCM, wr, src.isPremultiplied, null);
- return image;
+ if (dstCM == null)
+ return new BufferedImage(src.getWidth(), src.getHeight(), src.getType());
+
+ return new BufferedImage(dstCM,
+ src.getRaster().createCompatibleWritableRaster(),
+ src.isAlphaPremultiplied(), null);
}
/* (non-Javadoc)
@@ -209,9 +372,13 @@ public class RescaleOp implements BufferedImageOp, RasterOp
/* (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);
+ public final Point2D getPoint2D(Point2D src, Point2D dst)
+ {
+ if (dst == null)
+ dst = (Point2D) src.clone();
+ else
+ dst.setLocation(src);
+
return dst;
}
diff --git a/java/io/FileDescriptor.java b/java/io/FileDescriptor.java
index dd3db1c74..cf9ff20d5 100644
--- a/java/io/FileDescriptor.java
+++ b/java/io/FileDescriptor.java
@@ -39,7 +39,7 @@ exception statement from your version. */
package java.io;
-import gnu.java.nio.channels.FileChannelImpl;
+import gnu.java.nio.FileChannelImpl;
import java.nio.channels.ByteChannel;
import java.nio.channels.FileChannel;
diff --git a/java/io/FileInputStream.java b/java/io/FileInputStream.java
index 8ca38b02f..8217668b4 100644
--- a/java/io/FileInputStream.java
+++ b/java/io/FileInputStream.java
@@ -38,8 +38,9 @@ exception statement from your version. */
package java.io;
-import gnu.java.nio.channels.FileChannelImpl;
+import gnu.java.nio.FileChannelImpl;
+import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
@@ -107,7 +108,20 @@ public class FileInputStream extends InputStream
if (s != null)
s.checkRead(file.getPath());
- ch = FileChannelImpl.create(file, FileChannelImpl.READ);
+ try
+ {
+ ch = FileChannelImpl.create(file, FileChannelImpl.READ);
+ }
+ catch (FileNotFoundException fnfe)
+ {
+ throw fnfe;
+ }
+ catch (IOException ioe)
+ {
+ FileNotFoundException fnfe = new FileNotFoundException(file.getPath());
+ fnfe.initCause(ioe);
+ throw fnfe;
+ }
}
/**
@@ -266,7 +280,7 @@ public class FileInputStream extends InputStream
|| offset + len > buf.length)
throw new ArrayIndexOutOfBoundsException();
- return ch.read(buf, offset, len);
+ return ch.read(ByteBuffer.wrap(buf, offset, len));
}
/**
diff --git a/java/io/FileOutputStream.java b/java/io/FileOutputStream.java
index 10ea6b536..d7561a9d7 100644
--- a/java/io/FileOutputStream.java
+++ b/java/io/FileOutputStream.java
@@ -38,8 +38,9 @@ exception statement from your version. */
package java.io;
-import gnu.java.nio.channels.FileChannelImpl;
+import gnu.java.nio.FileChannelImpl;
+import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
@@ -155,10 +156,23 @@ public class FileOutputStream extends OutputStream
if (s != null)
s.checkWrite(file.getPath());
- ch = FileChannelImpl.create(file, (append
- ? FileChannelImpl.WRITE
- | FileChannelImpl.APPEND
- : FileChannelImpl.WRITE));
+ try
+ {
+ ch = FileChannelImpl.create(file, (append
+ ? FileChannelImpl.WRITE
+ | FileChannelImpl.APPEND
+ : FileChannelImpl.WRITE));
+ }
+ catch (FileNotFoundException fnfe)
+ {
+ throw fnfe;
+ }
+ catch (IOException ioe)
+ {
+ FileNotFoundException fnfe = new FileNotFoundException(file.getPath());
+ fnfe.initCause(ioe);
+ throw fnfe;
+ }
}
/**
@@ -266,7 +280,7 @@ public class FileOutputStream extends OutputStream
|| offset + len > buf.length)
throw new ArrayIndexOutOfBoundsException ();
- ch.write (buf, offset, len);
+ ch.write(ByteBuffer.wrap(buf, offset, len));
}
/**
diff --git a/java/io/InputStreamReader.java b/java/io/InputStreamReader.java
index 8d97799d5..6c5297f6b 100644
--- a/java/io/InputStreamReader.java
+++ b/java/io/InputStreamReader.java
@@ -368,6 +368,8 @@ public class InputStreamReader extends Reader
if(decoder != null)
{
int totalBytes = (int)((double) length * maxBytesPerChar);
+ if (byteBuffer != null)
+ totalBytes = Math.max(totalBytes, byteBuffer.remaining());
byte[] bytes;
// Fetch cached bytes array if available and big enough.
synchronized(cacheLock)
diff --git a/java/io/ObjectStreamClass.java b/java/io/ObjectStreamClass.java
index 21a80c392..52a1ad428 100644
--- a/java/io/ObjectStreamClass.java
+++ b/java/io/ObjectStreamClass.java
@@ -323,8 +323,8 @@ public class ObjectStreamClass implements Serializable
else
{
// Check that the actual UID of the resolved class matches the UID from
- // the stream.
- if (uid != class_uid)
+ // the stream. Mismatches for array classes are ignored.
+ if (!cl.isArray() && uid != class_uid)
{
String msg = cl +
": Local class not compatible: stream serialVersionUID="
diff --git a/java/io/PipedInputStream.java b/java/io/PipedInputStream.java
index 523ae2c70..c0396d206 100644
--- a/java/io/PipedInputStream.java
+++ b/java/io/PipedInputStream.java
@@ -279,6 +279,10 @@ public class PipedInputStream extends InputStream
if (closed)
throw new IOException ("Pipe closed");
+ // Don't block if nothing was requested.
+ if (len == 0)
+ return 0;
+
// If the buffer is empty, wait until there is something in the pipe
// to read.
try
diff --git a/java/io/PipedReader.java b/java/io/PipedReader.java
index 90fc10f67..8a3363a60 100644
--- a/java/io/PipedReader.java
+++ b/java/io/PipedReader.java
@@ -261,6 +261,10 @@ public class PipedReader extends Reader
if (closed)
throw new IOException ("Pipe closed");
+ // Don't block if nothing was requested.
+ if (len == 0)
+ return 0;
+
// If the buffer is empty, wait until there is something in the pipe
// to read.
try
diff --git a/java/io/RandomAccessFile.java b/java/io/RandomAccessFile.java
index d719a1e3b..036fc8c6b 100644
--- a/java/io/RandomAccessFile.java
+++ b/java/io/RandomAccessFile.java
@@ -38,7 +38,7 @@ exception statement from your version. */
package java.io;
-import gnu.java.nio.channels.FileChannelImpl;
+import gnu.java.nio.FileChannelImpl;
import java.nio.channels.FileChannel;
@@ -122,7 +122,20 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable
s.checkWrite(fileName);
}
- ch = FileChannelImpl.create(file, fdmode);
+ try
+ {
+ ch = FileChannelImpl.create(file, fdmode);
+ }
+ catch (FileNotFoundException fnfe)
+ {
+ throw fnfe;
+ }
+ catch (IOException ioe)
+ {
+ FileNotFoundException fnfe = new FileNotFoundException(file.getPath());
+ fnfe.initCause(ioe);
+ throw fnfe;
+ }
fd = new FileDescriptor(ch);
if ((fdmode & FileChannelImpl.WRITE) != 0)
out = new DataOutputStream (new FileOutputStream (fd));
diff --git a/java/net/DatagramSocket.java b/java/net/DatagramSocket.java
index d8837c006..974827cbb 100644
--- a/java/net/DatagramSocket.java
+++ b/java/net/DatagramSocket.java
@@ -1,5 +1,5 @@
/* DatagramSocket.java -- A class to model UDP sockets
- Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005
+ Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -180,7 +180,18 @@ public class DatagramSocket
if (factory != null)
impl = factory.createDatagramSocketImpl();
else
- impl = new PlainDatagramSocketImpl();
+ {
+ try
+ {
+ impl = new PlainDatagramSocketImpl();
+ }
+ catch (IOException ioe)
+ {
+ SocketException se = new SocketException();
+ se.initCause(ioe);
+ throw se;
+ }
+ }
}
else
try
@@ -194,7 +205,16 @@ public class DatagramSocket
{
System.err.println("Could not instantiate class: java.net."
+ propVal + "DatagramSocketImpl");
- impl = new PlainDatagramSocketImpl();
+ try
+ {
+ impl = new PlainDatagramSocketImpl();
+ }
+ catch (IOException ioe)
+ {
+ SocketException se = new SocketException();
+ se.initCause(ioe);
+ throw se;
+ }
}
if (address != null)
@@ -578,7 +598,13 @@ public class DatagramSocket
&& ! ((DatagramChannelImpl) getChannel()).isInChannelOperation())
throw new IllegalBlockingModeException();
- getImpl().receive(p);
+ DatagramPacket p2 = new DatagramPacket(p.getData(), p.getOffset(), p.maxlen);
+ getImpl().receive(p2);
+ p.length = p2.length;
+ if (p2.getAddress() != null)
+ p.setAddress(p2.getAddress());
+ if (p2.getPort() != -1)
+ p.setPort(p2.getPort());
SecurityManager s = System.getSecurityManager();
if (s != null && isConnected())
@@ -649,6 +675,9 @@ public class DatagramSocket
{
if (isClosed())
throw new SocketException("socket is closed");
+
+ if (address == null)
+ address = new InetSocketAddress(InetAddress.ANY_IF, 0);
if (! (address instanceof InetSocketAddress))
throw new IllegalArgumentException("unsupported address type");
diff --git a/java/net/Inet4Address.java b/java/net/Inet4Address.java
index c80f1f175..a8a726ecf 100644
--- a/java/net/Inet4Address.java
+++ b/java/net/Inet4Address.java
@@ -1,5 +1,5 @@
/* Inet4Address.java --
- Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -57,11 +57,16 @@ public final class Inet4Address extends InetAddress
static final long serialVersionUID = 3286316764910316507L;
/**
- * needed for serialization
+ * The address family of these addresses (used for serialization).
+ */
+ private static final int AF_INET = 2;
+
+ /**
+ * Inet4Address objects are serialized as InetAddress objects.
*/
private Object writeReplace() throws ObjectStreamException
{
- return new InetAddress(addr, hostName);
+ return new InetAddress(addr, hostName, AF_INET);
}
/**
@@ -74,7 +79,7 @@ public final class Inet4Address extends InetAddress
*/
Inet4Address(byte[] addr, String host)
{
- super(addr, host);
+ super(addr, host, AF_INET);
}
/**
@@ -84,7 +89,7 @@ public final class Inet4Address extends InetAddress
*/
public boolean isMulticastAddress()
{
- return super.isMulticastAddress();
+ return (addr[0] & 0xf0) == 0xe0;
}
/**
@@ -92,7 +97,7 @@ public final class Inet4Address extends InetAddress
*/
public boolean isLoopbackAddress()
{
- return super.isLoopbackAddress();
+ return (addr[0] & 0xff) == 0x7f;
}
/**
@@ -102,7 +107,7 @@ public final class Inet4Address extends InetAddress
*/
public boolean isAnyLocalAddress()
{
- return super.isAnyLocalAddress();
+ return equals(InetAddress.ANY_IF);
}
/**
@@ -112,7 +117,7 @@ public final class Inet4Address extends InetAddress
*/
public boolean isLinkLocalAddress()
{
- return super.isLinkLocalAddress();
+ return false;
}
/**
@@ -122,7 +127,19 @@ public final class Inet4Address extends InetAddress
*/
public boolean isSiteLocalAddress()
{
- return super.isSiteLocalAddress();
+ // 10.0.0.0/8
+ if ((addr[0] & 0xff) == 0x0a)
+ return true;
+
+ // 172.16.0.0/12
+ if ((addr[0] & 0xff) == 0xac && (addr[1] & 0xf0) == 0x10)
+ return true;
+
+ // 192.168.0.0/16
+ if ((addr[0] & 0xff) == 0xc0 && (addr[1] & 0xff) == 0xa8)
+ return true;
+
+ return false;
}
/**
@@ -132,7 +149,7 @@ public final class Inet4Address extends InetAddress
*/
public boolean isMCGlobal()
{
- return super.isMCGlobal();
+ return false;
}
/**
@@ -142,7 +159,7 @@ public final class Inet4Address extends InetAddress
*/
public boolean isMCNodeLocal()
{
- return super.isMCNodeLocal();
+ return false;
}
/**
@@ -152,7 +169,12 @@ public final class Inet4Address extends InetAddress
*/
public boolean isMCLinkLocal()
{
- return super.isMCLinkLocal();
+ if (! isMulticastAddress())
+ return false;
+
+ return ((addr[0] & 0xff) == 0xe0
+ && (addr[1] & 0xff) == 0x00
+ && (addr[2] & 0xff) == 0x00);
}
/**
@@ -162,7 +184,7 @@ public final class Inet4Address extends InetAddress
*/
public boolean isMCSiteLocal()
{
- return super.isMCSiteLocal();
+ return false;
}
/**
@@ -172,7 +194,7 @@ public final class Inet4Address extends InetAddress
*/
public boolean isMCOrgLocal()
{
- return super.isMCOrgLocal();
+ return false;
}
/**
@@ -190,7 +212,23 @@ public final class Inet4Address extends InetAddress
*/
public String getHostAddress()
{
- return super.getHostAddress();
+ StringBuffer sb = new StringBuffer(40);
+
+ int len = addr.length;
+ int i = 0;
+
+ for ( ; ; )
+ {
+ sb.append(addr[i] & 0xff);
+ i++;
+
+ if (i == len)
+ break;
+
+ sb.append('.');
+ }
+
+ return sb.toString();
}
/**
diff --git a/java/net/Inet6Address.java b/java/net/Inet6Address.java
index 8d834a6fd..ef3c4431a 100644
--- a/java/net/Inet6Address.java
+++ b/java/net/Inet6Address.java
@@ -1,5 +1,5 @@
/* Inet6Address.java --
- Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -93,6 +93,11 @@ public final class Inet6Address extends InetAddress
private transient NetworkInterface nif;
/**
+ * The address family of these addresses (used for serialization).
+ */
+ private static final int AF_INET6 = 10;
+
+ /**
* Create an Inet6Address object
*
* @param addr The IP address
@@ -100,7 +105,7 @@ public final class Inet6Address extends InetAddress
*/
Inet6Address(byte[] addr, String host)
{
- super(addr, host);
+ super(addr, host, AF_INET6);
// Super constructor clones the addr. Get a reference to the clone.
this.ipaddress = this.addr;
ifname = null;
diff --git a/java/net/InetAddress.java b/java/net/InetAddress.java
index ce65bc773..1f2667980 100644
--- a/java/net/InetAddress.java
+++ b/java/net/InetAddress.java
@@ -1,5 +1,6 @@
/* InetAddress.java -- Class to model an Internet address
- Copyright (C) 1998, 1999, 2002, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2002, 2004, 2005, 2006
+ Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -43,7 +44,6 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
-import java.util.StringTokenizer;
/**
* This class models an Internet address. It does not have a public
@@ -57,45 +57,56 @@ import java.util.StringTokenizer;
*
* @author Aaron M. Renn (arenn@urbanophile.com)
* @author Per Bothner
+ * @author Gary Benson (gbenson@redhat.com)
*
- * @specnote This class is not final since JK 1.4
+ * @specnote This class is not final since JDK 1.4
*/
public class InetAddress implements Serializable
{
private static final long serialVersionUID = 3286316764910316507L;
/**
- * The special IP address INADDR_ANY.
- */
- private static InetAddress inaddr_any;
-
- /**
* Dummy InetAddress, used to bind socket to any (all) network interfaces.
*/
static InetAddress ANY_IF;
-
+ static
+ {
+ byte[] addr;
+ try
+ {
+ addr = VMInetAddress.lookupInaddrAny();
+ }
+ catch (UnknownHostException e)
+ {
+ // Make one up and hope it works.
+ addr = new byte[] {0, 0, 0, 0};
+ }
+ try
+ {
+ ANY_IF = getByAddress(addr);
+ }
+ catch (UnknownHostException e)
+ {
+ throw (InternalError) new InternalError().initCause(e);
+ }
+ ANY_IF.hostName = ANY_IF.getHostName();
+ }
+
/**
* Stores static localhost address object.
*/
static InetAddress LOCALHOST;
-
static
{
- // precompute the ANY_IF address
try
{
- ANY_IF = getInaddrAny();
-
- byte[] ip_localhost = { 127, 0, 0, 1 };
- LOCALHOST = new Inet4Address(ip_localhost, "localhost");
+ LOCALHOST = getByAddress("localhost", new byte[] {127, 0, 0, 1});
}
- catch (UnknownHostException uhe)
+ catch (UnknownHostException e)
{
- // Hmmm, make one up and hope that it works.
- byte[] zeros = { 0, 0, 0, 0 };
- ANY_IF = new Inet4Address(zeros, "0.0.0.0");
+ throw (InternalError) new InternalError().initCause(e);
}
- }
+ }
/**
* The Serialized Form specifies that an int 'address' is saved/restored.
@@ -115,28 +126,28 @@ public class InetAddress implements Serializable
String hostName;
/**
- * The field 'family' seems to be the AF_ value.
- * FIXME: Much of the code in the other java.net classes does not make
- * use of this family field. A better implementation would be to make
- * use of getaddrinfo() and have other methods just check the family
- * field rather than examining the length of the address each time.
+ * Needed for serialization.
*/
- int family;
+ private int family;
/**
- * Initializes this object's addr instance variable from the passed in
- * byte array. Note that this constructor is protected and is called
- * only by static methods in this class.
+ * Constructor. Prior to the introduction of IPv6 support in 1.4,
+ * methods such as InetAddress.getByName() would return InetAddress
+ * objects. From 1.4 such methods returned either Inet4Address or
+ * Inet6Address objects, but for compatibility Inet4Address objects
+ * are serialized as InetAddresses. As such, there are only two
+ * places where it is appropriate to invoke this constructor: within
+ * subclasses constructors and within Inet4Address.writeReplace().
*
* @param ipaddr The IP number of this address as an array of bytes
* @param hostname The hostname of this IP address.
+ * @param family The address family of this IP address.
*/
- InetAddress(byte[] ipaddr, String hostname)
+ InetAddress(byte[] ipaddr, String hostname, int family)
{
addr = (null == ipaddr) ? null : (byte[]) ipaddr.clone();
hostName = hostname;
-
- family = 2; /* AF_INET */
+ this.family = family;
}
/**
@@ -144,150 +155,144 @@ public class InetAddress implements Serializable
* An address is multicast if the high four bits are "1110". These are
* also known as "Class D" addresses.
*
+ * <p>This method cannot be abstract for backward compatibility reasons. By
+ * default it always throws {@link UnsupportedOperationException} unless
+ * overridden.</p>
+ *
* @return true if mulitcast, false if not
*
* @since 1.1
*/
public boolean isMulticastAddress()
{
- // Mask against high order bits of 1110
- if (addr.length == 4)
- return (addr[0] & 0xf0) == 0xe0;
-
- return false;
+ throw new UnsupportedOperationException();
}
/**
* Utility routine to check if the InetAddress in a wildcard address
*
+ * <p>This method cannot be abstract for backward compatibility reasons. By
+ * default it always throws {@link UnsupportedOperationException} unless
+ * overridden.</p>
+ *
* @since 1.4
*/
public boolean isAnyLocalAddress()
{
- // This is the IPv4 implementation.
- // Any class derived from InetAddress should override this.
- return equals(ANY_IF);
+ throw new UnsupportedOperationException();
}
/**
* Utility routine to check if the InetAddress is a loopback address
*
+ * <p>This method cannot be abstract for backward compatibility reasons. By
+ * default it always throws {@link UnsupportedOperationException} unless
+ * overridden.</p>
+ *
* @since 1.4
*/
public boolean isLoopbackAddress()
{
- // This is the IPv4 implementation.
- // Any class derived from InetAddress should override this.
- return (addr[0] & 0xff) == 0x7f;
+ throw new UnsupportedOperationException();
}
/**
* Utility routine to check if InetAddress is a link local address
*
+ * <p>This method cannot be abstract for backward compatibility reasons. By
+ * default it always throws {@link UnsupportedOperationException} unless
+ * overridden.</p>
+ *
* @since 1.4
*/
public boolean isLinkLocalAddress()
{
- // This is the IPv4 implementation.
- // Any class derived from InetAddress should override this.
- // XXX: This seems to not exist with IPv4 addresses
- return false;
+ throw new UnsupportedOperationException();
}
/**
* Utility routine to check if InetAddress is a site local address
*
+ * <p>This method cannot be abstract for backward compatibility reasons. By
+ * default it always throws {@link UnsupportedOperationException} unless
+ * overridden.</p>
+ *
* @since 1.4
*/
public boolean isSiteLocalAddress()
{
- // This is the IPv4 implementation.
- // Any class derived from InetAddress should override this.
-
- // 10.0.0.0/8
- if ((addr[0] & 0xff) == 0x0a)
- return true;
-
- // 172.16.0.0/12
- if ((addr[0] & 0xff) == 0xac && (addr[1] & 0xf0) == 0x10)
- return true;
-
- // 192.168.0.0/16
- if ((addr[0] & 0xff) == 0xc0 && (addr[1] & 0xff) == 0xa8)
- return true;
-
- // XXX: Do we need to check more addresses here ?
- return false;
+ throw new UnsupportedOperationException();
}
/**
* Utility routine to check if InetAddress is a global multicast address
*
+ * <p>This method cannot be abstract for backward compatibility reasons. By
+ * default it always throws {@link UnsupportedOperationException} unless
+ * overridden.</p>
+ *
* @since 1.4
*/
public boolean isMCGlobal()
{
- // This is the IPv4 implementation.
- // Any class derived from InetAddress should override this.
- // XXX: This seems to not exist with IPv4 addresses
- return false;
+ throw new UnsupportedOperationException();
}
/**
* Utility routine to check if InetAddress is a node local multicast address.
*
+ * <p>This method cannot be abstract for backward compatibility reasons. By
+ * default it always throws {@link UnsupportedOperationException} unless
+ * overridden.</p>
+ *
* @since 1.4
*/
public boolean isMCNodeLocal()
{
- // This is the IPv4 implementation.
- // Any class derived from InetAddress should override this.
- // XXX: This seems to not exist with IPv4 addresses
- return false;
+ throw new UnsupportedOperationException();
}
/**
* Utility routine to check if InetAddress is a link local multicast address.
*
+ * <p>This method cannot be abstract for backward compatibility reasons. By
+ * default it always throws {@link UnsupportedOperationException} unless
+ * overridden.</p>
+ *
* @since 1.4
*/
public boolean isMCLinkLocal()
{
- // This is the IPv4 implementation.
- // Any class derived from InetAddress should override this.
- if (! isMulticastAddress())
- return false;
-
- return ((addr[0] & 0xff) == 0xe0
- && (addr[1] & 0xff) == 0x00
- && (addr[2] & 0xff) == 0x00);
+ throw new UnsupportedOperationException();
}
/**
* Utility routine to check if InetAddress is a site local multicast address.
*
+ * <p>This method cannot be abstract for backward compatibility reasons. By
+ * default it always throws {@link UnsupportedOperationException} unless
+ * overridden.</p>
+ *
* @since 1.4
*/
public boolean isMCSiteLocal()
{
- // This is the IPv4 implementation.
- // Any class derived from InetAddress should override this.
- // XXX: This seems to not exist with IPv4 addresses
- return false;
+ throw new UnsupportedOperationException();
}
/**
* Utility routine to check if InetAddress is a organization local
* multicast address.
*
+ * <p>This method cannot be abstract for backward compatibility reasons. By
+ * default it always throws {@link UnsupportedOperationException} unless
+ * overridden.</p>
+ *
* @since 1.4
*/
public boolean isMCOrgLocal()
{
- // This is the IPv4 implementation.
- // Any class derived from InetAddress should override this.
- // XXX: This seems to not exist with IPv4 addresses
- return false;
+ throw new UnsupportedOperationException();
}
/**
@@ -298,13 +303,20 @@ public class InetAddress implements Serializable
*/
public String getHostName()
{
- if (hostName != null)
- return hostName;
+ if (hostName == null)
+ hostName = getCanonicalHostName();
+ return hostName;
+ }
+
+ /**
+ * Returns the canonical hostname represented by this InetAddress
+ */
+ String internalGetCanonicalHostName()
+ {
try
{
- hostName = VMInetAddress.getHostByAddr(addr);
- return hostName;
+ return ResolverCache.getHostByAddr(addr);
}
catch (UnknownHostException e)
{
@@ -319,12 +331,14 @@ public class InetAddress implements Serializable
*/
public String getCanonicalHostName()
{
+ String hostname = internalGetCanonicalHostName();
+
SecurityManager sm = System.getSecurityManager();
if (sm != null)
{
try
{
- sm.checkConnect(hostName, -1);
+ sm.checkConnect(hostname, -1);
}
catch (SecurityException e)
{
@@ -332,16 +346,7 @@ public class InetAddress implements Serializable
}
}
- // Try to find the FDQN now
- InetAddress address;
- byte[] ipaddr = getAddress();
-
- if (ipaddr.length == 16)
- address = new Inet6Address(getAddress(), null);
- else
- address = new Inet4Address(getAddress(), null);
-
- return address.getHostName();
+ return hostname;
}
/**
@@ -357,32 +362,19 @@ public class InetAddress implements Serializable
}
/**
- * Returns the IP address of this object as a String. The address is in
- * the dotted octet notation, for example, "127.0.0.1".
+ * Returns the IP address of this object as a String.
*
+ * <p>This method cannot be abstract for backward compatibility reasons. By
+ * default it always throws {@link UnsupportedOperationException} unless
+ * overridden.</p>
+ *
* @return The IP address of this object in String form
*
* @since 1.0.2
*/
public String getHostAddress()
{
- StringBuffer sb = new StringBuffer(40);
-
- int len = addr.length;
- int i = 0;
-
- for ( ; ; )
- {
- sb.append(addr[i] & 0xff);
- i++;
-
- if (i == len)
- break;
-
- sb.append('.');
- }
-
- return sb.toString();
+ throw new UnsupportedOperationException();
}
/**
@@ -488,48 +480,50 @@ public class InetAddress implements Serializable
return new Inet4Address(addr, host);
if (addr.length == 16)
- return new Inet6Address(addr, host);
+ {
+ for (int i = 0; i < 12; i++)
+ {
+ if (addr[i] != (i < 10 ? 0 : (byte) 0xFF))
+ return new Inet6Address(addr, host);
+ }
+
+ byte[] ip4addr = new byte[4];
+ ip4addr[0] = addr[12];
+ ip4addr[1] = addr[13];
+ ip4addr[2] = addr[14];
+ ip4addr[3] = addr[15];
+ return new Inet4Address(ip4addr, host);
+ }
throw new UnknownHostException("IP address has illegal length");
}
/**
- * If hostname is a valid numeric IP address, return the numeric address.
- * Otherwise, return null.
+ * Returns an InetAddress object representing the IP address of
+ * the given literal IP address in dotted decimal format such as
+ * "127.0.0.1". This is used by SocketPermission.setHostPort()
+ * to parse literal IP addresses without performing a DNS lookup.
+ *
+ * @param literal The literal IP address to create the InetAddress
+ * object from
*
- * @param hostname the name of the host
+ * @return The address of the host as an InetAddress object, or
+ * null if the IP address is invalid.
*/
- private static byte[] aton(String hostname)
+ static InetAddress getByLiteral(String literal)
{
- StringTokenizer st = new StringTokenizer(hostname, ".");
-
- if (st.countTokens() == 4)
+ byte[] address = VMInetAddress.aton(literal);
+ if (address == null)
+ return null;
+
+ try
{
- int index;
- byte[] address = new byte[4];
-
- for (index = 0; index < 4; index++)
- {
- try
- {
- short n = Short.parseShort(st.nextToken());
-
- if ((n < 0) || (n > 255))
- break;
-
- address[index] = (byte) n;
- }
- catch (NumberFormatException e)
- {
- break;
- }
- }
-
- if (index == 4)
- return address;
+ return getByAddress(address);
+ }
+ catch (UnknownHostException e)
+ {
+ throw (InternalError) new InternalError().initCause(e);
}
-
- return null;
}
/**
@@ -577,63 +571,34 @@ public class InetAddress implements Serializable
public static InetAddress[] getAllByName(String hostname)
throws UnknownHostException
{
- SecurityManager s = System.getSecurityManager();
- if (s != null)
- s.checkConnect(hostname, -1);
-
- InetAddress[] addresses;
-
- if (hostname != null)
- hostname = hostname.trim();
+ // If null or the empty string is supplied, the loopback address
+ // is returned.
+ if (hostname == null || hostname.length() == 0)
+ return new InetAddress[] {LOCALHOST};
- // Default to current host if necessary
- if (hostname == null || hostname.equals(""))
- {
- addresses = new InetAddress[1];
- addresses[0] = LOCALHOST;
- return addresses;
- }
+ // Check if hostname is an IP address
+ InetAddress address = getByLiteral(hostname);
+ if (address != null)
+ return new InetAddress[] {address};
- // Not in cache, try the lookup
- byte[][] iplist = VMInetAddress.getHostByName(hostname);
+ // Perform security check before resolving
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkConnect(hostname, -1);
+ // Resolve the hostname
+ byte[][] iplist = ResolverCache.getHostByName(hostname);
if (iplist.length == 0)
throw new UnknownHostException(hostname);
- addresses = new InetAddress[iplist.length];
-
+ InetAddress[] addresses = new InetAddress[iplist.length];
for (int i = 0; i < iplist.length; i++)
- {
- if (iplist[i].length != 4)
- throw new UnknownHostException(hostname);
-
- addresses[i] = new Inet4Address(iplist[i], hostname);
- }
+ addresses[i] = getByAddress(hostname, iplist[i]);
return addresses;
}
/**
- * Returns the special address INADDR_ANY used for binding to a local
- * port on all IP addresses hosted by a the local host.
- *
- * @return An InetAddress object representing INDADDR_ANY
- *
- * @exception UnknownHostException If an error occurs
- */
- static InetAddress getInaddrAny() throws UnknownHostException
- {
- if (inaddr_any == null)
- {
- byte[] tmp = VMInetAddress.lookupInaddrAny();
- inaddr_any = new Inet4Address(tmp, null);
- inaddr_any.hostName = inaddr_any.getHostName();
- }
-
- return inaddr_any;
- }
-
- /**
* Returns an InetAddress object representing the address of the current
* host.
*
@@ -645,11 +610,19 @@ public class InetAddress implements Serializable
public static InetAddress getLocalHost() throws UnknownHostException
{
String hostname = VMInetAddress.getLocalHostname();
- return getByName(hostname);
+ try
+ {
+ return getByName(hostname);
+ }
+ catch (SecurityException e)
+ {
+ return LOCALHOST;
+ }
}
- /*
- * Needed for serialization
+ /**
+ * Inet4Address objects are serialized as InetAddress objects.
+ * This deserializes them back into Inet4Address objects.
*/
private Object readResolve() throws ObjectStreamException
{
@@ -665,8 +638,6 @@ public class InetAddress implements Serializable
for (int i = 2; i >= 0; --i)
addr[i] = (byte) (address >>= 8);
-
- family = 2; /* AF_INET */
}
private void writeObject(ObjectOutputStream oos) throws IOException
diff --git a/java/net/NetworkInterface.java b/java/net/NetworkInterface.java
index 7ad62a713..af595a1ee 100644
--- a/java/net/NetworkInterface.java
+++ b/java/net/NetworkInterface.java
@@ -1,5 +1,5 @@
/* NetworkInterface.java --
- Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,6 +38,8 @@ exception statement from your version. */
package java.net;
+import gnu.classpath.SystemProperties;
+
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
@@ -58,25 +60,13 @@ import java.util.Vector;
*/
public final class NetworkInterface
{
- private String name;
- private Vector<InetAddress> inetAddresses;
-
- NetworkInterface(String name, InetAddress address)
- {
- this.name = name;
- this.inetAddresses = new Vector(1, 1);
- this.inetAddresses.add(address);
- }
-
- NetworkInterface(String name, InetAddress[] addresses)
- {
- this.name = name;
- this.inetAddresses = new Vector(addresses.length, 1);
-
- for (int i = 0; i < addresses.length; i++)
- this.inetAddresses.add(addresses[i]);
- }
-
+ private final VMNetworkInterface netif;
+
+ private NetworkInterface(VMNetworkInterface netif)
+ {
+ this.netif = netif;
+ }
+
/**
* Returns the name of the network interface
*
@@ -84,7 +74,7 @@ public final class NetworkInterface
*/
public String getName()
{
- return name;
+ return netif.name;
}
/**
@@ -100,6 +90,7 @@ public final class NetworkInterface
public Enumeration<InetAddress> getInetAddresses()
{
SecurityManager s = System.getSecurityManager();
+ Vector inetAddresses = new Vector(netif.addresses);
if (s == null)
return inetAddresses.elements();
@@ -112,7 +103,7 @@ public final class NetworkInterface
InetAddress addr = addresses.nextElement();
try
{
- s.checkConnect(addr.getHostAddress(), 58000);
+ s.checkConnect(addr.getHostAddress(), -1);
tmpInetAddresses.add(addr);
}
catch (SecurityException e)
@@ -131,7 +122,7 @@ public final class NetworkInterface
*/
public String getDisplayName()
{
- return name;
+ return netif.name;
}
/**
@@ -148,15 +139,14 @@ public final class NetworkInterface
public static NetworkInterface getByName(String name)
throws SocketException
{
- for (Enumeration e = getNetworkInterfaces(); e.hasMoreElements();)
+ if (name == null)
+ throw new NullPointerException();
+ VMNetworkInterface[] netifs = VMNetworkInterface.getVMInterfaces();
+ for (int i = 0; i < netifs.length; i++)
{
- NetworkInterface tmp = (NetworkInterface) e.nextElement();
-
- if (name.equals(tmp.getName()))
- return tmp;
+ if (netifs[i].name.equals(name))
+ return new NetworkInterface(netifs[i]);
}
-
- // No interface with the given name found.
return null;
}
@@ -173,55 +163,15 @@ public final class NetworkInterface
public static NetworkInterface getByInetAddress(InetAddress addr)
throws SocketException
{
- for (Enumeration interfaces = getNetworkInterfaces();
- interfaces.hasMoreElements();)
+ if (addr == null)
+ throw new NullPointerException();
+ VMNetworkInterface[] netifs = VMNetworkInterface.getVMInterfaces();
+ for (int i = 0; i < netifs.length; i++)
{
- NetworkInterface tmp = (NetworkInterface) interfaces.nextElement();
-
- for (Enumeration addresses = tmp.inetAddresses.elements();
- addresses.hasMoreElements();)
- {
- if (addr.equals((InetAddress) addresses.nextElement()))
- return tmp;
- }
+ if (netifs[i].addresses.contains(addr))
+ return new NetworkInterface(netifs[i]);
}
-
- throw new SocketException("no network interface is bound to such an IP address");
- }
-
- static private Collection condense(Collection interfaces)
- {
- final Map condensed = new HashMap();
-
- final Iterator interfs = interfaces.iterator();
- while (interfs.hasNext()) {
-
- final NetworkInterface face = (NetworkInterface) interfs.next();
- final String name = face.getName();
-
- if (condensed.containsKey(name))
- {
- final NetworkInterface conface = (NetworkInterface) condensed.get(name);
- if (!conface.inetAddresses.containsAll(face.inetAddresses))
- {
- final Iterator faceAddresses = face.inetAddresses.iterator();
- while (faceAddresses.hasNext())
- {
- final InetAddress faceAddress = (InetAddress) faceAddresses.next();
- if (!conface.inetAddresses.contains(faceAddress))
- {
- conface.inetAddresses.add(faceAddress);
- }
- }
- }
- }
- else
- {
- condensed.put(name, face);
- }
- }
-
- return condensed.values();
+ return null;
}
/**
@@ -234,15 +184,15 @@ public final class NetworkInterface
public static Enumeration<NetworkInterface> getNetworkInterfaces()
throws SocketException
{
- Vector<NetworkInterface> networkInterfaces =
- VMNetworkInterface.getInterfaces();
-
- if (networkInterfaces.isEmpty())
- return null;
-
- Collection condensed = condense(networkInterfaces);
-
- return Collections.enumeration(condensed);
+ VMNetworkInterface[] netifs = VMNetworkInterface.getVMInterfaces();
+ Vector<NetworkInterface> networkInterfaces =
+ new Vector<NetworkInterface>(netifs.length);
+ for (int i = 0; i < netifs.length; i++)
+ {
+ if (!netifs[i].addresses.isEmpty())
+ networkInterfaces.add(new NetworkInterface(netifs[i]));
+ }
+ return networkInterfaces.elements();
}
/**
@@ -259,7 +209,8 @@ public final class NetworkInterface
NetworkInterface tmp = (NetworkInterface) obj;
- return (name.equals(tmp.name) && inetAddresses.equals(tmp.inetAddresses));
+ return (netif.name.equals(tmp.netif.name)
+ && (netif.addresses.equals(tmp.netif.addresses)));
}
/**
@@ -270,7 +221,7 @@ public final class NetworkInterface
public int hashCode()
{
// FIXME: hash correctly
- return name.hashCode() + inetAddresses.hashCode();
+ return netif.name.hashCode() + netif.addresses.hashCode();
}
/**
@@ -281,19 +232,22 @@ public final class NetworkInterface
public String toString()
{
// FIXME: check if this is correct
- String result;
- String separator = System.getProperty("line.separator");
+ StringBuffer result;
+ String separator = SystemProperties.getProperty("line.separator");
- result =
- "name: " + getDisplayName() + " (" + getName() + ") addresses:"
- + separator;
+ result = new StringBuffer();
+
+ result.append("name: ");
+ result.append(getDisplayName());
+ result.append(" (").append(getName()).append(") addresses:");
+ result.append(separator);
- for (Enumeration e = inetAddresses.elements(); e.hasMoreElements();)
+ for (Iterator it = netif.addresses.iterator(); it.hasNext(); )
{
- InetAddress address = (InetAddress) e.nextElement();
- result += address.toString() + ";" + separator;
+ InetAddress address = (InetAddress) it.next();
+ result.append(address.toString()).append(";").append(separator);
}
- return result;
+ return result.toString();
}
}
diff --git a/java/net/ResolverCache.java b/java/net/ResolverCache.java
new file mode 100644
index 000000000..f8790666a
--- /dev/null
+++ b/java/net/ResolverCache.java
@@ -0,0 +1,269 @@
+/* ResolverCache.java -- A cache of resolver lookups for InetAddress.
+ 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.net;
+
+import java.security.Security;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+/**
+ * This class provides a cache of name service resolutions. By
+ * default successful resolutions are cached forever to guard
+ * against DNS spoofing attacks and failed resolutions are cached
+ * for 10 seconds to improve performance. The length of time that
+ * results remain in the cache is determined by the following
+ * security properties:
+ * <dl>
+ * <dt><code>networkaddress.cache.ttl</code></dt>
+ * <dd>
+ * This property specifies the length of time in seconds that
+ * successful resolutions remain in the cache. The default is
+ * -1, indicating to cache forever.
+ * </dd>
+ * <dt><code>networkaddress.cache.negative.ttl</code></dt>
+ * <dd>
+ * This property specifies the length of time in seconds that
+ * unsuccessful resolutions remain in the cache. The default
+ * is 10, indicating to cache for 10 seconds.
+ * </dd>
+ * In both cases, a value of -1 indicates to cache forever and a
+ * value of 0 indicates not to cache.
+ *
+ * @author Gary Benson (gbenson@redhat.com)
+ */
+class ResolverCache
+{
+ /**
+ * The time in seconds for which successful lookups are cached.
+ */
+ private static final int POSITIVE_TTL =
+ getTTL("networkaddress.cache.ttl", -1);
+
+ /**
+ * The time in seconds for which unsuccessful lookups are cached.
+ */
+ private static final int NEGATIVE_TTL =
+ getTTL("networkaddress.cache.negative.ttl", 10);
+
+ /**
+ * Helper function to set the TTLs.
+ */
+ private static int getTTL(String propName, int defaultValue)
+ {
+ String propValue = Security.getProperty(propName);
+ if (propValue == null)
+ return defaultValue;
+
+ return Integer.parseInt(propValue);
+ }
+
+ /**
+ * The cache itself.
+ */
+ private static HashMap cache = new HashMap();
+
+ /**
+ * List of entries which may expire.
+ */
+ private static LinkedList killqueue = new LinkedList();
+
+ /**
+ * Return the hostname for the specified IP address.
+ *
+ * @param ip The IP address as a byte array
+ *
+ * @return The hostname
+ *
+ * @exception UnknownHostException If the reverse lookup fails
+ */
+ public static String getHostByAddr(byte[] addr) throws UnknownHostException
+ {
+ Object key = makeHashableAddress(addr);
+ Entry entry = (Entry) get(key);
+ if (entry != null)
+ {
+ if (entry.value == null)
+ throw new UnknownHostException();
+ return (String) entry.value;
+ }
+
+ try
+ {
+ String hostname = VMInetAddress.getHostByAddr(addr);
+ put(new Entry(key, hostname));
+ return hostname;
+ }
+ catch (UnknownHostException e)
+ {
+ put(new Entry(key, null));
+ throw e;
+ }
+ }
+
+ /**
+ * Return a list of all IP addresses for the specified hostname.
+ *
+ * @param hostname The hostname
+ *
+ * @return An list of IP addresses as byte arrays
+ *
+ * @exception UnknownHostException If the lookup fails
+ */
+ public static byte[][] getHostByName(String hostname)
+ throws UnknownHostException
+ {
+ Entry entry = (Entry) get(hostname);
+ if (entry != null)
+ {
+ if (entry.value == null)
+ throw new UnknownHostException();
+ return (byte[][]) entry.value;
+ }
+
+ try
+ {
+ byte[][] addrs = VMInetAddress.getHostByName(hostname);
+ put(new Entry(hostname, addrs));
+ return addrs;
+ }
+ catch (UnknownHostException e)
+ {
+ put(new Entry(hostname, null));
+ throw e;
+ }
+ }
+
+ /**
+ * Convert an IP address expressed as a byte array into something
+ * we can use as a hashtable key.
+ */
+ private static Object makeHashableAddress(byte[] addr)
+ {
+ char[] chars = new char[addr.length];
+ for (int i = 0; i < addr.length; i++)
+ chars[i] = (char) addr[i];
+ return new String(chars);
+ }
+
+ /**
+ * Return the entry in the cache associated with the supplied key,
+ * or <code>null</code> if the cache does not contain an entry
+ * associated with this key.
+ */
+ private static synchronized Entry get(Object key)
+ {
+ reap();
+ return (Entry) cache.get(key);
+ }
+
+ /**
+ * Insert the supplied entry into the cache.
+ */
+ private static synchronized void put(Entry entry)
+ {
+ reap();
+ if (entry.expires != 0)
+ {
+ if (entry.expires != -1)
+ killqueue.add(entry);
+ cache.put(entry.key, entry);
+ }
+ }
+
+ /**
+ * Clear expired entries. This method is not synchronized, so
+ * it must only be called by methods that are.
+ */
+ private static void reap()
+ {
+ if (!killqueue.isEmpty())
+ {
+ long now = System.currentTimeMillis();
+
+ Iterator iter = killqueue.iterator();
+ while (iter.hasNext())
+ {
+ Entry entry = (Entry) iter.next();
+ if (entry.expires > now)
+ break;
+ cache.remove(entry.key);
+ iter.remove();
+ }
+ }
+ }
+
+ /**
+ * An entry in the cache.
+ */
+ private static class Entry
+ {
+ /**
+ * The key by which this entry is referenced.
+ */
+ public final Object key;
+
+ /**
+ * The entry itself. A null value indicates a failed lookup.
+ */
+ public final Object value;
+
+ /**
+ * The time when this cache entry expires. If set to -1 then
+ * this entry will never expire. If set to 0 then this entry
+ * expires immediately and will not be inserted into the cache.
+ */
+ public final long expires;
+
+ /**
+ * Constructor.
+ */
+ public Entry(Object key, Object value)
+ {
+ this.key = key;
+ this.value = value;
+
+ int ttl = value != null ? POSITIVE_TTL : NEGATIVE_TTL;
+ if (ttl < 1)
+ expires = ttl;
+ else
+ expires = System.currentTimeMillis() + ttl * 1000;
+ }
+ }
+}
diff --git a/java/net/ServerSocket.java b/java/net/ServerSocket.java
index 2b889531a..533626e0b 100644
--- a/java/net/ServerSocket.java
+++ b/java/net/ServerSocket.java
@@ -79,6 +79,7 @@ public class ServerSocket
* We need to retain the local address even after the socket is closed.
*/
private InetSocketAddress local;
+ private int port;
/*
* This constructor is only used by java.nio.
@@ -93,6 +94,7 @@ public class ServerSocket
this.impl = impl;
this.impl.create(true);
+ setReuseAddress(true);
}
/*
@@ -219,43 +221,53 @@ public class ServerSocket
if (isClosed())
throw new SocketException("ServerSocket is closed");
- if (! (endpoint instanceof InetSocketAddress))
- throw new IllegalArgumentException("Address type not supported");
+ if (isBound())
+ throw new SocketException("Already bound");
- InetSocketAddress tmp = (InetSocketAddress) endpoint;
+ InetAddress addr;
+ int port;
+
+ if (endpoint == null)
+ {
+ addr = InetAddress.ANY_IF;
+ port = 0;
+ }
+ else if (! (endpoint instanceof InetSocketAddress))
+ {
+ throw new IllegalArgumentException("Address type not supported");
+ }
+ else
+ {
+ InetSocketAddress tmp = (InetSocketAddress) endpoint;
+ if (tmp.isUnresolved())
+ throw new SocketException("Unresolved address");
+ addr = tmp.getAddress();
+ port = tmp.getPort();
+ }
SecurityManager s = System.getSecurityManager();
if (s != null)
- s.checkListen(tmp.getPort());
-
- InetAddress addr = tmp.getAddress();
-
- // Initialize addr with 0.0.0.0.
- if (addr == null)
- addr = InetAddress.ANY_IF;
+ s.checkListen(port);
try
{
- impl.bind(addr, tmp.getPort());
+ impl.bind(addr, port);
impl.listen(backlog);
- local = new InetSocketAddress(
+ this.port = port;
+ local = new InetSocketAddress(
(InetAddress) impl.getOption(SocketOptions.SO_BINDADDR),
impl.getLocalPort());
}
- catch (IOException exception)
+ finally
{
- close();
- throw exception;
- }
- catch (RuntimeException exception)
- {
- close();
- throw exception;
- }
- catch (Error error)
- {
- close();
- throw error;
+ try
+ {
+ if (local == null)
+ close();
+ }
+ catch (IOException _)
+ {
+ }
}
}
@@ -367,7 +379,6 @@ public class ServerSocket
throw new IllegalBlockingModeException();
impl.accept(socket.impl);
- socket.implCreated = true;
socket.bound = true;
}
@@ -378,14 +389,11 @@ public class ServerSocket
*/
public void close() throws IOException
{
- if (isClosed())
- return;
-
- impl.close();
- impl = null;
-
- if (getChannel() != null)
- getChannel().close();
+ if (impl != null)
+ {
+ impl.close();
+ impl = null;
+ }
}
/**
@@ -425,7 +433,8 @@ public class ServerSocket
*/
public boolean isClosed()
{
- return impl == null;
+ ServerSocketChannel channel = getChannel();
+ return impl == null || (channel != null && ! channel.isOpen());
}
/**
@@ -573,7 +582,7 @@ public class ServerSocket
return "ServerSocket[unbound]";
return ("ServerSocket[addr=" + getInetAddress() + ",port="
- + impl.getPort() + ",localport=" + impl.getLocalPort() + "]");
+ + port + ",localport=" + getLocalPort() + "]");
}
/**
diff --git a/java/net/Socket.java b/java/net/Socket.java
index b2249ffaa..63ba43727 100644
--- a/java/net/Socket.java
+++ b/java/net/Socket.java
@@ -1,5 +1,5 @@
/* Socket.java -- Client socket implementation
- Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004
+ Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2006
Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -83,13 +83,6 @@ public class Socket
SocketImpl impl;
/**
- * True if socket implementation was created by calling their
- * create() method.
- */
- // package-private because ServerSocket.implAccept() needs to access it.
- boolean implCreated;
-
- /**
* True if the socket is bound.
* Package private so it can be set from ServerSocket when accept is called.
*/
@@ -315,21 +308,6 @@ public class Socket
private SocketImpl getImpl() throws SocketException
{
- try
- {
- if (! implCreated)
- {
- impl.create(true);
- implCreated = true;
- }
- }
- catch (IOException e)
- {
- SocketException se = new SocketException(e.toString());
- se.initCause(e);
- throw se;
- }
-
return impl;
}
@@ -363,6 +341,7 @@ public class Socket
// bind to address/port
try
{
+ getImpl().create(true);
getImpl().bind(tmp.getAddress(), tmp.getPort());
bound = true;
}
@@ -479,16 +458,22 @@ public class Socket
InetAddress addr = null;
- try
- {
- addr = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR);
- }
- catch (SocketException e)
+ if (impl instanceof PlainSocketImpl)
+ addr = ((PlainSocketImpl) impl).getLocalAddress().getAddress();
+
+ if (addr == null)
{
- // (hopefully) shouldn't happen
- // throw new java.lang.InternalError
- // ("Error in PlainSocketImpl.getOption");
- return null;
+ try
+ {
+ addr = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR);
+ }
+ catch (SocketException e)
+ {
+ // (hopefully) shouldn't happen
+ // throw new java.lang.InternalError
+ // ("Error in PlainSocketImpl.getOption");
+ return null;
+ }
}
// FIXME: According to libgcj, checkConnect() is supposed to be called
@@ -1001,12 +986,8 @@ public class Socket
if (isClosed())
return;
- getImpl().close();
+ impl.close();
impl = null;
- bound = false;
-
- if (getChannel() != null)
- getChannel().close();
}
/**
@@ -1019,16 +1000,17 @@ public class Socket
try
{
if (isConnected())
- return ("Socket[addr=" + getImpl().getInetAddress() + ",port="
- + getImpl().getPort() + ",localport="
- + getImpl().getLocalPort() + "]");
+ return (super.toString()
+ + " [addr=" + getImpl().getInetAddress() + ",port="
+ + getImpl().getPort() + ",localport="
+ + getImpl().getLocalPort() + "]");
}
catch (SocketException e)
{
// This cannot happen as we are connected.
}
- return "Socket[unconnected]";
+ return super.toString() + " [unconnected]";
}
/**
@@ -1206,17 +1188,10 @@ public class Socket
*/
public boolean isConnected()
{
- try
- {
- if (getImpl() == null)
- return false;
+ if (impl == null)
+ return false;
- return getImpl().getInetAddress() != null;
- }
- catch (SocketException e)
- {
- return false;
- }
+ return impl.getInetAddress() != null;
}
/**
@@ -1228,6 +1203,13 @@ public class Socket
*/
public boolean isBound()
{
+ if (isClosed())
+ return false;
+ if (impl instanceof PlainSocketImpl)
+ {
+ InetSocketAddress addr = ((PlainSocketImpl) impl).getLocalAddress();
+ return addr != null && addr.getAddress() != null;
+ }
return bound;
}
@@ -1240,7 +1222,8 @@ public class Socket
*/
public boolean isClosed()
{
- return impl == null;
+ SocketChannel channel = getChannel();
+ return impl == null || (channel != null && ! channel.isOpen());
}
/**
diff --git a/java/net/SocketPermission.java b/java/net/SocketPermission.java
index 97e93dcbb..64885438a 100644
--- a/java/net/SocketPermission.java
+++ b/java/net/SocketPermission.java
@@ -117,11 +117,18 @@ public final class SocketPermission extends Permission implements Serializable
static final long serialVersionUID = -7204263841984476862L;
/**
- * A hostname (possibly wildcarded) or IP address (IPv4 or IPv6).
+ * A hostname (possibly wildcarded). Will be set if and only if
+ * this object was initialized with a hostname.
*/
- private transient String host;
+ private transient String hostname = null;
/**
+ * An IP address (IPv4 or IPv6). Will be set if and only if this
+ * object was initialized with a single literal IP address.
+ */
+ private transient InetAddress address = null;
+
+ /**
* A range of ports.
*/
private transient int minport;
@@ -186,16 +193,19 @@ public final class SocketPermission extends Permission implements Serializable
if (hostport.charAt(0) == '[')
return hostport;
- int colons = 0, last_colon = 0;
+ int colons = 0;
+ boolean colon_allowed = true;
for (int i = 0; i < hostport.length(); i++)
{
if (hostport.charAt(i) == ':')
{
- if (i - last_colon == 1)
+ if (!colon_allowed)
throw new IllegalArgumentException("Ambiguous hostport part");
colons++;
- last_colon = i;
+ colon_allowed = false;
}
+ else
+ colon_allowed = true;
}
switch (colons)
@@ -211,6 +221,7 @@ public final class SocketPermission extends Permission implements Serializable
case 8:
// an IPv6 address with ports
+ int last_colon = hostport.lastIndexOf(':');
return "[" + hostport.substring(0, last_colon) + "]"
+ hostport.substring(last_colon);
@@ -225,7 +236,7 @@ public final class SocketPermission extends Permission implements Serializable
private void setHostPort(String hostport)
{
// Split into host and ports
- String ports;
+ String host, ports;
if (hostport.charAt(0) == '[')
{
// host is a bracketed IPv6 address
@@ -234,6 +245,10 @@ public final class SocketPermission extends Permission implements Serializable
throw new IllegalArgumentException("Unmatched '['");
host = hostport.substring(1, end);
+ address = InetAddress.getByLiteral(host);
+ if (address == null)
+ throw new IllegalArgumentException("Bad IPv6 address");
+
if (end == hostport.length() - 1)
ports = "";
else if (hostport.charAt(end + 1) == ':')
@@ -255,6 +270,15 @@ public final class SocketPermission extends Permission implements Serializable
host = hostport.substring(0, sep);
ports = hostport.substring(sep + 1);
}
+
+ address = InetAddress.getByLiteral(host);
+ if (address == null)
+ {
+ if (host.lastIndexOf('*') > 0)
+ throw new IllegalArgumentException("Bad hostname");
+
+ hostname = host;
+ }
}
// Parse and validate the ports
@@ -362,10 +386,25 @@ public final class SocketPermission extends Permission implements Serializable
else
return false;
- return p.actionmask == actionmask &&
- p.minport == minport &&
- p.maxport == maxport &&
- p.host.equals(host);
+ if (p.actionmask != actionmask ||
+ p.minport != minport ||
+ p.maxport != maxport)
+ return false;
+
+ if (address != null)
+ {
+ if (p.address == null)
+ return false;
+ else
+ return p.address.equals(address);
+ }
+ else
+ {
+ if (p.hostname == null)
+ return false;
+ else
+ return p.hostname.equals(hostname);
+ }
}
/**
@@ -376,7 +415,12 @@ public final class SocketPermission extends Permission implements Serializable
*/
public int hashCode()
{
- return actionmask + minport + maxport + host.hashCode();
+ int code = actionmask + minport + maxport;
+ if (address != null)
+ code += address.hashCode();
+ else
+ code += hostname.hashCode();
+ return code;
}
/**
@@ -416,6 +460,44 @@ public final class SocketPermission extends Permission implements Serializable
}
/**
+ * Returns an array of all IP addresses represented by this object.
+ */
+ private InetAddress[] getAddresses()
+ {
+ if (address != null)
+ return new InetAddress[] {address};
+
+ try
+ {
+ return InetAddress.getAllByName(hostname);
+ }
+ catch (UnknownHostException e)
+ {
+ return new InetAddress[0];
+ }
+ }
+
+ /**
+ * Returns the canonical hostname represented by this object,
+ * or null if this object represents a wildcarded domain.
+ */
+ private String getCanonicalHostName()
+ {
+ if (address != null)
+ return address.internalGetCanonicalHostName();
+ if (hostname.charAt(0) == '*')
+ return null;
+ try
+ {
+ return InetAddress.getByName(hostname).internalGetCanonicalHostName();
+ }
+ catch (UnknownHostException e)
+ {
+ return null;
+ }
+ }
+
+ /**
* Returns true if the permission object passed it is implied by the
* this permission. This will be true if:
*
@@ -450,6 +532,11 @@ public final class SocketPermission extends Permission implements Serializable
else
return false;
+ // If p was initialised with an empty hostname then we do not
+ // imply it. This is not part of the spec, but it seems necessary.
+ if (p.hostname != null && p.hostname.length() == 0)
+ return false;
+
// Next check the actions
if ((p.actionmask & actionmask) != p.actionmask)
return false;
@@ -459,36 +546,54 @@ public final class SocketPermission extends Permission implements Serializable
return false;
// Finally check the hosts
- if (host.equals(p.host))
- return true;
+ String p_canon = null;
- // Try the canonical names
- String ourcanonical = null;
- String theircanonical = null;
- try
+ // Return true if this object was initialized with a single
+ // IP address which one of p's IP addresses is equal to.
+ if (address != null)
{
- ourcanonical = InetAddress.getByName(host).getHostName();
- theircanonical = InetAddress.getByName(p.host).getHostName();
+ InetAddress[] addrs = p.getAddresses();
+ for (int i = 0; i < addrs.length; i++)
+ {
+ if (address.equals(addrs[i]))
+ return true;
+ }
}
- catch (UnknownHostException e)
+
+ // Return true if this object is a wildcarded domain that
+ // p's canonical name matches.
+ if (hostname != null && hostname.charAt(0) == '*')
{
- // Who didn't resolve? Just assume current address is canonical enough
- // Is this ok to do?
- if (ourcanonical == null)
- ourcanonical = host;
- if (theircanonical == null)
- theircanonical = p.host;
+ p_canon = p.getCanonicalHostName();
+ if (p_canon != null && p_canon.endsWith(hostname.substring(1)))
+ return true;
+
}
- if (ourcanonical.equals(theircanonical))
- return true;
+ // Return true if this one of this object's IP addresses
+ // is equal to one of p's.
+ if (address == null)
+ {
+ InetAddress[] addrs = p.getAddresses();
+ InetAddress[] p_addrs = p.getAddresses();
+
+ for (int i = 0; i < addrs.length; i++)
+ {
+ for (int j = 0; j < p_addrs.length; j++)
+ {
+ if (addrs[i].equals(p_addrs[j]))
+ return true;
+ }
+ }
+ }
- // Well, last chance. Try for a wildcard
- if (host.indexOf("*.") != -1)
+ // Return true if this object's canonical name equals p's.
+ String canon = getCanonicalHostName();
+ if (canon != null)
{
- String wild_domain =
- host.substring(host.indexOf("*" + 1));
- if (theircanonical.endsWith(wild_domain))
+ if (p_canon == null)
+ p_canon = p.getCanonicalHostName();
+ if (p_canon != null && canon.equals(p_canon))
return true;
}
diff --git a/java/nio/channels/spi/AbstractSelectableChannel.java b/java/nio/channels/spi/AbstractSelectableChannel.java
index 847c02cce..5d5277b4a 100644
--- a/java/nio/channels/spi/AbstractSelectableChannel.java
+++ b/java/nio/channels/spi/AbstractSelectableChannel.java
@@ -44,6 +44,7 @@ import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.IllegalBlockingModeException;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
@@ -106,7 +107,15 @@ public abstract class AbstractSelectableChannel extends SelectableChannel
*/
protected final void implCloseChannel() throws IOException
{
- implCloseSelectableChannel();
+ try
+ {
+ implCloseSelectableChannel();
+ }
+ finally
+ {
+ for (Iterator it = keys.iterator(); it.hasNext(); )
+ ((SelectionKey) it.next()).cancel();
+ }
}
/**
@@ -234,8 +243,8 @@ public abstract class AbstractSelectableChannel extends SelectableChannel
if (key != null && key.isValid())
{
- if (att != null)
- key.attach(att);
+ key.interestOps(ops);
+ key.attach(att);
}
else
{
diff --git a/java/text/AttributedCharacterIterator.java b/java/text/AttributedCharacterIterator.java
index 7a87cc556..4f9c762b3 100644
--- a/java/text/AttributedCharacterIterator.java
+++ b/java/text/AttributedCharacterIterator.java
@@ -1,5 +1,5 @@
/* AttributedCharacterIterator.java -- Iterate over attributes
- Copyright (C) 1998, 1999, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -53,6 +53,8 @@ import java.util.Set;
* that is defined for a particular value across an entire range of
* characters or which is undefined over a range of characters.
*
+ * @since 1.2
+ *
* @author Aaron M. Renn (arenn@urbanophile.com)
* @since 1.2
*/
@@ -69,7 +71,7 @@ public interface AttributedCharacterIterator extends CharacterIterator
* This is the attribute for the language of the text. The value of
* attributes of this key type are instances of <code>Locale</code>.
*/
- public static final Attribute LANGUAGE = new Attribute ("LANGUAGE");
+ public static final Attribute LANGUAGE = new Attribute("language");
/**
* This is the attribute for the reading form of text. This is used
@@ -78,7 +80,7 @@ public interface AttributedCharacterIterator extends CharacterIterator
* instances of <code>Annotation</code> which wrappers a
* <code>String</code>.
*/
- public static final Attribute READING = new Attribute ("READING");
+ public static final Attribute READING = new Attribute("reading");
/**
* This is the attribute for input method segments. The value of attributes
@@ -86,7 +88,7 @@ public interface AttributedCharacterIterator extends CharacterIterator
* a <code>String</code>.
*/
public static final Attribute INPUT_METHOD_SEGMENT =
- new Attribute ("INPUT_METHOD_SEGMENT");
+ new Attribute("input_method_segment");
/**
* The name of the attribute key
@@ -99,7 +101,7 @@ public interface AttributedCharacterIterator extends CharacterIterator
*
* @param name The name of this attribute key.
*/
- protected Attribute (String name)
+ protected Attribute(String name)
{
this.name = name;
}
@@ -157,7 +159,7 @@ public interface AttributedCharacterIterator extends CharacterIterator
* @return <code>true</code> if the specified object is equal to this one,
* <code>false</code> otherwise.
*/
- public final boolean equals (Object obj)
+ public final boolean equals(Object obj)
{
if (obj == this)
return true;
@@ -212,7 +214,7 @@ public interface AttributedCharacterIterator extends CharacterIterator
*
* @return The value of the specified attribute
*/
- Object getAttribute (AttributedCharacterIterator.Attribute attrib);
+ Object getAttribute(AttributedCharacterIterator.Attribute attrib);
/**
* Returns the index of the first character in the run that
@@ -231,7 +233,7 @@ public interface AttributedCharacterIterator extends CharacterIterator
*
* @return The start index of the run.
*/
- int getRunStart (Set<? extends Attribute> attribs);
+ int getRunStart(Set<? extends Attribute> attribs);
/**
* Returns the index of the first character in the run that
@@ -241,7 +243,7 @@ public interface AttributedCharacterIterator extends CharacterIterator
*
* @return The start index of the run.
*/
- int getRunStart (AttributedCharacterIterator.Attribute attrib);
+ int getRunStart(AttributedCharacterIterator.Attribute attrib);
/**
* Returns the index of the character after the end of the run
@@ -260,7 +262,7 @@ public interface AttributedCharacterIterator extends CharacterIterator
*
* @return The end index of the run.
*/
- int getRunLimit (Set<? extends Attribute> attribs);
+ int getRunLimit(Set<? extends Attribute> attribs);
/**
* Returns the index of the character after the end of the run
@@ -270,6 +272,6 @@ public interface AttributedCharacterIterator extends CharacterIterator
*
* @return The end index of the run.
*/
- int getRunLimit (AttributedCharacterIterator.Attribute attrib);
+ int getRunLimit(AttributedCharacterIterator.Attribute attrib);
} // interface AttributedCharacterIterator
diff --git a/java/text/AttributedString.java b/java/text/AttributedString.java
index c220f6025..6785bd3c5 100644
--- a/java/text/AttributedString.java
+++ b/java/text/AttributedString.java
@@ -1,5 +1,5 @@
/* AttributedString.java -- Models text with attributes
- Copyright (C) 1998, 1999, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2004, 2005, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -50,6 +50,8 @@ import java.util.Set;
* This class models a <code>String</code> with attributes over various
* subranges of the string. It allows applications to access this
* information via the <code>AttributedCharacterIterator</code> interface.
+ *
+ * @since 1.2
*
* @author Aaron M. Renn (arenn@urbanophile.com)
* @since 1.2
@@ -67,23 +69,23 @@ public class AttributedString
Map attribs;
/** The beginning index of the attributes */
- int begin_index;
+ int beginIndex;
/** The ending index of the attributes */
- int end_index;
+ int endIndex;
/**
* Creates a new attribute range.
*
* @param attribs the attributes.
- * @param begin_index the start index.
- * @param end_index the end index.
+ * @param beginIndex the start index.
+ * @param endIndex the end index.
*/
- AttributeRange(Map attribs, int begin_index, int end_index)
+ AttributeRange(Map attribs, int beginIndex, int endIndex)
{
this.attribs = attribs;
- this.begin_index = begin_index;
- this.end_index = end_index;
+ this.beginIndex = beginIndex;
+ this.endIndex = endIndex;
}
} // Inner class AttributeRange
@@ -149,13 +151,13 @@ public class AttributedString
*
* @param aci The <code>AttributedCharacterIterator</code> containing the
* text and attribute information.
- * @param begin_index The beginning index of the text subrange.
- * @param end_index The ending index of the text subrange.
+ * @param beginIndex The beginning index of the text subrange.
+ * @param endIndex The ending index of the text subrange.
*/
- public AttributedString(AttributedCharacterIterator aci, int begin_index,
- int end_index)
+ public AttributedString(AttributedCharacterIterator aci, int beginIndex,
+ int endIndex)
{
- this(aci, begin_index, end_index, null);
+ this(aci, beginIndex, endIndex, null);
}
/**
@@ -183,9 +185,9 @@ public class AttributedString
StringBuffer sb = new StringBuffer("");
// Get the valid attribute list
- Set all_attribs = aci.getAllAttributeKeys();
+ Set allAttribs = aci.getAllAttributeKeys();
if (attributes != null)
- all_attribs.retainAll(Arrays.asList(attributes));
+ allAttribs.retainAll(Arrays.asList(attributes));
// Loop through and extract the attributes
char c = aci.setIndex(begin);
@@ -195,7 +197,7 @@ public class AttributedString
{
sb.append(c);
- Iterator iter = all_attribs.iterator();
+ Iterator iter = allAttribs.iterator();
while(iter.hasNext())
{
Object obj = iter.next();
@@ -208,9 +210,10 @@ public class AttributedString
(AttributedCharacterIterator.Attribute)obj;
// Make sure the attribute is defined.
- int rl = aci.getRunLimit(attrib);
- if (rl == -1)
+ Object attribObj = aci.getAttribute(attrib);
+ if (attribObj == null)
continue;
+ int rl = aci.getRunLimit(attrib);
if (rl > end)
rl = end;
rl -= begin;
@@ -222,22 +225,21 @@ public class AttributedString
// If the attribute run starts before the beginning index, we
// need to junk it if it is an Annotation.
- Object attrib_obj = aci.getAttribute(attrib);
- rs -= begin;
+ rs -= begin;
if (rs < 0)
{
- if (attrib_obj instanceof Annotation)
+ if (attribObj instanceof Annotation)
continue;
rs = 0;
}
// Create a map object. Yes this will only contain one attribute
- Map new_map = new Hashtable();
- new_map.put(attrib, attrib_obj);
+ Map newMap = new Hashtable();
+ newMap.put(attrib, attribObj);
// Add it to the attribute list.
- accum.add(new AttributeRange(new_map, rs, rl));
+ accum.add(new AttributeRange(newMap, rs, rl));
}
c = aci.next();
@@ -292,28 +294,28 @@ public class AttributedString
* specified subrange of the string.
*
* @param attributes The list of attributes.
- * @param begin_index The beginning index.
- * @param end_index The ending index
+ * @param beginIndex The beginning index.
+ * @param endIndex The ending index
*
* @throws NullPointerException if <code>attributes</code> is
* <code>null</code>.
* @throws IllegalArgumentException if the subrange is not valid.
*/
public void addAttributes(Map<? extends AttributedCharacterIterator.Attribute, ?> attributes,
- int begin_index, int end_index)
+ int beginIndex, int endIndex)
{
if (attributes == null)
throw new NullPointerException("null attribute");
- if ((begin_index < 0) || (end_index > sci.getEndIndex()) ||
- (end_index <= begin_index))
+ if ((beginIndex < 0) || (endIndex > sci.getEndIndex()) ||
+ (endIndex <= beginIndex))
throw new IllegalArgumentException("bad range");
AttributeRange[] new_list = new AttributeRange[attribs.length + 1];
System.arraycopy(attribs, 0, new_list, 0, attribs.length);
attribs = new_list;
- attribs[attribs.length - 1] = new AttributeRange(attributes, begin_index,
- end_index);
+ attribs[attribs.length - 1] = new AttributeRange(attributes, beginIndex,
+ endIndex);
}
/**
@@ -354,20 +356,20 @@ public class AttributedString
* returned.
*
* @param attributes A list of attributes to include in the returned iterator.
- * @param begin_index The beginning index of the subrange.
- * @param end_index The ending index of the subrange.
+ * @param beginIndex The beginning index of the subrange.
+ * @param endIndex The ending index of the subrange.
*
* @return An <code>AttributedCharacterIterator</code> for this string.
*/
public AttributedCharacterIterator getIterator(
AttributedCharacterIterator.Attribute[] attributes,
- int begin_index, int end_index)
+ int beginIndex, int endIndex)
{
- if ((begin_index < 0) || (end_index > sci.getEndIndex()) ||
- (end_index < begin_index))
+ if ((beginIndex < 0) || (endIndex > sci.getEndIndex()) ||
+ (endIndex < beginIndex))
throw new IllegalArgumentException("bad range");
- return(new AttributedStringIterator(sci, attribs, begin_index, end_index,
+ return(new AttributedStringIterator(sci, attribs, beginIndex, endIndex,
attributes));
}
diff --git a/java/text/AttributedStringIterator.java b/java/text/AttributedStringIterator.java
index f6b9b1868..422876c09 100644
--- a/java/text/AttributedStringIterator.java
+++ b/java/text/AttributedStringIterator.java
@@ -1,5 +1,5 @@
/* AttributedStringIterator.java -- Class to iterate over AttributedString
- Copyright (C) 1998, 1999, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2004, 2005, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -71,12 +71,21 @@ class AttributedStringIterator implements AttributedCharacterIterator
/*************************************************************************/
+ /**
+ * Creates a new instance.
+ *
+ * @param sci an iterator for the string content.
+ * @param attribs the attribute ranges.
+ * @param beginIndex the start index.
+ * @param endIndex the end index.
+ * @param restricts the attributes that the user is interested in.
+ */
AttributedStringIterator(StringCharacterIterator sci,
AttributedString.AttributeRange[] attribs,
- int begin_index, int end_index,
+ int beginIndex, int endIndex,
AttributedCharacterIterator.Attribute[] restricts)
{
- this.ci = new StringCharacterIterator(sci, begin_index, end_index);
+ this.ci = new StringCharacterIterator(sci, beginIndex, endIndex);
this.attribs = attribs;
this.restricts = restricts;
}
@@ -154,8 +163,8 @@ class AttributedStringIterator implements AttributedCharacterIterator
for (int i = 0; i < attribs.length; i++)
{
- if (attribs[i].begin_index > getEndIndex()
- || attribs[i].end_index <= getBeginIndex())
+ if (attribs[i].beginIndex > getEndIndex()
+ || attribs[i].endIndex <= getBeginIndex())
continue;
Set key_set = attribs[i].attribs.keySet();
@@ -178,7 +187,7 @@ class AttributedStringIterator implements AttributedCharacterIterator
public int getRunLimit()
{
- return(getRunLimit(getAttributes().keySet()));
+ return getRunLimit(getAllAttributeKeys());
}
public int getRunLimit(AttributedCharacterIterator.Attribute attrib)
@@ -333,7 +342,7 @@ class AttributedStringIterator implements AttributedCharacterIterator
return null;
for (int i = attribs.length - 1; i >= 0; i--)
{
- if (pos >= attribs[i].begin_index && pos < attribs[i].end_index)
+ if (pos >= attribs[i].beginIndex && pos < attribs[i].endIndex)
{
Set keys = attribs[i].attribs.keySet();
if (keys.contains(key))
@@ -373,8 +382,8 @@ class AttributedStringIterator implements AttributedCharacterIterator
for (int i = 0; i < attribs.length; i++)
{
- if ((ci.getIndex() >= attribs[i].begin_index) &&
- (ci.getIndex() < attribs[i].end_index))
+ if ((ci.getIndex() >= attribs[i].beginIndex) &&
+ (ci.getIndex() < attribs[i].endIndex))
m.putAll(attribs[i].attribs);
}
diff --git a/java/util/IdentityHashMap.java b/java/util/IdentityHashMap.java
index e64f7d532..8dead96c1 100644
--- a/java/util/IdentityHashMap.java
+++ b/java/util/IdentityHashMap.java
@@ -97,16 +97,13 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
private static final int DEFAULT_CAPACITY = 21;
/**
- * This object is used to mark deleted items. Package visible for use by
- * nested classes.
+ * This object is used to mark a slot whose key or value is 'null'.
+ * This is more efficient than using a special value to mark an empty
+ * slot, because null entries are rare, empty slots are common, and
+ * the JVM will clear new arrays for us.
+ * Package visible for use by nested classes.
*/
- static final Object tombstone = new Object();
-
- /**
- * This object is used to mark empty slots. We need this because
- * using null is ambiguous. Package visible for use by nested classes.
- */
- static final Object emptyslot = new Object();
+ static final Object nullslot = new Object();
/**
* Compatible with JDK 1.4.
@@ -166,7 +163,6 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
if (max < 2)
max = 2;
table = new Object[max << 1];
- Arrays.fill(table, emptyslot);
threshold = (max >> 2) * 3;
}
@@ -191,7 +187,7 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
if (size != 0)
{
modCount++;
- Arrays.fill(table, emptyslot);
+ Arrays.fill(table, null);
size = 0;
}
}
@@ -227,6 +223,7 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
*/
public boolean containsKey(Object key)
{
+ key = xform(key);
return key == table[hash(key)];
}
@@ -241,6 +238,7 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
*/
public boolean containsValue(Object value)
{
+ value = xform(value);
for (int i = table.length - 1; i > 0; i -= 2)
if (table[i] == value)
return true;
@@ -299,7 +297,9 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
if (! (o instanceof Map.Entry))
return false;
Map.Entry m = (Map.Entry) o;
- return m.getValue() == table[hash(m.getKey()) + 1];
+ Object value = xform(m.getValue());
+ Object key = xform(m.getKey());
+ return value == table[hash(key) + 1];
}
public int hashCode()
@@ -311,14 +311,13 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
{
if (! (o instanceof Map.Entry))
return false;
- Object key = ((Map.Entry) o).getKey();
+ Object key = xform(((Map.Entry) o).getKey());
int h = hash(key);
if (table[h] == key)
{
size--;
modCount++;
- table[h] = tombstone;
- table[h + 1] = tombstone;
+ IdentityHashMap.this.removeAtIndex(h);
return true;
}
return false;
@@ -360,8 +359,9 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
*/
public V get(Object key)
{
+ key = xform(key);
int h = hash(key);
- return (V) (table[h] == key ? table[h + 1] : null);
+ return (V) (table[h] == key ? unxform(table[h + 1]) : null);
}
/**
@@ -378,10 +378,11 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
for (int i = table.length - 2; i >= 0; i -= 2)
{
Object key = table[i];
- if (key == emptyslot || key == tombstone)
+ if (key == null)
continue;
- hash += (System.identityHashCode(key)
- ^ System.identityHashCode(table[i + 1]));
+ // FIXME: this is a lame computation.
+ hash += (System.identityHashCode(unxform(key))
+ ^ System.identityHashCode(unxform(table[i + 1])));
}
return hash;
}
@@ -445,23 +446,22 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
for (int i = table.length - 2; i >= 0; i -= 2)
{
Object key = table[i];
- if (key == emptyslot || key == tombstone)
+ if (key == null)
continue;
- hash += System.identityHashCode(key);
+ hash += System.identityHashCode(unxform(key));
}
return hash;
-
}
public boolean remove(Object o)
{
+ o = xform(o);
int h = hash(o);
if (table[h] == o)
{
size--;
modCount++;
- table[h] = tombstone;
- table[h + 1] = tombstone;
+ removeAtIndex(h);
return true;
}
return false;
@@ -486,6 +486,18 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
*/
public V put(K key, V value)
{
+ key = (K) xform(key);
+ value = (V) xform(value);
+
+ // We don't want to rehash if we're overwriting an existing slot.
+ int h = hash(key);
+ if (table[h] == key)
+ {
+ V r = (V) unxform(table[h + 1]);
+ table[h + 1] = value;
+ return r;
+ }
+
// Rehash if the load factor is too high.
if (size > threshold)
{
@@ -493,25 +505,25 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
// This isn't necessarily prime, but it is an odd number of key/value
// slots, which has a higher probability of fewer collisions.
table = new Object[(old.length * 2) + 2];
- Arrays.fill(table, emptyslot);
size = 0;
threshold = (table.length >>> 3) * 3;
for (int i = old.length - 2; i >= 0; i -= 2)
{
K oldkey = (K) old[i];
- if (oldkey != tombstone && oldkey != emptyslot)
- // Just use put. This isn't very efficient, but it is ok.
- put(oldkey, (V) old[i + 1]);
+ if (oldkey != null)
+ {
+ h = hash(oldkey);
+ table[h] = oldkey;
+ table[h + 1] = old[i + 1];
+ ++size;
+ // No need to update modCount here, we'll do it
+ // just after the loop.
+ }
}
- }
- int h = hash(key);
- if (table[h] == key)
- {
- Object r = table[h + 1];
- table[h + 1] = value;
- return (V) r;
+ // Now that we've resize, recompute the hash value.
+ h = hash(key);
}
// At this point, we add a new mapping.
@@ -536,6 +548,40 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
}
/**
+ * Remove the element at index and update the table to compensate.
+ * This is package-private for use by inner classes.
+ * @param i index of the removed element
+ */
+ final void removeAtIndex(int i)
+ {
+ // This is Algorithm R from Knuth, section 6.4.
+ // Variable names are taken directly from the text.
+ while (true)
+ {
+ table[i] = null;
+ table[i + 1] = null;
+ int j = i;
+ int r;
+ do
+ {
+ i -= 2;
+ if (i < 0)
+ i = table.length - 2;
+ Object key = table[i];
+ if (key == null)
+ return;
+ r = Math.abs(System.identityHashCode(key)
+ % (table.length >> 1)) << 1;
+ }
+ while ((i <= r && r < j)
+ || (r < j && j < i)
+ || (j < i && i <= r));
+ table[j] = table[i];
+ table[j + 1] = table[i + 1];
+ }
+ }
+
+ /**
* Removes from the HashMap and returns the value which is mapped by
* the supplied key. If the key maps to nothing, then the HashMap
* remains unchanged, and <code>null</code> is returned.
@@ -551,14 +597,14 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
*/
public V remove(Object key)
{
+ key = xform(key);
int h = hash(key);
if (table[h] == key)
{
modCount++;
size--;
- Object r = table[h + 1];
- table[h] = tombstone;
- table[h + 1] = tombstone;
+ Object r = unxform(table[h + 1]);
+ removeAtIndex(h);
return (V) r;
}
return null;
@@ -613,13 +659,14 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
public boolean remove(Object o)
{
+ o = xform(o);
+ // This approach may look strange, but it is ok.
for (int i = table.length - 1; i > 0; i -= 2)
if (table[i] == o)
{
modCount++;
- table[i - 1] = tombstone;
- table[i] = tombstone;
size--;
+ IdentityHashMap.this.removeAtIndex(i - 1);
return true;
}
return false;
@@ -629,8 +676,31 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
}
/**
+ * Transform a reference from its external form to its internal form.
+ * This is package-private for use by inner classes.
+ */
+ final Object xform(Object o)
+ {
+ if (o == null)
+ o = nullslot;
+ return o;
+ }
+
+ /**
+ * Transform a reference from its internal form to its external form.
+ * This is package-private for use by inner classes.
+ */
+ final Object unxform(Object o)
+ {
+ if (o == nullslot)
+ o = null;
+ return o;
+ }
+
+ /**
* Helper method which computes the hash code, then traverses the table
- * until it finds the key, or the spot where the key would go.
+ * until it finds the key, or the spot where the key would go. the key
+ * must already be in its internal form.
*
* @param key the key to check
* @return the index where the key belongs
@@ -638,36 +708,23 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
* @see #put(Object, Object)
*/
// Package visible for use by nested classes.
- int hash(Object key)
+ final int hash(Object key)
{
- // Implementation note: it is feasible for the table to have no
- // emptyslots, if it is full with entries and tombstones, so we must
- // remember where we started. If we encounter the key or an emptyslot,
- // we are done. If we encounter a tombstone, the key may still be in
- // the array. If we don't encounter the key, we use the first emptyslot
- // or tombstone we encountered as the location where the key would go.
- // By requiring at least 2 key/value slots, and rehashing at 75%
- // capacity, we guarantee that there will always be either an emptyslot
- // or a tombstone somewhere in the table.
int h = Math.abs(System.identityHashCode(key) % (table.length >> 1)) << 1;
- int del = -1;
- int save = h;
- do
+ while (true)
{
- if (table[h] == key)
+ // By requiring at least 2 key/value slots, and rehashing at 75%
+ // capacity, we guarantee that there will always be either an empty
+ // slot somewhere in the table.
+ if (table[h] == key || table[h] == null)
return h;
- if (table[h] == emptyslot)
- break;
- if (table[h] == tombstone && del < 0)
- del = h;
+ // We use linear probing as it is friendlier to the cache and
+ // it lets us efficiently remove entries.
h -= 2;
if (h < 0)
h = table.length - 2;
}
- while (h != save);
-
- return del < 0 ? h : del;
}
/**
@@ -731,10 +788,11 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
loc -= 2;
key = table[loc];
}
- while (key == emptyslot || key == tombstone);
-
- return (I) (type == KEYS ? key : (type == VALUES ? table[loc + 1]
- : new IdentityEntry(loc)));
+ while (key == null);
+
+ return (I) (type == KEYS ? unxform(key)
+ : (type == VALUES ? unxform(table[loc + 1])
+ : new IdentityEntry(loc)));
}
/**
@@ -748,12 +806,11 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
{
if (knownMod != modCount)
throw new ConcurrentModificationException();
- if (loc == table.length || table[loc] == tombstone)
+ if (loc == table.length)
throw new IllegalStateException();
modCount++;
size--;
- table[loc] = tombstone;
- table[loc + 1] = tombstone;
+ removeAtIndex(loc);
knownMod++;
}
} // class IdentityIterator
@@ -797,12 +854,13 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
*/
public boolean equals(Object o)
{
- if (knownMod != modCount || table[loc] == tombstone)
+ if (knownMod != modCount)
throw new ConcurrentModificationException();
if (! (o instanceof Map.Entry))
return false;
Map.Entry e = (Map.Entry) o;
- return table[loc] == e.getKey() && table[loc + 1] == e.getValue();
+ return table[loc] == xform(e.getKey())
+ && table[loc + 1] == xform(e.getValue());
}
/**
@@ -814,9 +872,9 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
*/
public EK getKey()
{
- if (knownMod != modCount || table[loc] == tombstone)
+ if (knownMod != modCount)
throw new ConcurrentModificationException();
- return (EK) table[loc];
+ return (EK) unxform(table[loc]);
}
/**
@@ -828,9 +886,9 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
*/
public EV getValue()
{
- if (knownMod != modCount || table[loc] == tombstone)
+ if (knownMod != modCount)
throw new ConcurrentModificationException();
- return (EV) table[loc + 1];
+ return (EV) unxform(table[loc + 1]);
}
/**
@@ -844,10 +902,10 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
*/
public int hashCode()
{
- if (knownMod != modCount || table[loc] == tombstone)
+ if (knownMod != modCount)
throw new ConcurrentModificationException();
- return (System.identityHashCode(table[loc])
- ^ System.identityHashCode(table[loc + 1]));
+ return (System.identityHashCode(unxform(table[loc]))
+ ^ System.identityHashCode(unxform(table[loc + 1])));
}
/**
@@ -860,10 +918,10 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
*/
public EV setValue(EV value)
{
- if (knownMod != modCount || table[loc] == tombstone)
+ if (knownMod != modCount)
throw new ConcurrentModificationException();
- EV r = (EV) table[loc + 1];
- table[loc + 1] = value;
+ EV r = (EV) unxform(table[loc + 1]);
+ table[loc + 1] = xform(value);
return r;
}
@@ -877,9 +935,9 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
*/
public String toString()
{
- if (knownMod != modCount || table[loc] == tombstone)
+ if (knownMod != modCount)
throw new ConcurrentModificationException();
- return table[loc] + "=" + table[loc + 1];
+ return unxform(table[loc]) + "=" + unxform(table[loc + 1]);
}
} // class IdentityEntry
@@ -922,10 +980,10 @@ public class IdentityHashMap<K,V> extends AbstractMap<K,V>
for (int i = table.length - 2; i >= 0; i -= 2)
{
Object key = table[i];
- if (key != tombstone && key != emptyslot)
+ if (key != null)
{
- s.writeObject(key);
- s.writeObject(table[i + 1]);
+ s.writeObject(unxform(key));
+ s.writeObject(unxform(table[i + 1]));
}
}
}
diff --git a/java/util/Locale.java b/java/util/Locale.java
index 001c7afde..4c91eeb0a 100644
--- a/java/util/Locale.java
+++ b/java/util/Locale.java
@@ -1,5 +1,5 @@
/* Locale.java -- i18n locales
- Copyright (C) 1998, 1999, 2001, 2002, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2001, 2002, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -188,17 +188,11 @@ public final class Locale implements Serializable, Cloneable
private String variant;
/**
- * This is where the JDK caches its hashcode. This is is only here
- * for serialization purposes. The actual cache is hashcodeCache
+ * This is the cached hashcode. When writing to stream, we write -1.
*
* @serial should be -1 in serial streams
*/
- private int hashcode = -1;
-
- /**
- * This is the cached hashcode.
- */
- private transient int hashcodeCache;
+ private int hashcode;
/**
* Array storing all available locales.
@@ -330,7 +324,7 @@ public final class Locale implements Serializable, Cloneable
this.language = language;
this.country = country;
this.variant = variant;
- hashcodeCache = language.hashCode() ^ country.hashCode() ^ variant.hashCode();
+ hashcode = language.hashCode() ^ country.hashCode() ^ variant.hashCode();
}
/**
@@ -905,7 +899,7 @@ public final class Locale implements Serializable, Cloneable
*/
public int hashCode()
{
- return hashcodeCache;
+ return hashcode;
}
/**
@@ -929,6 +923,24 @@ public final class Locale implements Serializable, Cloneable
}
/**
+ * Write the locale to an object stream.
+ *
+ * @param s the stream to write to
+ * @throws IOException if the write fails
+ * @serialData The first three fields are Strings representing language,
+ * country, and variant. The fourth field is a placeholder for
+ * the cached hashcode, but this is always written as -1, and
+ * recomputed when reading it back.
+ */
+ private void writeObject(ObjectOutputStream s)
+ throws IOException
+ {
+ ObjectOutputStream.PutField fields = s.putFields();
+ fields.put("hashcode", -1);
+ s.defaultWriteObject();
+ }
+
+ /**
* Reads a locale from the input stream.
*
* @param s the stream to read from
@@ -943,6 +955,6 @@ public final class Locale implements Serializable, Cloneable
language = language.intern();
country = country.intern();
variant = variant.intern();
- hashcodeCache = language.hashCode() ^ country.hashCode() ^ variant.hashCode();
+ hashcode = language.hashCode() ^ country.hashCode() ^ variant.hashCode();
}
} // class Locale
diff --git a/java/util/logging/LogManager.java b/java/util/logging/LogManager.java
index 444ab6a26..7ff8c509d 100644
--- a/java/util/logging/LogManager.java
+++ b/java/util/logging/LogManager.java
@@ -318,26 +318,23 @@ public class LogManager
* When adding "foo.bar", the logger "foo.bar.baz" should change
* its parent to "foo.bar".
*/
- if (parent != Logger.root)
+ for (Iterator iter = loggers.keySet().iterator(); iter.hasNext();)
{
- for (Iterator<String> iter = loggers.keySet().iterator();
- iter.hasNext(); )
- {
- Logger possChild = loggers.get(iter.next()).get();
- if ((possChild == null) || (possChild == logger)
- || (possChild.getParent() != parent))
- continue;
-
- if (! possChild.getName().startsWith(name))
- continue;
-
- if (possChild.getName().charAt(name.length()) != '.')
- continue;
-
- possChild.setParent(logger);
- }
+ Logger possChild = (Logger) ((WeakReference) loggers.get(iter.next()))
+ .get();
+ if ((possChild == null) || (possChild == logger)
+ || (possChild.getParent() != parent))
+ continue;
+
+ if (! possChild.getName().startsWith(name))
+ continue;
+
+ if (possChild.getName().charAt(name.length()) != '.')
+ continue;
+
+ possChild.setParent(logger);
}
-
+
return true;
}