diff options
Diffstat (limited to 'libjava/classpath/java/awt')
77 files changed, 6400 insertions, 2892 deletions
diff --git a/libjava/classpath/java/awt/AWTEvent.java b/libjava/classpath/java/awt/AWTEvent.java index d10433cb3c3..a6151b424c1 100644 --- a/libjava/classpath/java/awt/AWTEvent.java +++ b/libjava/classpath/java/awt/AWTEvent.java @@ -103,6 +103,11 @@ public abstract class AWTEvent extends EventObject */ byte[] bdata; + /** + * Indicates if this event is dispatched by the KeyboardFocusManager. + */ + boolean isFocusManagerEvent = false; + /** Mask for selecting component events. */ public static final long COMPONENT_EVENT_MASK = 0x00001; diff --git a/libjava/classpath/java/awt/BasicStroke.java b/libjava/classpath/java/awt/BasicStroke.java index 3e259216fa7..160a3eb0f74 100644 --- a/libjava/classpath/java/awt/BasicStroke.java +++ b/libjava/classpath/java/awt/BasicStroke.java @@ -43,7 +43,6 @@ import gnu.java.awt.java2d.LineSegment; import gnu.java.awt.java2d.QuadSegment; import gnu.java.awt.java2d.Segment; -import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; @@ -118,6 +117,7 @@ public class BasicStroke implements Stroke /** The dash phase. */ private final float phase; + // The inner and outer paths of the stroke private Segment start, end; /** @@ -260,7 +260,7 @@ public class BasicStroke implements Stroke */ public Shape createStrokedShape(Shape s) { - PathIterator pi = s.getPathIterator( new AffineTransform() ); + PathIterator pi = s.getPathIterator(null); if( dash == null ) return solidStroke( pi ); @@ -435,8 +435,8 @@ public class BasicStroke implements Stroke else addSegments(p); - x = coords[0]; - y = coords[1]; + x = coords[2]; + y = coords[3]; break; case PathIterator.SEG_CUBICTO: @@ -452,17 +452,25 @@ public class BasicStroke implements Stroke else addSegments(p); - x = coords[0]; - y = coords[1]; + x = coords[4]; + y = coords[5]; break; case PathIterator.SEG_CLOSE: - p = (new LineSegment(x, y, x0, y0)).getDisplacedSegments(width/2.0); - addSegments(p); + if (x == x0 && y == y0) + { + joinSegments(new Segment[] { start.first, end.first }); + } + else + { + p = (new LineSegment(x, y, x0, y0)).getDisplacedSegments(width / 2.0); + addSegments(p); + } convertPath(output, start); convertPath(output, end); start = end = null; pathOpen = false; + output.setWindingRule(GeneralPath.WIND_EVEN_ODD); break; } pi.next(); @@ -499,7 +507,7 @@ public class BasicStroke implements Stroke } /** - * Convert and add the linked list of Segments in s to a GeneralPath p. + * Append the Segments in s to the GeneralPath p */ private void convertPath(GeneralPath p, Segment s) { @@ -527,18 +535,28 @@ public class BasicStroke implements Stroke p.closePath(); } - + /** - * Add to segments to start and end, joining the outer pair and + * Add the segments to start and end (the inner and outer edges of the stroke) */ private void addSegments(Segment[] segments) { - double[] p0 = start.last.last(); + joinSegments(segments); + start.add(segments[0]); + end.add(segments[1]); + } + + private void joinSegments(Segment[] segments) + { + double[] p0 = start.last.cp2(); double[] p1 = new double[]{start.last.P2.getX(), start.last.P2.getY()}; - double[] p2 = new double[]{segments[0].P1.getX(), segments[0].P1.getY()}; - double[] p3 = segments[0].first(); + double[] p2 = new double[]{segments[0].first.P1.getX(), segments[0].first.P1.getY()}; + double[] p3 = segments[0].cp1(); Point2D p; + p = lineIntersection(p0[0],p0[1],p1[0],p1[1], + p2[0],p2[1],p3[0],p3[1], false); + double det = (p1[0] - p0[0])*(p3[1] - p2[1]) - (p3[0] - p2[0])*(p1[1] - p0[1]); @@ -546,42 +564,14 @@ public class BasicStroke implements Stroke { // start and segment[0] form the 'inner' part of a join, // connect the overlapping segments - p = lineIntersection(p0[0],p0[1],p1[0],p1[1],p2[0],p2[1],p3[0],p3[1], false); - if( p == null ) - { - // Dodgy. - start.add(new LineSegment(start.last.P2, segments[0].P1)); - p = new Point2D.Double((segments[0].P1.getX()+ start.last.P2.getX())/2.0, - (segments[0].P1.getY()+ start.last.P2.getY())/2.0); - } - else - segments[0].P1 = start.last.P2 = p; - - start.add( segments[0] ); - joinSegments(end, segments[1], p); + joinInnerSegments(start, segments[0], p); + joinOuterSegments(end, segments[1], p); } else { // end and segment[1] form the 'inner' part - p0 = end.last.last(); - p1 = new double[]{end.last.P2.getX(), end.last.P2.getY()}; - p2 = new double[]{segments[1].P1.getX(), segments[1].P1.getY()}; - p3 = segments[1].first(); - - p = lineIntersection(p0[0],p0[1],p1[0],p1[1], - p2[0],p2[1],p3[0],p3[1], false); - if( p == null ) - { - // Dodgy. - end.add(new LineSegment(end.last.P2, segments[1].P1)); - p = new Point2D.Double((segments[1].P1.getX()+ end.last.P2.getX())/2.0, - (segments[1].P1.getY()+ end.last.P2.getY())/2.0); - } - else - segments[1].P1 = end.last.P2 = p; - - end.add( segments[1] ); - joinSegments(start, segments[0], p); + joinInnerSegments(end, segments[1], p); + joinOuterSegments(start, segments[0], p); } } @@ -602,7 +592,7 @@ public class BasicStroke implements Stroke break; case CAP_SQUARE: - p0 = a.last.last(); + p0 = a.last.cp2(); p1 = new double[]{a.last.P2.getX(), a.last.P2.getY()}; dx = p1[0] - p0[0]; dy = p1[1] - p0[1]; @@ -617,7 +607,7 @@ public class BasicStroke implements Stroke break; case CAP_ROUND: - p0 = a.last.last(); + p0 = a.last.cp2(); p1 = new double[]{a.last.P2.getX(), a.last.P2.getY()}; dx = p1[0] - p0[0]; dy = p1[1] - p0[1]; @@ -676,7 +666,7 @@ public class BasicStroke implements Stroke * insideP is the inside intersection point of the join, needed for * calculating miter lengths. */ - private void joinSegments(Segment a, Segment b, Point2D insideP) + private void joinOuterSegments(Segment a, Segment b, Point2D insideP) { double[] p0, p1; double dx, dy, l; @@ -685,10 +675,10 @@ public class BasicStroke implements Stroke switch( join ) { case JOIN_MITER: - p0 = a.last.last(); + p0 = a.last.cp2(); p1 = new double[]{a.last.P2.getX(), a.last.P2.getY()}; double[] p2 = new double[]{b.P1.getX(), b.P1.getY()}; - double[] p3 = b.first(); + double[] p3 = b.cp1(); Point2D p = lineIntersection(p0[0],p0[1],p1[0],p1[1],p2[0],p2[1],p3[0],p3[1], true); if( p == null || insideP == null ) a.add(new LineSegment(a.last.P2, b.P1)); @@ -705,7 +695,7 @@ public class BasicStroke implements Stroke break; case JOIN_ROUND: - p0 = a.last.last(); + p0 = a.last.cp2(); p1 = new double[]{a.last.P2.getX(), a.last.P2.getY()}; dx = p1[0] - p0[0]; dy = p1[1] - p0[1]; @@ -715,7 +705,7 @@ public class BasicStroke implements Stroke c1 = new Point2D.Double(p1[0] + dx, p1[1] + dy); p0 = new double[]{b.P1.getX(), b.P1.getY()}; - p1 = b.first(); + p1 = b.cp1(); dx = p0[0] - p1[0]; // backwards direction. dy = p0[1] - p1[1]; @@ -730,6 +720,29 @@ public class BasicStroke implements Stroke a.add(new LineSegment(a.last.P2, b.P1)); break; } - a.add(b); } -} + + /** + * Join a and b segments, removing any overlap + */ + private void joinInnerSegments(Segment a, Segment b, Point2D p) + { + double[] p0 = a.last.cp2(); + double[] p1 = new double[] { a.last.P2.getX(), a.last.P2.getY() }; + double[] p2 = new double[] { b.P1.getX(), b.P1.getY() }; + double[] p3 = b.cp1(); + + if (p == null) + { + // Dodgy. + a.add(new LineSegment(a.last.P2, b.P1)); + p = new Point2D.Double((b.P1.getX() + a.last.P2.getX()) / 2.0, + (b.P1.getY() + a.last.P2.getY()) / 2.0); + } + else + // This assumes segments a and b are single segments, which is + // incorrect - if they are a linked list of segments (ie, passed in + // from a flattening operation), this produces strange results!! + a.last.P2 = b.P1 = p; + } +} diff --git a/libjava/classpath/java/awt/Canvas.java b/libjava/classpath/java/awt/Canvas.java index b599582ba93..843fded44db 100644 --- a/libjava/classpath/java/awt/Canvas.java +++ b/libjava/classpath/java/awt/Canvas.java @@ -68,6 +68,11 @@ public class Canvas * Compatible with Sun's JDK. */ private static final long serialVersionUID = -2284879212465893870L; + + /** + * The number used to generate the name returned by getName. + */ + private static transient long next_canvas_number; /** * The graphics configuration associated with the canvas. @@ -343,4 +348,19 @@ public class Canvas /* Call the paint method */ paint(graphics); } + + /** + * Generate a unique name for this <code>Canvas</code>. + * + * @return A unique name for this <code>Canvas</code>. + */ + String generateName() + { + return "canvas" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_canvas_number++; + } } diff --git a/libjava/classpath/java/awt/CardLayout.java b/libjava/classpath/java/awt/CardLayout.java index 8b3fea2ca23..fcb05215af9 100644 --- a/libjava/classpath/java/awt/CardLayout.java +++ b/libjava/classpath/java/awt/CardLayout.java @@ -350,6 +350,7 @@ public class CardLayout implements LayoutManager2, Serializable } } ((Component) target).setVisible (true); + parent.validate(); } } diff --git a/libjava/classpath/java/awt/CheckboxMenuItem.java b/libjava/classpath/java/awt/CheckboxMenuItem.java index 197065f6535..2df621b71b7 100644 --- a/libjava/classpath/java/awt/CheckboxMenuItem.java +++ b/libjava/classpath/java/awt/CheckboxMenuItem.java @@ -63,6 +63,11 @@ public class CheckboxMenuItem extends MenuItem * Static Variables */ +/** + * The number used to generate the name returned by getName. + */ +private static transient long next_chkmenuitem_number; + // Serialization constant private static final long serialVersionUID = 6190621106981774043L; @@ -352,6 +357,21 @@ paramString() accessibleContext = new AccessibleAWTCheckboxMenuItem(); return accessibleContext; } + + /** + * Generate a unique name for this <code>CheckboxMenuItem</code>. + * + * @return A unique name for this <code>CheckboxMenuItem</code>. + */ + String generateName() + { + return "chkmenuitem" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_chkmenuitem_number++; + } } // class CheckboxMenuItem diff --git a/libjava/classpath/java/awt/Choice.java b/libjava/classpath/java/awt/Choice.java index 90a8d3141c8..f1da94bbeb8 100644 --- a/libjava/classpath/java/awt/Choice.java +++ b/libjava/classpath/java/awt/Choice.java @@ -63,6 +63,11 @@ public class Choice extends Component * Static Variables */ +/** + * The number used to generate the name returned by getName. + */ +private static transient long next_choice_number; + // Serialization constant private static final long serialVersionUID = -4075310674757313071L; @@ -639,4 +644,19 @@ paramString() accessibleContext = new AccessibleAWTChoice(); return accessibleContext; } + + /** + * Generate a unique name for this <code>Choice</code>. + * + * @return A unique name for this <code>Choice</code>. + */ + String generateName() + { + return "choice" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_choice_number++; + } } // class Choice diff --git a/libjava/classpath/java/awt/Component.java b/libjava/classpath/java/awt/Component.java index 3d3dcc319cc..44f277ac783 100644 --- a/libjava/classpath/java/awt/Component.java +++ b/libjava/classpath/java/awt/Component.java @@ -70,6 +70,7 @@ import java.awt.image.ImageProducer; import java.awt.image.VolatileImage; import java.awt.peer.ComponentPeer; import java.awt.peer.LightweightPeer; +import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.IOException; @@ -213,6 +214,12 @@ public abstract class Component */ static final Object treeLock = new String("AWT_TREE_LOCK"); + /** + * The default maximum size. + */ + private static final Dimension DEFAULT_MAX_SIZE + = new Dimension(Short.MAX_VALUE, Short.MAX_VALUE); + // Serialized fields from the serialization spec. /** @@ -427,6 +434,24 @@ public abstract class Component Dimension minSize; /** + * Flag indicating whether the minimum size for the component has been set + * by a call to {@link #setMinimumSize(Dimension)} with a non-null value. + */ + boolean minSizeSet; + + /** + * The maximum size for the component. + * @see #setMaximumSize(Dimension) + */ + Dimension maxSize; + + /** + * A flag indicating whether the maximum size for the component has been set + * by a call to {@link #setMaximumSize(Dimension)} with a non-null value. + */ + boolean maxSizeSet; + + /** * Cached information on the preferred size. Should have been transient. * * @serial ignore @@ -434,6 +459,12 @@ public abstract class Component Dimension prefSize; /** + * Flag indicating whether the preferred size for the component has been set + * by a call to {@link #setPreferredSize(Dimension)} with a non-null value. + */ + boolean prefSizeSet; + + /** * Set to true if an event is to be handled by this component, false if * it is to be passed up the hierarcy. * @@ -563,6 +594,17 @@ public abstract class Component transient BufferStrategy bufferStrategy; /** + * The number of hierarchy listeners of this container plus all of its + * children. This is needed for efficient handling of HierarchyEvents. + * These must be propagated to all child components with HierarchyListeners + * attached. To avoid traversal of the whole subtree, we keep track of + * the number of HierarchyListeners here and only walk the paths that + * actually have listeners. + */ + int numHierarchyListeners; + int numHierarchyBoundsListeners; + + /** * true if requestFocus was called on this component when its * top-level ancestor was not focusable. */ @@ -607,16 +649,19 @@ public abstract class Component } /** - * Sets the name of this component to the specified name. + * Sets the name of this component to the specified name (this is a bound + * property with the name 'name'). * - * @param name the new name of this component + * @param name the new name (<code>null</code> permitted). * @see #getName() * @since 1.1 */ public void setName(String name) { nameExplicitlySet = true; + String old = this.name; this.name = name; + firePropertyChange("name", old, name); } /** @@ -718,7 +763,9 @@ public abstract class Component */ public boolean isValid() { - return valid; + // Tests show that components are invalid as long as they are not showing, even after validate() + // has been called on them. + return peer != null && valid; } /** @@ -804,9 +851,17 @@ public abstract class Component */ public void enable() { - this.enabled = true; - if (peer != null) - peer.setEnabled (true); + if (! enabled) + { + // Need to lock the tree here, because the peers are involved. + synchronized (getTreeLock()) + { + enabled = true; + ComponentPeer p = peer; + if (p != null) + p.enable(); + } + } } /** @@ -831,9 +886,17 @@ public abstract class Component */ public void disable() { - this.enabled = false; - if (peer != null) - peer.setEnabled (false); + if (enabled) + { + // Need to lock the tree here, because the peers are involved. + synchronized (getTreeLock()) + { + enabled = false; + ComponentPeer p = peer; + if (p != null) + p.disable(); + } + } } /** @@ -898,16 +961,38 @@ public abstract class Component // and its children. if(!isVisible()) { - this.visible = true; - // Avoid NullPointerExceptions by creating a local reference. - ComponentPeer currentPeer=peer; - if (currentPeer != null) - currentPeer.show(); - - // The JDK repaints the component before invalidating the parent. - // So do we. - if (isShowing() && isLightweight()) - repaint(); + // Need to lock the tree here to avoid races and inconsistencies. + synchronized (getTreeLock()) + { + visible = true; + // Avoid NullPointerExceptions by creating a local reference. + ComponentPeer currentPeer=peer; + if (currentPeer != null) + { + currentPeer.show(); + + // Fire HierarchyEvent. + fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, + this, parent, + HierarchyEvent.SHOWING_CHANGED); + + // The JDK repaints the component before invalidating the parent. + // So do we. + if (isLightweight()) + repaint(); + } + + // Only post an event if this component actually has a listener + // or has this event explicitly enabled. + if (componentListener != null + || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0) + { + ComponentEvent ce = + new ComponentEvent(this,ComponentEvent.COMPONENT_SHOWN); + getToolkit().getSystemEventQueue().postEvent(ce); + } + } + // Invalidate the parent if we have one. The component itself must // not be invalidated. We also avoid NullPointerException with // a local reference here. @@ -915,9 +1000,6 @@ public abstract class Component if (currentParent != null) currentParent.invalidate(); - ComponentEvent ce = - new ComponentEvent(this,ComponentEvent.COMPONENT_SHOWN); - getToolkit().getSystemEventQueue().postEvent(ce); } } @@ -945,27 +1027,45 @@ public abstract class Component { if (isVisible()) { - // Avoid NullPointerExceptions by creating a local reference. - ComponentPeer currentPeer=peer; - if (currentPeer != null) - currentPeer.setVisible(false); - boolean wasShowing = isShowing(); - this.visible = false; - - // The JDK repaints the component before invalidating the parent. - // So do we. - if (wasShowing) - repaint(); - // Invalidate the parent if we have one. The component itself must + // Need to lock the tree here to avoid races and inconsistencies. + synchronized (getTreeLock()) + { + visible = false; + + // Avoid NullPointerExceptions by creating a local reference. + ComponentPeer currentPeer=peer; + if (currentPeer != null) + { + currentPeer.hide(); + + // Fire hierarchy event. + fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, + this, parent, + HierarchyEvent.SHOWING_CHANGED); + // The JDK repaints the component before invalidating the + // parent. So do we. This only applies for lightweights. + if (peer instanceof LightweightPeer) + repaint(); + } + + // Only post an event if this component actually has a listener + // or has this event explicitly enabled. + if (componentListener != null + || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0) + { + ComponentEvent ce = + new ComponentEvent(this,ComponentEvent.COMPONENT_HIDDEN); + getToolkit().getSystemEventQueue().postEvent(ce); + } + } + + // Invalidate the parent if we have one. The component itself need // not be invalidated. We also avoid NullPointerException with // a local reference here. Container currentParent = parent; if (currentParent != null) currentParent.invalidate(); - ComponentEvent ce = - new ComponentEvent(this,ComponentEvent.COMPONENT_HIDDEN); - getToolkit().getSystemEventQueue().postEvent(ce); } } @@ -1088,16 +1188,13 @@ public abstract class Component */ public void setFont(Font newFont) { - if((newFont != null && (font == null || !font.equals(newFont))) - || newFont == null) - { - Font oldFont = font; - font = newFont; - if (peer != null) - peer.setFont(font); - firePropertyChange("font", oldFont, newFont); - invalidate(); - } + Font oldFont = font; + font = newFont; + if (peer != null) + peer.setFont(font); + firePropertyChange("font", oldFont, newFont); + if (valid) + invalidate(); } /** @@ -1189,8 +1286,15 @@ public abstract class Component throw new IllegalComponentStateException("component " + getClass().getName() + " not showing"); - // We know peer != null here. - return peer.getLocationOnScreen(); + + // Need to lock the tree here. We get crazy races and explosions when + // the tree changes while we are trying to find the location of this + // component. + synchronized (getTreeLock()) + { + // We know peer != null here. + return peer.getLocationOnScreen(); + } } /** @@ -1384,53 +1488,98 @@ public abstract class Component */ public void reshape(int x, int y, int width, int height) { - int oldx = this.x; - int oldy = this.y; - int oldwidth = this.width; - int oldheight = this.height; + // We need to lock the tree here, otherwise we risk races and + // inconsistencies. + synchronized (getTreeLock()) + { + int oldx = this.x; + int oldy = this.y; + int oldwidth = this.width; + int oldheight = this.height; - if (this.x == x && this.y == y && this.width == width - && this.height == height) - return; + boolean resized = oldwidth != width || oldheight != height; + boolean moved = oldx != x || oldy != y; - invalidate(); - - this.x = x; - this.y = y; - this.width = width; - this.height = height; - if (peer != null) - peer.setBounds (x, y, width, height); - - // Erase old bounds and repaint new bounds for lightweights. - if (isLightweight() && isShowing()) - { - if (parent != null) + if (resized || moved) { - Rectangle oldBounds = new Rectangle(oldx, oldy, oldwidth, - oldheight); - Rectangle newBounds = new Rectangle(x, y, width, height); - Rectangle destroyed = oldBounds.union(newBounds); - if (!destroyed.isEmpty()) - parent.repaint(0, destroyed.x, destroyed.y, destroyed.width, - destroyed.height); + // Update the fields. + this.x = x; + this.y = y; + this.width = width; + this.height = height; + + if (peer != null) + { + peer.setBounds (x, y, width, height); + if (resized) + invalidate(); + if (parent != null && parent.valid) + parent.invalidate(); + } + + // Send some events to interested listeners. + notifyReshape(resized, moved); + + // Repaint this component and the parent if appropriate. + if (parent != null && peer instanceof LightweightPeer + && isShowing()) + { + // The parent repaints the area that we occupied before. + parent.repaint(oldx, oldy, oldwidth, oldheight); + // This component repaints the area that we occupy now. + repaint(); + } } } + } - // Only post event if this component is visible and has changed size. - if (isShowing () - && (oldx != x || oldy != y)) + private void notifyReshape(boolean resized, boolean moved) + { + // Only post an event if this component actually has a listener + // or has this event explicitly enabled. + if (componentListener != null + || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0) { - ComponentEvent ce = new ComponentEvent(this, - ComponentEvent.COMPONENT_MOVED); - getToolkit().getSystemEventQueue().postEvent(ce); + // Fire component event on this component. + if (moved) + { + ComponentEvent ce = new ComponentEvent(this, + ComponentEvent.COMPONENT_MOVED); + getToolkit().getSystemEventQueue().postEvent(ce); + } + if (resized) + { + ComponentEvent ce = new ComponentEvent(this, + ComponentEvent.COMPONENT_RESIZED); + getToolkit().getSystemEventQueue().postEvent(ce); + } } - if (isShowing () - && (oldwidth != width || oldheight != height)) + else { - ComponentEvent ce = new ComponentEvent(this, - ComponentEvent.COMPONENT_RESIZED); - getToolkit().getSystemEventQueue().postEvent(ce); + // Otherwise we might need to notify child components when this is + // a Container. + if (this instanceof Container) + { + Container cont = (Container) this; + if (resized) + { + for (int i = 0; i < cont.getComponentCount(); i++) + { + Component child = cont.getComponent(i); + child.fireHierarchyEvent(HierarchyEvent.ANCESTOR_RESIZED, + this, parent, 0); + } + } + if (moved) + { + for (int i = 0; i < cont.getComponentCount(); i++) + { + Component child = cont.getComponent(i); + child.fireHierarchyEvent(HierarchyEvent.ANCESTOR_MOVED, + this, parent, 0); + } + } + } } } @@ -1584,6 +1733,7 @@ public abstract class Component * * @return the component's preferred size * @see #getMinimumSize() + * @see #setPreferredSize(Dimension) * @see LayoutManager */ public Dimension getPreferredSize() @@ -1592,6 +1742,40 @@ public abstract class Component } /** + * Sets the preferred size that will be returned by + * {@link #getPreferredSize()} always, and sends a + * {@link PropertyChangeEvent} (with the property name 'preferredSize') to + * all registered listeners. + * + * @param size the preferred size (<code>null</code> permitted). + * + * @since 1.5 + * + * @see #getPreferredSize() + */ + public void setPreferredSize(Dimension size) + { + Dimension old = prefSizeSet ? prefSize : null; + prefSize = size; + prefSizeSet = (size != null); + firePropertyChange("preferredSize", old, size); + } + + /** + * Returns <code>true</code> if the current preferred size is not + * <code>null</code> and was set by a call to + * {@link #setPreferredSize(Dimension)}, otherwise returns <code>false</code>. + * + * @return A boolean. + * + * @since 1.5 + */ + public boolean isPreferredSizeSet() + { + return prefSizeSet; + } + + /** * Returns the component's preferred size. * * @return the component's preferred size @@ -1599,14 +1783,36 @@ public abstract class Component */ public Dimension preferredSize() { - if (prefSize == null) + // Create a new Dimension object, so that the application doesn't mess + // with the actual values. + return new Dimension(preferredSizeImpl()); + } + + /** + * The actual calculation is pulled out of preferredSize() so that + * we can call it from Container.preferredSize() and avoid creating a + * new intermediate Dimension object. + * + * @return the preferredSize of the component + */ + Dimension preferredSizeImpl() + { + Dimension size = prefSize; + // Try to use a cached value. + if (size == null || !(valid || prefSizeSet)) { - if (peer == null) - prefSize = minimumSize(); - else - prefSize = peer.getPreferredSize(); + // We need to lock here, because the calculation depends on the + // component structure not changing. + synchronized (getTreeLock()) + { + ComponentPeer p = peer; + if (p != null) + size = peer.preferredSize(); + else + size = minimumSizeImpl(); + } } - return prefSize; + return size; } /** @@ -1614,6 +1820,7 @@ public abstract class Component * * @return the component's minimum size * @see #getPreferredSize() + * @see #setMinimumSize(Dimension) * @see LayoutManager */ public Dimension getMinimumSize() @@ -1622,6 +1829,39 @@ public abstract class Component } /** + * Sets the minimum size that will be returned by {@link #getMinimumSize()} + * always, and sends a {@link PropertyChangeEvent} (with the property name + * 'minimumSize') to all registered listeners. + * + * @param size the minimum size (<code>null</code> permitted). + * + * @since 1.5 + * + * @see #getMinimumSize() + */ + public void setMinimumSize(Dimension size) + { + Dimension old = minSizeSet ? minSize : null; + minSize = size; + minSizeSet = (size != null); + firePropertyChange("minimumSize", old, size); + } + + /** + * Returns <code>true</code> if the current minimum size is not + * <code>null</code> and was set by a call to + * {@link #setMinimumSize(Dimension)}, otherwise returns <code>false</code>. + * + * @return A boolean. + * + * @since 1.5 + */ + public boolean isMinimumSizeSet() + { + return minSizeSet; + } + + /** * Returns the component's minimum size. * * @return the component's minimum size @@ -1629,10 +1869,36 @@ public abstract class Component */ public Dimension minimumSize() { - if (minSize == null) - minSize = (peer != null ? peer.getMinimumSize() - : new Dimension(width, height)); - return minSize; + // Create a new Dimension object, so that the application doesn't mess + // with the actual values. + return new Dimension(minimumSizeImpl()); + } + + /** + * The actual calculation is pulled out of minimumSize() so that + * we can call it from Container.preferredSize() and + * Component.preferredSizeImpl and avoid creating a + * new intermediate Dimension object. + * + * @return the minimum size of the component + */ + Dimension minimumSizeImpl() + { + Dimension size = minSize; + if (size == null || !(valid || minSizeSet)) + { + // We need to lock here, because the calculation depends on the + // component structure not changing. + synchronized (getTreeLock()) + { + ComponentPeer p = peer; + if (p != null) + size = peer.minimumSize(); + else + size = size(); + } + } + return size; } /** @@ -1640,15 +1906,66 @@ public abstract class Component * * @return the component's maximum size * @see #getMinimumSize() + * @see #setMaximumSize(Dimension) * @see #getPreferredSize() * @see LayoutManager */ public Dimension getMaximumSize() { - return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE); + return new Dimension(maximumSizeImpl()); + } + + /** + * This is pulled out from getMaximumSize(), so that we can access it + * from Container.getMaximumSize() without creating an additional + * intermediate Dimension object. + * + * @return the maximum size of the component + */ + Dimension maximumSizeImpl() + { + Dimension size; + if (maxSizeSet) + size = maxSize; + else + size = DEFAULT_MAX_SIZE; + return size; + } + + /** + * Sets the maximum size that will be returned by {@link #getMaximumSize()} + * always, and sends a {@link PropertyChangeEvent} (with the property name + * 'maximumSize') to all registered listeners. + * + * @param size the maximum size (<code>null</code> permitted). + * + * @since 1.5 + * + * @see #getMaximumSize() + */ + public void setMaximumSize(Dimension size) + { + Dimension old = maxSizeSet ? maxSize : null; + maxSize = size; + maxSizeSet = (size != null); + firePropertyChange("maximumSize", old, size); } /** + * Returns <code>true</code> if the current maximum size is not + * <code>null</code> and was set by a call to + * {@link #setMaximumSize(Dimension)}, otherwise returns <code>false</code>. + * + * @return A boolean. + * + * @since 1.5 + */ + public boolean isMaximumSizeSet() + { + return maxSizeSet; + } + + /** * Returns the preferred horizontal alignment of this component. The value * returned will be between {@link #LEFT_ALIGNMENT} and * {@link #RIGHT_ALIGNMENT}, inclusive. @@ -1716,11 +2033,25 @@ public abstract class Component */ public void invalidate() { - valid = false; - prefSize = null; - minSize = null; - if (parent != null && parent.isValid()) - parent.invalidate(); + // Need to lock here, to avoid races and other ugly stuff when doing + // layout or structure changes in other threads. + synchronized (getTreeLock()) + { + // Invalidate. + valid = false; + + // Throw away cached layout information. + if (! minSizeSet) + minSize = null; + if (! prefSizeSet) + prefSize = null; + if (! maxSizeSet) + maxSize = null; + + // Also invalidate the parent, if it hasn't already been invalidated. + if (parent != null && parent.isValid()) + parent.invalidate(); + } } /** @@ -1826,11 +2157,9 @@ public abstract class Component } /** - * Updates this component. This is called in response to - * <code>repaint</code>. This method fills the component with the - * background color, then sets the foreground color of the specified - * graphics context to the foreground color of this component and calls - * the <code>paint()</code> method. The coordinates of the graphics are + * Updates this component. This is called for heavyweight components in + * response to {@link #repaint()}. The default implementation simply forwards + * to {@link #paint(Graphics)}. The coordinates of the graphics are * relative to this component. Subclasses should call either * <code>super.update(g)</code> or <code>paint(g)</code>. * @@ -1838,27 +2167,17 @@ public abstract class Component * * @see #paint(Graphics) * @see #repaint() - * - * @specnote In contrast to what the spec says, tests show that the exact - * behaviour is to clear the background on lightweight and - * top-level components only. Heavyweight components are not - * affected by this method and only call paint(). */ public void update(Graphics g) { - // Tests show that the clearing of the background is only done in - // two cases: - // - If the component is lightweight (yes this is in contrast to the spec). - // or - // - If the component is a toplevel container. - if (isLightweight() || getParent() == null) - { - Rectangle clip = g.getClipBounds(); - if (clip == null) - g.clearRect(0, 0, width, height); - else - g.clearRect(clip.x, clip.y, clip.width, clip.height); - } + // Note 1: We used to clear the background here for lightweights and + // toplevel components. Tests show that this is not what the JDK does + // here. Note that there is some special handling and background + // clearing code in Container.update(Graphics). + + // Note 2 (for peer implementors): The JDK doesn't seem call update() for + // toplevel components, even when an UPDATE event is sent (as a result + // of repaint). paint(g); } @@ -1934,11 +2253,46 @@ public abstract class Component */ public void repaint(long tm, int x, int y, int width, int height) { - if (isShowing()) + // The repaint() call has previously been delegated to + // {@link ComponentPeer.repaint()}. Testing on the JDK using some + // dummy peers show that this methods is never called. I think it makes + // sense to actually perform the tasks below here, since it's pretty + // much peer independent anyway, and makes sure only heavyweights are + // bothered by this. + ComponentPeer p = peer; + + // Let the nearest heavyweight parent handle repainting for lightweight + // components. + // 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) + { + 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.peer; + } + + // Now send an UPDATE event to the heavyweight component that we've found. + if (par != null && par.isVisible() && p != null && pw > 0 && ph > 0) { - ComponentPeer p = peer; - if (p != null) - p.repaint(tm, x, y, width, height); + assert ! (p instanceof LightweightPeer); + PaintEvent pe = new PaintEvent(par, PaintEvent.UPDATE, + new Rectangle(px, py, pw, ph)); + getToolkit().getSystemEventQueue().postEvent(pe); } } @@ -1957,10 +2311,7 @@ public abstract class Component } /** - * Prints this component, including all sub-components. This method is - * provided so that printing can be done in a different manner from - * painting. However, the implementation in this class simply calls the - * <code>paintAll()</code> method. + * Prints this component, including all sub-components. * * @param g the graphics context of the print device * @@ -1968,7 +2319,9 @@ public abstract class Component */ public void printAll(Graphics g) { - paintAll(g); + if( peer != null ) + peer.print( g ); + paintAll( g ); } /** @@ -2318,6 +2671,17 @@ public abstract class Component } /** + * By default, no old mouse events should be ignored. + * This can be overridden by subclasses. + * + * @return false, no mouse events are ignored. + */ + static boolean ignoreOldMouseEvents() + { + return false; + } + + /** * AWT 1.0 event handler. * * This method simply calls handleEvent and returns the result. @@ -2449,6 +2813,14 @@ public abstract class Component 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()) + { + numHierarchyListeners++; + if (parent != null) + parent.updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK, 1); + } } /** @@ -2464,6 +2836,15 @@ public abstract class Component public synchronized void removeHierarchyListener(HierarchyListener listener) { hierarchyListener = AWTEventMulticaster.remove(hierarchyListener, listener); + + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyListeners--; + if (parent != null) + parent.updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK, + -1); + } } /** @@ -2499,6 +2880,16 @@ public abstract class Component 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()) + { + numHierarchyBoundsListeners++; + if (parent != null) + parent.updateHierarchyListenerCount + (AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, + 1); + } } /** @@ -2516,6 +2907,16 @@ public abstract class Component { hierarchyBoundsListener = AWTEventMulticaster.remove(hierarchyBoundsListener, listener); + + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyBoundsListeners--; + if (parent != null) + parent.updateHierarchyListenerCount + (AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, + -1); + } } /** @@ -2534,6 +2935,40 @@ public abstract class Component } /** + * Fires a HierarchyEvent or HierarchyChangeEvent on this component. + * + * @param id the event id + * @param changed the changed component + * @param parent the parent + * @param flags the event flags + */ + void fireHierarchyEvent(int id, Component changed, Container parent, + long flags) + { + boolean enabled = false; + switch (id) + { + case HierarchyEvent.HIERARCHY_CHANGED: + enabled = hierarchyListener != null + || (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) != 0; + break; + case HierarchyEvent.ANCESTOR_MOVED: + case HierarchyEvent.ANCESTOR_RESIZED: + enabled = hierarchyBoundsListener != null + || (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0; + break; + default: + assert false : "Should not reach here"; + } + if (enabled) + { + HierarchyEvent ev = new HierarchyEvent(this, id, changed, parent, + flags); + dispatchEvent(ev); + } + } + + /** * Adds the specified listener to this component. This is harmless if the * listener is null, but if the listener has already been registered, it * will now be registered twice. @@ -3435,18 +3870,24 @@ public abstract class Component */ public void addNotify() { - if (peer == null) - peer = getToolkit().createComponent(this); - else if (parent != null && parent.isLightweight()) - new HeavyweightInLightweightListener(parent); - /* Now that all the children has gotten their peers, we should + // We need to lock the tree here to avoid races and inconsistencies. + synchronized (getTreeLock()) + { + if (peer == null) + peer = getToolkit().createComponent(this); + else if (parent != null && parent.isLightweight()) + new HeavyweightInLightweightListener(parent); + /* Now that all the children has gotten their peers, we should have the event mask needed for this component and its lightweight subcomponents. */ - peer.setEventMask(eventMask); - /* We do not invalidate here, but rather leave that job up to + 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); + } } /** @@ -3460,17 +3901,21 @@ public abstract class Component */ public void removeNotify() { - // We null our peer field before disposing of it, such that if we're - // not the event dispatch thread and the dispatch thread is awoken by - // the dispose call, there will be no race checking the peer's null - // status. - - ComponentPeer tmp = peer; - peer = null; - if (tmp != null) + // We need to lock the tree here to avoid races and inconsistencies. + synchronized (getTreeLock()) { - tmp.hide(); - tmp.dispose(); + // We null our peer field before disposing of it, such that if we're + // not the event dispatch thread and the dispatch thread is awoken by + // the dispose call, there will be no race checking the peer's null + // status. + + ComponentPeer tmp = peer; + peer = null; + if (tmp != null) + { + tmp.hide(); + tmp.dispose(); + } } } @@ -3791,56 +4236,7 @@ public abstract class Component */ public void requestFocus () { - if (isDisplayable () - && isShowing () - && isFocusable ()) - { - synchronized (getTreeLock ()) - { - // Find this Component's top-level ancestor. - Container parent = (this instanceof Container) ? (Container) this - : getParent(); - while (parent != null - && !(parent instanceof Window)) - parent = parent.getParent (); - - if (parent == null) - return; - - Window toplevel = (Window) parent; - if (toplevel.isFocusableWindow ()) - { - if (peer != null && !isLightweight()) - // This call will cause a FOCUS_GAINED event to be - // posted to the system event queue if the native - // windowing system grants the focus request. - peer.requestFocus (); - else - { - // Either our peer hasn't been created yet or we're a - // lightweight component. In either case we want to - // post a FOCUS_GAINED event. - EventQueue eq = Toolkit.getDefaultToolkit ().getSystemEventQueue (); - synchronized (eq) - { - KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); - Component currentFocusOwner = manager.getGlobalPermanentFocusOwner (); - if (currentFocusOwner != null) - { - eq.postEvent (new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST, - false, this)); - eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED, false, - currentFocusOwner)); - } - else - eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED, false)); - } - } - } - else - pendingFocusRequest = new FocusEvent(this, FocusEvent.FOCUS_GAINED); - } - } + requestFocusImpl(false, true); } /** @@ -3880,61 +4276,7 @@ public abstract class Component */ protected boolean requestFocus (boolean temporary) { - if (isDisplayable () - && isShowing () - && isFocusable ()) - { - synchronized (getTreeLock ()) - { - // Find this Component's top-level ancestor. - Container parent = getParent (); - - while (parent != null - && !(parent instanceof Window)) - parent = parent.getParent (); - - Window toplevel = (Window) parent; - if (toplevel.isFocusableWindow ()) - { - if (peer != null && !isLightweight()) - // This call will cause a FOCUS_GAINED event to be - // posted to the system event queue if the native - // windowing system grants the focus request. - peer.requestFocus (); - else - { - // Either our peer hasn't been created yet or we're a - // lightweight component. In either case we want to - // post a FOCUS_GAINED event. - EventQueue eq = Toolkit.getDefaultToolkit ().getSystemEventQueue (); - synchronized (eq) - { - KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); - Component currentFocusOwner = manager.getGlobalPermanentFocusOwner (); - if (currentFocusOwner != null) - { - eq.postEvent (new FocusEvent(currentFocusOwner, - FocusEvent.FOCUS_LOST, - temporary, this)); - eq.postEvent (new FocusEvent(this, - FocusEvent.FOCUS_GAINED, - temporary, - currentFocusOwner)); - } - else - eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED, temporary)); - } - } - } - else - // FIXME: need to add a focus listener to our top-level - // ancestor, so that we can post this event when it becomes - // the focused window. - pendingFocusRequest = new FocusEvent(this, FocusEvent.FOCUS_GAINED, temporary); - } - } - // Always return true. - return true; + return requestFocusImpl(temporary, true); } /** @@ -3962,7 +4304,7 @@ public abstract class Component */ public boolean requestFocusInWindow () { - return requestFocusInWindow (false); + return requestFocusImpl(false, false); } /** @@ -3993,65 +4335,84 @@ public abstract class Component */ protected boolean requestFocusInWindow (boolean temporary) { - KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); - - Window focusedWindow = manager.getFocusedWindow (); + return requestFocusImpl(temporary, false); + } - if (isDisplayable () - && isShowing () - && isFocusable ()) + /** + * Helper method for all 4 requestFocus variants. + * + * @param temporary indicates if the focus change is temporary + * @param focusWindow indicates if the window focus may be changed + * + * @return <code>false</code> if the request has been definitely denied, + * <code>true</code> otherwise + */ + private boolean requestFocusImpl(boolean temporary, boolean focusWindow) + { + boolean retval = false; + + // Don't try to focus non-focusable and non-visible components. + if (isFocusable() && isVisible()) { - if (focusedWindow != null) + ComponentPeer myPeer = peer; + if (peer != null) { - synchronized (getTreeLock ()) + // Find Window ancestor and find out if we're showing while + // doing this. + boolean showing = true; + Component window = this; + while (! (window instanceof Window)) { - Container parent = getParent (); - - while (parent != null - && !(parent instanceof Window)) - parent = parent.getParent (); - - Window toplevel = (Window) parent; - - // Check if top-level ancestor is currently focused window. - if (focusedWindow == toplevel) + if (! window.isVisible()) + showing = false; + window = window.parent; + } + // Don't allow focus when there is no window or the window + // is not focusable. + if (window != null && ((Window) window).isFocusableWindow() + && showing) + { + // Search for nearest heavy ancestor (including this + // component). + Component heavyweightParent = this; + while (heavyweightParent.peer instanceof LightweightPeer) + heavyweightParent = heavyweightParent.parent; + + // Don't allow focus on lightweight components without + // visible heavyweight ancestor + if (heavyweightParent != null && heavyweightParent.isVisible()) { - if (peer != null - && !isLightweight() - && !(this instanceof Window)) - // This call will cause a FOCUS_GAINED event to be - // posted to the system event queue if the native - // windowing system grants the focus request. - peer.requestFocus (); - else + // Don't allow focus when heavyweightParent has no peer. + myPeer = heavyweightParent.peer; + if (myPeer != null) { - // Either our peer hasn't been created yet or we're a - // lightweight component. In either case we want to - // post a FOCUS_GAINED event. - EventQueue eq = Toolkit.getDefaultToolkit ().getSystemEventQueue (); - synchronized (eq) + // Register lightweight focus request. + if (heavyweightParent != this) + { + KeyboardFocusManager + .addLightweightFocusRequest(heavyweightParent, + this); + } + + // Try to focus the component. + long time = EventQueue.getMostRecentEventTime(); + boolean success = myPeer.requestFocus(this, temporary, + focusWindow, + time); + if (! success) { - Component currentFocusOwner = manager.getGlobalPermanentFocusOwner (); - if (currentFocusOwner != null) - { - eq.postEvent (new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST, - temporary, this)); - eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED, temporary, - currentFocusOwner)); - } - else - eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED, temporary)); + // Dequeue key events if focus request failed. + KeyboardFocusManager kfm = + KeyboardFocusManager.getCurrentKeyboardFocusManager(); + kfm.dequeueKeyEvents(time, this); } + retval = success; } } - else - return false; } } - - return true; } - return false; + return retval; } /** @@ -4552,7 +4913,7 @@ p * <li>the set of backward traversal keys Object newValue) { if (changeSupport != null) - changeSupport.firePropertyChange(propertyName, oldValue, newValue); + changeSupport.firePropertyChange(propertyName, oldValue, newValue); } /** @@ -4693,14 +5054,12 @@ p * <li>the set of backward traversal keys * {@link #applyComponentOrientation(ComponentOrientation)} affects the * entire hierarchy. * - * @param o the new orientation - * @throws NullPointerException if o is null + * @param o the new orientation (<code>null</code> is accepted) * @see #getComponentOrientation() */ public void setComponentOrientation(ComponentOrientation o) { - if (o == null) - throw new NullPointerException(); + ComponentOrientation oldOrientation = orientation; orientation = o; firePropertyChange("componentOrientation", oldOrientation, o); @@ -4709,7 +5068,7 @@ p * <li>the set of backward traversal keys /** * Determines the text layout orientation used by this component. * - * @return the component orientation + * @return the component orientation (this can be <code>null</code>) * @see #setComponentOrientation(ComponentOrientation) */ public ComponentOrientation getComponentOrientation() @@ -4864,7 +5223,7 @@ p * <li>the set of backward traversal keys if ((mods & InputEvent.ALT_DOWN_MASK) != 0) oldMods |= Event.ALT_MASK; - if (e instanceof MouseEvent) + if (e instanceof MouseEvent && !ignoreOldMouseEvents()) { if (id == MouseEvent.MOUSE_PRESSED) oldID = Event.MOUSE_DOWN; @@ -5045,52 +5404,26 @@ p * <li>the set of backward traversal keys void dispatchEventImpl(AWTEvent e) { - // This boolean tells us not to process focus events when the focus - // opposite component is the same as the focus component. - boolean ignoreFocus = - (e instanceof FocusEvent && - ((FocusEvent)e).getComponent() == ((FocusEvent)e).getOppositeComponent()); - - if (eventTypeEnabled (e.id)) + // Retarget focus events before dispatching it to the KeyboardFocusManager + // in order to handle lightweight components properly. + boolean dispatched = false; + if (! e.isFocusManagerEvent) { - if (e.id != PaintEvent.PAINT && e.id != PaintEvent.UPDATE - && !ignoreFocus) - processEvent(e); - - // the trick we use to communicate between dispatch and redispatch - // is to have KeyboardFocusManager.redispatch synchronize on the - // object itself. we then do not redispatch to KeyboardFocusManager - // if we are already holding the lock. - if (! Thread.holdsLock(e)) + e = KeyboardFocusManager.retargetFocusEvent(e); + dispatched = KeyboardFocusManager.getCurrentKeyboardFocusManager() + .dispatchEvent(e); + } + + if (! dispatched) + { + if (eventTypeEnabled (e.id)) { - switch (e.id) - { - case WindowEvent.WINDOW_GAINED_FOCUS: - case WindowEvent.WINDOW_LOST_FOCUS: - case KeyEvent.KEY_PRESSED: - case KeyEvent.KEY_RELEASED: - case KeyEvent.KEY_TYPED: - case FocusEvent.FOCUS_GAINED: - case FocusEvent.FOCUS_LOST: - if (KeyboardFocusManager - .getCurrentKeyboardFocusManager() - .dispatchEvent(e)) - return; - case MouseEvent.MOUSE_PRESSED: - // A mouse click on an enabled lightweight component - // which has not yet been marked as consumed by any - // other mouse listener results in a focus traversal - // to that component. - if (isLightweight() - && isEnabled() && !e.isConsumed()) - requestFocus(); - break; - } + if (e.id != PaintEvent.PAINT && e.id != PaintEvent.UPDATE) + processEvent(e); } + if (peer != null) + peer.handleEvent(e); } - - if (peer != null) - peer.handleEvent(e); } /** diff --git a/libjava/classpath/java/awt/Container.java b/libjava/classpath/java/awt/Container.java index 85a68ce13c2..409d164a13c 100644 --- a/libjava/classpath/java/awt/Container.java +++ b/libjava/classpath/java/awt/Container.java @@ -42,6 +42,7 @@ package java.awt; import java.awt.event.ComponentListener; import java.awt.event.ContainerEvent; import java.awt.event.ContainerListener; +import java.awt.event.HierarchyEvent; import java.awt.event.KeyEvent; import java.awt.peer.ComponentPeer; import java.awt.peer.ContainerPeer; @@ -88,14 +89,16 @@ public class Container extends Component Dimension maxSize; /** - * Keeps track if the Container was cleared during a paint/update. + * @since 1.4 */ - private boolean backCleared; + boolean focusCycleRoot; /** - * @since 1.4 + * Indicates if this container provides a focus traversal policy. + * + * @since 1.5 */ - boolean focusCycleRoot; + private boolean focusTraversalPolicyProvider; int containerSerializedDataVersion; @@ -341,7 +344,7 @@ public class Container extends Component if (component == null) component = new Component[4]; // FIXME, better initial size? - + // This isn't the most efficient implementation. We could do less // copying when growing the array. It probably doesn't matter. if (ncomponents >= component.length) @@ -362,6 +365,16 @@ public class Container extends Component ++ncomponents; } + // Update the counter for Hierarchy(Bounds)Listeners. + int childHierarchyListeners = comp.numHierarchyListeners; + if (childHierarchyListeners > 0) + updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK, + childHierarchyListeners); + int childHierarchyBoundsListeners = comp.numHierarchyBoundsListeners; + if (childHierarchyBoundsListeners > 0) + updateHierarchyListenerCount(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, + childHierarchyListeners); + // Notify the layout manager. if (layoutMgr != null) { @@ -388,6 +401,10 @@ public class Container extends Component ContainerListener[] listeners = getContainerListeners(); for (int i = 0; i < listeners.length; i++) listeners[i].componentAdded(ce); + + // Notify hierarchy listeners. + comp.fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, comp, + this, HierarchyEvent.PARENT_CHANGED); } } @@ -412,6 +429,16 @@ public class Container extends Component ncomponents - index - 1); 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); + invalidate(); if (layoutMgr != null) @@ -423,10 +450,14 @@ public class Container extends Component { // Post event to notify of removing the component. ContainerEvent ce = new ContainerEvent(this, - ContainerEvent.COMPONENT_REMOVED, - r); + ContainerEvent.COMPONENT_REMOVED, + r); getToolkit().getSystemEventQueue().postEvent(ce); } + + // Notify hierarchy listeners. + r.fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, r, + this, HierarchyEvent.PARENT_CHANGED); } } @@ -517,7 +548,8 @@ public class Container extends Component public void setLayout(LayoutManager mgr) { layoutMgr = mgr; - invalidate(); + if (valid) + invalidate(); } /** @@ -572,19 +604,22 @@ public class Container extends Component */ void invalidateTree() { - super.invalidate(); // Clean cached layout state. - for (int i = 0; i < ncomponents; i++) + synchronized (getTreeLock()) { - Component comp = component[i]; - comp.invalidate(); - if (comp instanceof Container) - ((Container) comp).invalidateTree(); - } + 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(); + } - if (layoutMgr != null && layoutMgr instanceof LayoutManager2) - { - LayoutManager2 lm2 = (LayoutManager2) layoutMgr; - lm2.invalidateLayout(this); + if (layoutMgr != null && layoutMgr instanceof LayoutManager2) + { + LayoutManager2 lm2 = (LayoutManager2) layoutMgr; + lm2.invalidateLayout(this); + } } } @@ -671,21 +706,25 @@ public class Container extends Component */ public Dimension preferredSize() { - synchronized(treeLock) - { - if(valid && prefSize != null) - return new Dimension(prefSize); - LayoutManager layout = getLayout(); - if (layout != null) + Dimension size = prefSize; + // Try to return cached value if possible. + if (size == null || !(prefSizeSet || valid)) + { + // Need to lock here. + synchronized (getTreeLock()) { - Dimension layoutSize = layout.preferredLayoutSize(this); - if(valid) - prefSize = layoutSize; - return new Dimension(layoutSize); + LayoutManager l = layoutMgr; + if (l != null) + prefSize = l.preferredLayoutSize(this); + else + prefSize = super.preferredSizeImpl(); + size = prefSize; } - else - return super.preferredSize (); } + if (size != null) + return new Dimension(size); + else + return size; } /** @@ -707,17 +746,25 @@ public class Container extends Component */ public Dimension minimumSize() { - if(valid && minSize != null) - return new Dimension(minSize); - - LayoutManager layout = getLayout(); - if (layout != null) + Dimension size = minSize; + // Try to return cached value if possible. + if (size == null || !(minSizeSet || valid)) { - minSize = layout.minimumLayoutSize (this); - return minSize; - } + // Need to lock here. + synchronized (getTreeLock()) + { + LayoutManager l = layoutMgr; + if (l != null) + minSize = l.minimumLayoutSize(this); + else + minSize = super.minimumSizeImpl(); + size = minSize; + } + } + if (size != null) + return new Dimension(size); else - return super.minimumSize (); + return size; } /** @@ -727,18 +774,25 @@ public class Container extends Component */ public Dimension getMaximumSize() { - if (valid && maxSize != null) - return new Dimension(maxSize); - - LayoutManager layout = getLayout(); - if (layout != null && layout instanceof LayoutManager2) + Dimension size = maxSize; + // Try to return cached value if possible. + if (size == null || !(maxSizeSet || valid)) { - LayoutManager2 lm2 = (LayoutManager2) layout; - maxSize = lm2.maximumLayoutSize(this); - return maxSize; + // Need to lock here. + synchronized (getTreeLock()) + { + LayoutManager l = layoutMgr; + if (l instanceof LayoutManager2) + maxSize = ((LayoutManager2) l).maximumLayoutSize(this); + else + maxSize = super.maximumSizeImpl(); + size = maxSize; + } } + if (size != null) + return new Dimension(size); else - return super.getMaximumSize(); + return size; } /** @@ -754,8 +808,11 @@ public class Container extends Component float alignmentX = 0.0F; if (layout != null && layout instanceof LayoutManager2) { - LayoutManager2 lm2 = (LayoutManager2) layout; - alignmentX = lm2.getLayoutAlignmentX(this); + synchronized (getTreeLock()) + { + LayoutManager2 lm2 = (LayoutManager2) layout; + alignmentX = lm2.getLayoutAlignmentX(this); + } } else alignmentX = super.getAlignmentX(); @@ -775,8 +832,11 @@ public class Container extends Component float alignmentY = 0.0F; if (layout != null && layout instanceof LayoutManager2) { - LayoutManager2 lm2 = (LayoutManager2) layout; - alignmentY = lm2.getLayoutAlignmentY(this); + synchronized (getTreeLock()) + { + LayoutManager2 lm2 = (LayoutManager2) layout; + alignmentY = lm2.getLayoutAlignmentY(this); + } } else alignmentY = super.getAlignmentY(); @@ -794,13 +854,10 @@ public class Container extends Component */ public void paint(Graphics g) { - if (!isShowing()) - return; - - // Visit heavyweights if the background was cleared - // for this container. - visitChildren(g, GfxPaintVisitor.INSTANCE, !backCleared); - backCleared = false; + if (isShowing()) + { + visitChildren(g, GfxPaintVisitor.INSTANCE, true); + } } /** @@ -830,14 +887,15 @@ public class Container extends Component // that overrides isLightweight() to return false, the background is // also not cleared. So we do a check on !(peer instanceof LightweightPeer) // instead. - ComponentPeer p = peer; - if (p != null && ! (p instanceof LightweightPeer)) + if (isShowing()) { - g.clearRect(0, 0, getWidth(), getHeight()); - backCleared = true; + ComponentPeer p = peer; + if (! (p instanceof LightweightPeer)) + { + g.clearRect(0, 0, getWidth(), getHeight()); + } + paint(g); } - - paint(g); } /** @@ -1173,8 +1231,11 @@ public class Container extends Component */ public void addNotify() { - super.addNotify(); - addNotifyContainerChildren(); + synchronized (getTreeLock()) + { + super.addNotify(); + addNotifyContainerChildren(); + } } /** @@ -1549,6 +1610,42 @@ public class Container extends Component } /** + * Set to <code>true</code> if this container provides a focus traversal + * policy, <code>false</code> when the root container's focus + * traversal policy should be used. + * + * @return <code>true</code> if this container provides a focus traversal + * policy, <code>false</code> when the root container's focus + * traversal policy should be used + * + * @see #setFocusTraversalPolicyProvider(boolean) + * + * @since 1.5 + */ + public final boolean isFocusTraversalPolicyProvider() + { + return focusTraversalPolicyProvider; + } + + /** + * Set to <code>true</code> if this container provides a focus traversal + * policy, <code>false</code> when the root container's focus + * traversal policy should be used. + * + * @param b <code>true</code> if this container provides a focus traversal + * policy, <code>false</code> when the root container's focus + * traversal policy should be used + * + * @see #isFocusTraversalPolicyProvider() + * + * @since 1.5 + */ + public final void setFocusTraversalPolicyProvider(boolean b) + { + focusTraversalPolicyProvider = b; + } + + /** * Check whether this Container is a focus cycle root. * * @return true if this is a focus cycle root, false otherwise @@ -1594,7 +1691,16 @@ public class Container extends Component public void applyComponentOrientation (ComponentOrientation orientation) { if (orientation == null) - throw new NullPointerException (); + throw new NullPointerException(); + + setComponentOrientation(orientation); + for (int i = 0; i < ncomponents; i++) + { + if (component[i] instanceof Container) + ((Container) component[i]).applyComponentOrientation(orientation); + else + component[i].setComponentOrientation(orientation); + } } public void addPropertyChangeListener (PropertyChangeListener listener) @@ -1646,24 +1752,27 @@ public class Container extends Component if (comp == this) throw new IllegalArgumentException("cannot add component to itself"); - // FIXME: Implement reparenting. - if ( comp.getParent() != this) - throw new AssertionError("Reparenting is not implemented yet"); - else + synchronized (getTreeLock()) { - // Find current component index. - int currentIndex = getComponentZOrder(comp); - if (currentIndex < index) - { - System.arraycopy(component, currentIndex + 1, component, - currentIndex, index - currentIndex); - } + // FIXME: Implement reparenting. + if ( comp.getParent() != this) + throw new AssertionError("Reparenting is not implemented yet"); else { - System.arraycopy(component, index, component, index + 1, - currentIndex - index); + // Find current component index. + int currentIndex = getComponentZOrder(comp); + if (currentIndex < index) + { + System.arraycopy(component, currentIndex + 1, component, + currentIndex, index - currentIndex); + } + else + { + System.arraycopy(component, index, component, index + 1, + currentIndex - index); + } + component[index] = comp; } - component[index] = comp; } } @@ -1682,19 +1791,22 @@ public class Container extends Component */ public final int getComponentZOrder(Component comp) { - int index = -1; - if (component != null) + synchronized (getTreeLock()) { - for (int i = 0; i < component.length; i++) + int index = -1; + if (component != null) { - if (component[i] == comp) + for (int i = 0; i < ncomponents; i++) { - index = i; - break; + if (component[i] == comp) + { + index = i; + break; + } } } + return index; } - return index; } // Hidden helper methods. @@ -1850,6 +1962,48 @@ public class Container extends Component } } + /** + * Fires hierarchy events to the children of this container and this + * container itself. This overrides {@link Component#fireHierarchyEvent} + * in order to forward this event to all children. + */ + void fireHierarchyEvent(int id, Component changed, Container parent, + long flags) + { + // Only propagate event if there is actually a listener waiting for it. + if ((id == HierarchyEvent.HIERARCHY_CHANGED && numHierarchyListeners > 0) + || ((id == HierarchyEvent.ANCESTOR_MOVED + || id == HierarchyEvent.ANCESTOR_RESIZED) + && numHierarchyBoundsListeners > 0)) + { + for (int i = 0; i < ncomponents; i++) + component[i].fireHierarchyEvent(id, changed, parent, flags); + super.fireHierarchyEvent(id, changed, parent, flags); + } + } + + /** + * Adjusts the number of hierarchy listeners of this container and all of + * its parents. This is called by the add/remove listener methods and + * structure changing methods in Container. + * + * @param type the type, either {@link AWTEvent#HIERARCHY_BOUNDS_EVENT_MASK} + * or {@link AWTEvent#HIERARCHY_EVENT_MASK} + * @param delta the number of listeners added or removed + */ + void updateHierarchyListenerCount(long type, int delta) + { + if (type == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) + numHierarchyBoundsListeners += delta; + else if (type == AWTEvent.HIERARCHY_EVENT_MASK) + numHierarchyListeners += delta; + else + assert false : "Should not reach here"; + + if (parent != null) + parent.updateHierarchyListenerCount(type, delta); + } + private void addNotifyContainerChildren() { synchronized (getTreeLock ()) diff --git a/libjava/classpath/java/awt/ContainerOrderFocusTraversalPolicy.java b/libjava/classpath/java/awt/ContainerOrderFocusTraversalPolicy.java index 23b4ac2e8d3..14afd364876 100644 --- a/libjava/classpath/java/awt/ContainerOrderFocusTraversalPolicy.java +++ b/libjava/classpath/java/awt/ContainerOrderFocusTraversalPolicy.java @@ -346,28 +346,30 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy || !root.isDisplayable ()) return null; - if (root.visible && root.isDisplayable() && root.enabled - && root.focusable) + if (accept(root)) return root; - Component[] componentArray = root.getComponents (); - - for (int i = 0; i < componentArray.length; i++) + int ncomponents = root.getComponentCount(); + for (int i = 0; i < ncomponents; i++) { - Component component = componentArray [i]; - - if (component.visible && component.isDisplayable() && component.enabled - && component.focusable) - return component; - - if (component instanceof Container) + Component component = root.getComponent(i); + if (component instanceof Container + && !((Container) component).isFocusCycleRoot()) { - Component result = getFirstComponent ((Container) component); - - if (result != null - && (result.visible && result.isDisplayable() && result.enabled && result.focusable)) - return result; + Component first = null; + Container cont = (Container) component; + if (cont.isFocusTraversalPolicyProvider()) + { + FocusTraversalPolicy childPol = cont.getFocusTraversalPolicy(); + first = childPol.getFirstComponent(cont); + } + else + first = getFirstComponent(cont); + if (first != null) + return first; } + else if (accept(component)) + return component; } return null; diff --git a/libjava/classpath/java/awt/Cursor.java b/libjava/classpath/java/awt/Cursor.java index 0ff987cd9ed..4d339b7211a 100644 --- a/libjava/classpath/java/awt/Cursor.java +++ b/libjava/classpath/java/awt/Cursor.java @@ -116,6 +116,16 @@ public class Cursor implements java.io.Serializable */ public static final int MOVE_CURSOR = 13; + private static String[] NAMES = { "Default Cursor", "Crosshair Cursor", + "Text Cursor", "Wait Cursor", + "Southwest Resize Cursor", + "Southeast Resize Cursor", + "Northwest Resize Cursor", + "Northeast Resize Cursor", + "North Resize Cursor", "South Resize Cursor", + "West Resize Cursor", "East Resize Cursor", + "Hand Cursor", "Move Cursor" }; + public static final int CUSTOM_CURSOR = 0xFFFFFFFF; private static final int PREDEFINED_COUNT = 14; @@ -142,7 +152,10 @@ public class Cursor implements java.io.Serializable throw new IllegalArgumentException ("invalid cursor " + type); this.type = type; - // FIXME: lookup and set name? + + name = NAMES[type]; + + // FIXME: lookup? } /** This constructor is used internally only. diff --git a/libjava/classpath/java/awt/DefaultKeyboardFocusManager.java b/libjava/classpath/java/awt/DefaultKeyboardFocusManager.java index 037cb834c40..9fea99b7839 100644 --- a/libjava/classpath/java/awt/DefaultKeyboardFocusManager.java +++ b/libjava/classpath/java/awt/DefaultKeyboardFocusManager.java @@ -163,7 +163,13 @@ public class DefaultKeyboardFocusManager extends KeyboardFocusManager if (e.id == WindowEvent.WINDOW_ACTIVATED) setGlobalActiveWindow (target); else if (e.id == WindowEvent.WINDOW_GAINED_FOCUS) - setGlobalFocusedWindow (target); + { + setGlobalFocusedWindow (target); + FocusTraversalPolicy p = target.getFocusTraversalPolicy(); + Component toFocus = p.getInitialComponent(target); + if (toFocus != null) + toFocus.requestFocusInWindow(); + } else if (e.id != WindowEvent.WINDOW_LOST_FOCUS && e.id != WindowEvent.WINDOW_DEACTIVATED) return false; @@ -173,51 +179,18 @@ public class DefaultKeyboardFocusManager extends KeyboardFocusManager } else if (e instanceof FocusEvent) { - Component target = (Component) e.getSource (); + FocusEvent fe = (FocusEvent) e; + Component target = fe.getComponent (); + boolean retval = false; if (e.id == FocusEvent.FOCUS_GAINED) { - if (! (target instanceof Window)) - { - if (((FocusEvent) e).isTemporary ()) - setGlobalFocusOwner (target); - else - setGlobalPermanentFocusOwner (target); - } - - // Keep track of this window's focus owner. - - // Find the target Component's top-level ancestor. target - // may be a window. - Container parent = target.getParent (); - - while (parent != null - && !(parent instanceof Window)) - parent = parent.getParent (); - - // If the parent is null and target is not a window, then target is an - // unanchored component and so we don't want to set the focus owner. - if (! (parent == null && ! (target instanceof Window))) - { - Window toplevel = parent == null ? - (Window) target : (Window) parent; - - Component focusOwner = getFocusOwner (); - if (focusOwner != null - && ! (focusOwner instanceof Window)) - toplevel.setFocusOwner (focusOwner); - } + retval = handleFocusGained(fe); } else if (e.id == FocusEvent.FOCUS_LOST) { - if (((FocusEvent) e).isTemporary ()) - setGlobalFocusOwner (null); - else - setGlobalPermanentFocusOwner (null); + retval = handleFocusLost(fe); } - - redispatchEvent(target, e); - return true; } else if (e instanceof KeyEvent) @@ -256,6 +229,95 @@ public class DefaultKeyboardFocusManager extends KeyboardFocusManager return false; } + /** + * Handles FOCUS_GAINED events in {@link #dispatchEvent(AWTEvent)}. + * + * @param fe the focus event + */ + private boolean handleFocusGained(FocusEvent fe) + { + Component target = fe.getComponent (); + + // If old focus owner != new focus owner, notify old focus + // owner that it has lost focus. + Component oldFocusOwner = getGlobalFocusOwner(); + if (oldFocusOwner != null && oldFocusOwner != target) + { + FocusEvent lost = new FocusEvent(oldFocusOwner, + FocusEvent.FOCUS_LOST, + fe.isTemporary(), target); + oldFocusOwner.dispatchEvent(lost); + } + + setGlobalFocusOwner (target); + if (target != getGlobalFocusOwner()) + { + // Focus transfer was rejected, like when the target is not + // focusable. + dequeueKeyEvents(-1, target); + // FIXME: Restore focus somehow. + } + else + { + if (! fe.isTemporary()) + { + setGlobalPermanentFocusOwner (target); + if (target != getGlobalPermanentFocusOwner()) + { + // Focus transfer was rejected, like when the target is not + // focusable. + dequeueKeyEvents(-1, target); + // FIXME: Restore focus somehow. + } + else + { + redispatchEvent(target, fe); + } + } + } + + return true; + } + + /** + * Handles FOCUS_LOST events for {@link #dispatchEvent(AWTEvent)}. + * + * @param fe the focus event + * + * @return if the event has been handled + */ + private boolean handleFocusLost(FocusEvent fe) + { + Component currentFocus = getGlobalFocusOwner(); + if (currentFocus != fe.getOppositeComponent()) + { + setGlobalFocusOwner(null); + if (getGlobalFocusOwner() != null) + { + // TODO: Is this possible? If so, then we should try to restore + // the focus. + } + else + { + if (! fe.isTemporary()) + { + setGlobalPermanentFocusOwner(null); + if (getGlobalPermanentFocusOwner() != null) + { + // TODO: Is this possible? If so, then we should try to + // restore the focus. + } + else + { + fe.setSource(currentFocus); + redispatchEvent(currentFocus, fe); + } + } + } + } + return true; + } + private boolean enqueueKeyEvent (KeyEvent e) { Iterator i = delayRequests.iterator (); diff --git a/libjava/classpath/java/awt/EventDispatchThread.java b/libjava/classpath/java/awt/EventDispatchThread.java index 7cb8af831bf..074a84975ac 100644 --- a/libjava/classpath/java/awt/EventDispatchThread.java +++ b/libjava/classpath/java/awt/EventDispatchThread.java @@ -82,17 +82,7 @@ class EventDispatchThread extends Thread try { AWTEvent evt = queue.getNextEvent(); - - KeyboardFocusManager manager; - manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); - - // Try to dispatch this event to the current keyboard focus - // manager. It will dispatch all FocusEvents, all - // WindowEvents related to focus, and all KeyEvents, - // returning true. Otherwise, it returns false and we - // dispatch the event normally. - if (!manager.dispatchEvent (evt)) - queue.dispatchEvent(evt); + queue.dispatchEvent(evt); } catch (ThreadDeath death) { diff --git a/libjava/classpath/java/awt/FileDialog.java b/libjava/classpath/java/awt/FileDialog.java index 7f2723e7e9a..f02d06be2c9 100644 --- a/libjava/classpath/java/awt/FileDialog.java +++ b/libjava/classpath/java/awt/FileDialog.java @@ -101,6 +101,58 @@ private int mode; * Constructors */ + /** + * Initializes a new instance of <code>FileDialog</code> with the specified + * parent. This dialog will have no title and will be for loading a file. + * + * @param parent The parent dialog for this. + * + * @since 1.5 + */ + public FileDialog(Dialog parent) + { + this(parent, "", LOAD); + } + + /** + * Initialized a new instance of <code>FileDialog</code> with the + * specified parent and title. This dialog will be for opening a file. + * + * @param parent The parent dialog for this. + * @param title The title for this dialog. + * + * @since 1.5 + */ + public FileDialog(Dialog parent, String title) + { + this(parent, title, LOAD); + } + + /** + * Initialized a new instance of <code>FileDialog</code> with the specified + * parent, title, and mode. + * + * @param parent The parent dialog for this. + * @param title The title for this dialog. + * @param mode The mode of the dialog, either <code>LOAD</code> or + * <code>SAVE</code>. + * @throws IllegalArgumentException - if illegal mode, if + * GraphicsEnvironment.isHeadless or if parent is null. + * + * @since 1.5 + */ + public FileDialog(Dialog parent, String title, int mode) + { + super(parent, title, true); + + // Other IllegalArgumentException cases are taken care of in Window.java + if (mode != LOAD && mode != SAVE) + throw new IllegalArgumentException ( + "Mode argument must be either LOAD or SAVE"); + + setMode(mode); + } + /** * Initializes a new instance of <code>FileDialog</code> with the * specified parent. This dialog will have no title and will be for diff --git a/libjava/classpath/java/awt/FlowLayout.java b/libjava/classpath/java/awt/FlowLayout.java index 7d0771d915b..8c99195289a 100644 --- a/libjava/classpath/java/awt/FlowLayout.java +++ b/libjava/classpath/java/awt/FlowLayout.java @@ -276,26 +276,24 @@ public class FlowLayout implements LayoutManager, Serializable } /** - * Sets the horizontal gap between components to the specified value. - * + * Sets the horizontal gap between lines of components to the specified value. + * No Exception is thrown if hgap < 0. + * * @param hgap The new horizontal gap between components. */ public void setHgap (int hgap) { - if (hgap < 0) - throw new IllegalArgumentException ("horizontal gap must be nonnegative"); this.hgap = hgap; } /** * Sets the vertical gap between lines of components to the specified value. + * No Exception is thrown if vgap < 0. * * @param vgap The new vertical gap. */ public void setVgap (int vgap) { - if (vgap < 0) - throw new IllegalArgumentException ("vertical gap must be nonnegative"); this.vgap = vgap; } diff --git a/libjava/classpath/java/awt/Font.java b/libjava/classpath/java/awt/Font.java index a52f63408da..1c22ce7b48f 100644 --- a/libjava/classpath/java/awt/Font.java +++ b/libjava/classpath/java/awt/Font.java @@ -48,6 +48,8 @@ import java.awt.font.TextLayout; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.awt.peer.FontPeer; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; @@ -114,7 +116,14 @@ public class Font implements Serializable * @since 1.3 */ public static final int TRUETYPE_FONT = 0; - + + /** + * Indicates to <code>createFont</code> that the supplied font data + * is in Type1 format. + * + * @since 1.5 + */ + public static final int TYPE1_FONT = 1; /** * A flag for <code>layoutGlyphVector</code>, indicating that the @@ -576,6 +585,34 @@ public class Font implements Serializable } /** + * Creates a new font from a File object. + * + * @see #layoutGlyphVector(FontRenderContext, char[], int, int, int) + * + * @param fontFormat - Integer code indicating the format the font data is + * in.Currently this can only be {@link #TRUETYPE_FONT}. + * @param file - a {@link File} from which font data will be read. + * + * @return A new {@link Font} of the format indicated. + * + * @throws IllegalArgumentException if <code>fontType</code> is not + * recognized. + * @throws NullPointerException if <code>file</code> is <code>null</code>. + * @throws FontFormatException if data in the file is invalid or cannot be read.. + * @throws SecurityException if the caller has no read permission for the file. + * @throws IOException if the file cannot be read + * + * @since 1.5 + */ + public static Font createFont (int fontFormat, File file) + throws FontFormatException, IOException + { + if( file == null ) + throw new NullPointerException("Null file argument"); + return tk().createFont(fontFormat, new FileInputStream( file )); + } + + /** * Maps characters to glyphs in a one-to-one relationship, returning a new * {@link GlyphVector} with a mapped glyph for each input character. This * sort of mapping is often sufficient for some scripts such as Roman, but diff --git a/libjava/classpath/java/awt/Graphics2D.java b/libjava/classpath/java/awt/Graphics2D.java index b3ecbc58a98..ada13edc512 100644 --- a/libjava/classpath/java/awt/Graphics2D.java +++ b/libjava/classpath/java/awt/Graphics2D.java @@ -53,23 +53,21 @@ import java.util.Map; /** * An abstract class defining a device independent two-dimensional vector * graphics API. Concrete subclasses implement this API for output of - * vector graphics to: (*) + * vector graphics to: * <p> * <ul> * <li>a {@link javax.swing.JComponent} - in the * {@link javax.swing.JComponent#paint(Graphics)} method, the incoming * {@link Graphics} should always be an instance of - * <code>Graphics2D</code> (*);</li> + * <code>Graphics2D</code>;</li> * <li>a {@link BufferedImage} - see - * {@link BufferedImage#createGraphics()} (*);</li> + * {@link BufferedImage#createGraphics()};</li> * <li>a {@link java.awt.print.PrinterJob} - in the * {@link Printable#print(Graphics, PageFormat, int)} method, the incoming - * {@link Graphics} should always be an instance of <code>Graphics2D</code> - * (*).</li> + * {@link Graphics} should always be an instance of + * <code>Graphics2D</code>.</li> * </ul> * <p> - * (*) Support for this API is not fully implemented in GNU Classpath yet. - * <p> * Third party libraries provide support for output to other formats via this * API, including encapsulated postscript (EPS), portable document format (PDF), * and scalable vector graphics (SVG). diff --git a/libjava/classpath/java/awt/GridBagConstraints.java b/libjava/classpath/java/awt/GridBagConstraints.java index 8d8b4fae534..a6a64c3bb8b 100644 --- a/libjava/classpath/java/awt/GridBagConstraints.java +++ b/libjava/classpath/java/awt/GridBagConstraints.java @@ -48,62 +48,99 @@ public class GridBagConstraints implements Cloneable, Serializable { static final long serialVersionUID = -1000070633030801713L; - /** Fill in both directions. */ - public static final int BOTH = 1; - /** Don't fill. */ + // Fill values. + /** + * Don't fill. + */ public static final int NONE = 0; - /** Fill horizontally. */ + + /** + * Fill in both directions. + */ + public static final int BOTH = 1; + + /** + * Fill horizontally. + */ public static final int HORIZONTAL = 2; - /** Fill vertically. */ + + /** + * Fill vertically. + */ public static final int VERTICAL = 3; - /** Position in the center. */ + // Anchor values. + /** + * Position in the center. + */ public static final int CENTER = 10; - /** Position to the east. */ - public static final int EAST = 13; - /** Position to the north. */ + + /** + * Position to the north. + */ public static final int NORTH = 11; - /** Position to the northeast. */ + + /** + * Position to the northeast. + */ public static final int NORTHEAST = 12; - /** Position to the northwest. */ - public static final int NORTHWEST = 18; - /** Position to the south. */ - public static final int SOUTH = 15; - /** Position to the southeast. */ + + /** + * Position to the east. + */ + public static final int EAST = 13; + + /** + * Position to the southeast. + */ public static final int SOUTHEAST = 14; - /** Position to the southwest. */ + + /** + * Position to the south. + */ + public static final int SOUTH = 15; + + /** + * Position to the southwest. + */ public static final int SOUTHWEST = 16; - /** Position to the west. */ + + /** + * Position to the west. + */ public static final int WEST = 17; - /** Occupy all remaining cells except last cell. */ + /** + * Position to the northwest. + */ + public static final int NORTHWEST = 18; + + // gridx and gridy values. + /** + * Occupy all remaining cells except last cell. + */ public static final int RELATIVE = -1; - /** Occupy all remaining cells. */ - public static final int REMAINDER = 0; /** - * Position to where the first text line would end. Equals to NORTHEAST for - * horizontal left-to-right orientations. + * Occupy all remaining cells. */ - public static final int FIRST_LINE_END = 24; + public static final int REMAINDER = 0; /** - * Position to where the first text line would start. Equals to NORTHWEST for - * horizontal left-to-right orientations. + * Position to where a page starts. Equals NORTH for horizontal orientations. */ - public static final int FIRST_LINE_START = 23; + public static final int PAGE_START = 19; /** - * Position to where the last text line would end. Equals to SOUTHEAST for - * horizontal left-to-right orientations. + * Position to where a page ends. Equals SOUTH for horizontal orientations. */ - public static final int LAST_LINE_END = 26; + public static final int PAGE_END = 20; /** - * Position to where the last text line would start. Equals to SOUTHWEST for - * horizontal left-to-right orientations. + * Position to where a text line would start. Equals to WEST for + * left-to-right orientations. */ - public static final int LAST_LINE_START = 25; + public static final int LINE_START = 21; /** * Position to where a text line would end. Equals to EAST for @@ -112,20 +149,28 @@ public class GridBagConstraints implements Cloneable, Serializable public static final int LINE_END = 22; /** - * Position to where a text line would start. Equals to WEST for - * left-to-right orientations. + * Position to where the first text line would start. Equals to NORTHWEST for + * horizontal left-to-right orientations. */ - public static final int LINE_START = 21; + public static final int FIRST_LINE_START = 23; /** - * Position to where a page ends. Equals SOUTH for horizontal orientations. + * Position to where the first text line would end. Equals to NORTHEAST for + * horizontal left-to-right orientations. */ - public static final int PAGE_END = 20; + public static final int FIRST_LINE_END = 24; /** - * Position to where a page starts. Equals NORTH for horizontal orientations. + * Position to where the last text line would start. Equals to SOUTHWEST for + * horizontal left-to-right orientations. */ - public static final int PAGE_START = 19; + public static final int LAST_LINE_START = 25; + + /** + * Position to where the last text line would end. Equals to SOUTHEAST for + * horizontal left-to-right orientations. + */ + public static final int LAST_LINE_END = 26; public int anchor; public int fill; @@ -139,7 +184,9 @@ public class GridBagConstraints implements Cloneable, Serializable public double weightx; public double weighty; - /** Create a copy of this object. */ + /** + * Create a copy of this object. + */ public Object clone () { try @@ -155,8 +202,10 @@ public class GridBagConstraints implements Cloneable, Serializable } } - /** Create a new GridBagConstraints object with the default - * parameters. */ + /** + * Create a new GridBagConstraints object with the default + * parameters. + */ public GridBagConstraints () { this.anchor = CENTER; @@ -172,8 +221,10 @@ public class GridBagConstraints implements Cloneable, Serializable this.weighty = 0; } - /** Create a new GridBagConstraints object with the indicated - * parameters. */ + /** + * Create a new GridBagConstraints object with the indicated + * parameters. + */ public GridBagConstraints (int gridx, int gridy, int gridwidth, int gridheight, double weightx, double weighty, diff --git a/libjava/classpath/java/awt/GridBagLayout.java b/libjava/classpath/java/awt/GridBagLayout.java index f827d21ca6a..d84b7d6df6c 100644 --- a/libjava/classpath/java/awt/GridBagLayout.java +++ b/libjava/classpath/java/awt/GridBagLayout.java @@ -1,5 +1,5 @@ /* GridBagLayout - Layout manager for components according to GridBagConstraints - 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,8 +38,6 @@ exception statement from your version. */ package java.awt; -import gnu.classpath.NotImplementedException; - import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; @@ -322,13 +320,24 @@ public class GridBagLayout } /** - * Obsolete. + * Move and resize a rectangle according to a set of grid bag + * constraints. The x, y, width and height fields of the + * rectangle argument are adjusted to the new values. + * + * @param constraints position and size constraints + * @param r rectangle to be moved and resized */ - protected void AdjustForGravity (GridBagConstraints gbc, Rectangle rect) - throws NotImplementedException + protected void AdjustForGravity (GridBagConstraints constraints, + Rectangle r) { - // FIXME - throw new Error ("Not implemented"); + Insets insets = constraints.insets; + if (insets != null) + { + r.x += insets.left; + r.y += insets.top; + r.width -= insets.left + insets.right; + r.height -= insets.top + insets.bottom; + } } /** @@ -353,10 +362,9 @@ public class GridBagLayout // layoutInfo. So we wait until after this for loop to set // layoutInfo. Component lastComp = null; - int cellx = 0; - int celly = 0; - int cellw = 0; - int cellh = 0; + + Rectangle cell = new Rectangle(); + for (int i = 0; i < components.length; i++) { Component component = components[i]; @@ -370,29 +378,23 @@ public class GridBagLayout if (lastComp != null && constraints.gridheight == GridBagConstraints.REMAINDER) - celly += cellh; + cell.y += cell.height; else - celly = sumIntArray(info.rowHeights, constraints.gridy); + cell.y = sumIntArray(info.rowHeights, constraints.gridy); if (lastComp != null && constraints.gridwidth == GridBagConstraints.REMAINDER) - cellx += cellw; + cell.x += cell.width; else - cellx = sumIntArray(info.colWidths, constraints.gridx); + cell.x = sumIntArray(info.colWidths, constraints.gridx); - cellw = sumIntArray(info.colWidths, constraints.gridx - + constraints.gridwidth) - cellx; - cellh = sumIntArray(info.rowHeights, constraints.gridy - + constraints.gridheight) - celly; - - Insets insets = constraints.insets; - if (insets != null) - { - cellx += insets.left; - celly += insets.top; - cellw -= insets.left + insets.right; - cellh -= insets.top + insets.bottom; - } + cell.width = sumIntArray(info.colWidths, constraints.gridx + + constraints.gridwidth) - cell.x; + cell.height = sumIntArray(info.rowHeights, constraints.gridy + + constraints.gridheight) - cell.y; + + // Adjust for insets. + AdjustForGravity( constraints, cell ); // Note: Documentation says that padding is added on both sides, but // visual inspection shows that the Sun implementation only adds it @@ -403,14 +405,14 @@ public class GridBagLayout switch (constraints.fill) { case GridBagConstraints.HORIZONTAL: - dim.width = cellw; + dim.width = cell.width; break; case GridBagConstraints.VERTICAL: - dim.height = cellh; + dim.height = cell.height; break; case GridBagConstraints.BOTH: - dim.width = cellw; - dim.height = cellh; + dim.width = cell.width; + dim.height = cell.height; break; } @@ -420,40 +422,40 @@ public class GridBagLayout switch (constraints.anchor) { case GridBagConstraints.NORTH: - x = cellx + (cellw - dim.width) / 2; - y = celly; + x = cell.x + (cell.width - dim.width) / 2; + y = cell.y; break; case GridBagConstraints.SOUTH: - x = cellx + (cellw - dim.width) / 2; - y = celly + cellh - dim.height; + x = cell.x + (cell.width - dim.width) / 2; + y = cell.y + cell.height - dim.height; break; case GridBagConstraints.WEST: - x = cellx; - y = celly + (cellh - dim.height) / 2; + x = cell.x; + y = cell.y + (cell.height - dim.height) / 2; break; case GridBagConstraints.EAST: - x = cellx + cellw - dim.width; - y = celly + (cellh - dim.height) / 2; + x = cell.x + cell.width - dim.width; + y = cell.y + (cell.height - dim.height) / 2; break; case GridBagConstraints.NORTHEAST: - x = cellx + cellw - dim.width; - y = celly; + x = cell.x + cell.width - dim.width; + y = cell.y; break; case GridBagConstraints.NORTHWEST: - x = cellx; - y = celly; + x = cell.x; + y = cell.y; break; case GridBagConstraints.SOUTHEAST: - x = cellx + cellw - dim.width; - y = celly + cellh - dim.height; + x = cell.x + cell.width - dim.width; + y = cell.y + cell.height - dim.height; break; case GridBagConstraints.SOUTHWEST: - x = cellx; - y = celly + cellh - dim.height; + x = cell.x; + y = cell.y + cell.height - dim.height; break; default: - x = cellx + (cellw - dim.width) / 2; - y = celly + (cellh - dim.height) / 2; + x = cell.x + (cell.width - dim.width) / 2; + y = cell.y + (cell.height - dim.height) / 2; break; } component.setBounds(info.pos_x + x, info.pos_y + y, dim.width, @@ -1082,10 +1084,18 @@ public class GridBagLayout } /** + * Move and resize a rectangle according to a set of grid bag + * constraints. The x, y, width and height fields of the + * rectangle argument are adjusted to the new values. + * + * @param constraints position and size constraints + * @param r rectangle to be moved and resized + * * @since 1.4 */ - protected void adjustForGravity (GridBagConstraints gbc, Rectangle rect) + protected void adjustForGravity (GridBagConstraints constraints, + Rectangle r) { - AdjustForGravity (gbc, rect); + AdjustForGravity (constraints, r); } } diff --git a/libjava/classpath/java/awt/GridLayout.java b/libjava/classpath/java/awt/GridLayout.java index 80d96414249..a6836681da5 100644 --- a/libjava/classpath/java/awt/GridLayout.java +++ b/libjava/classpath/java/awt/GridLayout.java @@ -254,14 +254,11 @@ public class GridLayout implements LayoutManager, Serializable this.cols = newCols; } - /** Set the horizontal gap + /** Set the horizontal gap. An Exception is not thrown if hgap < 0. * @param hgap The horizontal gap - * @exception IllegalArgumentException If the hgap value is less than zero. */ public void setHgap (int hgap) { - if (hgap < 0) - throw new IllegalArgumentException ("horizontal gap must be nonnegative"); this.hgap = hgap; } @@ -280,21 +277,18 @@ public class GridLayout implements LayoutManager, Serializable this.rows = newRows; } - /** Set the vertical gap. + /** Set the vertical gap. An Exception is not thrown if vgap < 0. * @param vgap The vertical gap - * @exception IllegalArgumentException If the vgap value is less than zero. */ public void setVgap (int vgap) { - if (vgap < 0) - throw new IllegalArgumentException ("vertical gap must be nonnegative"); this.vgap = vgap; } /** Return String description of this object. */ public String toString () { - return ("[" + getClass ().getName () + return (getClass ().getName () + "[" + ",hgap=" + hgap + ",vgap=" + vgap + ",rows=" + rows + ",cols=" + cols + "]"); diff --git a/libjava/classpath/java/awt/Image.java b/libjava/classpath/java/awt/Image.java index 6ade302a147..8a1cc0f0039 100644 --- a/libjava/classpath/java/awt/Image.java +++ b/libjava/classpath/java/awt/Image.java @@ -1,5 +1,5 @@ /* Image.java -- superclass for images - Copyright (C) 1999, 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 1999, 2002, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -50,7 +50,7 @@ import java.awt.image.ReplicateScaleFilter; * * @author Aaron M. Renn (arenn@urbanophile.com) * @since 1.0 - * @status updated to 1.4 + * @status updated to 1.5 */ public abstract class Image { @@ -102,6 +102,12 @@ public abstract class Image public static final int SCALE_AREA_AVERAGING = 16; /** + * The acceleration priority of the image + * @since 1.5 + */ + protected float accelerationPriority; + + /** * A default constructor for subclasses. */ public Image() @@ -205,4 +211,32 @@ public abstract class Image * includes the actual image data. */ public abstract void flush(); + + /** + * Sets the acceleration priority of the image. + * This is a value from 0 (lowest) to 1 (highest), which may + * be used as a hint for image acceleration. + * E.g. higher priority images may be stored in video memory. + * @param priority - the priority + * @throws IllegalArgumentException if priority is not >= 0 and <= 1. + * + * @since 1.5 + */ + public void setAccelerationPriority(float priority) + { + if( priority < 0f || priority > 1f) + throw new IllegalArgumentException("Invalid priority value."); + accelerationPriority = priority; + } + + /** + * Returns the acceleration priority of the image. + * + * @see #setAccelerationPriority(float) + * @since 1.5 + */ + public float getAccelerationPriority() + { + return accelerationPriority; + } } // class Image diff --git a/libjava/classpath/java/awt/Insets.java b/libjava/classpath/java/awt/Insets.java index 6d5bd122e9d..762b6975b3f 100644 --- a/libjava/classpath/java/awt/Insets.java +++ b/libjava/classpath/java/awt/Insets.java @@ -1,5 +1,5 @@ /* Insets.java -- information about a container border - Copyright (C) 1999, 2000, 2002, 2005 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2002, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -149,14 +149,13 @@ public class Insets implements Cloneable, Serializable /** * Returns a string representation of this object, which will be non-null. - * The format is unspecified, but appears to be <code>XXX what is it?</code>. * * @return a string representation of this object */ public String toString() { - return getClass().getName() + "(top=" + top + ",bottom=" + bottom + - ",left=" + left + ",right=" + right + ')'; + return getClass().getName() + "[top=" + top + ",left=" + left + + ",bottom=" + bottom + ",right=" + right + ']'; } /** diff --git a/libjava/classpath/java/awt/KeyboardFocusManager.java b/libjava/classpath/java/awt/KeyboardFocusManager.java index 371ea9bdf8a..eacbceb7d50 100644 --- a/libjava/classpath/java/awt/KeyboardFocusManager.java +++ b/libjava/classpath/java/awt/KeyboardFocusManager.java @@ -304,10 +304,7 @@ public abstract class KeyboardFocusManager */ public Component getFocusOwner () { - Component owner = (Component) getObject (currentFocusOwners); - if (owner == null) - owner = (Component) getObject (currentPermanentFocusOwners); - return owner; + return (Component) getObject (currentFocusOwners); } /** @@ -323,10 +320,7 @@ public abstract class KeyboardFocusManager */ protected Component getGlobalFocusOwner () { - // Check if there is a temporary focus owner. - Component focusOwner = (Component) getGlobalObject (currentFocusOwners); - - return (focusOwner == null) ? getGlobalPermanentFocusOwner () : focusOwner; + return (Component) getGlobalObject(currentFocusOwners, true); } /** @@ -409,7 +403,7 @@ public abstract class KeyboardFocusManager */ protected Component getGlobalPermanentFocusOwner () { - return (Component) getGlobalObject (currentPermanentFocusOwners); + return (Component) getGlobalObject (currentPermanentFocusOwners, true); } /** @@ -455,7 +449,7 @@ public abstract class KeyboardFocusManager */ protected Window getGlobalFocusedWindow () { - return (Window) getGlobalObject (currentFocusedWindows); + return (Window) getGlobalObject (currentFocusedWindows, true); } /** @@ -497,7 +491,7 @@ public abstract class KeyboardFocusManager */ protected Window getGlobalActiveWindow() { - return (Window) getGlobalObject (currentActiveWindows); + return (Window) getGlobalObject (currentActiveWindows, true); } /** @@ -663,7 +657,7 @@ public abstract class KeyboardFocusManager */ protected Container getGlobalCurrentFocusCycleRoot () { - return (Container) getGlobalObject (currentFocusCycleRoots); + return (Container) getGlobalObject (currentFocusCycleRoots, true); } /** @@ -1105,11 +1099,9 @@ public abstract class KeyboardFocusManager */ public final void redispatchEvent (Component target, AWTEvent e) { - synchronized (e) - { - e.setSource (target); - target.dispatchEvent (e); - } + e.isFocusManagerEvent = true; + target.dispatchEvent (e); + e.isFocusManagerEvent = false; } /** @@ -1355,17 +1347,19 @@ public abstract class KeyboardFocusManager * @see #getGlobalActiveWindow() * @see #getGlobalCurrentFocusCycleRoot() */ - private Object getGlobalObject (Map globalMap) + private Object getGlobalObject (Map globalMap, boolean checkThread) { - ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); - KeyboardFocusManager managerForCallingThread - = (KeyboardFocusManager) currentKeyboardFocusManagers.get (currentGroup); - - if (this != managerForCallingThread) - throw new SecurityException ("Attempted to retrieve an object from a " - + "keyboard focus manager that isn't " - + "associated with the current thread group."); + if (checkThread) + { + ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); + KeyboardFocusManager managerForCallingThread = + (KeyboardFocusManager) currentKeyboardFocusManagers.get(currentGroup); + if (this != managerForCallingThread) + throw new SecurityException ("Attempted to retrieve an object from a " + + "keyboard focus manager that isn't " + + "associated with the current thread group."); + } synchronized (globalMap) { Collection globalObjects = globalMap.values (); @@ -1406,7 +1400,7 @@ public abstract class KeyboardFocusManager synchronized (globalMap) { // Save old object. - Object oldObject = getGlobalObject (globalMap); + Object oldObject = getGlobalObject(globalMap, false); // Nullify old object. Collection threadGroups = globalMap.keySet (); @@ -1436,4 +1430,48 @@ public abstract class KeyboardFocusManager } } } + + + /** + * Maps focus requests from heavyweight to lightweight components. + */ + private static HashMap focusRequests = new HashMap(); + + /** + * Retargets focus events that come from the peer (which only know about + * heavyweight components) to go to the correct lightweight component + * if appropriate. + * + * @param ev the event to check + * + * @return the retargetted event + */ + static AWTEvent retargetFocusEvent(AWTEvent ev) + { + if (ev instanceof FocusEvent) + { + FocusEvent fe = (FocusEvent) ev; + Component target = fe.getComponent(); + if (focusRequests.containsKey(target)) + { + Component lightweight = (Component) focusRequests.get(target); + ev = new FocusEvent(lightweight, fe.id, fe.isTemporary()); + focusRequests.remove(target); + } + } + return ev; + } + + /** + * Adds a lightweight focus request for a heavyweight component. + * + * @param heavyweight the heavyweight from which we will receive a focus + * event soon + * @param lightweight the lightweight that ultimately receives the request + */ + static void addLightweightFocusRequest(Component heavyweight, + Component lightweight) + { + focusRequests.put(heavyweight, lightweight); + } } diff --git a/libjava/classpath/java/awt/Label.java b/libjava/classpath/java/awt/Label.java index d6db329106f..71614da6482 100644 --- a/libjava/classpath/java/awt/Label.java +++ b/libjava/classpath/java/awt/Label.java @@ -1,5 +1,6 @@ /* Label.java -- Java label widget - Copyright (C) 1999, 2000, 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2002, 2004, 2005, 2006, Free Software + Foundation, Inc. This file is part of GNU Classpath. @@ -45,275 +46,250 @@ import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; /** - * This component is used for displaying simple text strings that cannot - * be edited by the user. - * - * @author Aaron M. Renn (arenn@urbanophile.com) - * @author Tom Tromey (tromey@cygnus.com) - * @author Andrew John Hughes (gnu_andrew@member.fsf.org) - */ + * This component is used for displaying simple text strings that cannot + * be edited by the user. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ public class Label extends Component implements Accessible { -/* - * Static Variables - */ - -/** - * Alignment constant aligning the text to the left of its window. - */ -public static final int LEFT = 0; - -/** - * Alignment constant aligning the text in the center of its window. - */ -public static final int CENTER = 1; - -/** - * Alignment constant aligning the text to the right of its window. - */ -public static final int RIGHT = 2; - -// Serialization version constant: -private static final long serialVersionUID = 3094126758329070636L; - -/*************************************************************************/ + /** + * Alignment constant aligning the text to the left of its window. + */ + public static final int LEFT = 0; -/* - * Instance Variables - */ + /** + * Alignment constant aligning the text in the center of its window. + */ + public static final int CENTER = 1; -/** - * @serial Indicates the alignment of the text within this label's window. - * This is one of the constants in this class. The default value is - * <code>LEFT</code>. - */ -private int alignment; + /** + * Alignment constant aligning the text to the right of its window. + */ + public static final int RIGHT = 2; -/** - * @serial The text displayed in the label - */ -private String text; + // Serialization version constant: + private static final long serialVersionUID = 3094126758329070636L; -/*************************************************************************/ + /** + * @serial Indicates the alignment of the text within this label's window. + * This is one of the constants in this class. The default value is + * <code>LEFT</code>. + */ + private int alignment; -/* - * Constructors - */ + /** + * @serial The text displayed in the label + */ + private String text; -/** - * Initializes a new instance of <code>Label</code> with no text. - * - * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. - */ -public -Label() -{ - this("", LEFT); -} + /** + * Initializes a new instance of <code>Label</code> with no text. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public Label() + { + this("", LEFT); + } -/*************************************************************************/ + /** + * Initializes a new instance of <code>Label</code> with the specified + * text that is aligned to the left. + * + * @param text The text of the label. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public Label(String text) + { + this(text, LEFT); + } -/** - * Initializes a new instance of <code>Label</code> with the specified - * text that is aligned to the left. - * - * @param text The text of the label. - * - * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. - */ -public -Label(String text) -{ - this(text, LEFT); -} + /** + * Initializes a new instance of <code>Label</code> with the specified + * text and alignment. + * + * @param text The text of the label. + * @param alignment The desired alignment for the text in this label, + * which must be one of <code>LEFT</code>, <code>CENTER</code>, or + * <code>RIGHT</code>. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public Label(String text, int alignment) + { + setAlignment(alignment); + setText(text); -/*************************************************************************/ + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException(); + } -/** - * Initializes a new instance of <code>Label</code> with the specified - * text and alignment. - * - * @param text The text of the label. - * @param alignment The desired alignment for the text in this label, - * which must be one of <code>LEFT</code>, <code>CENTER</code>, or - * <code>RIGHT</code>. - * - * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. - */ -public -Label(String text, int alignment) -{ - setAlignment (alignment); - setText (text); + /** + * Returns the constant indicating the alignment of the text in this + * label. The value returned will be one of the alignment constants + * from this class. + * + * @return The alignment of the text in the label. + */ + public int getAlignment() + { + return(alignment); + } - if (GraphicsEnvironment.isHeadless()) - throw new HeadlessException (); -} + /** + * Sets the text alignment of this label to the specified value. + * + * @param alignment The desired alignment for the text in this label, + * which must be one of <code>LEFT</code>, <code>CENTER</code>, or + * <code>RIGHT</code>. + */ + public synchronized void setAlignment(int alignment) + { + if (alignment != CENTER && alignment != LEFT && alignment != RIGHT) + throw new IllegalArgumentException("invalid alignment: " + alignment); + this.alignment = alignment; + if (peer != null) + { + LabelPeer lp = (LabelPeer) peer; + lp.setAlignment(alignment); + } + } -/*************************************************************************/ + /** + * Returns the text displayed in this label. + * + * @return The text for this label. + */ + public String getText() + { + return text; + } -/* - * Instance Variables - */ + /** + * Sets the text in this label to the specified value. + * + * @param text The new text for this label. + */ + public synchronized void setText(String text) + { + if ((this.text == null && text != null) + || (this.text != null && ! this.text.equals(text))) + { + this.text = text; + + if (peer != null) + { + LabelPeer lp = (LabelPeer) peer; + lp.setText(text); + } + invalidate(); + } + } -/** - * Returns the constant indicating the alignment of the text in this - * label. The value returned will be one of the alignment constants - * from this class. - * - * @return The alignment of the text in the label. - */ -public int -getAlignment() -{ - return(alignment); -} + /** + * Notifies this label that it has been added to a container, causing + * the peer to be created. This method is called internally by the AWT + * system. + */ + public void addNotify() + { + if (peer == null) + peer = getToolkit().createLabel(this); + super.addNotify(); + } -/*************************************************************************/ + /** + * Returns a parameter string useful for debugging. + * + * @return A debugging string. + */ + protected String paramString() + { + return ("text=" + getText() + ",alignment=" + + getAlignment() + "," + super.paramString()); + } -/** - * Sets the text alignment of this label to the specified value. - * - * @param alignment The desired alignment for the text in this label, - * which must be one of <code>LEFT</code>, <code>CENTER</code>, or - * <code>RIGHT</code>. - */ -public synchronized void -setAlignment(int alignment) -{ - if (alignment != CENTER && alignment != LEFT && alignment != RIGHT) - throw new IllegalArgumentException ("invalid alignment: " + alignment); - this.alignment = alignment; - if (peer != null) + /** + * This class provides accessibility support for the label. + */ + protected class AccessibleAWTLabel + extends AccessibleAWTComponent + { + /** + * For compatability with Sun's JDK 1.4.2 rev. 5 + */ + private static final long serialVersionUID = -3568967560160480438L; + + /** + * Constructor for the accessible label. + */ + public AccessibleAWTLabel() { - LabelPeer lp = (LabelPeer) peer; - lp.setAlignment (alignment); } -} - -/*************************************************************************/ - -/** - * Returns the text displayed in this label. - * - * @return The text for this label. - */ -public String -getText() -{ - return(text); -} - -/*************************************************************************/ -/** - * Sets the text in this label to the specified value. - * - * @param text The new text for this label. - */ -public synchronized void -setText(String text) -{ - if ((this.text == null && text != null) - || (this.text != null && ! this.text.equals(text))) + /** + * Returns the accessible name for the label. This is + * the text used in the label. + * + * @return a <code>String</code> containing the accessible + * name for this label. + */ + public String getAccessibleName() { - this.text = text; - - if (peer != null) - { - LabelPeer lp = (LabelPeer) peer; - lp.setText (text); - } - invalidate(); + return getText(); } -} - -/*************************************************************************/ - -/** - * Notifies this label that it has been added to a container, causing - * the peer to be created. This method is called internally by the AWT - * system. - */ -public void -addNotify() -{ - if (peer == null) - peer = getToolkit ().createLabel (this); - super.addNotify (); -} -/*************************************************************************/ - -/** - * Returns a parameter string useful for debugging. - * - * @return A debugging string. - */ -protected String -paramString() -{ - return ("text=" + getText() + ",alignment=" + - getAlignment() + "," + super.paramString()); -} + /** + * Returns the accessible role for the label. + * + * @return an instance of <code>AccessibleRole</code>, describing + * the role of the label. + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.LABEL; + } -/** - * This class provides accessibility support for the label. - */ -protected class AccessibleAWTLabel - extends AccessibleAWTComponent -{ - /** - * For compatability with Sun's JDK 1.4.2 rev. 5 - */ - private static final long serialVersionUID = -3568967560160480438L; + } /** - * Constructor for the accessible label. + * Gets the AccessibleContext associated with this <code>Label</code>. + * The context is created, if necessary. + * + * @return the associated context */ - public AccessibleAWTLabel() + public AccessibleContext getAccessibleContext() { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTLabel(); + return accessibleContext; } /** - * Returns the accessible name for the label. This is - * the text used in the label. + * Generate a unique name for this button. * - * @return a <code>String</code> containing the accessible - * name for this label. + * @return A unique name for this button. */ - public String getAccessibleName() + String generateName() { - return getText(); + return "label" + getUniqueLong(); } - + /** - * Returns the accessible role for the label. - * - * @return an instance of <code>AccessibleRole</code>, describing - * the role of the label. + * The number used to generate the name returned by getName. */ - public AccessibleRole getAccessibleRole() + private static transient long nextLabelNumber; + + private static synchronized long getUniqueLong() { - return AccessibleRole.LABEL; + return nextLabelNumber++; } } -/** - * Gets the AccessibleContext associated with this <code>Label</code>. - * The context is created, if necessary. - * - * @return the associated context - */ -public AccessibleContext getAccessibleContext() -{ - /* Create the context if this is the first request */ - if (accessibleContext == null) - accessibleContext = new AccessibleAWTLabel(); - return accessibleContext; -} - -} // class Label - diff --git a/libjava/classpath/java/awt/LightweightDispatcher.java b/libjava/classpath/java/awt/LightweightDispatcher.java index 7e33bd4e9ce..3ea3f90a643 100644 --- a/libjava/classpath/java/awt/LightweightDispatcher.java +++ b/libjava/classpath/java/awt/LightweightDispatcher.java @@ -152,8 +152,11 @@ class LightweightDispatcher target = findTarget(parent, loc); while (target == null && parent != null) { - if (parent.getMouseListeners().length > 0 - || parent.getMouseMotionListeners().length > 0) + if (parent.mouseListener != null + || parent.mouseMotionListener != null + || (parent.eventMask + & (AWTEvent.MOUSE_EVENT_MASK + | AWTEvent.MOUSE_MOTION_EVENT_MASK)) != 0) { target = parent; } @@ -175,24 +178,22 @@ class LightweightDispatcher 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 only if - // there is currently no component from which a drag operation - // started (dragTarget == null) or the target is that component - // (dragTarget == target) - // That way a user can click and hold on a button (putting it into - // the armed state), move the cursor above other buttons without - // affecting their rollover state and get back to the initial - // button. - if (target != null && (dragTarget == null || dragTarget == target)) + // 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(), + 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); } } @@ -219,7 +220,11 @@ class LightweightDispatcher // it was released. if (dragTarget != null && dragButton == ev.getButton()) { - target = dragTarget; + // 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; } @@ -287,18 +292,21 @@ class LightweightDispatcher */ private Component findTarget(Container c, Point loc) { - Component[] children = c.getComponents(); + int numComponents = c.getComponentCount(); Component target = null; if (c != null) { - for (int i = 0; i < children.length; i++) + for (int i = 0; i < numComponents; i++) { - Component child = children[i]; + Component child = c.getComponent(i); if (child.isShowing()) { if (child.contains(loc.x - child.getX(), loc.y - child.getY()) - && (child.getMouseListeners().length > 0 - || child.getMouseMotionListeners().length > 0)) + && (child.mouseListener != null + || child.mouseMotionListener != null + || (child.eventMask + & (AWTEvent.MOUSE_EVENT_MASK + | AWTEvent.MOUSE_MOTION_EVENT_MASK)) != 0)) { target = child; break; diff --git a/libjava/classpath/java/awt/List.java b/libjava/classpath/java/awt/List.java index b28e2016d2e..86270234345 100644 --- a/libjava/classpath/java/awt/List.java +++ b/libjava/classpath/java/awt/List.java @@ -66,6 +66,11 @@ public class List extends Component * 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; @@ -161,7 +166,11 @@ List(int rows) public List(int rows, boolean multipleMode) { - this.rows = rows; + if (rows == 0) + this.rows = 4; + else + this.rows = rows; + this.multipleMode = multipleMode; selected = new int[0]; @@ -645,13 +654,13 @@ clear() * @param item The new item value. * @param index The index of the item to replace. * - * @exception IllegalArgumentException If the index is not valid. + * @exception ArrayIndexOutOfBoundsException If the index is not valid. */ public synchronized void -replaceItem(String item, int index) throws IllegalArgumentException +replaceItem(String item, int index) throws ArrayIndexOutOfBoundsException { if ((index < 0) || (index >= items.size())) - throw new IllegalArgumentException("Bad list index: " + index); + throw new ArrayIndexOutOfBoundsException("Bad list index: " + index); items.insertElementAt(item, index + 1); items.removeElementAt (index); @@ -818,15 +827,11 @@ isSelected(int index) /** * This method ensures that the item at the specified index is visible. * - * @exception IllegalArgumentException If the specified index is out of - * range. + * @param index The index of the item to be made visible. */ public synchronized void makeVisible(int index) throws IllegalArgumentException { - if ((index < 0) || (index >= items.size())) - throw new IllegalArgumentException("Bad list index: " + index); - visibleIndex = index; if (peer != null) { @@ -1266,4 +1271,19 @@ paramString() accessibleContext = new AccessibleAWTList(); return accessibleContext; } + + /** + * Generate a unique name for this <code>List</code>. + * + * @return A unique name for this <code>List</code>. + */ + String generateName() + { + return "list" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_list_number++; + } } // class List diff --git a/libjava/classpath/java/awt/Menu.java b/libjava/classpath/java/awt/Menu.java index 6daec72cf44..f900d929574 100644 --- a/libjava/classpath/java/awt/Menu.java +++ b/libjava/classpath/java/awt/Menu.java @@ -58,6 +58,11 @@ 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; @@ -485,5 +490,20 @@ paramString() accessibleContext = new AccessibleAWTMenu(); return accessibleContext; } + + /** + * Generate a unique name for this <code>Menu</code>. + * + * @return A unique name for this <code>Menu</code>. + */ + String generateName() + { + return "menu" + getUniqueLong(); + } + private static synchronized long getUniqueLong() + { + return next_menu_number++; + } + } // class Menu diff --git a/libjava/classpath/java/awt/MenuBar.java b/libjava/classpath/java/awt/MenuBar.java index 3c6b915649f..bd658cde6e3 100644 --- a/libjava/classpath/java/awt/MenuBar.java +++ b/libjava/classpath/java/awt/MenuBar.java @@ -60,10 +60,15 @@ public class MenuBar extends MenuComponent implements MenuContainer, Serializable, Accessible { -//Serialization Constant + // Serialization Constant private static final long serialVersionUID = -4930327919388951260L; /** + * The number used to generate the name returned by getName. + */ + private static transient long next_menubar_number; + + /** * @serial The menu used for providing help information */ private Menu helpMenu; @@ -331,6 +336,21 @@ public class MenuBar extends MenuComponent accessibleContext = new AccessibleAWTMenuBar(); return accessibleContext; } + + /** + * Generate a unique name for this <code>MenuBar</code>. + * + * @return A unique name for this <code>MenuBar</code>. + */ + String generateName() + { + return "menubar" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_menubar_number++; + } /** * This class provides accessibility support for AWT menu bars. diff --git a/libjava/classpath/java/awt/MenuComponent.java b/libjava/classpath/java/awt/MenuComponent.java index 9bb875069e0..163092685e7 100644 --- a/libjava/classpath/java/awt/MenuComponent.java +++ b/libjava/classpath/java/awt/MenuComponent.java @@ -200,8 +200,22 @@ public abstract class MenuComponent implements Serializable */ public String getName() { + if (name == null && ! nameExplicitlySet) + name = generateName(); return name; } + + /** + * Subclasses should override this to return unique component names like + * "menuitem0". + * + * @return the generated name for this menu component + */ + String generateName() + { + // MenuComponent is abstract. + return null; + } /** * Sets the name of this component to the specified name. diff --git a/libjava/classpath/java/awt/MenuItem.java b/libjava/classpath/java/awt/MenuItem.java index a7ac79643be..7cbc9219f54 100644 --- a/libjava/classpath/java/awt/MenuItem.java +++ b/libjava/classpath/java/awt/MenuItem.java @@ -63,9 +63,15 @@ public class MenuItem extends MenuComponent /* * Static Variables */ + + + /** + * The number used to generate the name returned by getName. + */ + private static transient long next_menuitem_number; -// Serialization Constant -private static final long serialVersionUID = -21757335363267194L; + // Serialization Constant + private static final long serialVersionUID = - 21757335363267194L; /*************************************************************************/ @@ -599,4 +605,19 @@ public AccessibleContext getAccessibleContext() return accessibleContext; } +/** + * Generate a unique name for this <code>MenuItem</code>. + * + * @return A unique name for this <code>MenuItem</code>. + */ +String generateName() +{ + return "menuitem" + getUniqueLong(); +} + +private static synchronized long getUniqueLong() +{ + return next_menuitem_number++; +} + } // class MenuItem diff --git a/libjava/classpath/java/awt/MouseInfo.java b/libjava/classpath/java/awt/MouseInfo.java new file mode 100644 index 00000000000..957b6bccbef --- /dev/null +++ b/libjava/classpath/java/awt/MouseInfo.java @@ -0,0 +1,95 @@ +/* MouseInfo.java -- utility methods for mice. + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt; + +import gnu.java.awt.ClasspathToolkit; +import java.awt.peer.MouseInfoPeer; + +/** + * MouseInfo is a class containing utility functions for mouse information. + * + * @author Sven de Marothy + * @since 1.5 + */ +public class MouseInfo +{ + private static MouseInfoPeer peer; + + /** + * Returns a PointerInfo object containing information about the current + * location of the mouse pointer + * + * @throws HeadlessException if the current GraphicsEnvironment is headless. + * @return a PointerInfo object. + */ + public static PointerInfo getPointerInfo() throws HeadlessException + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission( new AWTPermission("watchMousePointer") ); + + if( GraphicsEnvironment.isHeadless() ) + throw new HeadlessException(); + + if( peer == null ) + peer = Toolkit.getDefaultToolkit().getMouseInfoPeer(); + + Point p = new Point(); + int screen = peer.fillPointWithCoords( p ); + + GraphicsDevice[] gds = GraphicsEnvironment.getLocalGraphicsEnvironment(). + getScreenDevices(); + + return new PointerInfo( gds[ screen ], p ); + } + + /** + * Returns the number of mouse buttons, or -1 if no mouse is connected. + * (mentioned in the 1.5 release notes) + * + * @throws HeadlessException if the current GraphicsEnvironment is headless. + * @return an integer number of buttons. + */ + public static int getNumberOfButtons() throws HeadlessException + { + if( GraphicsEnvironment.isHeadless() ) + throw new HeadlessException(); + return ((ClasspathToolkit)Toolkit.getDefaultToolkit()). + getMouseNumberOfButtons(); + } +} diff --git a/libjava/classpath/java/awt/Point.java b/libjava/classpath/java/awt/Point.java index 31b72e2cc75..64bc07eaf72 100644 --- a/libjava/classpath/java/awt/Point.java +++ b/libjava/classpath/java/awt/Point.java @@ -1,5 +1,5 @@ /* Point.java -- represents a point in 2-D space - Copyright (C) 1999, 2002 Free Software Foundation + Copyright (C) 1999, 2002, 2006 Free Software Foundation This file is part of GNU Classpath. @@ -83,7 +83,7 @@ public class Point extends Point2D implements Serializable /** * Initializes a new instance of <code>Point</code> representing the - * coordiates (0,0). + * coordinates (0, 0). * * @since 1.1 */ @@ -93,7 +93,7 @@ public class Point extends Point2D implements Serializable /** * Initializes a new instance of <code>Point</code> with coordinates - * identical to the coordinates of the specified points. + * identical to the coordinates of the specified point. * * @param p the point to copy the coordinates from * @throws NullPointerException if p is null @@ -178,15 +178,16 @@ public class Point extends Point2D implements Serializable /** * Sets this object's coordinates to the specified values. This method - * performs normal casting from double to int, so you may lose precision. + * rounds to the nearest integer coordinates by adding 0.5 and calling + * {@link Math#floor(double)}. * * @param x the new X coordinate * @param y the new Y coordinate */ public void setLocation(double x, double y) { - this.x = (int) x; - this.y = (int) y; + this.x = (int) Math.floor(x + 0.5); + this.y = (int) Math.floor(y + 0.5); } /** diff --git a/libjava/classpath/java/awt/PointerInfo.java b/libjava/classpath/java/awt/PointerInfo.java new file mode 100644 index 00000000000..14d44a69b3f --- /dev/null +++ b/libjava/classpath/java/awt/PointerInfo.java @@ -0,0 +1,84 @@ +/* PointerInfo.java -- mouse pointer data + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt; + +/** + * PointerInfo represents information about the mouse pointer, + * i.e. its GraphicsDevice and location. + * + * PointerInfo objects cannot be instantiated directly, but are + * retrieved from MouseInfo.getPointerInfo(). PointerInfo objects + * are immutable and will not be updated for future mouse motions. + * + * @since 1.5 + * @author Sven de Marothy + */ +public class PointerInfo +{ + private GraphicsDevice gd; + private Point p; + + /** + * Package-private constructor used by MouseInfo. + */ + PointerInfo( GraphicsDevice gd, Point p ) + { + this.gd = gd; + this.p = p; + } + + /** + * Returns the GraphicsDevice on which the mouse pointer was located + * + * @return a GraphicsDevice object. + */ + public GraphicsDevice getDevice() + { + return gd; + } + + /** + * Returns the coordinates of the mouse pointer. + * + * @return a Point object containing the pointer coordinates. + */ + public Point getLocation() + { + return p; + } +} diff --git a/libjava/classpath/java/awt/PopupMenu.java b/libjava/classpath/java/awt/PopupMenu.java index 540fffda718..9268678026d 100644 --- a/libjava/classpath/java/awt/PopupMenu.java +++ b/libjava/classpath/java/awt/PopupMenu.java @@ -55,8 +55,13 @@ public class PopupMenu extends Menu * Static Variables */ -// Serialization Constant -private static final long serialVersionUID = -4620452533522760060L; + /** + * The number used to generate the name returned by getName. + */ + private static transient long next_popup_number; + + // Serialization Constant + private static final long serialVersionUID = - 4620452533522760060L; /*************************************************************************/ @@ -166,6 +171,21 @@ show(Component component, int x, int y) accessibleContext = new AccessibleAWTPopupMenu(); return accessibleContext; } + + /** + * Generate a unique name for this <code>PopupMenu</code>. + * + * @return A unique name for this <code>PopupMenu</code>. + */ + String generateName() + { + return "popup" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_popup_number++; + } } // class PopupMenu diff --git a/libjava/classpath/java/awt/ScrollPane.java b/libjava/classpath/java/awt/ScrollPane.java index 525d9d3e7da..65ce484b88d 100644 --- a/libjava/classpath/java/awt/ScrollPane.java +++ b/libjava/classpath/java/awt/ScrollPane.java @@ -46,6 +46,7 @@ import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; + /** * This widget provides a scrollable region that allows a single * subcomponent to be viewed through a smaller window. @@ -76,6 +77,11 @@ public static final int SCROLLBARS_ALWAYS = 1; */ public static final int SCROLLBARS_NEVER = 2; +/** + * The number used to generate the name returned by getName. + */ +private static transient long next_scrollpane_number; + // Serialization constant private static final long serialVersionUID = 7956609840827222915L; @@ -221,7 +227,7 @@ getVAdjustable() * @return The viewport size. */ public Dimension getViewportSize () -{ +{ Dimension viewsize = getSize (); Insets insets = getInsets (); @@ -231,9 +237,9 @@ public Dimension getViewportSize () Component[] list = getComponents(); if ((list == null) || (list.length <= 0)) return viewsize; - + Dimension dim = list[0].getPreferredSize(); - + if (dim.width <= 0 && dim.height <= 0) return viewsize; @@ -276,7 +282,7 @@ public Dimension getViewportSize () needHorizontal = true; else if (dim.width > (viewsize.width - vScrollbarWidth)) mayNeedHorizontal = true; - + if (needVertical && mayNeedHorizontal) needHorizontal = true; @@ -288,7 +294,7 @@ public Dimension getViewportSize () if (needVertical) viewsize.width -= vScrollbarWidth; - + return viewsize; } @@ -613,5 +619,21 @@ paramString() accessibleContext = new AccessibleAWTScrollPane(); return accessibleContext; } + + /** + * Generate a unique name for this <code>ScrollPane</code>. + * + * @return A unique name for this <code>ScrollPane</code>. + */ + String generateName() + { + return "scrollpane" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_scrollpane_number++; + } + } // class ScrollPane diff --git a/libjava/classpath/java/awt/Shape.java b/libjava/classpath/java/awt/Shape.java index bd8a4343528..d76bbaba69d 100644 --- a/libjava/classpath/java/awt/Shape.java +++ b/libjava/classpath/java/awt/Shape.java @@ -1,5 +1,5 @@ /* Shape.java -- the classic Object-Oriented shape interface - Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc. + Copyright (C) 1999, 2002, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -176,7 +176,8 @@ public interface Shape * not required, that the Shape isolate iterations from future changes to * the boundary, and document this fact. * - * @param transform an optional transform to apply to the iterator + * @param transform an optional transform to apply to the + * iterator (<code>null</code> permitted). * @return a new iterator over the boundary * @since 1.2 */ @@ -185,7 +186,7 @@ public interface Shape /** * Return an iterator along the flattened version of the shape boundary. * Only SEG_MOVETO, SEG_LINETO, and SEG_CLOSE points are returned in the - * iterator. The flatness paramter controls how far points are allowed to + * iterator. The flatness parameter controls how far points are allowed to * differ from the real curve; although a limit on accuracy may cause this * parameter to be enlarged if needed. * @@ -194,10 +195,11 @@ public interface Shape * use. It is recommended, but not required, that the Shape isolate * iterations from future changes to the boundary, and document this fact. * - * @param transform an optional transform to apply to the iterator + * @param transform an optional transform to apply to the + * iterator (<code>null</code> permitted). * @param flatness the maximum distance for deviation from the real boundary * @return a new iterator over the boundary * @since 1.2 */ PathIterator getPathIterator(AffineTransform transform, double flatness); -} // interface Shape +} diff --git a/libjava/classpath/java/awt/TextArea.java b/libjava/classpath/java/awt/TextArea.java index b04cdc89204..7e3463ab849 100644 --- a/libjava/classpath/java/awt/TextArea.java +++ b/libjava/classpath/java/awt/TextArea.java @@ -125,9 +125,11 @@ public class TextArea extends TextComponent implements java.io.Serializable * the specified text. Conceptually the <code>TextArea</code> has 0 * rows and 0 columns but its initial bounds are defined by its peer * or by the container in which it is packed. Both horizontal and - * veritcal scrollbars will be displayed. + * veritcal scrollbars will be displayed. The TextArea initially contains + * the specified text. If text specified as <code>null<code>, it will + * be set to "". * - * @param text The text to display in this text area. + * @param text The text to display in this text area (<code>null</code> permitted). * * @exception HeadlessException if GraphicsEnvironment.isHeadless () is true */ @@ -156,9 +158,10 @@ public class TextArea extends TextComponent implements java.io.Serializable * Initialize a new instance of <code>TextArea</code> that can * display the specified number of rows and columns of text, without * the need to scroll. The TextArea initially contains the - * specified text. + * specified text. If text specified as <code>null<code>, it will + * be set to "". * - * @param text The text to display in this text area. + * @param text The text to display in this text area (<code>null</code> permitted). * @param rows The number of rows in this text area. * @param columns The number of columns in this text area. * @@ -174,9 +177,10 @@ public class TextArea extends TextComponent implements java.io.Serializable * contains the specified text. The TextArea can display the * specified number of rows and columns of text, without the need to * scroll. This constructor allows specification of the scroll bar - * display policy. + * display policy. The TextArea initially contains the specified text. + * If text specified as <code>null<code>, it will be set to "". * - * @param text The text to display in this text area. + * @param text The text to display in this text area (<code>null</code> permitted). * @param rows The number of rows in this text area. * @param columns The number of columns in this text area. * @param scrollbarVisibility The scroll bar display policy. One of @@ -192,18 +196,20 @@ public class TextArea extends TextComponent implements java.io.Serializable if (GraphicsEnvironment.isHeadless ()) throw new HeadlessException (); - if (rows < 0 || columns < 0) - throw new IllegalArgumentException ("Bad row or column value"); - - if (scrollbarVisibility != SCROLLBARS_BOTH - && scrollbarVisibility != SCROLLBARS_VERTICAL_ONLY - && scrollbarVisibility != SCROLLBARS_HORIZONTAL_ONLY - && scrollbarVisibility != SCROLLBARS_NONE) - throw new IllegalArgumentException ("Bad scrollbar visibility value"); + if (rows < 0) + this.rows = 0; + else + this.rows = rows; + + if (columns < 0) + this.columns = 0; + else + this.columns = columns; - this.rows = rows; - this.columns = columns; - this.scrollbarVisibility = scrollbarVisibility; + if (scrollbarVisibility < 0 || scrollbarVisibility > 4) + this.scrollbarVisibility = SCROLLBARS_BOTH; + else + this.scrollbarVisibility = scrollbarVisibility; // TextAreas need to receive tab key events so we override the // default forward and backward traversal key sets. @@ -478,6 +484,8 @@ public class TextArea extends TextComponent implements java.io.Serializable if (peer != null) peer.insert (str, peer.getText().length ()); + else + setText(getText() + str); } /** @@ -504,10 +512,19 @@ public class TextArea extends TextComponent implements java.io.Serializable */ public void insertText (String str, int pos) { + String tmp1 = null; + String tmp2 = null; + TextAreaPeer peer = (TextAreaPeer) getPeer (); if (peer != null) peer.insert (str, pos); + else + { + tmp1 = getText().substring(0, pos); + tmp2 = getText().substring(pos, getText().length()); + setText(tmp1 + str + tmp2); + } } /** @@ -544,10 +561,19 @@ public class TextArea extends TextComponent implements java.io.Serializable */ public void replaceText (String str, int start, int end) { - TextAreaPeer peer = (TextAreaPeer) getPeer (); + String tmp1 = null; + String tmp2 = null; + + TextAreaPeer peer = (TextAreaPeer) getPeer(); if (peer != null) - peer.replaceRange (str, start, end); + peer.replaceRange(str, start, end); + else + { + tmp1 = getText().substring(0, start); + tmp2 = getText().substring(end, getText().length()); + setText(tmp1 + str + tmp2); + } } /** diff --git a/libjava/classpath/java/awt/TextComponent.java b/libjava/classpath/java/awt/TextComponent.java index f08e59c9fc9..f811122f2b2 100644 --- a/libjava/classpath/java/awt/TextComponent.java +++ b/libjava/classpath/java/awt/TextComponent.java @@ -1,5 +1,5 @@ /* TextComponent.java -- Widgets for entering text - Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1999, 2002, 2003, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -54,54 +54,45 @@ import javax.accessibility.AccessibleText; import javax.swing.text.AttributeSet; /** - * This class provides common functionality for widgets than - * contain text. - * - * @author Aaron M. Renn (arenn@urbanophile.com) - */ + * This class provides common functionality for widgets than + * contain text. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ public class TextComponent extends Component implements Serializable, Accessible { -/* - * Static Variables - */ - -// Constant for serialization -private static final long serialVersionUID = -2214773872412987419L; + private static final long serialVersionUID = -2214773872412987419L; -/* - * Instance Variables - */ - -/** - * @serial Indicates whether or not this component is editable. - * This is package-private to avoid an accessor method. - */ -boolean editable; + /** + * @serial Indicates whether or not this component is editable. + * This is package-private to avoid an accessor method. + */ + boolean editable; -/** - * @serial The starting position of the selected text region. - * This is package-private to avoid an accessor method. - */ -int selectionStart; + /** + * @serial The starting position of the selected text region. + * This is package-private to avoid an accessor method. + */ + int selectionStart; -/** - * @serial The ending position of the selected text region. - * This is package-private to avoid an accessor method. - */ -int selectionEnd; + /** + * @serial The ending position of the selected text region. + * This is package-private to avoid an accessor method. + */ + int selectionEnd; -/** - * @serial The text in the component - * This is package-private to avoid an accessor method. - */ -String text; + /** + * @serial The text in the component + * This is package-private to avoid an accessor method. + */ + String text; -/** - * A list of listeners that will receive events from this object. - */ -protected transient TextListener textListener; + /** + * A list of listeners that will receive events from this object. + */ + protected transient TextListener textListener; protected class AccessibleAWTTextComponent extends AccessibleAWTComponent @@ -318,360 +309,298 @@ protected transient TextListener textListener; } -/*************************************************************************/ - -/* - * Constructors - */ - -TextComponent(String text) -{ - this.text = text; - this.editable = true; -} - -/*************************************************************************/ -/* - * Instance Methods - */ - -/** - * Returns the text in this component - * - * @return The text in this component. - */ -public synchronized String -getText() -{ - TextComponentPeer tcp = (TextComponentPeer)getPeer(); - if (tcp != null) - text = tcp.getText(); + TextComponent(String text) + { + if (text == null) + this.text = ""; + else + this.text = text; + + this.editable = true; + } - return(text); -} -/*************************************************************************/ + /** + * Returns the text in this component + * + * @return The text in this component. + */ + public synchronized String getText() + { + TextComponentPeer tcp = (TextComponentPeer) getPeer(); + if (tcp != null) + text = tcp.getText(); -/** - * Sets the text in this component to the specified string. - * - * @param text The new text for this component. - */ -public synchronized void -setText(String text) -{ - if (text == null) - text = ""; + return(text); + } - this.text = text; + /** + * Sets the text in this component to the specified string. + * + * @param text The new text for this component. + */ + public synchronized void setText(String text) + { + if (text == null) + text = ""; - TextComponentPeer tcp = (TextComponentPeer)getPeer(); - if (tcp != null) - tcp.setText(text); - setCaretPosition(0); -} + this.text = text; -/*************************************************************************/ + TextComponentPeer tcp = (TextComponentPeer) getPeer(); + if (tcp != null) + tcp.setText(text); + setCaretPosition(0); + } -/** - * Returns a string that contains the text that is currently selected. - * - * @return The currently selected text region. - */ -public synchronized String -getSelectedText() -{ - String alltext = getText(); - int start = getSelectionStart(); - int end = getSelectionEnd(); + /** + * Returns a string that contains the text that is currently selected. + * + * @return The currently selected text region. + */ + public synchronized String getSelectedText() + { + String alltext = getText(); + int start = getSelectionStart(); + int end = getSelectionEnd(); - return(alltext.substring(start, end)); -} - -/*************************************************************************/ - -/** - * Returns the starting position of the selected text region. - * If the text is not selected then caret position is returned. - * - * @return The starting position of the selected text region. - */ -public synchronized int -getSelectionStart() -{ - TextComponentPeer tcp = (TextComponentPeer)getPeer(); - if (tcp != null) - selectionStart = tcp.getSelectionStart(); - - return(selectionStart); -} - -/*************************************************************************/ - -/** - * Sets the starting position of the selected region to the - * specified value. If the specified value is out of range, then it - * will be silently changed to the nearest legal value. - * - * @param selectionStart The new start position for selected text. - */ -public synchronized void -setSelectionStart(int selectionStart) -{ - select(selectionStart, getSelectionEnd()); -} - -/*************************************************************************/ - -/** - * Returns the ending position of the selected text region. - * If the text is not selected, then caret position is returned - * - * @return The ending position of the selected text region. - */ -public synchronized int -getSelectionEnd() -{ - TextComponentPeer tcp = (TextComponentPeer)getPeer(); - if (tcp != null) - selectionEnd = tcp.getSelectionEnd(); - - return(selectionEnd); -} + return(alltext.substring(start, end)); + } -/*************************************************************************/ + /** + * Returns the starting position of the selected text region. + * If the text is not selected then caret position is returned. + * + * @return The starting position of the selected text region. + */ + public synchronized int getSelectionStart() + { + TextComponentPeer tcp = (TextComponentPeer) getPeer(); + if (tcp != null) + selectionStart = tcp.getSelectionStart(); -/** - * Sets the ending position of the selected region to the - * specified value. If the specified value is out of range, then it - * will be silently changed to the nearest legal value. - * - * @param selectionEnd The new start position for selected text. - */ -public synchronized void -setSelectionEnd(int selectionEnd) -{ - select(getSelectionStart(), selectionEnd); -} + return(selectionStart); + } -/*************************************************************************/ + /** + * Sets the starting position of the selected region to the + * specified value. If the specified value is out of range, then it + * will be silently changed to the nearest legal value. + * + * @param selectionStart The new start position for selected text. + */ + public synchronized void setSelectionStart(int selectionStart) + { + select(selectionStart, getSelectionEnd()); + } -/** - * This method sets the selected text range to the text between the - * specified start and end positions. Illegal values for these - * positions are silently fixed. - * - * @param selectionStart The new start position for the selected text. - * @param selectionEnd The new end position for the selected text. - */ -public synchronized void -select(int selectionStart, int selectionEnd) -{ - if (selectionStart < 0) - selectionStart = 0; + /** + * Returns the ending position of the selected text region. + * If the text is not selected, then caret position is returned + * + * @return The ending position of the selected text region. + */ + public synchronized int getSelectionEnd() + { + TextComponentPeer tcp = (TextComponentPeer) getPeer(); + if (tcp != null) + selectionEnd = tcp.getSelectionEnd(); - if (selectionStart > getText().length()) - selectionStart = text.length(); + return(selectionEnd); + } - if (selectionEnd > text.length()) - selectionEnd = text.length(); + /** + * Sets the ending position of the selected region to the + * specified value. If the specified value is out of range, then it + * will be silently changed to the nearest legal value. + * + * @param selectionEnd The new start position for selected text. + */ + public synchronized void setSelectionEnd(int selectionEnd) + { + select(getSelectionStart(), selectionEnd); + } - if (selectionStart > selectionEnd) - selectionStart = selectionEnd; + /** + * This method sets the selected text range to the text between the + * specified start and end positions. Illegal values for these + * positions are silently fixed. + * + * @param selectionStart The new start position for the selected text. + * @param selectionEnd The new end position for the selected text. + */ + public synchronized void select(int selectionStart, int selectionEnd) + { + if (selectionStart < 0) + selectionStart = 0; - this.selectionStart = selectionStart; - this.selectionEnd = selectionEnd; + if (selectionStart > getText().length()) + selectionStart = text.length(); - TextComponentPeer tcp = (TextComponentPeer)getPeer(); - if (tcp != null) - tcp.select(selectionStart, selectionEnd); -} + if (selectionEnd > text.length()) + selectionEnd = text.length(); -/*************************************************************************/ + if (selectionStart > selectionEnd) + selectionStart = selectionEnd; -/** - * Selects all of the text in the component. - */ -public synchronized void -selectAll() -{ - select(0, getText().length()); -} - -/*************************************************************************/ + this.selectionStart = selectionStart; + this.selectionEnd = selectionEnd; + + TextComponentPeer tcp = (TextComponentPeer) getPeer(); + if (tcp != null) + tcp.select(selectionStart, selectionEnd); + } -/** - * Returns the current caret position in the text. - * - * @return The caret position in the text. - */ -public synchronized int -getCaretPosition() -{ - TextComponentPeer tcp = (TextComponentPeer)getPeer(); - if (tcp != null) - return(tcp.getCaretPosition()); - else - return(0); -} + /** + * Selects all of the text in the component. + */ + public synchronized void selectAll() + { + select(0, getText().length()); + } -/*************************************************************************/ + /** + * Returns the current caret position in the text. + * + * @return The caret position in the text. + */ + public synchronized int getCaretPosition() + { + TextComponentPeer tcp = (TextComponentPeer) getPeer(); + if (tcp != null) + return(tcp.getCaretPosition()); + else + return(0); + } -/** - * Sets the caret position to the specified value. - * - * @param caretPosition The new caret position. - * - * @exception IllegalArgumentException If the value supplied for position - * is less than zero. - * - * @since 1.1 - */ -public synchronized void -setCaretPosition(int caretPosition) -{ - if (caretPosition < 0) - throw new IllegalArgumentException (); + /** + * Sets the caret position to the specified value. + * + * @param caretPosition The new caret position. + * + * @exception IllegalArgumentException If the value supplied for position + * is less than zero. + * + * @since 1.1 + */ + public synchronized void setCaretPosition(int caretPosition) + { + if (caretPosition < 0) + throw new IllegalArgumentException(); - TextComponentPeer tcp = (TextComponentPeer)getPeer(); - if (tcp != null) - tcp.setCaretPosition(caretPosition); -} - -/*************************************************************************/ - -/** - * Tests whether or not this component's text can be edited. - * - * @return <code>true</code> if the text can be edited, <code>false</code> - * otherwise. - */ -public boolean -isEditable() -{ - return(editable); -} - -/*************************************************************************/ - -/** - * Sets whether or not this component's text can be edited. - * - * @param editable <code>true</code> to enable editing of the text, - * <code>false</code> to disable it. - */ -public synchronized void -setEditable(boolean editable) -{ - this.editable = editable; - - TextComponentPeer tcp = (TextComponentPeer)getPeer(); - if (tcp != null) - tcp.setEditable(editable); -} - -/*************************************************************************/ - -/** - * Notifies the component that it should destroy its native peer. - */ -public void -removeNotify() -{ - super.removeNotify(); -} - -/*************************************************************************/ + TextComponentPeer tcp = (TextComponentPeer) getPeer(); + if (tcp != null) + tcp.setCaretPosition(caretPosition); + } -/** - * Adds a new listener to the list of text listeners for this - * component. - * - * @param listener The listener to be added. - */ -public synchronized void -addTextListener(TextListener listener) -{ - textListener = AWTEventMulticaster.add(textListener, listener); + /** + * Tests whether or not this component's text can be edited. + * + * @return <code>true</code> if the text can be edited, <code>false</code> + * otherwise. + */ + public boolean isEditable() + { + return(editable); + } - enableEvents(AWTEvent.TEXT_EVENT_MASK); -} + /** + * Sets whether or not this component's text can be edited. + * + * @param editable <code>true</code> to enable editing of the text, + * <code>false</code> to disable it. + */ + public synchronized void setEditable(boolean editable) + { + this.editable = editable; -/*************************************************************************/ + TextComponentPeer tcp = (TextComponentPeer) getPeer(); + if (tcp != null) + tcp.setEditable(editable); + } -/** - * Removes the specified listener from the list of listeners - * for this component. - * - * @param listener The listener to remove. - */ -public synchronized void -removeTextListener(TextListener listener) -{ - textListener = AWTEventMulticaster.remove(textListener, listener); -} + /** + * Notifies the component that it should destroy its native peer. + */ + public void removeNotify() + { + super.removeNotify(); + } -/*************************************************************************/ + /** + * Adds a new listener to the list of text listeners for this + * component. + * + * @param listener The listener to be added. + */ + public synchronized void addTextListener(TextListener listener) + { + textListener = AWTEventMulticaster.add(textListener, listener); -/** - * Processes the specified event for this component. Text events are - * processed by calling the <code>processTextEvent()</code> method. - * All other events are passed to the superclass method. - * - * @param event The event to process. - */ -protected void -processEvent(AWTEvent event) -{ - if (event instanceof TextEvent) - processTextEvent((TextEvent)event); - else - super.processEvent(event); -} + enableEvents(AWTEvent.TEXT_EVENT_MASK); + } -/*************************************************************************/ + /** + * Removes the specified listener from the list of listeners + * for this component. + * + * @param listener The listener to remove. + */ + public synchronized void removeTextListener(TextListener listener) + { + textListener = AWTEventMulticaster.remove(textListener, listener); + } -/** - * Processes the specified text event by dispatching it to any listeners - * that are registered. Note that this method will only be called - * if text event's are enabled. This will be true if there are any - * registered listeners, or if the event has been specifically - * enabled using <code>enableEvents()</code>. - * - * @param event The text event to process. - */ -protected void -processTextEvent(TextEvent event) -{ - if (textListener != null) - textListener.textValueChanged(event); -} + /** + * Processes the specified event for this component. Text events are + * processed by calling the <code>processTextEvent()</code> method. + * All other events are passed to the superclass method. + * + * @param event The event to process. + */ + protected void processEvent(AWTEvent event) + { + if (event instanceof TextEvent) + processTextEvent((TextEvent)event); + else + super.processEvent(event); + } -void -dispatchEventImpl(AWTEvent e) -{ - if (e.id <= TextEvent.TEXT_LAST - && e.id >= TextEvent.TEXT_FIRST - && (textListener != null - || (eventMask & AWTEvent.TEXT_EVENT_MASK) != 0)) - processEvent(e); - else - super.dispatchEventImpl(e); -} + /** + * Processes the specified text event by dispatching it to any listeners + * that are registered. Note that this method will only be called + * if text event's are enabled. This will be true if there are any + * registered listeners, or if the event has been specifically + * enabled using <code>enableEvents()</code>. + * + * @param event The text event to process. + */ + protected void processTextEvent(TextEvent event) + { + if (textListener != null) + textListener.textValueChanged(event); + } -/*************************************************************************/ + void dispatchEventImpl(AWTEvent e) + { + if (e.id <= TextEvent.TEXT_LAST + && e.id >= TextEvent.TEXT_FIRST + && (textListener != null + || (eventMask & AWTEvent.TEXT_EVENT_MASK) != 0)) + processEvent(e); + else + super.dispatchEventImpl(e); + } -/** - * Returns a debugging string. - * - * @return A debugging string. - */ -protected String -paramString() -{ - return(getClass().getName() + "(text=" + getText() + ")"); -} + /** + * Returns a debugging string. + * + * @return A debugging string. + */ + protected String paramString() + { + return(getClass().getName() + "(text=" + getText() + ")"); + } /** * Returns an array of all the objects currently registered as FooListeners @@ -681,20 +610,20 @@ paramString() * @exception ClassCastException If listenerType doesn't specify a class or * interface that implements java.util.EventListener. */ - public EventListener[] getListeners (Class listenerType) + public EventListener[] getListeners(Class listenerType) { if (listenerType == TextListener.class) - return AWTEventMulticaster.getListeners (textListener, listenerType); + return AWTEventMulticaster.getListeners(textListener, listenerType); - return super.getListeners (listenerType); + return super.getListeners(listenerType); } /** * Returns all text listeners registered to this object. */ - public TextListener[] getTextListeners () + public TextListener[] getTextListeners() { - return (TextListener[]) getListeners (TextListener.class); + return (TextListener[]) getListeners(TextListener.class); } /** @@ -712,30 +641,35 @@ paramString() } - /*******************************/ // Provide AccessibleAWTTextComponent access to several peer functions that // aren't publicly exposed. This is package-private to avoid an accessor // method. - synchronized int - getIndexAtPoint(Point p) + synchronized int getIndexAtPoint(Point p) { - TextComponentPeer tcp = (TextComponentPeer)getPeer(); + TextComponentPeer tcp = (TextComponentPeer) getPeer(); if (tcp != null) return tcp.getIndexAtPoint(p.x, p.y); return -1; } - synchronized Rectangle - getCharacterBounds(int i) + synchronized Rectangle getCharacterBounds(int i) { - TextComponentPeer tcp = (TextComponentPeer)getPeer(); + TextComponentPeer tcp = (TextComponentPeer) getPeer(); if (tcp != null) return tcp.getCharacterBounds(i); return null; } - - + /** + * All old mouse events for this component should + * be ignored. + * + * @return true to ignore all old mouse events. + */ + static boolean ignoreOldMouseEvents() + { + return true; + } } // class TextComponent diff --git a/libjava/classpath/java/awt/TextField.java b/libjava/classpath/java/awt/TextField.java index 23d3d918ff4..b76f393a0b6 100644 --- a/libjava/classpath/java/awt/TextField.java +++ b/libjava/classpath/java/awt/TextField.java @@ -1,5 +1,5 @@ /* TextField.java -- A one line text entry field - 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. @@ -48,450 +48,369 @@ import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleStateSet; /** - * This class implements a single line text entry field widget - * - * @author Aaron M. Renn (arenn@urbanophile.com) - */ -public class TextField extends TextComponent -{ - -/* - * Static Variables - */ - -// Serialization constant -private static final long serialVersionUID = -2966288784432217853L; - -/*************************************************************************/ - -/* - * Instance Variables - */ - -/** - * @serial The number of columns in the text entry field. - */ -private int columns; - -/** - * @serial The character that is echoed when doing protected input - */ -private char echoChar; - -// List of registered ActionListener's for this object. -private ActionListener action_listeners; - -/*************************************************************************/ - -/* - * Constructors - */ - -/** - * Initializes a new instance of <code>TextField</code> that is empty - * and has one column. + * This class implements a single line text entry field widget * - * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, - */ -public -TextField() -{ - this("", 1); -} - -/*************************************************************************/ - -/** - * Initializes a new instance of <code>TextField</code> containing - * the specified text. The number of columns will be equal to the - * length of the text string. - * - * @param text The text to display in the field. - * - * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, - */ -public -TextField(String text) -{ - this(text, text.length()); -} - -/*************************************************************************/ - -/** - * Initializes a new instance of <code>TextField</code> that is empty - * and has the specified number of columns. - * - * @param columns The number of columns in the text field. - * - * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, - */ -public -TextField(int columns) -{ - this("", columns); -} - -/*************************************************************************/ - -/** - * Initializes a new instance of <code>TextField</code> with the - * specified text and number of columns. - * - * @param text The text to display in the field. - * @param columns The number of columns in the field. - * - * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, - */ -public -TextField(String text, int columns) -{ - super(text); - this.columns = columns; - - if (GraphicsEnvironment.isHeadless()) - throw new HeadlessException (); -} - -/*************************************************************************/ - -/* - * Instance Methods + * @author Aaron M. Renn (arenn@urbanophile.com) */ - -/** - * Returns the number of columns in the field. - * - * @return The number of columns in the field. - */ -public int -getColumns() -{ - return(columns); -} - -/*************************************************************************/ - -/** - * Sets the number of columns in this field to the specified value. - * - * @param columns The new number of columns in the field. - * - * @exception IllegalArgumentException If columns is less than zero. - */ -public synchronized void -setColumns(int columns) -{ - if (columns < 0) - throw new IllegalArgumentException("Value is less than zero: " + - columns); - - this.columns = columns; - // FIXME: How to we communicate this to our peer? -} - -/*************************************************************************/ - -/** - * Returns the character that is echoed to the screen when a text - * field is protected (such as when a password is being entered). - * - * @return The echo character for this text field. - */ -public char -getEchoChar() -{ - return(echoChar); -} - -/*************************************************************************/ - -/** - * Sets the character that is echoed when protected input such as - * a password is displayed. - * - * @param echoChar The new echo character. - */ -public void -setEchoChar(char echoChar) +public class TextField extends TextComponent { - setEchoCharacter (echoChar); -} - -/*************************************************************************/ + + /** + * The number used to generate the name returned by getName. + */ + private static transient long next_textfield_number; -/** - * Sets the character that is echoed when protected input such as - * a password is displayed. - * - * @param echoChar The new echo character. - * - * @deprecated This method is deprecated in favor of - * <code>setEchoChar()</code> - */ -public void -setEchoCharacter(char echoChar) -{ - this.echoChar = echoChar; + + private static final long serialVersionUID = -2966288784432217853L; - TextFieldPeer peer = (TextFieldPeer) getPeer (); - if (peer != null) - peer.setEchoChar (echoChar); -} -/*************************************************************************/ + /** + * @serial The number of columns in the text entry field. + */ + private int columns; -/** - * Tests whether or not this text field has an echo character set - * so that characters the user type are not echoed to the screen. - * - * @return <code>true</code> if an echo character is set, - * <code>false</code> otherwise. - */ -public boolean -echoCharIsSet() -{ - if (echoChar == '\u0000') - return(false); - else - return(true); -} + /** + * @serial The character that is echoed when doing protected input + */ + private char echoChar; -/*************************************************************************/ + // List of registered ActionListener's for this object. + private ActionListener action_listeners; -/** - * Returns the minimum size for this text field. - * - * @return The minimum size for this text field. - */ -public Dimension -getMinimumSize() -{ - return getMinimumSize (getColumns ()); -} + /** + * Initializes a new instance of <code>TextField</code> that is empty + * and has one column. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, + */ + public TextField() + { + this("", 0); + } -/*************************************************************************/ + /** + * Initializes a new instance of <code>TextField</code> containing + * the specified text. The number of columns will be equal to the + * length of the text string. + * + * @param text The text to display in the field. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, + */ + public TextField(String text) + { + this(text, (text == null) ? 0 : text.length()); + } -/** - * Returns the minimum size of a text field with the specified number - * of columns. - * - * @param columns The number of columns to get the minimum size for. - */ -public Dimension -getMinimumSize(int columns) -{ - return minimumSize (columns); -} + /** + * Initializes a new instance of <code>TextField</code> that is empty + * and has the specified number of columns. + * + * @param columns The number of columns in the text field. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, + */ + public TextField(int columns) + { + this("", columns); + } -/*************************************************************************/ + /** + * Initializes a new instance of <code>TextField</code> with the + * specified text and number of columns. + * + * @param text The text to display in the field. + * @param columns The number of columns in the field. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true, + */ + public TextField(String text, int columns) + { + super(text); + + if (columns < 0) + this.columns = 0; + else + this.columns = columns; -/** - * Returns the minimum size for this text field. - * - * @return The minimum size for this text field. - * - * @deprecated This method is deprecated in favor of - * <code>getMinimumSize()</code>. - */ -public Dimension -minimumSize() -{ - return minimumSize (getColumns ()); -} + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException (); + } -/*************************************************************************/ + /** + * Returns the number of columns in the field. + * + * @return The number of columns in the field. + */ + public int getColumns() + { + return(columns); + } -/** - * Returns the minimum size of a text field with the specified number - * of columns. - * - * @param columns The number of columns to get the minimum size for. - * - * @deprecated This method is deprecated in favor of - * <code>getMinimumSize(int)</code>. - */ -public Dimension -minimumSize(int columns) -{ - TextFieldPeer peer = (TextFieldPeer) getPeer (); - if (peer == null) - return null; // FIXME: What do we do if there is no peer? + /** + * Sets the number of columns in this field to the specified value. + * + * @param columns The new number of columns in the field. + * + * @exception IllegalArgumentException If columns is less than zero. + */ + public synchronized void setColumns(int columns) + { + if (columns < 0) + throw new IllegalArgumentException("Value is less than zero: " + + columns); - return peer.getMinimumSize (columns); -} + this.columns = columns; + // FIXME: How to we communicate this to our peer? + } -/*************************************************************************/ + /** + * Returns the character that is echoed to the screen when a text + * field is protected (such as when a password is being entered). + * + * @return The echo character for this text field. + */ + public char getEchoChar() + { + return(echoChar); + } -/** - * Returns the preferred size for this text field. - * - * @return The preferred size for this text field. - */ -public Dimension -getPreferredSize() -{ - return getPreferredSize (getColumns ()); -} + /** + * Sets the character that is echoed when protected input such as + * a password is displayed. + * + * @param echoChar The new echo character. + */ + public void setEchoChar(char echoChar) + { + setEchoCharacter(echoChar); + } -/*************************************************************************/ + /** + * Sets the character that is echoed when protected input such as + * a password is displayed. + * + * @param echoChar The new echo character. + * + * @deprecated This method is deprecated in favor of + * <code>setEchoChar()</code> + */ + public void setEchoCharacter(char echoChar) + { + this.echoChar = echoChar; -/** - * Returns the preferred size of a text field with the specified number - * of columns. - * - * @param columns The number of columns to get the preferred size for. - */ -public Dimension -getPreferredSize(int columns) -{ - return preferredSize (columns); -} + TextFieldPeer peer = (TextFieldPeer) getPeer (); + if (peer != null) + peer.setEchoChar (echoChar); + } -/*************************************************************************/ + /** + * Tests whether or not this text field has an echo character set + * so that characters the user type are not echoed to the screen. + * + * @return <code>true</code> if an echo character is set, + * <code>false</code> otherwise. + */ + public boolean echoCharIsSet() + { + if (echoChar == '\u0000') + return(false); + else + return(true); + } -/** - * Returns the preferred size for this text field. - * - * @return The preferred size for this text field. - * - * @deprecated This method is deprecated in favor of - * <code>getPreferredSize()</code>. - */ -public Dimension -preferredSize() -{ - return preferredSize (getColumns ()); -} + /** + * Returns the minimum size for this text field. + * + * @return The minimum size for this text field. + */ + public Dimension getMinimumSize() + { + return getMinimumSize (getColumns ()); + } -/*************************************************************************/ + /** + * Returns the minimum size of a text field with the specified number + * of columns. + * + * @param columns The number of columns to get the minimum size for. + */ + public Dimension getMinimumSize(int columns) + { + return minimumSize(columns); + } -/** - * Returns the preferred size of a text field with the specified number - * of columns. - * - * @param columns The number of columns to get the preferred size for. - * - * @deprecated This method is deprecated in favor of - * <code>getPreferredSize(int)</code>. - */ -public Dimension -preferredSize(int columns) -{ - TextFieldPeer peer = (TextFieldPeer) getPeer (); - if (peer == null) - return new Dimension (0, 0); + /** + * Returns the minimum size for this text field. + * + * @return The minimum size for this text field. + * + * @deprecated This method is deprecated in favor of + * <code>getMinimumSize()</code>. + */ + public Dimension minimumSize() + { + return minimumSize(getColumns ()); + } - return peer.getPreferredSize (columns); -} + /** + * Returns the minimum size of a text field with the specified number + * of columns. + * + * @param columns The number of columns to get the minimum size for. + * + * @deprecated This method is deprecated in favor of + * <code>getMinimumSize(int)</code>. + */ + public Dimension minimumSize(int columns) + { + TextFieldPeer peer = (TextFieldPeer) getPeer (); + if (peer == null) + return null; // FIXME: What do we do if there is no peer? -/*************************************************************************/ + return peer.getMinimumSize (columns); + } -/** - * Notifies this object that it should create its native peer. - */ -public void -addNotify() -{ - if (getPeer() != null) - return; + /** + * Returns the preferred size for this text field. + * + * @return The preferred size for this text field. + */ + public Dimension getPreferredSize() + { + return getPreferredSize(getColumns ()); + } - setPeer((ComponentPeer)getToolkit().createTextField(this)); - super.addNotify(); -} + /** + * Returns the preferred size of a text field with the specified number + * of columns. + * + * @param columns The number of columns to get the preferred size for. + */ + public Dimension getPreferredSize(int columns) + { + return preferredSize(columns); + } -/*************************************************************************/ + /** + * Returns the preferred size for this text field. + * + * @return The preferred size for this text field. + * + * @deprecated This method is deprecated in favor of + * <code>getPreferredSize()</code>. + */ + public Dimension preferredSize() + { + return preferredSize(getColumns ()); + } -/** - * Addes a new listener to the list of action listeners for this - * object. - * - * @param listener The listener to add to the list. - */ -public synchronized void -addActionListener(ActionListener listener) -{ - action_listeners = AWTEventMulticaster.add(action_listeners, listener); + /** + * Returns the preferred size of a text field with the specified number + * of columns. + * + * @param columns The number of columns to get the preferred size for. + * + * @deprecated This method is deprecated in favor of + * <code>getPreferredSize(int)</code>. + */ + public Dimension preferredSize(int columns) + { + TextFieldPeer peer = (TextFieldPeer) getPeer (); + if (peer == null) + return new Dimension (0, 0); - enableEvents(AWTEvent.ACTION_EVENT_MASK); -} + return peer.getPreferredSize (columns); + } -/*************************************************************************/ + /** + * Notifies this object that it should create its native peer. + */ + public void addNotify() + { + if (getPeer() != null) + return; -/** - * Removes the specified listener from the list of action listeners - * for this object. - * - * @param listener The listener to remove from the list. - */ -public synchronized void -removeActionListener(ActionListener listener) -{ - action_listeners = AWTEventMulticaster.remove(action_listeners, listener); -} + setPeer((ComponentPeer)getToolkit().createTextField(this)); + super.addNotify(); + } -/*************************************************************************/ + /** + * Addes a new listener to the list of action listeners for this + * object. + * + * @param listener The listener to add to the list. + */ + public synchronized void addActionListener(ActionListener listener) + { + action_listeners = AWTEventMulticaster.add(action_listeners, listener); -/** - * Processes the specified event. If the event is an instance of - * <code>ActionEvent</code> then <code>processActionEvent()</code> is - * called to process it, otherwise the event is sent to the - * superclass. - * - * @param event The event to process. - */ -protected void -processEvent(AWTEvent event) -{ - if (event instanceof ActionEvent) - processActionEvent((ActionEvent)event); - else - super.processEvent(event); -} + enableEvents(AWTEvent.ACTION_EVENT_MASK); + } -/*************************************************************************/ + /** + * Removes the specified listener from the list of action listeners + * for this object. + * + * @param listener The listener to remove from the list. + */ + public synchronized void removeActionListener(ActionListener listener) + { + action_listeners = AWTEventMulticaster.remove(action_listeners, listener); + } -/** - * Processes an action event by calling any registered listeners. - * Note to subclasses: This method is not called unless action events - * are enabled on this object. This will be true if any listeners - * are registered, or if action events were specifically enabled - * using <code>enableEvents()</code>. - * - * @param event The event to process. - */ -protected void -processActionEvent(ActionEvent event) -{ - if (action_listeners != null) - action_listeners.actionPerformed(event); -} + /** + * Processes the specified event. If the event is an instance of + * <code>ActionEvent</code> then <code>processActionEvent()</code> is + * called to process it, otherwise the event is sent to the + * superclass. + * + * @param event The event to process. + */ + protected void processEvent(AWTEvent event) + { + if (event instanceof ActionEvent) + processActionEvent((ActionEvent)event); + else + super.processEvent(event); + } -void -dispatchEventImpl(AWTEvent e) -{ - if (e.id <= ActionEvent.ACTION_LAST - && e.id >= ActionEvent.ACTION_FIRST - && (action_listeners != null - || (eventMask & AWTEvent.ACTION_EVENT_MASK) != 0)) - processEvent(e); - else - super.dispatchEventImpl(e); -} + /** + * Processes an action event by calling any registered listeners. + * Note to subclasses: This method is not called unless action events + * are enabled on this object. This will be true if any listeners + * are registered, or if action events were specifically enabled + * using <code>enableEvents()</code>. + * + * @param event The event to process. + */ + protected void processActionEvent(ActionEvent event) + { + if (action_listeners != null) + action_listeners.actionPerformed(event); + } -/*************************************************************************/ + void dispatchEventImpl(AWTEvent e) + { + if (e.id <= ActionEvent.ACTION_LAST + && e.id >= ActionEvent.ACTION_FIRST + && (action_listeners != null + || (eventMask & AWTEvent.ACTION_EVENT_MASK) != 0)) + processEvent(e); + else + super.dispatchEventImpl(e); + } -/** + /** * Returns a debug string for this object. * * @return A debug string for this object. */ -protected String -paramString() -{ - return(getClass().getName() + "(columns=" + getColumns() + ",echoChar=" + - getEchoChar()); -} + protected String paramString() + { + return(getClass().getName() + "(columns=" + getColumns() + ",echoChar=" + + getEchoChar()); + } /** * Returns an array of all the objects currently registered as FooListeners @@ -521,6 +440,21 @@ paramString() { return (ActionListener[]) getListeners (ActionListener.class); } + + /** + * Generate a unique name for this <code>TextField</code>. + * + * @return A unique name for this <code>TextField</code>. + */ + String generateName() + { + return "textfield" + getUniqueLong(); + } + + private static synchronized long getUniqueLong() + { + return next_textfield_number++; + } protected class AccessibleAWTTextField extends AccessibleAWTTextComponent { @@ -541,4 +475,4 @@ paramString() return new AccessibleAWTTextField(); } -} // class TextField +} diff --git a/libjava/classpath/java/awt/Toolkit.java b/libjava/classpath/java/awt/Toolkit.java index 282e50d2c50..2842091c139 100644 --- a/libjava/classpath/java/awt/Toolkit.java +++ b/libjava/classpath/java/awt/Toolkit.java @@ -70,6 +70,7 @@ import java.awt.peer.ListPeer; import java.awt.peer.MenuBarPeer; import java.awt.peer.MenuItemPeer; import java.awt.peer.MenuPeer; +import java.awt.peer.MouseInfoPeer; import java.awt.peer.PanelPeer; import java.awt.peer.PopupMenuPeer; import java.awt.peer.ScrollPanePeer; @@ -332,6 +333,18 @@ public abstract class Toolkit protected abstract MenuItemPeer createMenuItem(MenuItem target); /** + * Returns a MouseInfoPeer. + * The default implementation of this method throws + * UnsupportedOperationException. + * + * Toolkit implementations should overload this if possible, however. + */ + protected MouseInfoPeer getMouseInfoPeer() + { + throw new UnsupportedOperationException("No mouse info peer."); + } + + /** * Creates a peer object for the specified <code>FileDialog</code>. * * @param target The <code>FileDialog</code> to create the peer for. @@ -695,6 +708,14 @@ public abstract class Toolkit public PrintJob getPrintJob(Frame frame, String title, JobAttributes jobAttr, PageAttributes pageAttr) { + // FIXME: it is possible this check may be removed + // if this method, when written, always delegates to + // getPrintJob(Frame, String, Properties). + SecurityManager sm; + sm = System.getSecurityManager(); + if (sm != null) + sm.checkPrintJobAccess(); + return null; } diff --git a/libjava/classpath/java/awt/Window.java b/libjava/classpath/java/awt/Window.java index 8bc4715aed5..8885821811d 100644 --- a/libjava/classpath/java/awt/Window.java +++ b/libjava/classpath/java/awt/Window.java @@ -39,8 +39,6 @@ exception statement from your version. */ package java.awt; import java.awt.event.ComponentEvent; -import java.awt.event.FocusEvent; -import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowFocusListener; import java.awt.event.WindowListener; @@ -80,6 +78,8 @@ public class Window extends Container implements Accessible private int state = 0; /** @since 1.4 */ private boolean focusableWindowState = true; + /** @since 1.5 */ + private boolean alwaysOnTop = false; // A list of other top-level windows owned by this window. private transient Vector ownedWindows = new Vector(); @@ -130,7 +130,6 @@ public class Window extends Container implements Accessible // cycle roots. focusCycleRoot = true; setLayout(new BorderLayout()); - addWindowFocusListener(); GraphicsEnvironment g = GraphicsEnvironment.getLocalGraphicsEnvironment(); graphicsConfiguration = g.getDefaultScreenDevice().getDefaultConfiguration(); @@ -142,67 +141,6 @@ public class Window extends Container implements Accessible graphicsConfiguration = gc; } - private void addWindowFocusListener() - { - addWindowFocusListener(new WindowAdapter() - { - public void windowGainedFocus(WindowEvent event) - { - EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); - if (windowFocusOwner != null) - { - synchronized (eq) - { - KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); - Component currentFocusOwner = manager.getGlobalPermanentFocusOwner(); - if (currentFocusOwner != null) - { - eq.postEvent(new FocusEvent(currentFocusOwner, - FocusEvent.FOCUS_LOST, false, - windowFocusOwner)); - eq.postEvent(new FocusEvent(windowFocusOwner, - FocusEvent.FOCUS_GAINED, false, - currentFocusOwner)); - } - else - eq.postEvent(new FocusEvent(windowFocusOwner, - FocusEvent.FOCUS_GAINED, false)); - } - } - else - eq.postEvent(new FocusEvent(Window.this, FocusEvent.FOCUS_GAINED, - false)); - } - - public void windowLostFocus(WindowEvent event) - { - EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); - if (windowFocusOwner != null) - { - synchronized (eq) - { - KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); - Component currentFocusOwner = manager.getGlobalPermanentFocusOwner(); - if (currentFocusOwner != null) - { - eq.postEvent(new FocusEvent(currentFocusOwner, - FocusEvent.FOCUS_GAINED, false, - windowFocusOwner)); - eq.postEvent(new FocusEvent(windowFocusOwner, - FocusEvent.FOCUS_LOST, false, - currentFocusOwner)); - } - else - eq.postEvent(new FocusEvent(windowFocusOwner, - FocusEvent.FOCUS_LOST, false)); - } - } - else - eq.postEvent(new FocusEvent(Window.this, FocusEvent.FOCUS_LOST, false)); - } - }); - } - /** * Initializes a new instance of <code>Window</code> with the specified * parent. The window will initially be invisible. @@ -420,13 +358,17 @@ public class Window extends Container implements Accessible /** * Sends this window to the back so that all other windows display in * front of it. + * + * If the window is set to be always-on-top, this will remove its + * always-on-top status. */ public void toBack() { if (peer != null) { - WindowPeer wp = (WindowPeer) peer; - wp.toBack(); + if( alwaysOnTop ) + setAlwaysOnTop( false ); + ( (WindowPeer) peer ).toBack(); } } @@ -437,10 +379,7 @@ public class Window extends Container implements Accessible public void toFront() { if (peer != null) - { - WindowPeer wp = (WindowPeer) peer; - wp.toFront(); - } + ( (WindowPeer) peer ).toFront(); } /** @@ -1236,6 +1175,55 @@ public class Window extends Container implements Accessible } /** + * Returns whether the Windows is an always-on-top window, + * meaning whether the window can be obscured by other windows or not. + * + * @return <code>true</code> if the windows is always-on-top, + * <code>false</code> otherwise. + * @since 1.5 + */ + public final boolean isAlwaysOnTop() + { + return alwaysOnTop; + } + + /** + * Sets the always-on-top state of this window (if supported). + * + * Setting a window to always-on-top means it will not be obscured + * by any other windows (with the exception of other always-on-top + * windows). Not all platforms may support this. + * + * If an window's always-on-top status is changed to false, the window + * will remain at the front but not be anchored there. + * + * Calling toBack() on an always-on-top window will change its + * always-on-top status to false. + * + * @since 1.5 + */ + public final void setAlwaysOnTop(boolean alwaysOnTop) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission( new AWTPermission("setWindowAlwaysOnTop") ); + + if( this.alwaysOnTop == alwaysOnTop ) + return; + + if( alwaysOnTop ) + toFront(); + + firePropertyChange("alwaysOnTop", this.alwaysOnTop, alwaysOnTop ); + this.alwaysOnTop = alwaysOnTop; + + if (peer != null) + ( (WindowPeer) peer).updateAlwaysOnTop(); + else + System.out.println("Null peer?!"); + } + + /** * Generate a unique name for this window. * * @return A unique name for this window. diff --git a/libjava/classpath/java/awt/datatransfer/Clipboard.java b/libjava/classpath/java/awt/datatransfer/Clipboard.java index 5fa1d1ab134..2029e2c351b 100644 --- a/libjava/classpath/java/awt/datatransfer/Clipboard.java +++ b/libjava/classpath/java/awt/datatransfer/Clipboard.java @@ -1,5 +1,5 @@ /* Clipboard.java -- Class for transferring data via cut and paste. - Copyright (C) 1999, 2001, 2005 Free Software Foundation, Inc. + Copyright (C) 1999, 2001, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -182,6 +182,9 @@ public class Clipboard public void addFlavorListener(FlavorListener listener) { + if (listener == null) + return; + synchronized(listeners) { listeners.add(listener); @@ -190,6 +193,9 @@ public class Clipboard public void removeFlavorListener(FlavorListener listener) { + if (listener == null) + return; + synchronized(listeners) { listeners.remove(listener); diff --git a/libjava/classpath/java/awt/datatransfer/DataFlavor.java b/libjava/classpath/java/awt/datatransfer/DataFlavor.java index 5944c2eb7ec..0228cd5786d 100644 --- a/libjava/classpath/java/awt/datatransfer/DataFlavor.java +++ b/libjava/classpath/java/awt/datatransfer/DataFlavor.java @@ -1,5 +1,5 @@ /* DataFlavor.java -- A type of data to transfer via the clipboard. - Copyright (C) 1999, 2001, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 1999, 2001, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -47,6 +47,7 @@ import java.io.InputStreamReader; import java.io.ObjectInput; import java.io.ObjectOutput; import java.io.Reader; +import java.io.Serializable; import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; @@ -197,31 +198,37 @@ public class DataFlavor implements java.io.Externalizable, Cloneable throw new ClassNotFoundException(className); } - private static Class getRepresentationClassFromMime(String mimeString, + private static Class getRepresentationClassFromMimeThrows(String mimeString, ClassLoader classLoader) + throws ClassNotFoundException { String classname = getParameter("class", mimeString); if (classname != null) - { - try - { - return tryToLoadClass(classname, classLoader); - } - catch(Exception e) - { - IllegalArgumentException iae; - iae = new IllegalArgumentException("mimeString: " - + mimeString - + " classLoader: " - + classLoader); - iae.initCause(e); - throw iae; - } - } + return tryToLoadClass(classname, classLoader); else return java.io.InputStream.class; } - + + // Same as above, but wraps any ClassNotFoundExceptions + private static Class getRepresentationClassFromMime(String mimeString, + ClassLoader classLoader) + { + try + { + return getRepresentationClassFromMimeThrows(mimeString, classLoader); + } + catch(ClassNotFoundException cnfe) + { + IllegalArgumentException iae; + iae = new IllegalArgumentException("mimeString: " + + mimeString + + " classLoader: " + + classLoader); + iae.initCause(cnfe); + throw iae; + } + } + /** * Returns the value of the named MIME type parameter, or <code>null</code> * if the parameter does not exist. Given the parameter name and the mime @@ -240,7 +247,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable String value = mimeString.substring(idx + paramName.length() + 1); - idx = value.indexOf(" "); + idx = value.indexOf(";"); if (idx == -1) return(value); else @@ -328,6 +335,14 @@ public class DataFlavor implements java.io.Externalizable, Cloneable { this.representationClass = representationClass; this.mimeType = mimeType; + + // Do some simple validity checks + String type = getPrimaryType() + "/" + getSubType(); + if (type.indexOf(' ') != -1 + || type.indexOf('=') != -1 + || type.indexOf(';') != -1) + throw new IllegalArgumentException(mimeType); + if (humanPresentableName != null) this.humanPresentableName = humanPresentableName; else @@ -375,7 +390,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable ClassLoader classLoader) throws ClassNotFoundException { - this(getRepresentationClassFromMime(mimeType, classLoader), + this(getRepresentationClassFromMimeThrows(mimeType, classLoader), mimeType, humanPresentableName); } @@ -417,7 +432,8 @@ public class DataFlavor implements java.io.Externalizable, Cloneable */ public DataFlavor(String mimeType) throws ClassNotFoundException { - this(mimeType, null); + this(getRepresentationClassFromMimeThrows(mimeType, null), + mimeType, null); } /** @@ -567,7 +583,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable */ public boolean isRepresentationClassInputStream() { - return representationClass.getName().equals("java.io.InputStream"); + return InputStream.class.isAssignableFrom(representationClass); } /** @@ -579,17 +595,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable */ public boolean isRepresentationClassSerializable() { - Class[] interfaces = representationClass.getInterfaces(); - - int i = 0; - while (i < interfaces.length) - { - if (interfaces[i].getName().equals("java.io.Serializable")) - return true; - ++i; - } - - return false; + return Serializable.class.isAssignableFrom(representationClass); } /** @@ -634,8 +640,10 @@ public class DataFlavor implements java.io.Externalizable, Cloneable */ public boolean isFlavorJavaFileListType() { - if (mimeType.equals(javaFileListFlavor.mimeType) - && representationClass.equals(javaFileListFlavor.representationClass)) + if (getPrimaryType().equals(javaFileListFlavor.getPrimaryType()) + && getSubType().equals(javaFileListFlavor.getSubType()) + && javaFileListFlavor.representationClass + .isAssignableFrom(representationClass)) return true; return false ; @@ -666,7 +674,11 @@ public class DataFlavor implements java.io.Externalizable, Cloneable /** * This method test the specified <code>DataFlavor</code> for equality * against this object. This will be true if the MIME type and - * representation type are the equal. + * representation class are the equal. If the primary type is 'text' + * then also the value of the charset parameter is compared. In such a + * case when the charset parameter isn't given then the charset is + * assumed to be equal to the default charset of the platform. All + * other parameters are ignored. * * @param flavor The <code>DataFlavor</code> to test against. * @@ -677,12 +689,34 @@ public class DataFlavor implements java.io.Externalizable, Cloneable { if (flavor == null) return false; - - if (! this.mimeType.toLowerCase().equals(flavor.mimeType.toLowerCase())) + + String primary = getPrimaryType(); + if (! primary.equals(flavor.getPrimaryType())) return false; - + + String sub = getSubType(); + if (! sub.equals(flavor.getSubType())) + return false; + if (! this.representationClass.equals(flavor.representationClass)) return false; + + if (primary.equals("text")) + if (! isRepresentationClassCharBuffer() + && ! isRepresentationClassReader() + && representationClass != java.lang.String.class + && ! (representationClass.isArray() + && representationClass.getComponentType() == Character.TYPE)) + { + String charset = getParameter("charset"); + String otherset = flavor.getParameter("charset"); + String defaultset = Charset.defaultCharset().name(); + + if (charset == null || charset.equals(defaultset)) + return (otherset == null || otherset.equals(defaultset)); + + return charset.equals(otherset); + } return true; } diff --git a/libjava/classpath/java/awt/dnd/DragGestureEvent.java b/libjava/classpath/java/awt/dnd/DragGestureEvent.java index 9f2bc7c98b8..351ae540072 100644 --- a/libjava/classpath/java/awt/dnd/DragGestureEvent.java +++ b/libjava/classpath/java/awt/dnd/DragGestureEvent.java @@ -48,13 +48,6 @@ import java.util.EventObject; import java.util.Iterator; import java.util.List; -/** - * STUBBED - * @see DragGestureRecognizer - * @see DragGestureListener - * @see DragSource - * @since 1.2 - */ public class DragGestureEvent extends EventObject { /** @@ -66,52 +59,121 @@ public class DragGestureEvent extends EventObject private Component component; private final Point origin; private final int action; + private List events; + private DragGestureRecognizer dgr; + /** + * Constructs a new DragGestureEvent. + * @param dgr - DragGestureRecognizer firing this event + * @param action - user's preferred action + * @param origin - origin of the drag + * @param events - List of events that make up the gesture + * @throws IllegalArgumentException - if input parameters are null + */ public DragGestureEvent(DragGestureRecognizer dgr, int action, Point origin, List events) - { + { super(dgr); - if (origin == null || events == null) + if (origin == null || events == null || dgr == null) throw new IllegalArgumentException(); + this.origin = origin; this.action = action; + this.events = events; + this.dgr = dgr; + this.component = dgr.getComponent(); + this.dragSource = dgr.getDragSource(); } + /** + * Returns the source casted as a DragGestureRecognizer. + * + * @return the source casted as a DragGestureRecognizer. + */ public DragGestureRecognizer getSourceAsDragGestureRecognizer() { - return (DragGestureRecognizer) source; + return (DragGestureRecognizer) getSource(); } + + /** + * Returns the Component corresponding to this. + * + * @return the Component corresponding to this. + */ public Component getComponent() { - return null; + return component; } + + /** + * Gets the DragSource corresponding to this. + * + * @return the DragSource corresponding to this. + */ public DragSource getDragSource() { - return null; + return dragSource; } + + /** + * Returns the origin of the drag. + * + * @return the origin of the drag. + */ public Point getDragOrigin() { return origin; } + + /** + * Gets an iterator representation of the List of events. + * + * @return an iterator representation of the List of events. + */ public Iterator iterator() { - return null; + return events.iterator(); } + + /** + * Gets an array representation of the List of events. + * + * @return an array representation of the List of events. + */ public Object[] toArray() { - return null; + return events.toArray(); } + + /** + * Gets an array representation of the List of events. + * + * @param array - the array to store the events in. + * @return an array representation of the List of events. + */ public Object[] toArray(Object[] array) { - return array; + return events.toArray(array); } + + /** + * Gets the user's preferred action. + * + * @return the user's preferred action. + */ public int getDragAction() { - return 0; + return action; } + + /** + * Get the event that triggered this gesture. + * + * @return the event that triggered this gesture. + */ public InputEvent getTriggerEvent() { - return null; + return dgr.getTriggerEvent(); } /** @@ -152,5 +214,6 @@ public class DragGestureEvent extends EventObject public void startDrag(Cursor dragCursor, Image dragImage, Point imageOffset, Transferable trans, DragSourceListener l) { + dragSource.startDrag(this, dragCursor, dragImage, imageOffset, trans, l); } } // class DragGestureEvent diff --git a/libjava/classpath/java/awt/dnd/DragGestureRecognizer.java b/libjava/classpath/java/awt/dnd/DragGestureRecognizer.java index 145a24a3850..32bbc56da5d 100644 --- a/libjava/classpath/java/awt/dnd/DragGestureRecognizer.java +++ b/libjava/classpath/java/awt/dnd/DragGestureRecognizer.java @@ -131,6 +131,7 @@ public abstract class DragGestureRecognizer implements Serializable throws NotImplementedException { events = new ArrayList(); + // FIXME: Not implemented fully. } /** diff --git a/libjava/classpath/java/awt/dnd/DragSource.java b/libjava/classpath/java/awt/dnd/DragSource.java index 05eb6709d47..48fa2388ee2 100644 --- a/libjava/classpath/java/awt/dnd/DragSource.java +++ b/libjava/classpath/java/awt/dnd/DragSource.java @@ -38,6 +38,8 @@ exception statement from your version. */ package java.awt.dnd; +import gnu.classpath.NotImplementedException; + import java.awt.Component; import java.awt.Cursor; import java.awt.GraphicsEnvironment; @@ -70,9 +72,12 @@ public class DragSource implements Serializable public static final Cursor DefaultLinkNoDrop = null; private transient FlavorMap flavorMap = SystemFlavorMap.getDefaultFlavorMap (); - private transient DragSourceListener dragSourceListener; private transient DragSourceMotionListener dragSourceMotionListener; + + private static DragSource ds; + private DragSourceContextPeer peer; + private DragSourceContext context; /** * Initializes the drag source. @@ -82,19 +87,34 @@ public class DragSource implements Serializable public DragSource() { if (GraphicsEnvironment.isHeadless()) - throw new HeadlessException (); + { + ds = null; + throw new HeadlessException(); + } } /** + * Gets the default drag source. + * * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. */ public static DragSource getDefaultDragSource() { - return new DragSource(); + if (GraphicsEnvironment.isHeadless()) + { + ds = null; + throw new HeadlessException(); + } + + if (ds == null) + ds = new DragSource(); + return ds; } public static boolean isDragImageSupported() + throws NotImplementedException { + // FIXME: Implement this return false; } @@ -110,6 +130,43 @@ public class DragSource implements Serializable Transferable trans, DragSourceListener dsl, FlavorMap map) { + // http://www.javaworld.com/javaworld/jw-03-1999/jw-03-dragndrop.html + + // This function creates a DragSourceContext object. This object tracks the + // state of the operation by listening to a native peer. In this situation, + // the DragSource may be obtained from the event or by an instance variable. + // This function also creates a new DragSourceContextPeer. + + // This function sends the same message to the context, which then forwards + // it to the peer, passing itself as a parameter. Now, the native system has + // access to the Transferable through the context. + + // FIXME: Add check to determine if dragging. + + try + { + flavorMap = map; + + if (peer == null) + peer = Toolkit.getDefaultToolkit().createDragSourceContextPeer(trigger); + + if (context == null) + context = createDragSourceContext(peer, trigger, + dragCursor, + dragImage, + imageOffset, trans, + dsl); + + if (peer == null) + throw new InvalidDnDOperationException(); + + peer.startDrag(context, dragCursor, dragImage, imageOffset); + } + catch (Exception e) + { + throw new InvalidDnDOperationException("Drag and Drop system is " + + "unable to initiate a drag operation."); + } } /** @@ -156,7 +213,7 @@ public class DragSource implements Serializable /** * Creates the DragSourceContext to handle this drag. * - * @exception IllegalArgumentException FIXME + * @exception IllegalArgumentException * @exception NullPointerException If dscp, dgl, dragImage or t is null. */ protected DragSourceContext @@ -164,7 +221,7 @@ public class DragSource implements Serializable Cursor cursor, Image image, Point offset, Transferable t, DragSourceListener dsl) { - return null; + return new DragSourceContext(peer, dge, cursor, image, offset, t, dsl); } public FlavorMap getFlavorMap() @@ -172,42 +229,22 @@ public class DragSource implements Serializable return flavorMap; } - /** - * Dummy DragGestureRecognizer when Toolkit doesn't support drag and drop. - */ - static class NoDragGestureRecognizer extends DragGestureRecognizer - { - NoDragGestureRecognizer(DragSource ds, Component c, int actions, - DragGestureListener dgl) - { - super(ds, c, actions, dgl); - } - - protected void registerListeners() { } - protected void unregisterListeners() { } - } - - public DragGestureRecognizer - createDragGestureRecognizer(Class recognizer, Component c, int actions, - DragGestureListener dgl) + public DragGestureRecognizer createDragGestureRecognizer(Class recognizer, + Component c, + int actions, + DragGestureListener dgl) { - DragGestureRecognizer dgr; - dgr = Toolkit.getDefaultToolkit () - .createDragGestureRecognizer (recognizer, this, c, actions, - dgl); - - if (dgr == null) - dgr = new NoDragGestureRecognizer(this, c, actions, dgl); - - return dgr; + return Toolkit.getDefaultToolkit().createDragGestureRecognizer(recognizer, + this, c, + actions, dgl); } - public DragGestureRecognizer - createDefaultDragGestureRecognizer(Component c, int actions, - DragGestureListener dgl) + public DragGestureRecognizer createDefaultDragGestureRecognizer(Component c, + int actions, + DragGestureListener dgl) { - return createDragGestureRecognizer (MouseDragGestureRecognizer.class, c, - actions, dgl); + return createDragGestureRecognizer(MouseDragGestureRecognizer.class, c, + actions, dgl); } /** @@ -275,4 +312,17 @@ public class DragSource implements Serializable // Return an empty EventListener array. return new EventListener [0]; } + + /** + * TODO + * @return + * + * @since 1.5 + */ + public static int getDragThreshold() + throws NotImplementedException + { + // FIXME: Not implemented. + return 4; + } } // class DragSource diff --git a/libjava/classpath/java/awt/dnd/DragSourceContext.java b/libjava/classpath/java/awt/dnd/DragSourceContext.java index 88607b090ea..1fee5c0c304 100644 --- a/libjava/classpath/java/awt/dnd/DragSourceContext.java +++ b/libjava/classpath/java/awt/dnd/DragSourceContext.java @@ -70,8 +70,8 @@ public class DragSourceContext private Transferable transferable; private DragGestureEvent trigger; private DragSourceListener dragSourceListener; - private boolean useCustomCursor; // FIXME: currently unused but needed for serialization. - private int sourceActions; // FIXME: currently unused but needed for serialization. + private boolean useCustomCursor; + private int sourceActions; private Image image; private Point offset; @@ -82,16 +82,17 @@ public class DragSourceContext * are null, the drag action for the trigger event is DnDConstants.ACTION_NONE * or if the source actions for the DragGestureRecognizer associated with the * trigger event are equal to DnDConstants.ACTION_NONE. - * @exception NullPointerException If peer or trigger is null. + * @exception NullPointerException If peer, trans or trigger is null or if the + * image is not null but the offset is. */ public DragSourceContext (DragSourceContextPeer peer, DragGestureEvent trigger, Cursor cursor, Image image, Point offset, Transferable trans, DragSourceListener dsl) - throws NotImplementedException - { + { if (peer == null - || trigger == null) + || trigger == null || trans == null + || (image != null && offset == null)) throw new NullPointerException (); if (trigger.getComponent () == null @@ -108,37 +109,77 @@ public class DragSourceContext this.offset = offset; this.transferable = trans; this.dragSourceListener = dsl; + this.sourceActions = trigger.getSourceAsDragGestureRecognizer().getSourceActions(); - throw new Error ("not implemented"); + setCursor(cursor); + updateCurrentCursor(trigger.getDragAction(), sourceActions, DEFAULT); } + /** + * Returns the DragSource object associated with the + * DragGestureEvent. + * + * @return the DragSource associated with the trigger. + */ public DragSource getDragSource() { return trigger.getDragSource (); } + /** + * Returns the component associated with this. + * + * @return the component associated with the trigger. + */ public Component getComponent() { return trigger.getComponent (); } + /** + * Gets the trigger associated with this. + * + * @return the trigger. + */ public DragGestureEvent getTrigger() { return trigger; } + /** + * Returns the source actions for the DragGestureRecognizer. + * + * @return the source actions for DragGestureRecognizer. + */ public int getSourceActions() { - return trigger.getSourceAsDragGestureRecognizer ().getSourceActions (); + if (sourceActions == 0) + sourceActions = trigger.getSourceAsDragGestureRecognizer().getSourceActions(); + return sourceActions; } - public void setCursor (Cursor cursor) - throws NotImplementedException + /** + * Sets the cursor for this drag operation to the specified cursor. + * + * @param cursor c - the Cursor to use, or null to use the default drag + * cursor. + */ + public void setCursor(Cursor cursor) { + if (cursor == null) + useCustomCursor = false; + else + useCustomCursor = true; this.cursor = cursor; - // FIXME: Check if we need to do more here + peer.setCursor(cursor); } + /** + * Returns the current cursor or null if the default + * drag cursor is used. + * + * @return the current cursor or null. + */ public Cursor getCursor() { return cursor; @@ -165,48 +206,160 @@ public class DragSourceContext dragSourceListener = null; } + /** + * This function tells the peer that the DataFlavors have been modified. + */ public void transferablesFlavorsChanged() - throws NotImplementedException { + peer.transferablesFlavorsChanged(); } + /** + * Calls dragEnter on the listeners registered with this + * and with the DragSource. + * + * @param e - the DragSourceDragEvent + */ public void dragEnter(DragSourceDragEvent e) - throws NotImplementedException { + if (dragSourceListener != null) + dragSourceListener.dragEnter(e); + + DragSource ds = getDragSource(); + DragSourceListener[] dsl = ds.getDragSourceListeners(); + for (int i = 0; i < dsl.length; i++) + dsl[i].dragEnter(e); + + updateCurrentCursor(e.getDropAction(), e.getTargetActions(), ENTER); } + /** + * Calls dragOver on the listeners registered with this + * and with the DragSource. + * + * @param e - the DragSourceDragEvent + */ public void dragOver(DragSourceDragEvent e) - throws NotImplementedException { + if (dragSourceListener != null) + dragSourceListener.dragOver(e); + + DragSource ds = getDragSource(); + DragSourceListener[] dsl = ds.getDragSourceListeners(); + for (int i = 0; i < dsl.length; i++) + dsl[i].dragOver(e); + + updateCurrentCursor(e.getDropAction(), e.getTargetActions(), OVER); } - + + /** + * Calls dragExit on the listeners registered with this + * and with the DragSource. + * + * @param e - the DragSourceEvent + */ public void dragExit(DragSourceEvent e) - throws NotImplementedException { + if (dragSourceListener != null) + dragSourceListener.dragExit(e); + + DragSource ds = getDragSource(); + DragSourceListener[] dsl = ds.getDragSourceListeners(); + for (int i = 0; i < dsl.length; i++) + dsl[i].dragExit(e); + + updateCurrentCursor(0, 0, DEFAULT); } + /** + * Calls dropActionChanged on the listeners registered with this + * and with the DragSource. + * + * @param e - the DragSourceDragEvent + */ public void dropActionChanged(DragSourceDragEvent e) - throws NotImplementedException { + if (dragSourceListener != null) + dragSourceListener.dropActionChanged(e); + + DragSource ds = getDragSource(); + DragSourceListener[] dsl = ds.getDragSourceListeners(); + for (int i = 0; i < dsl.length; i++) + dsl[i].dropActionChanged(e); + + updateCurrentCursor(e.getDropAction(), e.getTargetActions(), CHANGED); } + /** + * Calls dragDropEnd on the listeners registered with this + * and with the DragSource. + * + * @param e - the DragSourceDropEvent + */ public void dragDropEnd(DragSourceDropEvent e) - throws NotImplementedException { + if (dragSourceListener != null) + dragSourceListener.dragDropEnd(e); + + DragSource ds = getDragSource(); + DragSourceListener[] dsl = ds.getDragSourceListeners(); + for (int i = 0; i < dsl.length; i++) + dsl[i].dragDropEnd(e); } + /** + * Calls dragMouseMoved on the listeners registered with the DragSource. + * + * @param e - the DragSourceDragEvent + */ public void dragMouseMoved(DragSourceDragEvent e) - throws NotImplementedException { + DragSource ds = getDragSource(); + DragSourceMotionListener[] dsml = ds.getDragSourceMotionListeners(); + for (int i = 0; i < dsml.length; i++) + dsml[i].dragMouseMoved(e); } + /** + * Returns the Transferable set with this object. + * + * @return the transferable. + */ public Transferable getTransferable() { return transferable; } + /** + * This function sets the drag cursor for the specified operation, actions and + * status if the default drag cursor is active. Otherwise, the cursor is not + * updated in any way. + * + * @param dropOp - the current operation. + * @param targetAct - the supported actions. + * @param status - the status of the cursor (constant). + */ protected void updateCurrentCursor(int dropOp, int targetAct, int status) throws NotImplementedException { + // FIXME: Not implemented fully + if (!useCustomCursor) + { + Cursor cursor = null; + switch (status) + { + case ENTER: + break; + case CHANGED: + break; + case OVER: + break; + default: + break; + } + + this.cursor = cursor; + peer.setCursor(cursor); + } } } // class DragSourceContext diff --git a/libjava/classpath/java/awt/dnd/DropTarget.java b/libjava/classpath/java/awt/dnd/DropTarget.java index b0d4c2ae7a1..a3650567f09 100644 --- a/libjava/classpath/java/awt/dnd/DropTarget.java +++ b/libjava/classpath/java/awt/dnd/DropTarget.java @@ -38,13 +38,18 @@ exception statement from your version. */ package java.awt.dnd; +import gnu.classpath.NotImplementedException; + import java.awt.Component; import java.awt.GraphicsEnvironment; import java.awt.HeadlessException; import java.awt.Point; import java.awt.datatransfer.FlavorMap; +import java.awt.dnd.peer.DropTargetPeer; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.peer.ComponentPeer; +import java.awt.peer.LightweightPeer; import java.io.Serializable; import java.util.EventListener; import java.util.TooManyListenersException; @@ -79,19 +84,25 @@ public class DropTarget } protected void stop () + throws NotImplementedException { + // FIXME: implement this } public void actionPerformed (ActionEvent e) + throws NotImplementedException { + // FIXME: implement this } } private Component component; private FlavorMap flavorMap; private int actions; + private DropTargetPeer peer; private DropTargetContext dropTargetContext; private DropTargetListener dropTargetListener; + private DropTarget.DropTargetAutoScroller autoscroller; private boolean active = true; /** @@ -150,12 +161,15 @@ public class DropTarget if (GraphicsEnvironment.isHeadless ()) throw new HeadlessException (); - component = c; - actions = i; + setComponent(c); + setDefaultActions(i); dropTargetListener = dtl; flavorMap = fm; setActive (b); + + if (c != null) + c.setDropTarget(this); } /** @@ -211,33 +225,46 @@ public class DropTarget public void addDropTargetListener (DropTargetListener dtl) throws TooManyListenersException { + if (dropTargetListener != null) + throw new TooManyListenersException (); + dropTargetListener = dtl; } public void removeDropTargetListener(DropTargetListener dtl) { - // FIXME: Do we need to do something with dtl ? - dropTargetListener = null; + if (dropTargetListener != null) + dropTargetListener = null; } public void dragEnter(DropTargetDragEvent dtde) { + if (dropTargetListener != null) + dropTargetListener.dragEnter(dtde); } public void dragOver(DropTargetDragEvent dtde) { + if (dropTargetListener != null) + dropTargetListener.dragOver(dtde); } public void dropActionChanged(DropTargetDragEvent dtde) { + if (dropTargetListener != null) + dropTargetListener.dropActionChanged(dtde); } public void dragExit(DropTargetEvent dte) { + if (dropTargetListener != null) + dropTargetListener.dragExit(dte); } public void drop(DropTargetDropEvent dtde) { + if (dropTargetListener != null) + dropTargetListener.drop(dtde); } public FlavorMap getFlavorMap() @@ -250,12 +277,29 @@ public class DropTarget flavorMap = fm; } - public void addNotify(java.awt.peer.ComponentPeer peer) + public void addNotify(ComponentPeer p) { + Component c = component; + while (c != null && p instanceof LightweightPeer) + { + p = c.getPeer(); + c = c.getParent(); + } + + if (p instanceof DropTargetPeer) + { + peer = ((DropTargetPeer) p); + peer.addDropTarget(this); + } + else + peer = null; } - public void removeNotify(java.awt.peer.ComponentPeer peer) + public void removeNotify(ComponentPeer p) { + ((DropTargetPeer) peer).removeDropTarget(this); + peer = null; + p = null; } public DropTargetContext getDropTargetContext() @@ -268,24 +312,34 @@ public class DropTarget protected DropTargetContext createDropTargetContext() { - return new DropTargetContext (this); + if (dropTargetContext == null) + dropTargetContext = new DropTargetContext (this); + + return dropTargetContext; } protected DropTarget.DropTargetAutoScroller createDropTargetAutoScroller (Component c, Point p) { - return new DropTarget.DropTargetAutoScroller (c, p); + if (autoscroller == null) + autoscroller = new DropTarget.DropTargetAutoScroller (c, p); + + return autoscroller; } protected void initializeAutoscrolling(Point p) { + createDropTargetAutoScroller (component, p); } protected void updateAutoscroll(Point dragCursorLocn) { + if (autoscroller != null) + autoscroller.updateLocation(dragCursorLocn); } protected void clearAutoscroll() { + autoscroller = null; } } // class DropTarget diff --git a/libjava/classpath/java/awt/dnd/DropTargetContext.java b/libjava/classpath/java/awt/dnd/DropTargetContext.java index 4a26d904880..31945c34bb1 100644 --- a/libjava/classpath/java/awt/dnd/DropTargetContext.java +++ b/libjava/classpath/java/awt/dnd/DropTargetContext.java @@ -37,12 +37,11 @@ exception statement from your version. */ package java.awt.dnd; -import gnu.classpath.NotImplementedException; - import java.awt.Component; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.peer.DropTargetContextPeer; import java.io.IOException; import java.io.Serializable; import java.util.Arrays; @@ -86,7 +85,7 @@ public class DropTargetContext implements Serializable private DropTarget dropTarget; private int targetActions; - private java.awt.dnd.peer.DropTargetContextPeer dtcp; + private DropTargetContextPeer dtcp; // package private DropTargetContext(DropTarget dropTarget) @@ -104,7 +103,7 @@ public class DropTargetContext implements Serializable return dropTarget.getComponent(); } - public void addNotify(java.awt.dnd.peer.DropTargetContextPeer dtcp) + public void addNotify(DropTargetContextPeer dtcp) { this.dtcp = dtcp; } @@ -130,39 +129,39 @@ public class DropTargetContext implements Serializable * @exception InvalidDnDOperationException If a drop is not outstanding. */ public void dropComplete(boolean success) - throws NotImplementedException { - // FIXME: implement this + if (dtcp != null) + dtcp.dropComplete(success); } protected void acceptDrag(int dragOperation) - throws NotImplementedException { - // FIXME: implement this + if (dtcp != null) + dtcp.acceptDrag(dragOperation); } protected void rejectDrag() - throws NotImplementedException { - // FIXME: implement this + if (dtcp != null) + dtcp.rejectDrag(); } protected void acceptDrop(int dropOperation) - throws NotImplementedException { - // FIXME: implement this + if (dtcp != null) + dtcp.acceptDrop(dropOperation); } protected void rejectDrop() - throws NotImplementedException { - // FIXME: implement this + if (dtcp != null) + dtcp.rejectDrop(); } protected DataFlavor[] getCurrentDataFlavors() - throws NotImplementedException { - // FIXME: implement this + if (dtcp != null) + dtcp.getTransferDataFlavors(); return null; } @@ -182,9 +181,11 @@ public class DropTargetContext implements Serializable * @exception InvalidDnDOperationException If a drag is not outstanding. */ protected Transferable getTransferable() - throws InvalidDnDOperationException, NotImplementedException + throws InvalidDnDOperationException { - // FIXME: implement this + // FIXME: Implement this + if (dtcp != null) + return dtcp.getTransferable(); return null; } diff --git a/libjava/classpath/java/awt/dnd/DropTargetDragEvent.java b/libjava/classpath/java/awt/dnd/DropTargetDragEvent.java index 6cdc3a292be..89bf1778a71 100644 --- a/libjava/classpath/java/awt/dnd/DropTargetDragEvent.java +++ b/libjava/classpath/java/awt/dnd/DropTargetDragEvent.java @@ -40,6 +40,7 @@ package java.awt.dnd; import java.awt.Point; import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; import java.util.List; /** @@ -114,8 +115,7 @@ public class DropTargetDragEvent extends DropTargetEvent public int getDropAction() { - return 0; - //return dropAction & ((DropTargetContext) source).getTargetActions(); + return dropAction & ((DropTargetContext) source).getTargetActions(); } public Point getLocation () @@ -137,4 +137,17 @@ public class DropTargetDragEvent extends DropTargetEvent { context.rejectDrag (); } + + /** + * TODO + * + * @return + * + * @since 1.5 + */ + public Transferable getTransferable() + { + // FIXME: Not implemented + return null; + } } // class DropTargetDragEvent diff --git a/libjava/classpath/java/awt/dnd/DropTargetDropEvent.java b/libjava/classpath/java/awt/dnd/DropTargetDropEvent.java index a745bd256f8..9754bb11ef5 100644 --- a/libjava/classpath/java/awt/dnd/DropTargetDropEvent.java +++ b/libjava/classpath/java/awt/dnd/DropTargetDropEvent.java @@ -37,8 +37,6 @@ exception statement from your version. */ package java.awt.dnd; -import gnu.classpath.NotImplementedException; - import java.awt.Point; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; @@ -161,9 +159,8 @@ public class DropTargetDropEvent extends DropTargetEvent } public void dropComplete(boolean success) - throws NotImplementedException { - // FIXME: implement this + context.dropComplete(success); } public boolean isLocalTransfer() diff --git a/libjava/classpath/java/awt/dnd/InvalidDnDOperationException.java b/libjava/classpath/java/awt/dnd/InvalidDnDOperationException.java index 2fd9767e03d..4a75610bf61 100644 --- a/libjava/classpath/java/awt/dnd/InvalidDnDOperationException.java +++ b/libjava/classpath/java/awt/dnd/InvalidDnDOperationException.java @@ -59,6 +59,7 @@ public class InvalidDnDOperationException extends IllegalStateException */ public InvalidDnDOperationException() { + super(); } /** diff --git a/libjava/classpath/java/awt/event/KeyEvent.java b/libjava/classpath/java/awt/event/KeyEvent.java index d4b93ba3e0b..42084d7333e 100644 --- a/libjava/classpath/java/awt/event/KeyEvent.java +++ b/libjava/classpath/java/awt/event/KeyEvent.java @@ -993,6 +993,27 @@ public class KeyEvent extends InputEvent public static final int VK_ALT_GRAPH = 65406; /** + * The 'begin' key VK_BEGIN + * + * @since 1.5 + */ + public static final int VK_BEGIN = 65368; + + /** + * The context-menu key VK_CONTEXT_MENU + * + * @since 1.5 + */ + public static final int VK_CONTEXT_MENU = 525; + + /** + * The 'Windows' key VK_WINDOWS + * + * @since 1.5 + */ + public static final int VK_WINDOWS = 524; + + /** * The virtual key VK_UNDEFINED. This is used for key typed events, which * do not have a virtual key. */ diff --git a/libjava/classpath/java/awt/font/FontRenderContext.java b/libjava/classpath/java/awt/font/FontRenderContext.java index 78564a647da..c50e5e5092a 100644 --- a/libjava/classpath/java/awt/font/FontRenderContext.java +++ b/libjava/classpath/java/awt/font/FontRenderContext.java @@ -83,7 +83,15 @@ public class FontRenderContext public boolean equals (FontRenderContext rhs) { - return (affineTransform.equals (rhs.getTransform ()) + if (rhs == null) + return false; + + if (affineTransform == null && rhs.affineTransform != null + || affineTransform != null && rhs.affineTransform == null) + return false; + + return ((affineTransform == rhs.affineTransform + || affineTransform.equals (rhs.getTransform ())) && isAntiAliased == rhs.isAntiAliased () && usesFractionalMetrics == rhs.usesFractionalMetrics ()); } diff --git a/libjava/classpath/java/awt/font/LineBreakMeasurer.java b/libjava/classpath/java/awt/font/LineBreakMeasurer.java index c2a6d45d9f5..816c7745c2b 100644 --- a/libjava/classpath/java/awt/font/LineBreakMeasurer.java +++ b/libjava/classpath/java/awt/font/LineBreakMeasurer.java @@ -41,57 +41,41 @@ package java.awt.font; import java.text.AttributedCharacterIterator; import java.text.AttributedString; import java.text.BreakIterator; -import java.awt.font.TextLayout; -import java.awt.font.FontRenderContext; import java.awt.Shape; public final class LineBreakMeasurer { private AttributedCharacterIterator text; private int position; - private FontRenderContext frc; - private TextLayout totalLayout; + private TextMeasurer tm; private int numChars; public LineBreakMeasurer(AttributedCharacterIterator text, BreakIterator breakIter, FontRenderContext frc) { - this.text = text; - this.frc = frc; - position = 0; - totalLayout = new TextLayout(text, frc); - numChars = totalLayout.getCharacterCount(); + this( text, frc ); } public LineBreakMeasurer(AttributedCharacterIterator text, FontRenderContext frc) { this.text = text; - this.frc = frc; position = 0; - totalLayout = new TextLayout(text, frc); - numChars = totalLayout.getCharacterCount(); + numChars = text.getEndIndex(); + tm = new TextMeasurer( text, frc ); } public void deleteChar(AttributedCharacterIterator newParagraph, int deletePos) { - totalLayout = new TextLayout(newParagraph, frc); - if( deletePos < 0 || deletePos > totalLayout.getCharacterCount() ) - throw new NullPointerException("Invalid deletePos:"+deletePos); - numChars = totalLayout.getCharacterCount(); - text = newParagraph; + tm.deleteChar( newParagraph, deletePos ); position = 0; } public void insertChar(AttributedCharacterIterator newParagraph, int insertPos) { - totalLayout = new TextLayout(newParagraph, frc); - if( insertPos < 0 || insertPos > totalLayout.getCharacterCount() ) - throw new NullPointerException("Invalid insertPos:"+insertPos); - numChars = totalLayout.getCharacterCount(); - text = newParagraph; + tm.insertChar( newParagraph, insertPos ); position = 0; } @@ -104,11 +88,9 @@ public final class LineBreakMeasurer boolean requireNextWord) { int next = nextOffset( wrappingWidth, offsetLimit, requireNextWord ); - AttributedCharacterIterator aci = (new AttributedString( text, - position, next ) - ).getIterator(); + TextLayout tl = tm.getLayout( position, next ); position = next; - return new TextLayout( aci, frc ); + return tl; } public int nextOffset(float wrappingWidth) @@ -119,69 +101,40 @@ public final class LineBreakMeasurer public int nextOffset(float wrappingWidth, int offsetLimit, boolean requireNextWord) { - Shape s = totalLayout.getBlackBoxBounds( position, offsetLimit ); - double remainingLength = s.getBounds2D().getWidth(); + int guessOffset = tm.getLineBreakIndex(position, wrappingWidth); + if( offsetLimit > numChars ) + offsetLimit = numChars; - int guessOffset = (int)( ( (double)wrappingWidth / (double)remainingLength) - * ( (double)numChars - (double)position ) ); - guessOffset += position; if( guessOffset > offsetLimit ) - guessOffset = offsetLimit; - - s = totalLayout.getBlackBoxBounds( position, guessOffset ); - double guessLength = s.getBounds2D().getWidth(); - - boolean makeSmaller = ( guessLength > wrappingWidth ); - int inc = makeSmaller ? -1 : 1; - boolean keepGoing = true; - - do { - guessOffset = guessOffset + inc; - if( guessOffset <= position || guessOffset > offsetLimit ) - { - keepGoing = false; - } - else - { - s = totalLayout.getBlackBoxBounds( position, guessOffset ); - guessLength = s.getBounds2D().getWidth(); - if( makeSmaller && ( guessLength <= wrappingWidth) ) - keepGoing = false; - if( !makeSmaller && ( guessLength >= wrappingWidth) ) - keepGoing = false; - } + text.setIndex( offsetLimit ); + return offsetLimit; } - while( keepGoing ); - if( !makeSmaller ) - guessOffset--; + text.setIndex( guessOffset ); - if( guessOffset >= offsetLimit ) - return offsetLimit; + // If we're on a breaking character, return directly + if( Character.isWhitespace( text.current() ) ) + return guessOffset; - text.setIndex( guessOffset ); + // Otherwise jump forward or backward to the last such char. if( !requireNextWord ) - { - char c = text.previous(); - while( !Character.isWhitespace( c ) && c != '-' && - guessOffset > position ) - { - guessOffset--; - c = text.previous(); - } - } + while( !Character.isWhitespace( text.previous() ) && + guessOffset > position ) + guessOffset--; else + while( !Character.isWhitespace( text.next() ) && + guessOffset < offsetLimit ) + guessOffset++; + + if( guessOffset > offsetLimit ) { - char c = text.next(); - while( !Character.isWhitespace( c ) && c != '-' && - guessOffset < offsetLimit ) - { - guessOffset++; - c = text.next(); - } + text.setIndex( offsetLimit ); + return offsetLimit; } + text.setIndex( guessOffset ); + return guessOffset; } diff --git a/libjava/classpath/java/awt/font/TextLayout.java b/libjava/classpath/java/awt/font/TextLayout.java index 4f8c1c644c1..b1473f25564 100644 --- a/libjava/classpath/java/awt/font/TextLayout.java +++ b/libjava/classpath/java/awt/font/TextLayout.java @@ -43,13 +43,12 @@ import gnu.classpath.NotImplementedException; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Shape; -import java.awt.Toolkit; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; +import java.text.CharacterIterator; import java.text.AttributedCharacterIterator; -import java.text.AttributedString; import java.text.Bidi; import java.util.Map; @@ -73,6 +72,12 @@ public final class TextLayout implements Cloneable private int[][] runIndices; /** + * Character indices. + * Fixt index is the glyphvector, second index is the (first) glyph. + */ + private int[][] charIndices; + + /** * Base directionality, determined from the first char. */ private boolean leftToRight; @@ -85,7 +90,7 @@ public final class TextLayout implements Cloneable /** * The default caret policy. */ - static TextLayout.CaretPolicy DEFAULT_CARET_POLICY = new CaretPolicy(); + public static final TextLayout.CaretPolicy DEFAULT_CARET_POLICY = new CaretPolicy(); /** * Constructs a TextLayout. @@ -139,6 +144,7 @@ public final class TextLayout implements Cloneable Font.LAYOUT_LEFT_TO_RIGHT : Font.LAYOUT_RIGHT_TO_LEFT ); } + setCharIndices(); } public TextLayout (String string, Map attributes, FontRenderContext frc) @@ -147,9 +153,97 @@ public final class TextLayout implements Cloneable } public TextLayout (AttributedCharacterIterator text, FontRenderContext frc) - throws NotImplementedException { - throw new Error ("not implemented"); + // FIXME: Very rudimentary. + this(getText(text), getFont(text), frc); + } + + /** + * Package-private constructor to make a textlayout from an existing one. + * This is used by TextMeasurer for returning sub-layouts, and it + * saves a lot of time in not having to relayout the text. + */ + TextLayout(TextLayout t, int startIndex, int endIndex) + { + font = t.font; + frc = t.frc; + boundsCache = null; + lm = t.lm; + leftToRight = t.leftToRight; + + if( endIndex > t.getCharacterCount() ) + endIndex = t.getCharacterCount(); + string = t.string.substring( startIndex, endIndex ); + + int startingRun = t.charIndices[startIndex][0]; + int nRuns = 1 + t.charIndices[endIndex - 1][0] - startingRun; + runIndices = new int[ nRuns ][2]; + + runs = new GlyphVector[ nRuns ]; + for( int i = 0; i < nRuns; i++ ) + { + GlyphVector run = t.runs[ i + startingRun ]; + // Copy only the relevant parts of the first and last runs. + int beginGlyphIndex = (i > 0) ? 0 : t.charIndices[startIndex][1]; + int numEntries = ( i < nRuns - 1) ? run.getNumGlyphs() : + 1 + t.charIndices[endIndex - 1][1] - beginGlyphIndex; + + int[] codes = run.getGlyphCodes(beginGlyphIndex, numEntries, null); + runs[ i ] = font.createGlyphVector( frc, codes ); + runIndices[ i ][0] = t.runIndices[i + startingRun][0] - startIndex; + runIndices[ i ][1] = t.runIndices[i + startingRun][1] - startIndex; + } + runIndices[ nRuns - 1 ][1] = endIndex - 1; + + setCharIndices(); + determineWhiteSpace(); + } + + private void setCharIndices() + { + charIndices = new int[ getCharacterCount() ][2]; + int i = 0; + int currentChar = 0; + for(int run = 0; run < runs.length; run++) + { + currentChar = -1; + for( int gi = 0; gi < runs[ run ].getNumGlyphs(); gi++) + { + if( runs[ run ].getGlyphCharIndex( gi ) != currentChar ) + { + charIndices[ i ][0] = run; + charIndices[ i ][1] = gi; + currentChar = runs[ run ].getGlyphCharIndex( gi ); + i++; + } + } + } + } + + private static String getText(AttributedCharacterIterator iter) + { + StringBuffer sb = new StringBuffer(); + int idx = iter.getIndex(); + for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) + sb.append(c); + iter.setIndex( idx ); + return sb.toString(); + } + + private static Font getFont(AttributedCharacterIterator iter) + { + Font f = (Font)iter.getAttribute(TextAttribute.FONT); + if( f == null ) + { + int size; + Float i = (Float)iter.getAttribute(TextAttribute.SIZE); + if( i != null ) + size = (int)i.floatValue(); + else + size = 14; + f = new Font("Dialog", Font.PLAIN, size ); + } + return f; } /** @@ -179,10 +273,14 @@ public final class TextLayout implements Cloneable gotDirection = true; break; } + determineWhiteSpace(); + } + private void determineWhiteSpace() + { // Determine if there's whitespace in the thing. // Ignore trailing chars. - i = string.length() - 1; + int i = string.length() - 1; hasWhitespace = false; while( i >= 0 && Character.isWhitespace( string.charAt(i) ) ) i--; @@ -251,56 +349,42 @@ public final class TextLayout implements Cloneable public Shape getBlackBoxBounds (int firstEndpoint, int secondEndpoint) { - if( firstEndpoint < 0 || secondEndpoint > getCharacterCount() ) + if( secondEndpoint - firstEndpoint <= 0 ) + return new Rectangle2D.Float(); // Hmm? + + if( firstEndpoint < 0 || secondEndpoint > getCharacterCount()) return new Rectangle2D.Float(); GeneralPath gp = new GeneralPath(); - int i = 0; // run index - double advance = 0; - - // go to first run - while( runIndices[i + 1][1] < firstEndpoint ) - { - advance += runs[i].getLogicalBounds().getWidth(); - i++; - } + + int ri = charIndices[ firstEndpoint ][0]; + int gi = charIndices[ firstEndpoint ][1]; - int j = 0; // index into the run. - if( runIndices[i][1] - runIndices[i][0] > 1 ) + double advance = 0; + + for( int i = 0; i < ri; i++ ) + advance += runs[i].getLogicalBounds().getWidth(); + + for( int i = ri; i <= charIndices[ secondEndpoint - 1 ][0]; i++ ) { - while( runs[i].getGlyphCharIndex( j + 1 ) < - (firstEndpoint - runIndices[i][0] ) )j++; - } - - gp.append(runs[i].getGlyphVisualBounds( j ), false); - boolean keepGoing = true;; + int dg; + if( i == charIndices[ secondEndpoint - 1 ][0] ) + dg = charIndices[ secondEndpoint - 1][1]; + else + dg = runs[i].getNumGlyphs() - 1; - do - { - while( j < runs[i].getNumGlyphs() && - runs[i].getGlyphCharIndex( j ) + runIndices[i][0] < - secondEndpoint ) + for( int j = 0; j <= dg; j++ ) { Rectangle2D r2 = (runs[i].getGlyphVisualBounds( j )). getBounds2D(); Point2D p = runs[i].getGlyphPosition( j ); - r2.setRect( advance + p.getX(), r2.getY(), + r2.setRect( advance + r2.getX(), r2.getY(), r2.getWidth(), r2.getHeight() ); gp.append(r2, false); - j++; } - if( j >= runs[i].getNumGlyphs() ) - { - advance += runs[i].getLogicalBounds().getWidth(); - i++; - j = 0; - } - else - keepGoing = false; + advance += runs[i].getLogicalBounds().getWidth(); } - while( keepGoing ); - return gp; } @@ -384,55 +468,42 @@ public final class TextLayout implements Cloneable public Shape getLogicalHighlightShape (int firstEndpoint, int secondEndpoint, Rectangle2D bounds) { - if( firstEndpoint < 0 || secondEndpoint > getCharacterCount() ) + if( secondEndpoint - firstEndpoint <= 0 ) + return new Rectangle2D.Float(); // Hmm? + + if( firstEndpoint < 0 || secondEndpoint > getCharacterCount()) return new Rectangle2D.Float(); - int i = 0; // run index - double advance = 0; + Rectangle2D r = null; + int ri = charIndices[ firstEndpoint ][0]; + int gi = charIndices[ firstEndpoint ][1]; - // go to first run - if( i > 0 ) - while( runIndices[i + 1][1] < firstEndpoint ) - { - advance += runs[i].getLogicalBounds().getWidth(); - i++; - } + double advance = 0; + + for( int i = 0; i < ri; i++ ) + advance += runs[i].getLogicalBounds().getWidth(); - int j = 0; // index into the run. - if( runIndices[i][1] - runIndices[i][0] > 1 ) + for( int i = ri; i <= charIndices[ secondEndpoint - 1 ][0]; i++ ) { - while( runs[i].getGlyphCharIndex( j + 1 ) < - (firstEndpoint - runIndices[i][0] ) )j++; - } - - Rectangle2D r = (runs[i].getGlyphLogicalBounds( j )).getBounds2D(); - boolean keepGoing = true;; + int dg; // last index in this run to use. + if( i == charIndices[ secondEndpoint - 1 ][0] ) + dg = charIndices[ secondEndpoint - 1][1]; + else + dg = runs[i].getNumGlyphs() - 1; - do - { - while( j < runs[i].getNumGlyphs() && - runs[i].getGlyphCharIndex( j ) + runIndices[i][0] < - secondEndpoint ) + for(; gi <= dg; gi++ ) { - Rectangle2D r2 = (runs[i].getGlyphLogicalBounds( j )). + Rectangle2D r2 = (runs[i].getGlyphLogicalBounds( gi )). getBounds2D(); - Point2D p = runs[i].getGlyphPosition( j ); - r2.setRect( advance + p.getX(), r2.getY(), - r2.getWidth(), r2.getHeight() ); - r = r.createUnion( r2 ); - j++; + if( r == null ) + r = r2; + else + r = r.createUnion(r2); } + gi = 0; // reset glyph index into run for next run. - if( j >= runs[i].getNumGlyphs() ) - { - advance += runs[i].getLogicalBounds().getWidth(); - i++; - j = 0; - } - else - keepGoing = false; + advance += runs[i].getLogicalBounds().getWidth(); } - while( keepGoing ); return r; } @@ -593,8 +664,9 @@ public final class TextLayout implements Cloneable } public TextHitInfo hitTestChar (float x, float y, Rectangle2D bounds) + throws NotImplementedException { - return hitTestChar( x, y, getBounds() ); + throw new Error ("not implemented"); } public boolean isLeftToRight () diff --git a/libjava/classpath/java/awt/font/TextMeasurer.java b/libjava/classpath/java/awt/font/TextMeasurer.java index 18c286c57c1..00cab8a878d 100644 --- a/libjava/classpath/java/awt/font/TextMeasurer.java +++ b/libjava/classpath/java/awt/font/TextMeasurer.java @@ -1,5 +1,5 @@ /* TextMeasurer.java - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,67 +38,154 @@ exception statement from your version. */ package java.awt.font; -import gnu.classpath.NotImplementedException; - import java.text.AttributedCharacterIterator; +import java.text.AttributedString; +import java.awt.Shape; /** - * @author Michael Koch + * TextMeasurer is a small utility class for measuring the length of laid-out + * text objects. + * + * @author Sven de Marothy * @since 1.3 */ public final class TextMeasurer implements Cloneable { - private AttributedCharacterIterator ci; + private AttributedCharacterIterator text; private FontRenderContext frc; - + private TextLayout totalLayout; + private int numChars; + + /** + * Creates a TextMeasurer from a given text in the form of an + * <code>AttributedCharacterIterator</code> and a + * <code>FontRenderContext</code>. + */ public TextMeasurer (AttributedCharacterIterator text, FontRenderContext frc) { - this.ci = text; + this.text = text; this.frc = frc; + totalLayout = new TextLayout( text, frc ); + numChars = totalLayout.getCharacterCount(); } + /** + * Clones the TextMeasurer object + */ protected Object clone () { - try - { - return super.clone (); - } - catch (CloneNotSupportedException e) - { - // This may never occur - throw new InternalError (); - } + return new TextMeasurer( text, frc ); } + /** + * Update the text if a character is deleted at the position deletePos + * @param newParagraph - the updated paragraph. + * @param deletePos - the deletion position + */ public void deleteChar (AttributedCharacterIterator newParagraph, int deletePos) - throws NotImplementedException { - throw new Error ("not implemented"); + totalLayout = new TextLayout(newParagraph, frc); + if( deletePos < 0 || deletePos > totalLayout.getCharacterCount() ) + throw new NullPointerException("Invalid deletePos:"+deletePos); + numChars = totalLayout.getCharacterCount(); + text = newParagraph; + } + + /** + * Update the text if a character is inserted at the position insertPos + * @param newParagraph - the updated paragraph. + * @param insertPos - the insertion position + */ + public void insertChar (AttributedCharacterIterator newParagraph, + int insertPos) + { + totalLayout = new TextLayout(newParagraph, frc); + if( insertPos < 0 || insertPos > totalLayout.getCharacterCount() ) + throw new NullPointerException("Invalid insertPos:"+insertPos); + numChars = totalLayout.getCharacterCount(); + text = newParagraph; } + /*** + * Returns the total advance between two positions in the paragraph. + * Characters from start to limit-1 (inclusive) are included in this count. + * + * @param start - the starting character index. + * @param limit - the limiting index. + */ public float getAdvanceBetween (int start, int limit) - throws NotImplementedException { - throw new Error ("not implemented"); + Shape s = totalLayout.getLogicalHighlightShape( start, limit ); + return (float)s.getBounds2D().getWidth(); } + /** + * Returns a <code>TextLayout</code> object corresponding to the characters + * from text to limit. + * @param start - the starting character index. + * @param limit - the limiting index. + */ public TextLayout getLayout (int start, int limit) - throws NotImplementedException { - throw new Error ("not implemented"); + if( start >= limit ) + throw new IllegalArgumentException("Start position must be < limit."); + return new TextLayout( totalLayout, start, limit ); } + /** + * Returns the line-break index from a given starting index and a maximum + * advance. The index returned is the first character outside the given + * advance (or the limit of the string, if all remaining characters fit.) + * + * @param start - the starting index. + * @param maxAdvance - the maximum advance allowed. + * @return the index of the first character beyond maxAdvance, or the + * index of the last character + 1. + */ public int getLineBreakIndex (int start, float maxAdvance) - throws NotImplementedException - { - throw new Error ("not implemented"); - } + { + if( start < 0 ) + throw new IllegalArgumentException("Start parameter must be > 0."); + + double remainingLength = getAdvanceBetween( start, numChars ); + + int guessOffset = (int)( ( (double)maxAdvance / (double)remainingLength) + * ( (double)numChars - (double)start ) ); + guessOffset += start; + if( guessOffset > numChars ) + guessOffset = numChars; + + double guessLength = getAdvanceBetween( start, guessOffset ); + boolean makeSmaller = ( guessLength > maxAdvance ); + int inc = makeSmaller ? -1 : 1; + boolean keepGoing = true; + + do + { + guessOffset = guessOffset + inc; + if( guessOffset <= start || guessOffset > numChars ) + { + keepGoing = false; + } + else + { + guessLength = getAdvanceBetween( start, guessOffset ); + if( makeSmaller && ( guessLength <= maxAdvance) ) + keepGoing = false; + if( !makeSmaller && ( guessLength >= maxAdvance) ) + keepGoing = false; + } + } + while( keepGoing ); - public void insertChar (AttributedCharacterIterator newParagraph, - int insertPos) - throws NotImplementedException - { - throw new Error ("not implemented"); + // Return first index that doesn't fit. + if( !makeSmaller ) + guessOffset--; + + if( guessOffset > numChars ) + return numChars; + + return guessOffset; } } diff --git a/libjava/classpath/java/awt/geom/GeneralPath.java b/libjava/classpath/java/awt/geom/GeneralPath.java index 123833b118b..e0ca8e18357 100644 --- a/libjava/classpath/java/awt/geom/GeneralPath.java +++ b/libjava/classpath/java/awt/geom/GeneralPath.java @@ -65,8 +65,8 @@ import java.awt.Shape; * ’up’ * direction, one in the ’down’ direction) Point <b>B</b> in * the image is inside (one intersection ’down’) - * Point <b>C</b> in the image is outside (two intersections - * ’down’) + * Point <b>C</b> in the image is inside (two intersections in the + * ’down’ direction) * * @see Line2D * @see CubicCurve2D @@ -247,10 +247,12 @@ public final class GeneralPath implements Shape, Cloneable /** * Closes the current subpath by drawing a line - * back to the point of the last moveTo. + * back to the point of the last moveTo, unless the path is already closed. */ public void closePath() { + if (index >= 1 && types[index - 1] == PathIterator.SEG_CLOSE) + return; ensureSize(index + 1); types[index] = PathIterator.SEG_CLOSE; xpoints[index] = xpoints[subpath]; diff --git a/libjava/classpath/java/awt/image/BandedSampleModel.java b/libjava/classpath/java/awt/image/BandedSampleModel.java index 24d315a1c35..afe62bdc4bd 100644 --- a/libjava/classpath/java/awt/image/BandedSampleModel.java +++ b/libjava/classpath/java/awt/image/BandedSampleModel.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2004, 2005, Free Software Foundation +/* Copyright (C) 2004, 2005, 2006, Free Software Foundation This file is part of GNU Classpath. @@ -36,10 +36,11 @@ exception statement from your version. */ package java.awt.image; +import gnu.java.awt.Buffers; + /** - * MultiPixelPackedSampleModel provides a single band model that supports - * multiple pixels in a single unit. Pixels have 2^n bits and 2^k pixels fit - * per data element. + * A sample model that reads each sample value from a separate band in the + * {@link DataBuffer}. * * @author Jerry Quinn (jlquinn@optonline.net) */ @@ -61,17 +62,61 @@ public final class BandedSampleModel extends ComponentSampleModel return result; } + /** + * Creates a new <code>BandedSampleModel</code>. + * + * @param dataType the data buffer type. + * @param w the width (in pixels). + * @param h the height (in pixels). + * @param numBands the number of bands. + */ public BandedSampleModel(int dataType, int w, int h, int numBands) { this(dataType, w, h, w, createBankArray(numBands), new int[numBands]); } + /** + * Creates a new <code>BandedSampleModel</code>. + * + * @param dataType the data buffer type. + * @param w the width (in pixels). + * @param h the height (in pixels). + * @param scanlineStride the number of data elements from a pixel in one + * row to the corresponding pixel in the next row. + * @param bankIndices the bank indices. + * @param bandOffsets the band offsets. + */ public BandedSampleModel(int dataType, int w, int h, int scanlineStride, int[] bankIndices, int[] bandOffsets) { super(dataType, w, h, 1, scanlineStride, bankIndices, bandOffsets); } + + /** + * Creates a new data buffer that is compatible with this sample model. + * + * @return The new data buffer. + */ + public DataBuffer createDataBuffer() + { + int size = scanlineStride * height; + return Buffers.createBuffer(getDataType(), size, numBanks); + } + /** + * Creates a new <code>SampleModel</code> that is compatible with this + * model and has the specified width and height. + * + * @param w the width (in pixels, must be greater than zero). + * @param h the height (in pixels, must be greater than zero). + * + * @return The new sample model. + * + * @throws IllegalArgumentException if <code>w</code> or <code>h</code> is + * not greater than zero. + * @throws IllegalArgumentException if <code>w * h</code> exceeds + * <code>Integer.MAX_VALUE</code>. + */ public SampleModel createCompatibleSampleModel(int w, int h) { // NOTE: blackdown 1.4.1 sets all offsets to 0. Sun's 1.4.2 docs @@ -80,32 +125,32 @@ public final class BandedSampleModel extends ComponentSampleModel // Compress offsets so minimum is 0, others w*scanlineStride int[] newoffsets = new int[bandOffsets.length]; int[] order = new int[bandOffsets.length]; - for (int i=0; i < bandOffsets.length; i++) + for (int i = 0; i < bandOffsets.length; i++) order[i] = i; // FIXME: This is N^2, but not a big issue, unless there's a lot of // bands... - for (int i=0; i < bandOffsets.length; i++) - for (int j=i+1; j < bandOffsets.length; i++) - if (bankIndices[order[i]] > bankIndices[order[j]] - || (bankIndices[order[i]] == bankIndices[order[j]] - && bandOffsets[order[i]] > bandOffsets[order[j]])) - { - int t = order[i]; order[i] = order[j]; order[j] = t; - } + for (int i = 0; i < bandOffsets.length; i++) + for (int j = i + 1; j < bandOffsets.length; j++) + if (bankIndices[order[i]] > bankIndices[order[j]] + || (bankIndices[order[i]] == bankIndices[order[j]] + && bandOffsets[order[i]] > bandOffsets[order[j]])) + { + int t = order[i]; order[i] = order[j]; order[j] = t; + } int bank = 0; int offset = 0; - for (int i=0; i < bandOffsets.length; i++) + for (int i = 0; i < bandOffsets.length; i++) { - if (bankIndices[order[i]] != bank) - { - bank = bankIndices[order[i]]; - offset = 0; - } - newoffsets[order[i]] = offset; - offset += w * scanlineStride; + if (bankIndices[order[i]] != bank) + { + bank = bankIndices[order[i]]; + offset = 0; + } + newoffsets[order[i]] = offset; + offset += w * scanlineStride; } - return new BandedSampleModel(dataType, w, h, scanlineStride, bankIndices, newoffsets); + return new BandedSampleModel(dataType, w, h, w, bankIndices, newoffsets); } @@ -117,7 +162,7 @@ public final class BandedSampleModel extends ComponentSampleModel +" many bands"); int[] newoff = new int[bands.length]; int[] newbanks = new int[bands.length]; - for (int i=0; i < bands.length; i++) + for (int i = 0; i < bands.length; i++) { int b = bands[i]; newoff[i] = bandOffsets[b]; @@ -134,57 +179,64 @@ public final class BandedSampleModel extends ComponentSampleModel * Extracts the pixel at x, y from data and stores samples into the array * obj. If obj is null, a new array of getTransferType() is created. * - * @param x The x-coordinate of the pixel rectangle to store in <code>obj</code>. - * @param y The y-coordinate of the pixel rectangle to store in <code>obj</code>. - * @param obj The primitive array to store the pixels into or null to force creation. + * @param x The x-coordinate of the pixel rectangle to store in + * <code>obj</code>. + * @param y The y-coordinate of the pixel rectangle to store in + * <code>obj</code>. + * @param obj The primitive array to store the pixels into or null to force + * creation. * @param data The DataBuffer that is the source of the pixel data. * @return The primitive array containing the pixel data. - * @see java.awt.image.SampleModel#getDataElements(int, int, java.lang.Object, java.awt.image.DataBuffer) + * @see java.awt.image.SampleModel#getDataElements(int, int, + * java.lang.Object, java.awt.image.DataBuffer) */ - public Object getDataElements(int x, int y, Object obj, - DataBuffer data) + public Object getDataElements(int x, int y, Object obj, DataBuffer data) { + if (x < 0 || y < 0) + throw new ArrayIndexOutOfBoundsException( + "x and y must not be less than 0."); int pixel = getSample(x, y, 0, data); switch (getTransferType()) { case DataBuffer.TYPE_BYTE: { - byte[] b = (byte[])obj; + byte[] b = (byte[]) obj; if (b == null) b = new byte[numBands]; - for (int i=0; i < numBands; i++) + for (int i = 0; i < numBands; i++) b[i] = (byte)getSample(x, y, i, data); return b; } case DataBuffer.TYPE_SHORT: case DataBuffer.TYPE_USHORT: { - short[] b = (short[])obj; + short[] b = (short[]) obj; if (b == null) b = new short[numBands]; - for (int i=0; i < numBands; i++) + for (int i = 0; i < numBands; i++) b[i] = (short)getSample(x, y, i, data); return b; } case DataBuffer.TYPE_INT: { - int[] b = (int[])obj; + int[] b = (int[]) obj; if (b == null) b = new int[numBands]; - for (int i=0; i < numBands; i++) + for (int i = 0; i < numBands; i++) b[i] = getSample(x, y, i, data); return b; } case DataBuffer.TYPE_FLOAT: { - float[] b = (float[])obj; + float[] b = (float[]) obj; if (b == null) b = new float[numBands]; - for (int i=0; i < numBands; i++) + for (int i = 0; i < numBands; i++) b[i] = getSampleFloat(x, y, i, data); return b; } case DataBuffer.TYPE_DOUBLE: { - double[] b = (double[])obj; - if (b == null) b = new double[numBands]; - for (int i=0; i < numBands; i++) + double[] b = (double[]) obj; + if (b == null) + b = new double[numBands]; + for (int i = 0; i < numBands; i++) b[i] = getSample(x, y, i, data); return b; } @@ -195,10 +247,27 @@ public final class BandedSampleModel extends ComponentSampleModel } } + /** + * Returns all the samples for the pixel at location <code>(x, y)</code> + * stored in the specified data buffer. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param iArray an array that will be populated with the sample values and + * returned as the result. The size of this array should be equal to the + * number of bands in the model. If the array is <code>null</code>, a new + * array is created. + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The samples for the specified pixel. + * + * @see #setPixel(int, int, int[], DataBuffer) + */ public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) { - if (iArray == null) iArray = new int[numBands]; - for (int i=0; i < numBands; i++) + if (iArray == null) + iArray = new int[numBands]; + for (int i = 0; i < numBands; i++) iArray[i] = getSample(x, y, i, data); return iArray; @@ -228,7 +297,11 @@ public final class BandedSampleModel extends ComponentSampleModel public int[] getPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { - if (iArray == null) iArray = new int[w*h*numBands]; + if (x < 0 || y < 0) + throw new ArrayIndexOutOfBoundsException( + "x and y must not be less than 0."); + if (iArray == null) + iArray = new int[w * h * numBands]; int outOffset = 0; int maxX = x + w; int maxY = y + h; @@ -247,18 +320,64 @@ public final class BandedSampleModel extends ComponentSampleModel return iArray; } + /** + * Returns a sample value for the pixel at (x, y) in the specified data + * buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample value. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public int getSample(int x, int y, int b, DataBuffer data) { int offset = bandOffsets[b] + y * scanlineStride + x; return data.getElem(bankIndices[b], offset); } + /** + * Returns a sample value for the pixel at (x, y) in the specified data + * buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample value. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + * + * @see #getSample(int, int, int, DataBuffer) + */ public float getSampleFloat(int x, int y, int b, DataBuffer data) { int offset = bandOffsets[b] + y * scanlineStride + x; return data.getElemFloat(bankIndices[b], offset); } + /** + * Returns the sample value for the pixel at (x, y) in the specified data + * buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample value. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + * + * @see #getSample(int, int, int, DataBuffer) + */ public double getSampleDouble(int x, int y, int b, DataBuffer data) { int offset = bandOffsets[b] + y * scanlineStride + x; @@ -288,7 +407,11 @@ public final class BandedSampleModel extends ComponentSampleModel public int[] getSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { - if (iArray == null) iArray = new int[w*h]; + if (x < 0 || y < 0) + throw new ArrayIndexOutOfBoundsException( + "x and y must not be less than 0."); + if (iArray == null) + iArray = new int[w * h]; int outOffset = 0; int maxX = x + w; int maxY = y + h; @@ -304,7 +427,6 @@ public final class BandedSampleModel extends ComponentSampleModel return iArray; } - /** * Set the pixel at x, y to the value in the first element of the primitive * array obj. @@ -338,7 +460,7 @@ public final class BandedSampleModel extends ComponentSampleModel { DataBufferByte out = (DataBufferByte) data; byte[] in = (byte[]) obj; - for (int i=0; i < numBands; i++) + for (int i = 0; i < numBands; i++) out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i]; return; } @@ -346,7 +468,7 @@ public final class BandedSampleModel extends ComponentSampleModel { DataBufferShort out = (DataBufferShort) data; short[] in = (short[]) obj; - for (int i=0; i < numBands; i++) + for (int i = 0; i < numBands; i++) out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i]; return; } @@ -354,7 +476,7 @@ public final class BandedSampleModel extends ComponentSampleModel { DataBufferUShort out = (DataBufferUShort) data; short[] in = (short[]) obj; - for (int i=0; i < numBands; i++) + for (int i = 0; i < numBands; i++) out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i]; return; } @@ -362,7 +484,7 @@ public final class BandedSampleModel extends ComponentSampleModel { DataBufferInt out = (DataBufferInt) data; int[] in = (int[]) obj; - for (int i=0; i < numBands; i++) + for (int i = 0; i < numBands; i++) out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i]; return; } @@ -370,7 +492,7 @@ public final class BandedSampleModel extends ComponentSampleModel { DataBufferFloat out = (DataBufferFloat) data; float[] in = (float[]) obj; - for (int i=0; i < numBands; i++) + for (int i = 0; i < numBands; i++) out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i]; return; } @@ -378,7 +500,7 @@ public final class BandedSampleModel extends ComponentSampleModel { DataBufferDouble out = (DataBufferDouble) data; double[] in = (double[]) obj; - for (int i=0; i < numBands; i++) + for (int i = 0; i < numBands; i++) out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i]; return; } @@ -388,26 +510,54 @@ public final class BandedSampleModel extends ComponentSampleModel } catch (ArrayIndexOutOfBoundsException aioobe) { - String msg = "While writing data elements" + - ", x="+x+", y="+y+ - ", width="+width+", height="+height+ - ", scanlineStride="+scanlineStride+ - ", offset="+offset+ - ", data.getSize()="+data.getSize()+ - ", data.getOffset()="+data.getOffset()+ - ": " + - aioobe; + String msg = "While writing data elements" + + ", x=" + x + ", y=" + y + + ", width=" + width + ", height=" + height + + ", scanlineStride=" + scanlineStride + + ", offset=" + offset + + ", data.getSize()=" + data.getSize() + + ", data.getOffset()=" + data.getOffset() + + ": " + aioobe; throw new ArrayIndexOutOfBoundsException(msg); } } + /** + * Sets the samples for the pixel at (x, y) in the specified data buffer to + * the specified values. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param iArray the sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>iArray</code> or + * <code>data</code> is <code>null</code>. + */ public void setPixel(int x, int y, int[] iArray, DataBuffer data) { - for (int b=0; b < numBands; b++) + for (int b = 0; b < numBands; b++) data.setElem(bankIndices[b], bandOffsets[b] + y * scanlineStride + x, iArray[b]); } + /** + * Sets the sample values for the pixels in the region specified by + * (x, y, w, h) in the specified data buffer. The array is + * ordered by pixels (that is, all the samples for the first pixel are + * grouped together, followed by all the samples for the second pixel, and so + * on). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param iArray the pixel sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>iArray</code> or + * <code>data</code> is <code>null</code>. + */ public void setPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { @@ -417,7 +567,7 @@ public final class BandedSampleModel extends ComponentSampleModel for (int ww = 0; ww < w; ww++) { int offset = y * scanlineStride + (x + ww); - for (int b=0; b < numBands; b++) + for (int b = 0; b < numBands; b++) data.setElem(bankIndices[b], bandOffsets[b] + offset, iArray[inOffset++]); } @@ -425,24 +575,83 @@ public final class BandedSampleModel extends ComponentSampleModel } } + /** + * Sets the sample value for band <code>b</code> of the pixel at location + * <code>(x, y)</code> in the specified data buffer. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param b the band index. + * @param s the sample value. + * @param data the data buffer (<code>null</code> not permitted). + * + * @see #getSample(int, int, int, DataBuffer) + */ public void setSample(int x, int y, int b, int s, DataBuffer data) { data.setElem(bankIndices[b], bandOffsets[b] + y * scanlineStride + x, s); } + /** + * Sets the sample value for a band for the pixel at (x, y) in the + * specified data buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param s the sample value. + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public void setSample(int x, int y, int b, float s, DataBuffer data) { - data.setElemFloat(bankIndices[b], bandOffsets[b] + y * scanlineStride + x, s); + data.setElemFloat(bankIndices[b], bandOffsets[b] + y * scanlineStride + x, + s); } + /** + * Sets the sample value for a band for the pixel at (x, y) in the + * specified data buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param s the sample value. + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public void setSample(int x, int y, int b, double s, DataBuffer data) { - data.setElemDouble(bankIndices[b], bandOffsets[b] + y * scanlineStride + x, s); + data.setElemDouble(bankIndices[b], bandOffsets[b] + y * scanlineStride + x, + s); } + /** + * Sets the sample values for one band for the pixels in the region + * specified by (x, y, w, h) in the specified data buffer. + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param iArray the sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>iArray</code> or + * <code>data</code> is <code>null</code>. + */ public void setSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { + if (x < 0 || y < 0) + throw new ArrayIndexOutOfBoundsException( + "x and y must not be less than 0."); int inOffset = 0; switch (getTransferType()) @@ -537,9 +746,10 @@ public final class BandedSampleModel extends ComponentSampleModel result.append(getClass().getName()); result.append("["); result.append("scanlineStride=").append(scanlineStride); - for(int i=0; i < bitMasks.length; i+=1) + for(int i = 0; i < bitMasks.length; i+=1) { - result.append(", mask[").append(i).append("]=0x").append(Integer.toHexString(bitMasks[i])); + result.append(", mask[").append(i).append("]=0x").append( + Integer.toHexString(bitMasks[i])); } result.append("]"); diff --git a/libjava/classpath/java/awt/image/BufferedImage.java b/libjava/classpath/java/awt/image/BufferedImage.java index 77b8d6cc174..76848db0833 100644 --- a/libjava/classpath/java/awt/image/BufferedImage.java +++ b/libjava/classpath/java/awt/image/BufferedImage.java @@ -100,11 +100,33 @@ public class BufferedImage extends Image Vector observers; /** - * Creates a new buffered image. + * Creates a new <code>BufferedImage</code> with the specified width, height + * and type. Valid <code>type</code> values are: * - * @param w the width. - * @param h the height. - * @param type the image type (see the constants defined by this class). + * <ul> + * <li>{@link #TYPE_INT_RGB}</li> + * <li>{@link #TYPE_INT_ARGB}</li> + * <li>{@link #TYPE_INT_ARGB_PRE}</li> + * <li>{@link #TYPE_INT_BGR}</li> + * <li>{@link #TYPE_3BYTE_BGR}</li> + * <li>{@link #TYPE_4BYTE_ABGR}</li> + * <li>{@link #TYPE_4BYTE_ABGR_PRE}</li> + * <li>{@link #TYPE_USHORT_565_RGB}</li> + * <li>{@link #TYPE_USHORT_555_RGB}</li> + * <li>{@link #TYPE_BYTE_GRAY}</li> + * <li>{@link #TYPE_USHORT_GRAY}</li> + * <li>{@link #TYPE_BYTE_BINARY}</li> + * <li>{@link #TYPE_BYTE_INDEXED}</li> + * </ul> + * + * @param w the width (must be > 0). + * @param h the height (must be > 0). + * @param type the image type (see the list of valid types above). + * + * @throws IllegalArgumentException if <code>w</code> or <code>h</code> is + * less than or equal to zero. + * @throws IllegalArgumentException if <code>type</code> is not one of the + * specified values. */ public BufferedImage(int w, int h, int type) { @@ -181,13 +203,15 @@ public class BufferedImage extends Image case TYPE_4BYTE_ABGR_PRE: bits = bits4; break; - case TYPE_BYTE_GRAY: - bits = bits1byte; - break; - case TYPE_USHORT_GRAY: - bits = bits1ushort; - dataType = DataBuffer.TYPE_USHORT; - break; + case TYPE_BYTE_GRAY: + bits = bits1byte; + cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); + break; + case TYPE_USHORT_GRAY: + bits = bits1ushort; + cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); + dataType = DataBuffer.TYPE_USHORT; + break; } cm = new ComponentColorModel(cs, bits, alpha, premultiplied, alpha ? @@ -203,6 +227,8 @@ public class BufferedImage extends Image String msg2 = "type not implemented yet"; throw new UnsupportedOperationException(msg2); // FIXME: build color-cube and create color model + default: + throw new IllegalArgumentException("Unknown image type " + type); } init(cm, @@ -504,7 +530,10 @@ public class BufferedImage extends Image int[] pixels = getRGB(x, y, width, height, (int[])null, offset, stride); - ColorModel model = getColorModel(); + // We already convert the color to RGB in the getRGB call, so + // we pass a simple RGB color model to the consumers. + ColorModel model = new DirectColorModel(32, 0xff0000, 0xff00, 0xff, + 0xff000000); consumers.add(ic); diff --git a/libjava/classpath/java/awt/image/BufferedImageOp.java b/libjava/classpath/java/awt/image/BufferedImageOp.java index 2ecbec056a0..f6a24c976ab 100644 --- a/libjava/classpath/java/awt/image/BufferedImageOp.java +++ b/libjava/classpath/java/awt/image/BufferedImageOp.java @@ -1,5 +1,5 @@ /* BufferedImageOp.java -- - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -43,13 +43,65 @@ import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; /** - * NEEDS DOCUMENTATION + * An operation that is performed on one <code>BufferedImage</code> (the + * source) producing a new <code>BufferedImage</code> (the destination). */ public interface BufferedImageOp { + /** + * Performs an operation on the source image, returning the result in a + * <code>BufferedImage</code>. If <code>dest</code> is <code>null</code>, a + * new <code>BufferedImage</code> will be created by calling the + * {@link #createCompatibleDestImage} method. If <code>dest</code> + * is not <code>null</code>, the result is written to <code>dest</code> then + * returned (this avoids creating a new <code>BufferedImage</code> each + * time this method is called). + * + * @param src the source image. + * @param dst the destination image (<code>null</code> permitted). + * + * @return The filterd image. + */ BufferedImage filter(BufferedImage src, BufferedImage dst); + + /** + * Returns the bounds of the destination image on the basis of this + * <code>BufferedImageOp</code> being applied to the specified source image. + * + * @param src the source image. + * + * @return The destination bounds. + */ Rectangle2D getBounds2D(BufferedImage src); + + /** + * Returns a new <code>BufferedImage</code> that can be used by this + * <code>BufferedImageOp</code> as the destination image when filtering + * the specified source image. + * + * @param src the source image. + * @param dstCM the color model for the destination image. + * + * @return A new image that can be used as the destination image. + */ BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM); + + /** + * Returns the point on the destination image that corresponds to the given + * point on the source image. + * + * @param src the source point. + * @param dst the destination point (<code>null</code> permitted). + * + * @return The destination point. + */ Point2D getPoint2D(Point2D src, Point2D dst); + + /** + * Returns the rendering hints for this operation. + * + * @return The rendering hints. + */ RenderingHints getRenderingHints(); -} // interface BufferedImageOp + +} diff --git a/libjava/classpath/java/awt/image/ByteLookupTable.java b/libjava/classpath/java/awt/image/ByteLookupTable.java index df02d0a1bf7..ecc0023aff6 100644 --- a/libjava/classpath/java/awt/image/ByteLookupTable.java +++ b/libjava/classpath/java/awt/image/ByteLookupTable.java @@ -1,5 +1,5 @@ /* ByteLookupTable.java -- Java class for a pixel translation table. - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -60,14 +60,20 @@ public class ByteLookupTable extends LookupTable * components. * * @param offset Offset to be subtracted. - * @param data Array of lookup tables. + * @param data Array of lookup tables (<code>null</code> not permitted). * @exception IllegalArgumentException if offset < 0 or data.length < 1. */ public ByteLookupTable(int offset, byte[][] data) throws IllegalArgumentException { super(offset, data.length); - this.data = data; + + // tests show that Sun's implementation creates a new array to store the + // references from the incoming 'data' array - not sure why, but we'll + // match that behaviour just in case it matters... + this.data = new byte[data.length][]; + for (int i = 0; i < data.length; i++) + this.data[i] = data[i]; } /** @@ -77,13 +83,16 @@ public class ByteLookupTable extends LookupTable * table. The same table is applied to all pixel components. * * @param offset Offset to be subtracted. - * @param data Lookup table for all components. + * @param data Lookup table for all components (<code>null</code> not + * permitted). * @exception IllegalArgumentException if offset < 0. */ public ByteLookupTable(int offset, byte[] data) throws IllegalArgumentException { super(offset, 1); + if (data == null) + throw new NullPointerException("Null 'data' argument."); this.data = new byte[][] {data}; } diff --git a/libjava/classpath/java/awt/image/ColorConvertOp.java b/libjava/classpath/java/awt/image/ColorConvertOp.java index 18609e0c4b0..1f85a5ecd99 100644 --- a/libjava/classpath/java/awt/image/ColorConvertOp.java +++ b/libjava/classpath/java/awt/image/ColorConvertOp.java @@ -1,5 +1,5 @@ -/* ColorModel.java -- - Copyright (C) 2004 Free Software Foundation +/* ColorConvertOp.java -- + Copyright (C) 2004, 2006 Free Software Foundation This file is part of GNU Classpath. @@ -177,8 +177,7 @@ public class ColorConvertOp implements BufferedImageOp, RasterOp ColorModel scm = src.getColorModel(); for (int i = 0; i < spaces.length; i++) { - ColorModel cm = scm.cloneColorModel(spaces[i]); - BufferedImage tmp = createCompatibleDestImage(src, cm); + BufferedImage tmp = createCompatibleDestImage(src, scm); copyimage(src, tmp); src = tmp; } @@ -189,6 +188,7 @@ public class ColorConvertOp implements BufferedImageOp, RasterOp // Apply final conversion copyimage(src, dst); + return dst; } @@ -287,7 +287,12 @@ public class ColorConvertOp implements BufferedImageOp, RasterOp private void copyimage(BufferedImage src, BufferedImage dst) { Graphics2D gg = dst.createGraphics(); - gg.setRenderingHints(hints); + + // If no hints are set there is no need to call + // setRenderingHints on the Graphics2D object. + if (hints != null) + gg.setRenderingHints(hints); + gg.drawImage(src, 0, 0, null); gg.dispose(); } diff --git a/libjava/classpath/java/awt/image/ColorModel.java b/libjava/classpath/java/awt/image/ColorModel.java index e2f5378b4da..9e559db37d8 100644 --- a/libjava/classpath/java/awt/image/ColorModel.java +++ b/libjava/classpath/java/awt/image/ColorModel.java @@ -1,5 +1,5 @@ /* ColorModel.java -- - Copyright (C) 1999, 2000, 2002, 2003, 2004 Free Software Foundation + Copyright (C) 1999, 2000, 2002, 2003, 2004, 2006 Free Software Foundation This file is part of GNU Classpath. @@ -43,7 +43,6 @@ import gnu.java.awt.Buffers; import java.awt.Point; import java.awt.Transparency; import java.awt.color.ColorSpace; -import java.lang.reflect.Constructor; import java.util.Arrays; /** @@ -163,32 +162,6 @@ public abstract class ColorModel implements Transparency this.transparency = transparency; this.transferType = transferType; } - - // This is a hook for ColorConvertOp to create a colormodel with - // a new colorspace - ColorModel cloneColorModel(ColorSpace cspace) - { - Class cls = this.getClass(); - ColorModel cm; - try { - // This constructor will exist. - Constructor ctor = - cls.getConstructor(new Class[]{int.class, int[].class, - ColorSpace.class, boolean.class, - boolean.class, int.class, int.class}); - cm = (ColorModel)ctor. - newInstance(new Object[]{new Integer(pixel_bits), - bits, cspace, Boolean.valueOf(hasAlpha), - Boolean.valueOf(isAlphaPremultiplied), - new Integer(transparency), - new Integer(transferType)}); - } - catch (Exception e) - { - throw new IllegalArgumentException(); - } - return cm; - } public void finalize() { diff --git a/libjava/classpath/java/awt/image/ComponentSampleModel.java b/libjava/classpath/java/awt/image/ComponentSampleModel.java index b4e9450b060..bccabbbcadb 100644 --- a/libjava/classpath/java/awt/image/ComponentSampleModel.java +++ b/libjava/classpath/java/awt/image/ComponentSampleModel.java @@ -272,9 +272,7 @@ public class ComponentSampleModel extends SampleModel // Maybe this value should be precalculated in the constructor? int highestOffset = 0; for (int b = 0; b < numBands; b++) - { - highestOffset = Math.max(highestOffset, bandOffsets[b]); - } + highestOffset = Math.max(highestOffset, bandOffsets[b]); int size = pixelStride * (width - 1) + scanlineStride * (height - 1) + highestOffset + 1; @@ -678,6 +676,9 @@ public class ComponentSampleModel extends SampleModel */ public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) { + if (x < 0 || x >= width || y < 0 || y >= height) + throw new ArrayIndexOutOfBoundsException("Pixel (" + x + ", " + y + + ") is out of bounds."); int offset = pixelStride * x + scanlineStride * y; if (iArray == null) iArray = new int[numBands]; @@ -736,10 +737,16 @@ public class ComponentSampleModel extends SampleModel * * @return The sample value. * + * @throws ArrayIndexOutOfBoundsException if <code>(x, y)</code> is outside + * the bounds <code>[0, 0, width, height]</code>. + * * @see #setSample(int, int, int, int, DataBuffer) */ public int getSample(int x, int y, int b, DataBuffer data) { + if (x < 0 || x >= width || y < 0 || y >= height) + throw new ArrayIndexOutOfBoundsException("Sample (" + x + ", " + y + + ") is out of bounds."); return data.getElem(bankIndices[b], getOffset(x, y, b)); } diff --git a/libjava/classpath/java/awt/image/ConvolveOp.java b/libjava/classpath/java/awt/image/ConvolveOp.java index 1f73f75b233..ffb834874fa 100644 --- a/libjava/classpath/java/awt/image/ConvolveOp.java +++ b/libjava/classpath/java/awt/image/ConvolveOp.java @@ -1,5 +1,5 @@ /* ConvolveOp.java -- - Copyright (C) 2004, 2005 Free Software Foundation -- ConvolveOp + Copyright (C) 2004, 2005, 2006, Free Software Foundation -- ConvolveOp This file is part of GNU Classpath. @@ -42,7 +42,6 @@ import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; -import java.util.Arrays; /** * Convolution filter. @@ -190,112 +189,101 @@ public class ConvolveOp implements BufferedImageOp, RasterOp * @see java.awt.image.RasterOp#filter(java.awt.image.Raster, * java.awt.image.WritableRaster) */ - public final WritableRaster filter(Raster src, WritableRaster dest) { + public final WritableRaster filter(Raster src, WritableRaster dest) + { if (src == dest) - throw new IllegalArgumentException(); - if (src.getWidth() < kernel.getWidth() || - src.getHeight() < kernel.getHeight()) - throw new ImagingOpException(null); - + throw new IllegalArgumentException("src == dest is not allowed."); + if (kernel.getWidth() > src.getWidth() + || kernel.getHeight() > src.getHeight()) + throw new ImagingOpException("The kernel is too large."); if (dest == null) dest = createCompatibleDestRaster(src); - else if (src.numBands != dest.numBands) - throw new ImagingOpException(null); + else if (src.getNumBands() != dest.getNumBands()) + throw new ImagingOpException("src and dest have different band counts."); - // Deal with bottom edge - if (edge == EDGE_ZERO_FILL) - { - float[] zeros = new float[src.getNumBands() * src.getWidth() - * (kernel.getYOrigin() - 1)]; - Arrays.fill(zeros, 0); - dest.setPixels(src.getMinX(), src.getMinY(), src.getWidth(), - kernel.getYOrigin() - 1, zeros); - } - else - { - float[] vals = new float[src.getNumBands() * src.getWidth() - * (kernel.getYOrigin() - 1)]; - src.getPixels(src.getMinX(), src.getMinY(), src.getWidth(), - kernel.getYOrigin() - 1, vals); - dest.setPixels(src.getMinX(), src.getMinY(), src.getWidth(), - kernel.getYOrigin() - 1, vals); - } + // calculate the borders that the op can't reach... + int kWidth = kernel.getWidth(); + int kHeight = kernel.getHeight(); + int left = kernel.getXOrigin(); + int right = Math.max(kWidth - left - 1, 0); + int top = kernel.getYOrigin(); + int bottom = Math.max(kHeight - top - 1, 0); - // Handle main section + // process the region that is reachable... + int regionW = src.width - left - right; + int regionH = src.height - top - bottom; float[] kvals = kernel.getKernelData(null); + float[] tmp = new float[kWidth * kHeight]; - float[] tmp = new float[kernel.getWidth() * kernel.getHeight()]; - for (int y = src.getMinY() + kernel.getYOrigin(); - y < src.getMinY() + src.getHeight() - kernel.getYOrigin() / 2; y++) - { - // Handle unfiltered edge pixels at start of line - float[] t1 = new float[(kernel.getXOrigin() - 1) * src.getNumBands()]; - if (edge == EDGE_ZERO_FILL) - Arrays.fill(t1, 0); - else - src.getPixels(src.getMinX(), y, kernel.getXOrigin() - 1, 1, t1); - dest.setPixels(src.getMinX(), y, kernel.getXOrigin() - 1, 1, t1); - - for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) + for (int x = 0; x < regionW; x++) { - // FIXME: This needs a much more efficient implementation - for (int b = 0; b < src.getNumBands(); b++) - { - float v = 0; - src.getSamples(x, y, kernel.getWidth(), kernel.getHeight(), b, tmp); - for (int i=0; i < tmp.length; i++) - v += tmp[i] * kvals[i]; - dest.setSample(x, y, b, v); - } + for (int y = 0; y < regionH; y++) + { + // FIXME: This needs a much more efficient implementation + for (int b = 0; b < src.getNumBands(); b++) + { + float v = 0; + src.getSamples(x, y, kWidth, kHeight, b, tmp); + for (int i = 0; i < tmp.length; i++) + v += tmp[tmp.length - i - 1] * kvals[i]; + // FIXME: in the above line, I've had to reverse the order of + // the samples array to make the tests pass. I haven't worked + // out why this is necessary. + dest.setSample(x + kernel.getXOrigin(), y + kernel.getYOrigin(), + b, v); + } + } } - - // Handle unfiltered edge pixels at end of line - float[] t2 = new float[(kernel.getWidth() / 2) * src.getNumBands()]; - if (edge == EDGE_ZERO_FILL) - Arrays.fill(t2, 0); - else - src.getPixels(src.getMinX() + src.getWidth() - - (kernel.getWidth() / 2), - y, kernel.getWidth() / 2, 1, t2); - dest.setPixels(src.getMinX() + src.getWidth() - (kernel.getWidth() / 2), - y, kernel.getWidth() / 2, 1, t2); - } - for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) - for (int x = src.getMinX(); x< src.getWidth() + src.getMinX(); x++) + + // fill in the top border + fillEdge(src, dest, 0, 0, src.width, top, edge); + + // fill in the bottom border + fillEdge(src, dest, 0, src.height - bottom, src.width, bottom, edge); + + // fill in the left border + fillEdge(src, dest, 0, top, left, regionH, edge); + + // fill in the right border + fillEdge(src, dest, src.width - right, top, right, regionH, edge); + + return dest; + } + + /** + * Fills a range of pixels (typically at the edge of a raster) with either + * zero values (if <code>edgeOp</code> is <code>EDGE_ZERO_FILL</code>) or the + * corresponding pixel values from the source raster (if <code>edgeOp</code> + * is <code>EDGE_NO_OP</code>). This utility method is called by the + * {@link #fillEdge(Raster, WritableRaster, int, int, int, int, int)} method. + * + * @param src the source raster. + * @param dest the destination raster. + * @param x the x-coordinate of the top left pixel in the range. + * @param y the y-coordinate of the top left pixel in the range. + * @param w the width of the pixel range. + * @param h the height of the pixel range. + * @param edgeOp indicates how to determine the values for the range + * (either {@link #EDGE_ZERO_FILL} or {@link #EDGE_NO_OP}). + */ + private void fillEdge(Raster src, WritableRaster dest, int x, int y, int w, + int h, int edgeOp) + { + if (w <= 0) + return; + if (h <= 0) + return; + if (edgeOp == EDGE_ZERO_FILL) // fill region with zeroes { - + float[] zeros = new float[src.getNumBands() * w * h]; + dest.setPixels(x, y, w, h, zeros); } - for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) - for (int x = src.getMinX(); x< src.getWidth() + src.getMinX(); x++) + else // copy pixels from source { - + float[] pixels = new float[src.getNumBands() * w * h]; + src.getPixels(x, y, w, h, pixels); + dest.setPixels(x, y, w, h, pixels); } - - // Handle top edge - if (edge == EDGE_ZERO_FILL) - { - float[] zeros = new float[src.getNumBands() * src.getWidth() * - (kernel.getHeight() / 2)]; - Arrays.fill(zeros, 0); - dest.setPixels(src.getMinX(), - src.getHeight() + src.getMinY() - (kernel.getHeight() / 2), - src.getWidth(), kernel.getHeight() / 2, zeros); - } - else - { - float[] vals = new float[src.getNumBands() * src.getWidth() * - (kernel.getHeight() / 2)]; - src.getPixels(src.getMinX(), - src.getHeight() + src.getMinY() - - (kernel.getHeight() / 2), - src.getWidth(), kernel.getHeight() / 2, vals); - dest.setPixels(src.getMinX(), - src.getHeight() + src.getMinY() - - (kernel.getHeight() / 2), - src.getWidth(), kernel.getHeight() / 2, vals); - } - - return dest; } /* (non-Javadoc) diff --git a/libjava/classpath/java/awt/image/DataBuffer.java b/libjava/classpath/java/awt/image/DataBuffer.java index 9e4f714180a..5a2cfd3b0e5 100644 --- a/libjava/classpath/java/awt/image/DataBuffer.java +++ b/libjava/classpath/java/awt/image/DataBuffer.java @@ -114,8 +114,7 @@ public abstract class DataBuffer */ protected DataBuffer(int dataType, int size) { - this.dataType = dataType; - this.size = size; + this(dataType, size, 1); } /** @@ -132,9 +131,7 @@ public abstract class DataBuffer * @param numBanks the number of data banks. */ protected DataBuffer(int dataType, int size, int numBanks) { - this(dataType, size); - banks = numBanks; - offsets = new int[numBanks]; + this(dataType, size, numBanks, 0); } /** @@ -153,11 +150,14 @@ public abstract class DataBuffer * @param offset the offset to the first element for all banks. */ protected DataBuffer(int dataType, int size, int numBanks, int offset) { - this(dataType, size, numBanks); - - java.util.Arrays.fill(offsets, offset); - + banks = numBanks; + this.dataType = dataType; + this.size = size; this.offset = offset; + + offsets = new int[ numBanks ]; + for(int i = 0; i < numBanks; i++ ) + offsets[i] = offset; } /** @@ -179,10 +179,11 @@ public abstract class DataBuffer * <code>numBanks != offsets.length</code>. */ protected DataBuffer(int dataType, int size, int numBanks, int[] offsets) { - this(dataType, size); if (numBanks != offsets.length) throw new ArrayIndexOutOfBoundsException(); - + + this.dataType = dataType; + this.size = size; banks = numBanks; this.offsets = offsets; diff --git a/libjava/classpath/java/awt/image/Kernel.java b/libjava/classpath/java/awt/image/Kernel.java index f7c29c3cde9..8361c0cf97d 100644 --- a/libjava/classpath/java/awt/image/Kernel.java +++ b/libjava/classpath/java/awt/image/Kernel.java @@ -1,5 +1,5 @@ /* Kernel.java -- Java class for an image processing kernel - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -44,21 +44,32 @@ package java.awt.image; * values representing a 2-dimensional array in row-major order. * * @author Jerry Quinn (jlquinn@optonline.net) - * @version 1.0 */ public class Kernel implements Cloneable { + /** The kernel width. */ private final int width; + + /** The kernel height. */ private final int height; + + /** Internal storage for the kernel's values. */ private final float[] data; /** - * Creates a new <code>Kernel</code> instance. + * Creates a new <code>Kernel</code> instance with the specified dimensions + * and values. The first <code>width * height</code> values in the specified + * <code>data</code> array are copied to internal storage. * - * @param width The 2D width of data. - * @param height The 2D height of data. - * @param data The source data array. - * @exception IllegalArgumentException if width * height < data.length. + * @param width the kernel width. + * @param height the kernel height. + * @param data the source data array (<code>null</code> not permitted). + * + * @throws IllegalArgumentException if <code>data.length</code> is less than + * <code>width * height</code>. + * @throws IllegalArgumentException if <code>width</code> or + * <code>height</code> is less than zero. + * @throws NullPointerException if <code>data</code> is <code>null</code>. */ public Kernel(int width, int height, float[] data) throws IllegalArgumentException @@ -72,7 +83,10 @@ public class Kernel implements Cloneable } /** - * Return the X origin: (width - 1) / 2 + * Returns the x-origin for the kernel, which is calculated as + * <code>(width - 1) / 2</code>. + * + * @return The x-origin for the kernel. */ public final int getXOrigin() { @@ -80,7 +94,10 @@ public class Kernel implements Cloneable } /** - * Return the Y origin: (height - 1) / 2 + * Returns the y-origin for the kernel, which is calculated as + * <code>(height - 1) / 2</code>. + * + * @return The y-origin for the kernel. */ public final int getYOrigin() { @@ -88,6 +105,8 @@ public class Kernel implements Cloneable } /** + * Returns the kernel width (as supplied to the constructor). + * * @return The kernel width. */ public final int getWidth() @@ -96,6 +115,8 @@ public class Kernel implements Cloneable } /** + * Returns the kernel height (as supplied to the constructor). + * * @return The kernel height. */ public final int getHeight() @@ -104,20 +125,25 @@ public class Kernel implements Cloneable } /** - * Return the kernel data. + * Returns an array containing a copy of the kernel data. If the + * <code>data</code> argument is non-<code>null</code>, the kernel values + * are copied into it and then <code>data</code> is returned as the result. + * If the <code>data</code> argument is <code>null</code>, this method + * allocates a new array then populates and returns it. * - * If data is null, allocates a new array and returns it. Otherwise, the - * kernel values are copied into data. - * - * @param data Array to copy values into, or null. + * @param data an array to copy the return values into (if + * <code>null</code>, a new array is allocated). + * * @return The array with copied values. - * @exception IllegalArgumentException if data != null and too small. + * + * @throws IllegalArgumentException if <code>data.length</code> is less than + * the kernel's <code>width * height</code>. */ public final float[] getKernelData(float[] data) throws IllegalArgumentException { if (data == null) - return (float[])this.data.clone(); + return (float[]) this.data.clone(); if (data.length < this.data.length) throw new IllegalArgumentException(); @@ -127,13 +153,15 @@ public class Kernel implements Cloneable } /** + * Returns a clone of this kernel. + * * @return a clone of this Kernel. */ public Object clone() { try { - return super.clone(); + return super.clone(); } catch (CloneNotSupportedException e) { diff --git a/libjava/classpath/java/awt/image/MultiPixelPackedSampleModel.java b/libjava/classpath/java/awt/image/MultiPixelPackedSampleModel.java index 18a6e555205..8732e57659e 100644 --- a/libjava/classpath/java/awt/image/MultiPixelPackedSampleModel.java +++ b/libjava/classpath/java/awt/image/MultiPixelPackedSampleModel.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. @@ -56,12 +56,43 @@ public class MultiPixelPackedSampleModel extends SampleModel private int numberOfBits; private int numElems; + /** + * Creates a new <code>MultiPixelPackedSampleModel</code> with the specified + * data type, which should be one of: + * <ul> + * <li>{@link DataBuffer#TYPE_BYTE};</li> + * <li>{@link DataBuffer#TYPE_USHORT};</li> + * <li>{@link DataBuffer#TYPE_INT};</li> + * </ul> + * + * @param dataType the data type. + * @param w the width (in pixels). + * @param h the height (in pixels). + * @param numberOfBits the number of bits per pixel (must be a power of 2). + */ public MultiPixelPackedSampleModel(int dataType, int w, int h, int numberOfBits) { this(dataType, w, h, numberOfBits, 0, 0); } + /** + * Creates a new <code>MultiPixelPackedSampleModel</code> with the specified + * data type, which should be one of: + * <ul> + * <li>{@link DataBuffer#TYPE_BYTE};</li> + * <li>{@link DataBuffer#TYPE_USHORT};</li> + * <li>{@link DataBuffer#TYPE_INT};</li> + * </ul> + * + * @param dataType the data type. + * @param w the width (in pixels). + * @param h the height (in pixels). + * @param numberOfBits the number of bits per pixel (must be a power of 2). + * @param scanlineStride the number of data elements from a pixel on one + * row to the corresponding pixel in the next row. + * @param dataBitOffset the offset to the first data bit. + */ public MultiPixelPackedSampleModel(int dataType, int w, int h, int numberOfBits, int scanlineStride, int dataBitOffset) @@ -101,7 +132,7 @@ public class MultiPixelPackedSampleModel extends SampleModel // Compute scan line large enough for w pixels. if (scanlineStride == 0) - scanlineStride = ((dataBitOffset + w * numberOfBits) / elemBits); + scanlineStride = ((dataBitOffset + w * numberOfBits) - 1) / elemBits + 1; this.scanlineStride = scanlineStride; @@ -118,6 +149,16 @@ public class MultiPixelPackedSampleModel extends SampleModel } } + /** + * Creates a new <code>MultiPixelPackedSample</code> model with the same + * data type and bits per pixel as this model, but with the specified + * dimensions. + * + * @param w the width (in pixels). + * @param h the height (in pixels). + * + * @return The new sample model. + */ public SampleModel createCompatibleSampleModel(int w, int h) { /* FIXME: We can avoid recalculation of bit offsets and sample @@ -126,78 +167,163 @@ public class MultiPixelPackedSampleModel extends SampleModel return new MultiPixelPackedSampleModel(dataType, w, h, numberOfBits); } - /** * Creates a DataBuffer for holding pixel data in the format and * layout described by this SampleModel. The returned buffer will * consist of one single bank. + * + * @return A new data buffer. */ public DataBuffer createDataBuffer() { - int size; - - // FIXME: The comment refers to SinglePixelPackedSampleModel. See if the - // same can be done for MultiPixelPackedSampleModel. - // We can save (scanlineStride - width) pixels at the very end of - // the buffer. The Sun reference implementation (J2SE 1.3.1 and - // 1.4.1_01) seems to do this; tested with Mauve test code. - size = scanlineStride * height; - + int size = scanlineStride * height; + if (dataBitOffset > 0) + size += (dataBitOffset - 1) / elemBits + 1; return Buffers.createBuffer(getDataType(), size); } - + /** + * Returns the number of data elements required to transfer a pixel in the + * get/setDataElements() methods. + * + * @return <code>1</code>. + */ public int getNumDataElements() { return 1; } + /** + * Returns an array containing the size (in bits) of the samples in each + * band. The <code>MultiPixelPackedSampleModel</code> class supports only + * one band, so this method returns an array with length <code>1</code>. + * + * @return An array containing the size (in bits) of the samples in band zero. + * + * @see #getSampleSize(int) + */ public int[] getSampleSize() { - return sampleSize; + return (int[]) sampleSize.clone(); } + /** + * Returns the size of the samples in the specified band. Note that the + * <code>MultiPixelPackedSampleModel</code> supports only one band -- this + * method ignored the <code>band</code> argument, and always returns the size + * of band zero. + * + * @param band the band (this parameter is ignored). + * + * @return The size of the samples in band zero. + * + * @see #getSampleSize() + */ public int getSampleSize(int band) { return sampleSize[0]; } + /** + * Returns the index in the data buffer that stores the pixel at (x, y). + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * + * @return The index in the data buffer that stores the pixel at (x, y). + * + * @see #getBitOffset(int) + */ public int getOffset(int x, int y) { - return scanlineStride * y + ((dataBitOffset + x*numberOfBits) / elemBits); + return scanlineStride * y + ((dataBitOffset + x * numberOfBits) / elemBits); } + /** + * The bit offset (within an element in the data buffer) of the pixels with + * the specified x-coordinate. + * + * @param x the x-coordinate. + * + * @return The bit offset. + */ public int getBitOffset(int x) { - return (dataBitOffset + x*numberOfBits) % elemBits; + return (dataBitOffset + x * numberOfBits) % elemBits; } + /** + * Returns the offset to the first data bit. + * + * @return The offset to the first data bit. + */ public int getDataBitOffset() { return dataBitOffset; } + /** + * Returns the number of data elements from a pixel in one row to the + * corresponding pixel in the next row. + * + * @return The scanline stride. + */ public int getScanlineStride() { return scanlineStride; } + /** + * Returns the number of bits per pixel. + * + * @return The number of bits per pixel. + */ public int getPixelBitStride() { return numberOfBits; } + + /** + * Returns the transfer type, which is one of the following (depending on + * the number of bits per sample for this model): + * <ul> + * <li>{@link DataBuffer#TYPE_BYTE};</li> + * <li>{@link DataBuffer#TYPE_USHORT};</li> + * <li>{@link DataBuffer#TYPE_INT};</li> + * </ul> + * + * @return The transfer type. + */ + public int getTransferType() + { + if (numberOfBits <= DataBuffer.getDataTypeSize(DataBuffer.TYPE_BYTE)) + return DataBuffer.TYPE_BYTE; + else if (numberOfBits <= DataBuffer.getDataTypeSize(DataBuffer.TYPE_USHORT)) + return DataBuffer.TYPE_USHORT; + return DataBuffer.TYPE_INT; + } - + /** + * Normally this method returns a sample model for accessing a subset of + * bands of image data, but since <code>MultiPixelPackedSampleModel</code> + * only supports a single band, this overridden implementation just returns + * a new instance of <code>MultiPixelPackedSampleModel</code>, with the same + * attributes as this instance. + * + * @param bands the bands to include in the subset (this is ignored, except + * that if it is non-<code>null</code> a check is made to ensure that the + * array length is equal to <code>1</code>). + * + * @throws RasterFormatException if <code>bands</code> is not + * <code>null</code> and <code>bands.length != 1</code>. + */ public SampleModel createSubsetSampleModel(int[] bands) { - int numBands = bands.length; - if (numBands != 1) + if (bands != null && bands.length != 1) throw new RasterFormatException("MultiPixelPackedSampleModel only" - + " supports one band"); - - return new MultiPixelPackedSampleModel(dataType, width, height, - numberOfBits, scanlineStride, - dataBitOffset); + + " supports one band"); + return new MultiPixelPackedSampleModel(dataType, width, height, + numberOfBits, scanlineStride, dataBitOffset); } /** @@ -207,68 +333,82 @@ public class MultiPixelPackedSampleModel extends SampleModel * array obj, since there is only one band. If obj is null, a new array of * getTransferType() is created. * - * @param x The x-coordinate of the pixel rectangle to store in <code>obj</code>. - * @param y The y-coordinate of the pixel rectangle to store in <code>obj</code>. - * @param obj The primitive array to store the pixels into or null to force creation. + * @param x The x-coordinate of the pixel rectangle to store in + * <code>obj</code>. + * @param y The y-coordinate of the pixel rectangle to store in + * <code>obj</code>. + * @param obj The primitive array to store the pixels into or null to force + * creation. * @param data The DataBuffer that is the source of the pixel data. * @return The primitive array containing the pixel data. - * @see java.awt.image.SampleModel#getDataElements(int, int, java.lang.Object, java.awt.image.DataBuffer) + * @see java.awt.image.SampleModel#getDataElements(int, int, Object, + * DataBuffer) */ - public Object getDataElements(int x, int y, Object obj, - DataBuffer data) + public Object getDataElements(int x, int y, Object obj, DataBuffer data) { int pixel = getSample(x, y, 0, data); switch (getTransferType()) - { - case DataBuffer.TYPE_BYTE: - if (obj == null) obj = new byte[1]; - ((byte[])obj)[0] = (byte)pixel; - return obj; - case DataBuffer.TYPE_USHORT: - if (obj == null) obj = new short[1]; - ((short[])obj)[0] = (short)pixel; - return obj; - case DataBuffer.TYPE_INT: - if (obj == null) obj = new int[1]; - ((int[])obj)[0] = pixel; - return obj; - default: - // Seems like the only sensible thing to do. - throw new ClassCastException(); - } + { + case DataBuffer.TYPE_BYTE: + if (obj == null) + obj = new byte[1]; + ((byte[]) obj)[0] = (byte) pixel; + return obj; + case DataBuffer.TYPE_USHORT: + if (obj == null) + obj = new short[1]; + ((short[]) obj)[0] = (short) pixel; + return obj; + case DataBuffer.TYPE_INT: + if (obj == null) + obj = new int[1]; + ((int[]) obj)[0] = pixel; + return obj; + default: + // Seems like the only sensible thing to do. + throw new ClassCastException(); + } } + /** + * Returns an array (of length 1) containing the sample for the pixel at + * (x, y) in the specified data buffer. If <code>iArray</code> is not + * <code>null</code>, it will be populated with the sample value and + * returned as the result of this function (this avoids allocating a new + * array instance). + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param iArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return An array containing the pixel sample value. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) { - if (iArray == null) iArray = new int[1]; + if (iArray == null) + iArray = new int[1]; iArray[0] = getSample(x, y, 0, data); - return iArray; } - public int[] getPixels(int x, int y, int w, int h, int[] iArray, - DataBuffer data) - { - int offset = getOffset(x, y); - if (iArray == null) iArray = new int[w*h]; - int outOffset = 0; - for (y=0; y<h; y++) - { - int lineOffset = offset; - for (x=0; x<w;) - { - int samples = data.getElem(lineOffset++); - for (int b=0; b<numElems && x<w; b++) - { - iArray[outOffset++] = (samples & bitMasks[b]) >>> bitOffsets[b]; - x++; - } - } - offset += scanlineStride; - } - return iArray; - } - + /** + * Returns the sample value for the pixel at (x, y) in the specified data + * buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample value. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public int getSample(int x, int y, int b, DataBuffer data) { int pos = @@ -286,72 +426,82 @@ public class MultiPixelPackedSampleModel extends SampleModel * @param y The y-coordinate of the data elements in <code>obj</code>. * @param obj The primitive array containing the data elements to set. * @param data The DataBuffer to store the data elements into. - * @see java.awt.image.SampleModel#setDataElements(int, int, int, int, java.lang.Object, java.awt.image.DataBuffer) */ public void setDataElements(int x, int y, Object obj, DataBuffer data) { int transferType = getTransferType(); - if (getTransferType() != data.getDataType()) - { - throw new IllegalArgumentException("transfer type ("+ - getTransferType()+"), "+ - "does not match data "+ - "buffer type (" + - data.getDataType() + - ")."); - } - - int offset = getOffset(x, y); - try { - switch (transferType) - { - case DataBuffer.TYPE_BYTE: - { - DataBufferByte out = (DataBufferByte) data; - byte[] in = (byte[]) obj; - out.getData()[offset] = in[0]; - return; - } - case DataBuffer.TYPE_USHORT: - { - DataBufferUShort out = (DataBufferUShort) data; - short[] in = (short[]) obj; - out.getData()[offset] = in[0]; - return; - } - case DataBuffer.TYPE_INT: - { - DataBufferInt out = (DataBufferInt) data; - int[] in = (int[]) obj; - out.getData()[offset] = in[0]; - return; - } - default: - throw new ClassCastException("Unsupported data type"); - } + switch (transferType) + { + case DataBuffer.TYPE_BYTE: + { + byte[] in = (byte[]) obj; + setSample(x, y, 0, in[0] & 0xFF, data); + return; + } + case DataBuffer.TYPE_USHORT: + { + short[] in = (short[]) obj; + setSample(x, y, 0, in[0] & 0xFFFF, data); + return; + } + case DataBuffer.TYPE_INT: + { + int[] in = (int[]) obj; + setSample(x, y, 0, in[0], data); + return; + } + default: + throw new ClassCastException("Unsupported data type"); + } } catch (ArrayIndexOutOfBoundsException aioobe) { - String msg = "While writing data elements" + - ", x="+x+", y="+y+ - ", width="+width+", height="+height+ - ", scanlineStride="+scanlineStride+ - ", offset="+offset+ - ", data.getSize()="+data.getSize()+ - ", data.getOffset()="+data.getOffset()+ - ": " + - aioobe; - throw new ArrayIndexOutOfBoundsException(msg); + String msg = "While writing data elements" + + ", x=" + x + ", y=" + y + + ", width=" + width + ", height=" + height + + ", scanlineStride=" + scanlineStride + + ", offset=" + getOffset(x, y) + + ", data.getSize()=" + data.getSize() + + ", data.getOffset()=" + data.getOffset() + + ": " + aioobe; + throw new ArrayIndexOutOfBoundsException(msg); } - } + } + /** + * Sets the sample value for the pixel at (x, y) in the specified data + * buffer to the specified value. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param iArray the sample value (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>iArray</code> or + * <code>data</code> is <code>null</code>. + * + * @see #setSample(int, int, int, int, DataBuffer) + */ public void setPixel(int x, int y, int[] iArray, DataBuffer data) { setSample(x, y, 0, iArray[0], data); } + /** + * Sets the sample value for a band for the pixel at (x, y) in the + * specified data buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param s the sample value. + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public void setSample(int x, int y, int b, int s, DataBuffer data) { int bitpos = @@ -367,6 +517,70 @@ public class MultiPixelPackedSampleModel extends SampleModel } /** + * Tests this sample model for equality with an arbitrary object. This + * method returns <code>true</code> if and only if: + * <ul> + * <li><code>obj</code> is not <code>null</code>; + * <li><code>obj</code> is an instance of + * <code>MultiPixelPackedSampleModel</code>; + * <li>both models have the same: + * <ul> + * <li><code>dataType</code>; + * <li><code>width</code>; + * <li><code>height</code>; + * <li><code>numberOfBits</code>; + * <li><code>scanlineStride</code>; + * <li><code>dataBitOffsets</code>. + * </ul> + * </li> + * </ul> + * + * @param obj the object (<code>null</code> permitted) + * + * @return <code>true</code> if this model is equal to <code>obj</code>, and + * <code>false</code> otherwise. + */ + public boolean equals(Object obj) + { + if (this == obj) + return true; + if (! (obj instanceof MultiPixelPackedSampleModel)) + return false; + MultiPixelPackedSampleModel that = (MultiPixelPackedSampleModel) obj; + if (this.dataType != that.dataType) + return false; + if (this.width != that.width) + return false; + if (this.height != that.height) + return false; + if (this.numberOfBits != that.numberOfBits) + return false; + if (this.scanlineStride != that.scanlineStride) + return false; + if (this.dataBitOffset != that.dataBitOffset) + return false; + return true; + } + + /** + * Returns a hash code for this <code>MultiPixelPackedSampleModel</code>. + * + * @return A hash code. + */ + public int hashCode() + { + // this hash code won't match Sun's, but that shouldn't matter... + int result = 193; + result = 37 * result + dataType; + result = 37 * result + width; + result = 37 * result + height; + result = 37 * result + numberOfBits; + result = 37 * result + scanlineStride; + result = 37 * result + dataBitOffset; + return result; + } + + /** * Creates a String with some information about this SampleModel. * @return A String describing this SampleModel. * @see java.lang.Object#toString() diff --git a/libjava/classpath/java/awt/image/Raster.java b/libjava/classpath/java/awt/image/Raster.java index 4af958a17c7..160f8be8b51 100644 --- a/libjava/classpath/java/awt/image/Raster.java +++ b/libjava/classpath/java/awt/image/Raster.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2000, 2002, 2003 Free Software Foundation +/* Copyright (C) 2000, 2002, 2003, 2006, Free Software Foundation This file is part of GNU Classpath. @@ -41,39 +41,80 @@ import java.awt.Point; import java.awt.Rectangle; /** + * A rectangular collection of pixels composed from a {@link DataBuffer} which + * stores the pixel values, and a {@link SampleModel} which is used to retrieve + * the pixel values. + * * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) */ public class Raster { + /** The sample model used to access the pixel values. */ protected SampleModel sampleModel; + + /** The data buffer used to store the pixel values. */ protected DataBuffer dataBuffer; + + /** The x-coordinate of the top left corner of the raster. */ protected int minX; + + /** The y-coordinate of the top left corner of the raster. */ protected int minY; + + /** The width of the raster. */ protected int width; + + /** The height of the raster. */ protected int height; + protected int sampleModelTranslateX; + protected int sampleModelTranslateY; + + /** The number of bands. */ protected int numBands; + protected int numDataElements; + + /** The raster's parent. */ protected Raster parent; + /** + * Creates a new raster. + * + * @param sampleModel the sample model. + * @param origin the origin. + */ protected Raster(SampleModel sampleModel, Point origin) { this(sampleModel, sampleModel.createDataBuffer(), origin); } + /** + * Creates a new raster. + * + * @param sampleModel the sample model. + * @param dataBuffer the data buffer. + * @param origin the origin. + */ protected Raster(SampleModel sampleModel, DataBuffer dataBuffer, - Point origin) + Point origin) { - this(sampleModel, dataBuffer, - new Rectangle(origin.x, origin.y, - sampleModel.getWidth(), sampleModel.getHeight()), - origin, null); + this(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y, + sampleModel.getWidth(), sampleModel.getHeight()), origin, null); } + /** + * Creates a new raster. + * + * @param sampleModel the sample model. + * @param dataBuffer the data buffer. + * @param aRegion the raster's bounds. + * @param sampleModelTranslate the translation (<code>null</code> permitted). + * @param parent the raster's parent. + */ protected Raster(SampleModel sampleModel, DataBuffer dataBuffer, - Rectangle aRegion, - Point sampleModelTranslate, Raster parent) + Rectangle aRegion, Point sampleModelTranslate, Raster parent) { this.sampleModel = sampleModel; this.dataBuffer = dataBuffer; @@ -95,70 +136,127 @@ public class Raster this.parent = parent; } + /** + * Creates an interleaved raster using the specified data type. + * + * @param dataType the data type. + * @param w the width. + * @param h the height. + * @param bands the number of bands. + * @param location + * + * @return The new raster. + */ public static WritableRaster createInterleavedRaster(int dataType, - int w, int h, - int bands, - Point location) + int w, int h, int bands, Point location) { int[] bandOffsets = new int[bands]; // TODO: Maybe not generate this every time. - for (int b=0; b<bands; b++) bandOffsets[b] = b; + for (int b = 0; b < bands; b++) + bandOffsets[b] = b; - int scanlineStride = bands*w; + int scanlineStride = bands * w; return createInterleavedRaster(dataType, w, h, scanlineStride, bands, - bandOffsets, location); + bandOffsets, location); } - public static WritableRaster createInterleavedRaster(int dataType, - int w, int h, - int scanlineStride, - int pixelStride, - int[] bandOffsets, - Point location) - { - SampleModel sm = new ComponentSampleModel(dataType, - w, h, - pixelStride, - scanlineStride, - bandOffsets); + /** + * Creates an interleaved raster. + * + * @param dataType the data type. + * @param w the width. + * @param h the height. + * @param scanlineStride the number of data elements from a sample on one + * row to the corresponding sample on the next row. + * @param pixelStride the number of elements from a sample in one pixel to + * the corresponding sample in the next pixel. + * @param bandOffsets the band offsets. + * @param location + * + * @return The new raster. + */ + public static WritableRaster createInterleavedRaster(int dataType, + int w, int h, int scanlineStride, int pixelStride, int[] bandOffsets, + Point location) + { + SampleModel sm = new ComponentSampleModel(dataType, w, h, pixelStride, + scanlineStride, bandOffsets); return createWritableRaster(sm, location); } - public static WritableRaster createBandedRaster(int dataType, - int w, int h, int bands, - Point location) + /** + * Creates a new banded raster. + * + * @param dataType the data type. + * @param w the width. + * @param h the height. + * @param bands the number of bands. + * @param location + * + * @return The new raster. + */ + public static WritableRaster createBandedRaster(int dataType, int w, int h, + int bands, Point location) { SampleModel sm = new BandedSampleModel(dataType, w, h, bands); return createWritableRaster(sm, location); } - public static WritableRaster createBandedRaster(int dataType, - int w, int h, - int scanlineStride, - int[] bankIndices, - int[] bandOffsets, - Point location) + /** + * Creates a new banded raster. + * + * @param dataType the data type. + * @param w the width. + * @param h the height. + * @param scanlineStride the number of data elements from a sample on one + * row to the corresponding sample on the next row. + * @param bankIndices the index for each bank. + * @param bandOffsets the offset for each band. + * @param location + * + * @return The new raster. + */ + public static WritableRaster createBandedRaster(int dataType, int w, int h, + int scanlineStride, int[] bankIndices, int[] bandOffsets, Point location) { SampleModel sm = new BandedSampleModel(dataType, w, h, scanlineStride, - bankIndices, bandOffsets); + bankIndices, bandOffsets); return createWritableRaster(sm, location); } - public static WritableRaster createPackedRaster(int dataType, - int w, int h, - int[] bandMasks, - Point location) + /** + * Creates a new packed raster. + * + * @param dataType the data type. + * @param w the width. + * @param h the height. + * @param bandMasks the bit mask for each band. + * @param location + * + * @return The new raster. + */ + public static WritableRaster createPackedRaster(int dataType, int w, int h, + int[] bandMasks, Point location) { - SampleModel sm = new SinglePixelPackedSampleModel(dataType, - w, h, - bandMasks); + SampleModel sm = new SinglePixelPackedSampleModel(dataType, w, h, + bandMasks); return createWritableRaster(sm, location); } + /** + * Creates a new raster. + * + * @param dataType the data type. + * @param w the width. + * @param h the height. + * @param bands the number of bands. + * @param bitsPerBand the number of bits per band. + * @param location + * + * @return The new raster. + */ public static WritableRaster createPackedRaster(int dataType, - int w, int h, - int bands, int bitsPerBand, - Point location) + int w, int h, int bands, int bitsPerBand, Point location) { if (bands <= 0 || (bands * bitsPerBand > getTypeBits(dataType))) throw new IllegalArgumentException(); @@ -166,135 +264,238 @@ public class Raster SampleModel sm; if (bands == 1) - sm = new MultiPixelPackedSampleModel(dataType, w, h, bitsPerBand); + sm = new MultiPixelPackedSampleModel(dataType, w, h, bitsPerBand); else { - int[] bandMasks = new int[bands]; - int mask = 0x1; - for (int bits = bitsPerBand; --bits != 0;) - mask = (mask << 1) | 0x1; - for (int i = 0; i < bands; i++) - { - bandMasks[i] = mask; - mask <<= bitsPerBand; - } - - sm = new SinglePixelPackedSampleModel(dataType, w, h, bandMasks); + int[] bandMasks = new int[bands]; + int mask = 0x1; + for (int bits = bitsPerBand; --bits != 0;) + mask = (mask << 1) | 0x1; + for (int i = 0; i < bands; i++) + { + bandMasks[i] = mask; + mask <<= bitsPerBand; + } + + sm = new SinglePixelPackedSampleModel(dataType, w, h, bandMasks); } return createWritableRaster(sm, location); } - public static WritableRaster - createInterleavedRaster(DataBuffer dataBuffer, int w, int h, - int scanlineStride, int pixelStride, - int[] bandOffsets, Point location) + /** + * Creates a new interleaved raster. + * + * @param dataBuffer the data buffer. + * @param w the width. + * @param h the height. + * @param scanlineStride the number of data elements from a sample on one + * row to the corresponding sample on the next row. + * @param pixelStride the number of elements from a sample in one pixel to + * the corresponding sample in the next pixel. + * @param bandOffsets the offset for each band. + * @param location + * + * @return The new raster. + */ + public static WritableRaster createInterleavedRaster(DataBuffer dataBuffer, + int w, int h, int scanlineStride, int pixelStride, int[] bandOffsets, + Point location) { SampleModel sm = new ComponentSampleModel(dataBuffer.getDataType(), - w, h, - scanlineStride, - pixelStride, - bandOffsets); + w, h, scanlineStride, pixelStride, bandOffsets); return createWritableRaster(sm, dataBuffer, location); } - public static - WritableRaster createBandedRaster(DataBuffer dataBuffer, - int w, int h, - int scanlineStride, - int[] bankIndices, - int[] bandOffsets, - Point location) + /** + * Creates a new banded raster. + * + * @param dataBuffer the data buffer. + * @param w the width. + * @param h the height. + * @param scanlineStride the number of data elements from a sample on one + * row to the corresponding sample on the next row. + * @param bankIndices the index for each bank. + * @param bandOffsets the band offsets. + * @param location + * + * @return The new raster. + */ + public static WritableRaster createBandedRaster(DataBuffer dataBuffer, + int w, int h, int scanlineStride, int[] bankIndices, int[] bandOffsets, + Point location) { SampleModel sm = new BandedSampleModel(dataBuffer.getDataType(), - w, h, scanlineStride, - bankIndices, bandOffsets); + w, h, scanlineStride, bankIndices, bandOffsets); return createWritableRaster(sm, dataBuffer, location); } - public static WritableRaster - createPackedRaster(DataBuffer dataBuffer, - int w, int h, - int scanlineStride, - int[] bandMasks, - Point location) + /** + * Creates a new packed raster. + * + * @param dataBuffer the data buffer. + * @param w the width. + * @param h the height. + * @param scanlineStride the number of data elements from a sample on one + * row to the corresponding sample on the next row. + * @param bandMasks the bit mask for each band. + * @param location + * + * @return The new raster. + */ + public static WritableRaster createPackedRaster(DataBuffer dataBuffer, + int w, int h, int scanlineStride, int[] bandMasks, Point location) { - SampleModel sm = - new SinglePixelPackedSampleModel(dataBuffer.getDataType(), - w, h, - scanlineStride, - bandMasks); + SampleModel sm = new SinglePixelPackedSampleModel(dataBuffer.getDataType(), + w, h, scanlineStride, bandMasks); return createWritableRaster(sm, dataBuffer, location); } - public static WritableRaster - createPackedRaster(DataBuffer dataBuffer, - int w, int h, - int bitsPerPixel, - Point location) - { - SampleModel sm = - new MultiPixelPackedSampleModel(dataBuffer.getDataType(), - w, h, - bitsPerPixel); + /** + * Creates a new packed raster. + * + * @param dataBuffer the data buffer. + * @param w the width. + * @param h the height. + * @param bitsPerPixel the number of bits per pixel. + * @param location + * + * @return The new raster. + */ + public static WritableRaster createPackedRaster(DataBuffer dataBuffer, + int w, int h, int bitsPerPixel, Point location) + { + SampleModel sm = new MultiPixelPackedSampleModel(dataBuffer.getDataType(), + w, h, bitsPerPixel); return createWritableRaster(sm, dataBuffer, location); } + /** + * Creates a new raster. + * + * @param sm the sample model. + * @param db the data buffer. + * @param location + * + * @return The new raster. + */ public static Raster createRaster(SampleModel sm, DataBuffer db, - Point location) + Point location) { return new Raster(sm, db, location); } + /** + * Creates a new writable raster. + * + * @param sm the sample model. + * @param location + * + * @return The new writable raster. + */ public static WritableRaster createWritableRaster(SampleModel sm, - Point location) + Point location) { return new WritableRaster(sm, location); } + /** + * Creates a new writable raster. + * + * @param sm the sample model. + * @param db the data buffer. + * @param location + * + * @return The new writable raster. + */ public static WritableRaster createWritableRaster(SampleModel sm, - DataBuffer db, - Point location) + DataBuffer db, Point location) { return new WritableRaster(sm, db, location); } + /** + * Returns the raster's parent. + * + * @return The raster's parent. + */ public Raster getParent() { return parent; } + /** + * Returns the x-translation. + * + * @return The x-translation. + */ public final int getSampleModelTranslateX() { return sampleModelTranslateX; } + /** + * Returns the y-translation. + * + * @return The y-translation. + */ public final int getSampleModelTranslateY() { return sampleModelTranslateY; } + /** + * Creates a new writable raster that is compatible with this raster. + * + * @return A new writable raster. + */ public WritableRaster createCompatibleWritableRaster() { return new WritableRaster(getSampleModel(), new Point(minX, minY)); } + /** + * Creates a new writable raster that is compatible with this raster. + * + * @param w the width. + * @param h the height. + * + * @return A new writable raster. + */ public WritableRaster createCompatibleWritableRaster(int w, int h) { return createCompatibleWritableRaster(minX, minY, w, h); } + /** + * Creates a new writable raster that is compatible with this raster, with + * the specified bounds. + * + * @param rect the raster bounds. + * + * @return A new writable raster. + */ public WritableRaster createCompatibleWritableRaster(Rectangle rect) { return createCompatibleWritableRaster(rect.x, rect.y, - rect.width, rect.height); + rect.width, rect.height); } + /** + * Creates a new writable raster that is compatible with this raster, with + * the specified bounds. + * + * @param x the x-coordinate of the top-left corner of the raster. + * @param y the y-coordinate of the top-left corner of the raster. + * @param w the raster width. + * @param h the raster height. + * + * @return A new writable raster. + */ public WritableRaster createCompatibleWritableRaster(int x, int y, - int w, int h) + int w, int h) { SampleModel sm = getSampleModel().createCompatibleSampleModel(w, h); - return new WritableRaster(sm, sm.createDataBuffer(), - new Point(x, y)); + return new WritableRaster(sm, sm.createDataBuffer(), new Point(x, y)); } public Raster createTranslatedChild(int childMinX, int childMinY) { @@ -302,15 +503,13 @@ public class Raster int tcy = sampleModelTranslateY - minY + childMinY; return new Raster(sampleModel, dataBuffer, - new Rectangle(childMinX, childMinY, - width, height), - new Point(tcx, tcy), - this); + new Rectangle(childMinX, childMinY, width, height), + new Point(tcx, tcy), this); } public Raster createChild(int parentX, int parentY, int width, - int height, int childMinX, int childMinY, - int[] bandList) + int height, int childMinX, int childMinY, + int[] bandList) { /* FIXME: Throw RasterFormatException if child bounds extends beyond the bounds of this raster. */ @@ -343,38 +542,67 @@ public class Raster */ return new Raster(sm, dataBuffer, - new Rectangle(childMinX, childMinY, - width, height), - new Point(sampleModelTranslateX+childMinX-parentX, - sampleModelTranslateY+childMinY-parentY), - this); + new Rectangle(childMinX, childMinY, width, height), + new Point(sampleModelTranslateX + childMinX - parentX, + sampleModelTranslateY + childMinY - parentY), + this); } + /** + * Returns a new rectangle containing the bounds of this raster. + * + * @return A new rectangle containing the bounds of this raster. + */ public Rectangle getBounds() { return new Rectangle(minX, minY, width, height); } + /** + * Returns the x-coordinate of the top left corner of the raster. + * + * @return The x-coordinate of the top left corner of the raster. + */ public final int getMinX() { return minX; } + /** + * Returns the t-coordinate of the top left corner of the raster. + * + * @return The t-coordinate of the top left corner of the raster. + */ public final int getMinY() { return minY; } + /** + * Returns the width of the raster. + * + * @return The width of the raster. + */ public final int getWidth() { return width; } + /** + * Returns the height of the raster. + * + * @return The height of the raster. + */ public final int getHeight() { return height; } + /** + * Returns the number of bands for this raster. + * + * @return The number of bands. + */ public final int getNumBands() { return numBands; @@ -384,17 +612,34 @@ public class Raster { return numDataElements; } - + + /** + * Returns the transfer type for the raster (this is determined by the + * raster's sample model). + * + * @return The transfer type. + */ public final int getTransferType() { return sampleModel.getTransferType(); } + /** + * Returns the data buffer that stores the pixel data for this raster. + * + * @return The data buffer. + */ public DataBuffer getDataBuffer() { return dataBuffer; } + /** + * Returns the sample model that accesses the data buffer (to extract pixel + * data) for this raster. + * + * @return The sample model. + */ public SampleModel getSampleModel() { return sampleModel; @@ -402,112 +647,275 @@ public class Raster public Object getDataElements(int x, int y, Object outData) { - return sampleModel.getDataElements(x-sampleModelTranslateX, - y-sampleModelTranslateY, - outData, dataBuffer); + return sampleModel.getDataElements(x - sampleModelTranslateX, + y - sampleModelTranslateY, outData, dataBuffer); } - public Object getDataElements(int x, int y, int w, int h, - Object outData) + public Object getDataElements(int x, int y, int w, int h, Object outData) { - return sampleModel.getDataElements(x-sampleModelTranslateX, - y-sampleModelTranslateY, - w, h, outData, dataBuffer); + return sampleModel.getDataElements(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, outData, dataBuffer); } + /** + * Returns an array containing the samples for the pixel at (x, y) in the + * raster. If <code>iArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of + * this function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param iArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * + * @return The pixel sample values. + */ public int[] getPixel(int x, int y, int[] iArray) { - return sampleModel.getPixel(x-sampleModelTranslateX, - y-sampleModelTranslateY, - iArray, dataBuffer); + return sampleModel.getPixel(x - sampleModelTranslateX, + y - sampleModelTranslateY, iArray, dataBuffer); } + /** + * Returns an array containing the samples for the pixel at (x, y) in the + * raster. If <code>fArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of + * this function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param fArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * + * @return The pixel sample values. + */ public float[] getPixel(int x, int y, float[] fArray) { - return sampleModel.getPixel(x-sampleModelTranslateX, - y-sampleModelTranslateY, - fArray, dataBuffer); + return sampleModel.getPixel(x - sampleModelTranslateX, + y - sampleModelTranslateY, fArray, dataBuffer); } + /** + * Returns an array containing the samples for the pixel at (x, y) in the + * raster. If <code>dArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of + * this function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param dArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * + * @return The pixel sample values. + */ public double[] getPixel(int x, int y, double[] dArray) { - return sampleModel.getPixel(x-sampleModelTranslateX, - y-sampleModelTranslateY, - dArray, dataBuffer); + return sampleModel.getPixel(x - sampleModelTranslateX, + y - sampleModelTranslateY, dArray, dataBuffer); } + /** + * Returns an array containing the samples for the pixels in the region + * specified by (x, y, w, h) in the raster. The array is ordered by pixels + * (that is, all the samples for the first pixel are grouped together, + * followed by all the samples for the second pixel, and so on). + * If <code>iArray</code> is not <code>null</code>, it will be populated + * with the sample values and returned as the result of this function (this + * avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param iArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * + * @return The pixel sample values. + */ public int[] getPixels(int x, int y, int w, int h, int[] iArray) { - return sampleModel.getPixels(x-sampleModelTranslateX, - y-sampleModelTranslateY, - w, h, iArray, dataBuffer); + return sampleModel.getPixels(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, iArray, dataBuffer); } - public float[] getPixels(int x, int y, int w, int h, - float[] fArray) + /** + * Returns an array containing the samples for the pixels in the region + * specified by (x, y, w, h) in the raster. The array is ordered by pixels + * (that is, all the samples for the first pixel are grouped together, + * followed by all the samples for the second pixel, and so on). + * If <code>fArray</code> is not <code>null</code>, it will be populated + * with the sample values and returned as the result of this function (this + * avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param fArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * + * @return The pixel sample values. + */ + public float[] getPixels(int x, int y, int w, int h, float[] fArray) { - return sampleModel.getPixels(x-sampleModelTranslateX, - y-sampleModelTranslateY, - w, h, fArray, dataBuffer); + return sampleModel.getPixels(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, fArray, dataBuffer); } - public double[] getPixels(int x, int y, int w, int h, - double[] dArray) + /** + * Returns an array containing the samples for the pixels in the region + * specified by (x, y, w, h) in the raster. The array is ordered by pixels + * (that is, all the samples for the first pixel are grouped together, + * followed by all the samples for the second pixel, and so on). + * If <code>dArray</code> is not <code>null</code>, it will be populated + * with the sample values and returned as the result of this function (this + * avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param dArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * + * @return The pixel sample values. + */ + public double[] getPixels(int x, int y, int w, int h, double[] dArray) { - return sampleModel.getPixels(x-sampleModelTranslateX, - y-sampleModelTranslateY, - w, h, dArray, dataBuffer); + return sampleModel.getPixels(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, dArray, dataBuffer); } + /** + * Returns the sample value for the pixel at (x, y) in the raster. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * + * @return The sample value. + */ public int getSample(int x, int y, int b) { - return sampleModel.getSample(x-sampleModelTranslateX, - y-sampleModelTranslateY, - b, dataBuffer); + return sampleModel.getSample(x - sampleModelTranslateX, + y - sampleModelTranslateY, b, dataBuffer); } + /** + * Returns the sample value for the pixel at (x, y) in the raster. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * + * @return The sample value. + * + * @see #getSample(int, int, int) + */ public float getSampleFloat(int x, int y, int b) { - return sampleModel.getSampleFloat(x-sampleModelTranslateX, - y-sampleModelTranslateY, - b, dataBuffer); + return sampleModel.getSampleFloat(x - sampleModelTranslateX, + y - sampleModelTranslateY, b, dataBuffer); } + /** + * Returns the sample value for the pixel at (x, y) in the raster. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * + * @return The sample value. + * + * @see #getSample(int, int, int) + */ public double getSampleDouble(int x, int y, int b) { - return sampleModel.getSampleDouble(x-sampleModelTranslateX, - y-sampleModelTranslateY, - b, dataBuffer); + return sampleModel.getSampleDouble(x - sampleModelTranslateX, + y - sampleModelTranslateY, b, dataBuffer); } + /** + * Returns an array containing the samples from one band for the pixels in + * the region specified by (x, y, w, h) in the raster. If + * <code>iArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of this + * function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param iArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * + * @return The sample values. + */ public int[] getSamples(int x, int y, int w, int h, int b, - int[] iArray) + int[] iArray) { - return sampleModel.getSamples(x-sampleModelTranslateX, - y-sampleModelTranslateY, - w, h, b, iArray, dataBuffer); + return sampleModel.getSamples(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, b, iArray, dataBuffer); } - public float[] getSamples(int x, int y, int w, int h, int b, - float[] fArray) - { - return sampleModel.getSamples(x-sampleModelTranslateX, - y-sampleModelTranslateY, - w, h, b, fArray, dataBuffer); + /** + * Returns an array containing the samples from one band for the pixels in + * the region specified by (x, y, w, h) in the raster. If + * <code>fArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of this + * function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param fArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * + * @return The sample values. + */ + public float[] getSamples(int x, int y, int w, int h, int b, float[] fArray) + { + return sampleModel.getSamples(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, b, fArray, dataBuffer); } - public double[] getSamples(int x, int y, int w, int h, int b, - double[] dArray) + /** + * Returns an array containing the samples from one band for the pixels in + * the region specified by (x, y, w, h) in the raster. If + * <code>dArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of this + * function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param dArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * + * @return The sample values. + */ + public double[] getSamples(int x, int y, int w, int h, int b, + double[] dArray) { - return sampleModel.getSamples(x-sampleModelTranslateX, - y-sampleModelTranslateY, - w, h, b, dArray, dataBuffer); + return sampleModel.getSamples(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, b, dArray, dataBuffer); } /** - * Create a String representing the stat of this Raster. + * Create a String representing the state of this Raster. + * * @return A String representing the stat of this Raster. - * @see java.lang.Object#toString() */ public String toString() { @@ -524,23 +932,39 @@ public class Raster return result.toString(); } - // Map from datatype to bits + /** + * Returns the number of bits used to represent the specified data type. + * Valid types are: + * <ul> + * <li>{@link DataBuffer#TYPE_BYTE};</li> + * <li>{@link DataBuffer#TYPE_USHORT};</li> + * <li>{@link DataBuffer#TYPE_SHORT};</li> + * <li>{@link DataBuffer#TYPE_INT};</li> + * <li>{@link DataBuffer#TYPE_FLOAT};</li> + * <li>{@link DataBuffer#TYPE_DOUBLE};</li> + * </ul> + * This method returns 0 for invalid data types. + * + * @param dataType the data type. + * + * @return The number of bits used to represent the specified data type. + */ private static int getTypeBits(int dataType) { switch (dataType) { case DataBuffer.TYPE_BYTE: - return 8; + return 8; case DataBuffer.TYPE_USHORT: case DataBuffer.TYPE_SHORT: - return 16; + return 16; case DataBuffer.TYPE_INT: case DataBuffer.TYPE_FLOAT: - return 32; + return 32; case DataBuffer.TYPE_DOUBLE: - return 64; + return 64; default: - return 0; + return 0; } } } diff --git a/libjava/classpath/java/awt/image/RasterOp.java b/libjava/classpath/java/awt/image/RasterOp.java index e081ca3d2ad..656370e8bcc 100644 --- a/libjava/classpath/java/awt/image/RasterOp.java +++ b/libjava/classpath/java/awt/image/RasterOp.java @@ -1,5 +1,5 @@ /* RasterOp.java -- - Copyright (C) 2000, 2002, 2004, 2005 Free Software Foundation + Copyright (C) 2000, 2002, 2004, 2005, 2006, Free Software Foundation This file is part of GNU Classpath. @@ -42,16 +42,64 @@ import java.awt.RenderingHints; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; +/** + * An operation that is performed on one raster (the source) producing a new + * raster (the destination). + */ public interface RasterOp { + /** + * Performs an operation on the source raster, returning the result in a + * writable raster. If <code>dest</code> is <code>null</code>, a new + * <code>WritableRaster</code> will be created by calling the + * {@link #createCompatibleDestRaster(Raster)} method. If <code>dest</code> + * is not <code>null</code>, the result is written to <code>dest</code> then + * returned (this avoids creating a new <code>WritableRaster</code> each + * time this method is called). + * + * @param src the source raster. + * @param dest the destination raster (<code>null</code> permitted). + * + * @return The filtered raster. + */ WritableRaster filter(Raster src, WritableRaster dest); + /** + * Returns the bounds of the destination raster on the basis of this + * <code>RasterOp</code> being applied to the specified source raster. + * + * @param src the source raster. + * + * @return The destination bounds. + */ Rectangle2D getBounds2D(Raster src); + /** + * Returns a raster that can be used by this <code>RasterOp</code> as the + * destination raster when operating on the specified source raster. + * + * @param src the source raster. + * + * @return A new writable raster that can be used as the destination raster. + */ WritableRaster createCompatibleDestRaster(Raster src); + /** + * Returns the point on the destination raster that corresponds to the given + * point on the source raster. + * + * @param srcPoint the source point. + * @param destPoint the destination point (<code>null</code> permitted). + * + * @return The destination point. + */ Point2D getPoint2D(Point2D srcPoint, Point2D destPoint); + /** + * Returns the rendering hints for this operation. + * + * @return The rendering hints. + */ RenderingHints getRenderingHints(); } diff --git a/libjava/classpath/java/awt/image/SampleModel.java b/libjava/classpath/java/awt/image/SampleModel.java index 6e3fd4069a3..cb352bb4d85 100644 --- a/libjava/classpath/java/awt/image/SampleModel.java +++ b/libjava/classpath/java/awt/image/SampleModel.java @@ -37,6 +37,9 @@ exception statement from your version. */ package java.awt.image; /** + * A <code>SampleModel</code> is used to access pixel data from a + * {@link DataBuffer}. This is used by the {@link Raster} class. + * * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) */ public abstract class SampleModel @@ -100,16 +103,37 @@ public abstract class SampleModel this.numBands = numBands; } + /** + * Returns the width of the pixel data accessible via this + * <code>SampleModel</code>. + * + * @return The width. + * + * @see #getHeight() + */ public final int getWidth() { return width; } + /** + * Returns the height of the pixel data accessible via this + * <code>SampleModel</code>. + * + * @return The height. + * + * @see #getWidth() + */ public final int getHeight() { return height; } + /** + * Returns the number of bands for this <code>SampleModel</code>. + * + * @return The number of bands. + */ public final int getNumBands() { return numBands; @@ -117,6 +141,12 @@ public abstract class SampleModel public abstract int getNumDataElements(); + /** + * Returns the type of the {@link DataBuffer} that this + * <code>SampleModel</code> accesses. + * + * @return The data buffer type. + */ public final int getDataType() { return dataType; @@ -128,6 +158,22 @@ public abstract class SampleModel return dataType; } + /** + * Returns an array containing the samples for the pixel at (x, y) in the + * specified data buffer. If <code>iArray</code> is not <code>null</code>, + * it will be populated with the sample values and returned as the result of + * this function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param iArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The pixel sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) { if (iArray == null) @@ -234,6 +280,22 @@ public abstract class SampleModel } } + /** + * Returns an array containing the samples for the pixel at (x, y) in the + * specified data buffer. If <code>fArray</code> is not <code>null</code>, + * it will be populated with the sample values and returned as the result of + * this function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param fArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The pixel sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public float[] getPixel(int x, int y, float[] fArray, DataBuffer data) { if (fArray == null) @@ -246,6 +308,22 @@ public abstract class SampleModel return fArray; } + /** + * Returns an array containing the samples for the pixel at (x, y) in the + * specified data buffer. If <code>dArray</code> is not <code>null</code>, + * it will be populated with the sample values and returned as the result of + * this function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param dArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The pixel sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public double[] getPixel(int x, int y, double[] dArray, DataBuffer data) { if (dArray == null) dArray = new double[numBands]; @@ -256,8 +334,27 @@ public abstract class SampleModel return dArray; } - /* FIXME: Should it return a banded or pixel interleaved array of - samples? (Assume interleaved.) */ + /** + * Returns an array containing the samples for the pixels in the region + * specified by (x, y, w, h) in the specified data buffer. The array is + * ordered by pixels (that is, all the samples for the first pixel are + * grouped together, followed by all the samples for the second pixel, and so + * on). If <code>iArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of this + * function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param iArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The pixel sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public int[] getPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { @@ -278,8 +375,27 @@ public abstract class SampleModel return iArray; } - /* FIXME: Should it return a banded or pixel interleaved array of - samples? (Assume interleaved.) */ + /** + * Returns an array containing the samples for the pixels in the region + * specified by (x, y, w, h) in the specified data buffer. The array is + * ordered by pixels (that is, all the samples for the first pixel are + * grouped together, followed by all the samples for the second pixel, and so + * on). If <code>fArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of this + * function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param fArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The pixel sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public float[] getPixels(int x, int y, int w, int h, float[] fArray, DataBuffer data) { @@ -299,8 +415,27 @@ public abstract class SampleModel return fArray; } - /* FIXME: Should it return a banded or pixel interleaved array of - samples? (Assume interleaved.) */ + /** + * Returns an array containing the samples for the pixels in the region + * specified by (x, y, w, h) in the specified data buffer. The array is + * ordered by pixels (that is, all the samples for the first pixel are + * grouped together, followed by all the samples for the second pixel, and so + * on). If <code>dArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of this + * function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param dArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The pixel sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public double[] getPixels(int x, int y, int w, int h, double[] dArray, DataBuffer data) { @@ -321,18 +456,85 @@ public abstract class SampleModel return dArray; } + /** + * Returns the sample value for the pixel at (x, y) in the specified data + * buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample value. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public abstract int getSample(int x, int y, int b, DataBuffer data); + /** + * Returns the sample value for the pixel at (x, y) in the specified data + * buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample value. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + * + * @see #getSample(int, int, int, DataBuffer) + */ public float getSampleFloat(int x, int y, int b, DataBuffer data) { return getSample(x, y, b, data); } + /** + * Returns the sample value for the pixel at (x, y) in the specified data + * buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample value. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + * + * @see #getSample(int, int, int, DataBuffer) + */ public double getSampleDouble(int x, int y, int b, DataBuffer data) { return getSampleFloat(x, y, b, data); } + /** + * Returns an array containing the samples from one band for the pixels in + * the region specified by (x, y, w, h) in the specified data buffer. If + * <code>iArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of this + * function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param iArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public int[] getSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { @@ -350,6 +552,27 @@ public abstract class SampleModel return iArray; } + /** + * Returns an array containing the samples from one band for the pixels in + * the region specified by (x, y, w, h) in the specified data buffer. If + * <code>fArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of this + * function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param fArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public float[] getSamples(int x, int y, int w, int h, int b, float[] fArray, DataBuffer data) { @@ -367,6 +590,27 @@ public abstract class SampleModel return fArray; } + /** + * Returns an array containing the samples from one band for the pixels in + * the region specified by (x, y, w, h) in the specified data buffer. If + * <code>dArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of this + * function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param dArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public double[] getSamples(int x, int y, int w, int h, int b, double[] dArray, DataBuffer data) { @@ -384,24 +628,77 @@ public abstract class SampleModel return dArray; } + /** + * Sets the samples for the pixel at (x, y) in the specified data buffer to + * the specified values. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param iArray the sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>iArray</code> or + * <code>data</code> is <code>null</code>. + */ public void setPixel(int x, int y, int[] iArray, DataBuffer data) { for (int b = 0; b < numBands; b++) setSample(x, y, b, iArray[b], data); } + /** + * Sets the samples for the pixel at (x, y) in the specified data buffer to + * the specified values. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param fArray the sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>fArray</code> or + * <code>data</code> is <code>null</code>. + */ public void setPixel(int x, int y, float[] fArray, DataBuffer data) { for (int b = 0; b < numBands; b++) setSample(x, y, b, fArray[b], data); } + /** + * Sets the samples for the pixel at (x, y) in the specified data buffer to + * the specified values. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param dArray the sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>dArray</code> or + * <code>data</code> is <code>null</code>. + */ public void setPixel(int x, int y, double[] dArray, DataBuffer data) { for (int b = 0; b < numBands; b++) setSample(x, y, b, dArray[b], data); } + /** + * Sets the sample values for the pixels in the region specified by + * (x, y, w, h) in the specified data buffer. The array is + * ordered by pixels (that is, all the samples for the first pixel are + * grouped together, followed by all the samples for the second pixel, and so + * on). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param iArray the pixel sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>iArray</code> or + * <code>data</code> is <code>null</code>. + */ public void setPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { @@ -418,6 +715,23 @@ public abstract class SampleModel } } + /** + * Sets the sample values for the pixels in the region specified by + * (x, y, w, h) in the specified data buffer. The array is + * ordered by pixels (that is, all the samples for the first pixel are + * grouped together, followed by all the samples for the second pixel, and so + * on). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param fArray the pixel sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>fArray</code> or + * <code>data</code> is <code>null</code>. + */ public void setPixels(int x, int y, int w, int h, float[] fArray, DataBuffer data) { @@ -434,6 +748,23 @@ public abstract class SampleModel } } + /** + * Sets the sample values for the pixels in the region specified by + * (x, y, w, h) in the specified data buffer. The array is + * ordered by pixels (that is, all the samples for the first pixel are + * grouped together, followed by all the samples for the second pixel, and so + * on). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param dArray the pixel sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>dArray</code> or + * <code>data</code> is <code>null</code>. + */ public void setPixels(int x, int y, int w, int h, double[] dArray, DataBuffer data) { @@ -450,21 +781,76 @@ public abstract class SampleModel } } + /** + * Sets the sample value for a band for the pixel at (x, y) in the + * specified data buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param s the sample value. + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public abstract void setSample(int x, int y, int b, int s, DataBuffer data); + /** + * Sets the sample value for a band for the pixel at (x, y) in the + * specified data buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param s the sample value. + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public void setSample(int x, int y, int b, float s, DataBuffer data) { setSample(x, y, b, (int) s, data); } + /** + * Sets the sample value for a band for the pixel at (x, y) in the + * specified data buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param s the sample value. + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public void setSample(int x, int y, int b, double s, DataBuffer data) { setSample(x, y, b, (float) s, data); } + /** + * Sets the sample values for one band for the pixels in the region + * specified by (x, y, w, h) in the specified data buffer. + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param iArray the sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>iArray</code> or + * <code>data</code> is <code>null</code>. + */ public void setSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { @@ -475,6 +861,22 @@ public abstract class SampleModel setSample(xx, yy, b, iArray[inOffset++], data); } + /** + * Sets the sample values for one band for the pixels in the region + * specified by (x, y, w, h) in the specified data buffer. + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param fArray the sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>iArray</code> or + * <code>data</code> is <code>null</code>. + */ public void setSamples(int x, int y, int w, int h, int b, float[] fArray, DataBuffer data) { @@ -486,6 +888,22 @@ public abstract class SampleModel } + /** + * Sets the sample values for one band for the pixels in the region + * specified by (x, y, w, h) in the specified data buffer. + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param dArray the sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>iArray</code> or + * <code>data</code> is <code>null</code>. + */ public void setSamples(int x, int y, int w, int h, int b, double[] dArray, DataBuffer data) { int size = w * h; @@ -495,6 +913,15 @@ public abstract class SampleModel setSample(xx, yy, b, dArray[inOffset++], data); } + /** + * Creates a new <code>SampleModel</code> that is compatible with this + * model and has the specified width and height. + * + * @param w the width (in pixels). + * @param h the height (in pixels). + * + * @return The new sample model. + */ public abstract SampleModel createCompatibleSampleModel(int w, int h); /** @@ -510,9 +937,31 @@ public abstract class SampleModel */ public abstract SampleModel createSubsetSampleModel(int[] bands); + /** + * Creates a new {@link DataBuffer} of the correct type and size for this + * <code>SampleModel</code>. + * + * @return The data buffer. + */ public abstract DataBuffer createDataBuffer(); + /** + * Returns an array containing the size (in bits) for each band accessed by + * the <code>SampleModel</code>. + * + * @return An array. + * + * @see #getSampleSize(int) + */ public abstract int[] getSampleSize(); + /** + * Returns the size (in bits) of the samples for the specified band. + * + * @param band the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * + * @return The sample size (in bits). + */ public abstract int getSampleSize(int band); } diff --git a/libjava/classpath/java/awt/image/ShortLookupTable.java b/libjava/classpath/java/awt/image/ShortLookupTable.java index 5915a7939a3..858818cf26d 100644 --- a/libjava/classpath/java/awt/image/ShortLookupTable.java +++ b/libjava/classpath/java/awt/image/ShortLookupTable.java @@ -1,5 +1,5 @@ /* ShortLookupTable.java -- Java class for a pixel translation table. - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -67,7 +67,13 @@ public class ShortLookupTable extends LookupTable throws IllegalArgumentException { super(offset, data.length); - this.data = data; + + // tests show that Sun's implementation creates a new array to store the + // references from the incoming 'data' array - not sure why, but we'll + // match that behaviour just in case it matters... + this.data = new short[data.length][]; + for (int i = 0; i < data.length; i++) + this.data[i] = data[i]; } /** @@ -77,17 +83,25 @@ public class ShortLookupTable extends LookupTable * table. The same table is applied to all pixel components. * * @param offset Offset to be subtracted. - * @param data Lookup table for all components. + * @param data Lookup table for all components (<code>null</code> not + * permitted). * @exception IllegalArgumentException if offset < 0. */ public ShortLookupTable(int offset, short[] data) throws IllegalArgumentException { super(offset, 1); + if (data == null) + throw new NullPointerException("Null 'data' argument."); this.data = new short[][] {data}; } - /** Return the lookup tables. */ + /** + * Return the lookup tables. This is a reference to the actual table, so + * modifying the contents of the returned array will modify the lookup table. + * + * @return The lookup table. + */ public final short[][] getTable() { return data; @@ -117,11 +131,11 @@ public class ShortLookupTable extends LookupTable dst = new int[src.length]; if (data.length == 1) - for (int i=0; i < src.length; i++) - dst[i] = data[0][src[i] - offset]; + for (int i = 0; i < src.length; i++) + dst[i] = data[0][src[i] - offset]; else - for (int i=0; i < src.length; i++) - dst[i] = data[i][src[i] - offset]; + for (int i = 0; i < src.length; i++) + dst[i] = data[i][src[i] - offset]; return dst; } @@ -142,6 +156,7 @@ public class ShortLookupTable extends LookupTable * @param src Component values of a pixel. * @param dst Destination array for values, or null. * @return Translated values for the pixel. + * */ public short[] lookupPixel(short[] src, short[] dst) throws ArrayIndexOutOfBoundsException @@ -150,11 +165,11 @@ public class ShortLookupTable extends LookupTable dst = new short[src.length]; if (data.length == 1) - for (int i=0; i < src.length; i++) - dst[i] = data[0][((int)src[i]) - offset]; + for (int i = 0; i < src.length; i++) + dst[i] = data[0][((int) src[i]) - offset]; else - for (int i=0; i < src.length; i++) - dst[i] = data[i][((int)src[i]) - offset]; + for (int i = 0; i < src.length; i++) + dst[i] = data[i][((int) src[i]) - offset]; return dst; diff --git a/libjava/classpath/java/awt/image/SinglePixelPackedSampleModel.java b/libjava/classpath/java/awt/image/SinglePixelPackedSampleModel.java index 6ccce753bd3..a37fc0bba3f 100644 --- a/libjava/classpath/java/awt/image/SinglePixelPackedSampleModel.java +++ b/libjava/classpath/java/awt/image/SinglePixelPackedSampleModel.java @@ -1,4 +1,4 @@ -/* 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. @@ -36,10 +36,16 @@ exception statement from your version. */ package java.awt.image; +import java.util.Arrays; + import gnu.java.awt.BitMaskExtent; import gnu.java.awt.Buffers; /** + * A <code>SampleModel</code> used when all samples are stored in a single + * data element in the {@link DataBuffer}, and each data element contains + * samples for one pixel only. + * * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) */ public class SinglePixelPackedSampleModel extends SampleModel @@ -49,12 +55,32 @@ public class SinglePixelPackedSampleModel extends SampleModel private int[] bitOffsets; private int[] sampleSize; + /** + * Creates a new <code>SinglePixelPackedSampleModel</code>. + * + * @param dataType the data buffer type. + * @param w the width (in pixels). + * @param h the height (in pixels). + * @param bitMasks an array containing the bit mask used to extract the + * sample value for each band. + */ public SinglePixelPackedSampleModel(int dataType, int w, int h, int[] bitMasks) { this(dataType, w, h, w, bitMasks); } + /** + * Creates a new <code>SinglePixelPackedSampleModel</code>. + * + * @param dataType the data buffer type. + * @param w the width (in pixels). + * @param h the height (in pixels). + * @param scanlineStride the number of data elements between a pixel on one + * row and the corresponding pixel on the next row. + * @param bitMasks an array containing the bit mask used to extract the + * sample value for each band. + */ public SinglePixelPackedSampleModel(int dataType, int w, int h, int scanlineStride, int[] bitMasks) { @@ -67,7 +93,8 @@ public class SinglePixelPackedSampleModel extends SampleModel case DataBuffer.TYPE_INT: break; default: - throw new IllegalArgumentException("SinglePixelPackedSampleModel unsupported dataType"); + throw new IllegalArgumentException( + "SinglePixelPackedSampleModel unsupported dataType"); } this.scanlineStride = scanlineStride; @@ -77,19 +104,35 @@ public class SinglePixelPackedSampleModel extends SampleModel sampleSize = new int[numBands]; BitMaskExtent extent = new BitMaskExtent(); - for (int b=0; b<numBands; b++) + for (int b = 0; b < numBands; b++) { - extent.setMask(bitMasks[b]); - sampleSize[b] = extent.bitWidth; - bitOffsets[b] = extent.leastSignificantBit; + // the mask is an unsigned integer + long mask = bitMasks[b] & 0xFFFFFFFFL; + extent.setMask(mask); + sampleSize[b] = extent.bitWidth; + bitOffsets[b] = extent.leastSignificantBit; } } + /** + * Returns the number of data elements. + * + * @return <code>1</code>. + */ public int getNumDataElements() { return 1; } + /** + * Creates a new <code>SampleModel</code> that is compatible with this + * model and has the specified width and height. + * + * @param w the width (in pixels). + * @param h the height (in pixels). + * + * @return The new sample model. + */ public SampleModel createCompatibleSampleModel(int w, int h) { /* FIXME: We can avoid recalculation of bit offsets and sample @@ -103,6 +146,8 @@ public class SinglePixelPackedSampleModel extends SampleModel * Creates a DataBuffer for holding pixel data in the format and * layout described by this SampleModel. The returned buffer will * consist of one single bank. + * + * @return The data buffer. */ public DataBuffer createDataBuffer() { @@ -116,17 +161,40 @@ public class SinglePixelPackedSampleModel extends SampleModel return Buffers.createBuffer(getDataType(), size); } - + /** + * Returns an array containing the size (in bits) for each band accessed by + * the <code>SampleModel</code>. + * + * @return An array. + * + * @see #getSampleSize(int) + */ public int[] getSampleSize() { - return sampleSize; + return (int[]) sampleSize.clone(); } + /** + * Returns the size (in bits) of the samples for the specified band. + * + * @param band the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * + * @return The sample size (in bits). + */ public int getSampleSize(int band) { return sampleSize[band]; } + /** + * Returns the index in the data buffer that stores the pixel at (x, y). + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * + * @return The index in the data buffer that stores the pixel at (x, y). + */ public int getOffset(int x, int y) { return scanlineStride*y + x; @@ -142,20 +210,40 @@ public class SinglePixelPackedSampleModel extends SampleModel return bitMasks; } + /** + * Returns the number of data elements from a pixel in one row to the + * corresponding pixel in the next row. + * + * @return The scanline stride. + */ public int getScanlineStride() { return scanlineStride; } + /** + * Creates a new <code>SinglePixelPackedSampleModel</code> that accesses + * the specified subset of bands. + * + * @param bands an array containing band indices (<code>null</code> not + * permitted). + * + * @return A new sample model. + * + * @throws NullPointerException if <code>bands</code> is <code>null</code>. + * @throws RasterFormatException if <code>bands.length</code> is greater + * than the number of bands in this model. + */ public SampleModel createSubsetSampleModel(int[] bands) { - // FIXME: Is this the right way to interpret bands? + if (bands.length > numBands) + throw new RasterFormatException("Too many bands."); int numBands = bands.length; int[] bitMasks = new int[numBands]; - for (int b=0; b<numBands; b++) + for (int b = 0; b < numBands; b++) bitMasks[b] = this.bitMasks[bands[b]]; return new SinglePixelPackedSampleModel(dataType, width, height, @@ -174,16 +262,20 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * This is a more efficient implementation of the default implementation in the super - * class. - * @param x The x-coordinate of the pixel rectangle to store in <code>obj</code>. - * @param y The y-coordinate of the pixel rectangle to store in <code>obj</code>. + * This is a more efficient implementation of the default implementation in + * the super class. + * @param x The x-coordinate of the pixel rectangle to store in + * <code>obj</code>. + * @param y The y-coordinate of the pixel rectangle to store in + * <code>obj</code>. * @param w The width of the pixel rectangle to store in <code>obj</code>. * @param h The height of the pixel rectangle to store in <code>obj</code>. - * @param obj The primitive array to store the pixels into or null to force creation. + * @param obj The primitive array to store the pixels into or null to force + * creation. * @param data The DataBuffer that is the source of the pixel data. * @return The primitive array containing the pixel data. - * @see java.awt.image.SampleModel#getDataElements(int, int, int, int, java.lang.Object, java.awt.image.DataBuffer) + * @see java.awt.image.SampleModel#getDataElements(int, int, int, int, + * java.lang.Object, java.awt.image.DataBuffer) */ public Object getDataElements(int x, int y, int w, int h, Object obj, DataBuffer data) @@ -209,10 +301,11 @@ public class SinglePixelPackedSampleModel extends SampleModel // Seems like the only sensible thing to do. throw new ClassCastException(); } - if(x==0 && scanlineStride == w) + if(x == 0 && scanlineStride == w) { // The full width need to be copied therefore we can copy in one shot. - System.arraycopy(pixelData, scanlineStride*y + data.getOffset(), obj, 0, size); + System.arraycopy(pixelData, scanlineStride*y + data.getOffset(), obj, + 0, size); } else { @@ -229,32 +322,68 @@ public class SinglePixelPackedSampleModel extends SampleModel return obj; } - + /** + * Returns an array containing the samples for the pixel at (x, y) in the + * specified data buffer. If <code>iArray</code> is not <code>null</code>, + * it will be populated with the sample values and returned as the result of + * this function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param iArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The pixel sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) { int offset = scanlineStride*y + x; if (iArray == null) iArray = new int[numBands]; int samples = data.getElem(offset); - for (int b=0; b<numBands; b++) + for (int b = 0; b < numBands; b++) iArray[b] = (samples & bitMasks[b]) >>> bitOffsets[b]; return iArray; } + /** + * Returns an array containing the samples for the pixels in the region + * specified by (x, y, w, h) in the specified data buffer. The array is + * ordered by pixels (that is, all the samples for the first pixel are + * grouped together, followed by all the samples for the second pixel, and so + * on). If <code>iArray</code> is not <code>null</code>, it will be + * populated with the sample values and returned as the result of this + * function (this avoids allocating a new array instance). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param iArray an array to populate with the sample values and return as + * the result (if <code>null</code>, a new array will be allocated). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The pixel sample values. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public int[] getPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { int offset = scanlineStride*y + x; if (iArray == null) iArray = new int[numBands*w*h]; int outOffset = 0; - for (y=0; y<h; y++) + for (y = 0; y < h; y++) { int lineOffset = offset; - for (x=0; x<w; x++) + for (x = 0; x < w; x++) { int samples = data.getElem(lineOffset++); - for (int b=0; b<numBands; b++) + for (int b = 0; b < numBands; b++) iArray[outOffset++] = (samples & bitMasks[b]) >>> bitOffsets[b]; } offset += scanlineStride; @@ -262,6 +391,20 @@ public class SinglePixelPackedSampleModel extends SampleModel return iArray; } + /** + * Returns the sample value for the pixel at (x, y) in the specified data + * buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample value. + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public int getSample(int x, int y, int b, DataBuffer data) { int offset = scanlineStride*y + x; @@ -270,16 +413,18 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * This method implements a more efficient way to set data elements than the default - * implementation of the super class. It sets the data elements line by line instead - * of pixel by pixel. + * This method implements a more efficient way to set data elements than the + * default implementation of the super class. It sets the data elements line + * by line instead of pixel by pixel. + * * @param x The x-coordinate of the data elements in <code>obj</code>. * @param y The y-coordinate of the data elements in <code>obj</code>. * @param w The width of the data elements in <code>obj</code>. * @param h The height of the data elements in <code>obj</code>. * @param obj The primitive array containing the data elements to set. * @param data The DataBuffer to store the data elements into. - * @see java.awt.image.SampleModel#setDataElements(int, int, int, int, java.lang.Object, java.awt.image.DataBuffer) + * @see java.awt.image.SampleModel#setDataElements(int, int, int, int, + * java.lang.Object, java.awt.image.DataBuffer) */ public void setDataElements(int x, int y, int w, int h, Object obj, DataBuffer data) @@ -373,12 +518,24 @@ public class SinglePixelPackedSampleModel extends SampleModel } } + /** + * Sets the samples for the pixel at (x, y) in the specified data buffer to + * the specified values. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param iArray the sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if either <code>iArray</code> or + * <code>data</code> is <code>null</code>. + */ public void setPixel(int x, int y, int[] iArray, DataBuffer data) { int offset = scanlineStride*y + x; int samples = 0; - for (int b=0; b<numBands; b++) + for (int b = 0; b < numBands; b++) samples |= (iArray[b] << bitOffsets[b]) & bitMasks[b]; data.setElem(offset, samples); @@ -394,7 +551,8 @@ public class SinglePixelPackedSampleModel extends SampleModel * @param h The height of the pixel rectangle in <code>obj</code>. * @param iArray The primitive array containing the pixels to set. * @param data The DataBuffer to store the pixels into. - * @see java.awt.image.SampleModel#setPixels(int, int, int, int, int[], java.awt.image.DataBuffer) + * @see java.awt.image.SampleModel#setPixels(int, int, int, int, int[], + * java.awt.image.DataBuffer) */ public void setPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) @@ -407,7 +565,7 @@ public class SinglePixelPackedSampleModel extends SampleModel for (int xx=x; xx<(x+w); xx++) { int samples = 0; - for (int b=0; b<numBands; b++) + for (int b = 0; b < numBands; b++) samples |= (iArray[inOffset+b] << bitOffsets[b]) & bitMasks[b]; data.setElem(0, offset, samples); inOffset += numBands; @@ -416,7 +574,19 @@ public class SinglePixelPackedSampleModel extends SampleModel } } - + /** + * Sets the sample value for a band for the pixel at (x, y) in the + * specified data buffer. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param s the sample value. + * @param data the data buffer (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>data</code> is <code>null</code>. + */ public void setSample(int x, int y, int b, int s, DataBuffer data) { int offset = scanlineStride*y + x; @@ -428,6 +598,76 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** + * Tests this sample model for equality with an arbitrary object. This + * method returns <code>true</code> if and only if: + * <ul> + * <li><code>obj</code> is not <code>null</code>; + * <li><code>obj</code> is an instance of + * <code>SinglePixelPackedSampleModel</code>; + * <li>both models have the same: + * <ul> + * <li><code>dataType</code>; + * <li><code>width</code>; + * <li><code>height</code>; + * <li><code>numBands</code>; + * <li><code>scanlineStride</code>; + * <li><code>bitMasks</code>; + * <li><code>bitOffsets</code>. + * </ul> + * </li> + * </ul> + * + * @param obj the object (<code>null</code> permitted) + * + * @return <code>true</code> if this model is equal to <code>obj</code>, and + * <code>false</code> otherwise. + */ + public boolean equals(Object obj) + { + if (this == obj) + return true; + if (! (obj instanceof SinglePixelPackedSampleModel)) + return false; + SinglePixelPackedSampleModel that = (SinglePixelPackedSampleModel) obj; + if (this.dataType != that.dataType) + return false; + if (this.width != that.width) + return false; + if (this.height != that.height) + return false; + if (this.numBands != that.numBands) + return false; + if (this.scanlineStride != that.scanlineStride) + return false; + if (!Arrays.equals(this.bitMasks, that.bitMasks)) + return false; + if (!Arrays.equals(this.bitOffsets, that.bitOffsets)) + return false; + return true; + } + + /** + * Returns a hash code for this <code>SinglePixelPackedSampleModel</code>. + * + * @return A hash code. + */ + public int hashCode() + { + // this hash code won't match Sun's, but that shouldn't matter... + int result = 193; + result = 37 * result + dataType; + result = 37 * result + width; + result = 37 * result + height; + result = 37 * result + numBands; + result = 37 * result + scanlineStride; + for (int i = 0; i < bitMasks.length; i++) + result = 37 * result + bitMasks[i]; + for (int i = 0; i < bitOffsets.length; i++) + result = 37 * result + bitOffsets[i]; + return result; + } + + /** * Creates a String with some information about this SampleModel. * @return A String describing this SampleModel. * @see java.lang.Object#toString() @@ -438,9 +678,10 @@ public class SinglePixelPackedSampleModel extends SampleModel result.append(getClass().getName()); result.append("["); result.append("scanlineStride=").append(scanlineStride); - for(int i=0; i < bitMasks.length; i+=1) + for(int i = 0; i < bitMasks.length; i+=1) { - result.append(", mask[").append(i).append("]=0x").append(Integer.toHexString(bitMasks[i])); + result.append(", mask[").append(i).append("]=0x").append( + Integer.toHexString(bitMasks[i])); } result.append("]"); diff --git a/libjava/classpath/java/awt/image/WritableRaster.java b/libjava/classpath/java/awt/image/WritableRaster.java index 2e5462fd92e..473c6fe41f9 100644 --- a/libjava/classpath/java/awt/image/WritableRaster.java +++ b/libjava/classpath/java/awt/image/WritableRaster.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2000, 2002, 2003 Free Software Foundation +/* Copyright (C) 2000, 2002, 2003, 2006, Free Software Foundation This file is part of GNU Classpath. @@ -41,61 +41,98 @@ import java.awt.Point; import java.awt.Rectangle; /** + * A raster with methods to support updating pixel values. + * * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) */ public class WritableRaster extends Raster { + /** + * Creates a new <code>WritableRaster</code>. + * + * @param sampleModel the sample model. + * @param origin the origin. + */ protected WritableRaster(SampleModel sampleModel, Point origin) { this(sampleModel, sampleModel.createDataBuffer(), origin); } - protected WritableRaster(SampleModel sampleModel, - DataBuffer dataBuffer, Point origin) + /** + * Creates a new <code>WritableRaster</code> instance. + * + * @param sampleModel the sample model. + * @param dataBuffer the data buffer. + * @param origin the origin. + */ + protected WritableRaster(SampleModel sampleModel, DataBuffer dataBuffer, + Point origin) { this(sampleModel, dataBuffer, - new Rectangle(origin != null ? origin.x : 0, + new Rectangle(origin != null ? origin.x : 0, origin != null ? origin.y : 0, - sampleModel.getWidth(), sampleModel.getHeight()), - origin, - null); + sampleModel.getWidth(), sampleModel.getHeight()), + origin, null); } + /** + * Creates a new <code>WritableRaster</code> instance. + * + * @param sampleModel the sample model. + * @param dataBuffer the data buffer. + * @param aRegion the raster's bounds. + * @param sampleModelTranslate the translation. + * @param parent the parent. + */ protected WritableRaster(SampleModel sampleModel, - DataBuffer dataBuffer, - Rectangle aRegion, - Point sampleModelTranslate, - WritableRaster parent) + DataBuffer dataBuffer, + Rectangle aRegion, + Point sampleModelTranslate, + WritableRaster parent) { - super(sampleModel, dataBuffer, aRegion, sampleModelTranslate, - parent); + super(sampleModel, dataBuffer, aRegion, sampleModelTranslate, parent); } + /** + * Returns the raster's parent, cast as a {@link WritableRaster}. + * + * @return The raster's parent. + */ public WritableRaster getWritableParent() { return (WritableRaster) getParent(); } + /** + * @param childMinX + * @param childMinY + * @return + */ public WritableRaster createWritableTranslatedChild(int childMinX, - int childMinY) + int childMinY) { // This mirrors the code from the super class int tcx = sampleModelTranslateX - minX + childMinX; int tcy = sampleModelTranslateY - minY + childMinY; return new WritableRaster(sampleModel, dataBuffer, - new Rectangle(childMinX, childMinY, - width, height), - new Point(tcx, tcy), - this); + new Rectangle(childMinX, childMinY, width, height), + new Point(tcx, tcy), this); } - public WritableRaster createWritableChild(int parentX, - int parentY, - int w, int h, - int childMinX, - int childMinY, - int[] bandList) + /** + * + * @param parentX + * @param parentY + * @param w + * @param h + * @param childMinX + * @param childMinY + * @param bandList + * @return + */ + public WritableRaster createWritableChild(int parentX, int parentY, + int w, int h, int childMinX, int childMinY, int[] bandList) { // This mirrors the code from the super class @@ -106,51 +143,52 @@ public class WritableRaster extends Raster sampleModel : sampleModel.createSubsetSampleModel(bandList); - return new - WritableRaster(sm, dataBuffer, - new Rectangle(childMinX, childMinY, - w, h), - new Point(sampleModelTranslateX+childMinX-parentX, - sampleModelTranslateY+childMinY-parentY), - this); + return new WritableRaster(sm, dataBuffer, + new Rectangle(childMinX, childMinY, w, h), + new Point(sampleModelTranslateX + childMinX - parentX, + sampleModelTranslateY + childMinY - parentY), + this); } public void setDataElements(int x, int y, Object inData) { - sampleModel.setDataElements(x-sampleModelTranslateX, - y-sampleModelTranslateY, - inData, dataBuffer); + sampleModel.setDataElements(x - sampleModelTranslateX, + y - sampleModelTranslateY, inData, dataBuffer); } public void setDataElements(int x, int y, Raster inRaster) { - Object dataElements = getDataElements(0, 0, - inRaster.getWidth(), - inRaster.getHeight(), - null); + Object dataElements = getDataElements(0, 0, inRaster.getWidth(), + inRaster.getHeight(), null); setDataElements(x, y, dataElements); } - public void setDataElements(int x, int y, int w, int h, - Object inData) + public void setDataElements(int x, int y, int w, int h, Object inData) { - sampleModel.setDataElements(x-sampleModelTranslateX, - y-sampleModelTranslateY, - w, h, inData, dataBuffer); + sampleModel.setDataElements(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, inData, dataBuffer); } + /** + * + * @param srcRaster + */ public void setRect(Raster srcRaster) { setRect(0, 0, srcRaster); } + /** + * + * @param dx + * @param dy + * @param srcRaster + */ public void setRect(int dx, int dy, Raster srcRaster) { - Rectangle targetUnclipped = new Rectangle(srcRaster.getMinX()+dx, - srcRaster.getMinY()+dy, - srcRaster.getWidth(), - srcRaster.getHeight()); - + Rectangle targetUnclipped = new Rectangle(srcRaster.getMinX() + dx, + srcRaster.getMinY() + dy, srcRaster.getWidth(), srcRaster.getHeight()); + Rectangle target = getBounds().intersection(targetUnclipped); if (target.isEmpty()) return; @@ -169,97 +207,225 @@ public class WritableRaster extends Raster But this is probably not the place to consider such optimizations.*/ - int[] pixels = srcRaster.getPixels(sx, sy, - target.width, target.height, - (int[]) null); + int[] pixels = srcRaster.getPixels(sx, sy, target.width, target.height, + (int[]) null); setPixels(target.x, target.y, target.width, target.height, pixels); } + /** + * Sets the samples for the pixel at (x, y) in the raster to the specified + * values. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param iArray the sample values (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>iArray</code> is <code>null</code>. + */ public void setPixel(int x, int y, int[] iArray) { - sampleModel.setPixel(x-sampleModelTranslateX, - y-sampleModelTranslateY, - iArray, dataBuffer); + sampleModel.setPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, + iArray, dataBuffer); } + /** + * Sets the samples for the pixel at (x, y) in the raster to the specified + * values. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param fArray the sample values (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>fArray</code> is <code>null</code>. + */ public void setPixel(int x, int y, float[] fArray) { - sampleModel.setPixel(x-sampleModelTranslateX, - y-sampleModelTranslateY, - fArray, dataBuffer); + sampleModel.setPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, + fArray, dataBuffer); } + /** + * Sets the samples for the pixel at (x, y) in the raster to the specified + * values. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param dArray the sample values (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>dArray</code> is <code>null</code>. + */ public void setPixel(int x, int y, double[] dArray) { - sampleModel.setPixel(x-sampleModelTranslateX, - y-sampleModelTranslateY, - dArray, dataBuffer); + sampleModel.setPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, + dArray, dataBuffer); } + /** + * Sets the sample values for the pixels in the region specified by + * (x, y, w, h) in the raster. The array is ordered by pixels (that is, all + * the samples for the first pixel are grouped together, followed by all the + * samples for the second pixel, and so on). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param iArray the pixel sample values (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>iArray</code> is <code>null</code>. + */ public void setPixels(int x, int y, int w, int h, int[] iArray) { - sampleModel.setPixels(x-sampleModelTranslateX, - y-sampleModelTranslateY, - w, h, iArray, dataBuffer); + sampleModel.setPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, + w, h, iArray, dataBuffer); } + /** + * Sets the sample values for the pixels in the region specified by + * (x, y, w, h) in the raster. The array is ordered by pixels (that is, all + * the samples for the first pixel are grouped together, followed by all the + * samples for the second pixel, and so on). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param fArray the pixel sample values (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>fArray</code> is <code>null</code>. + */ public void setPixels(int x, int y, int w, int h, float[] fArray) { - sampleModel.setPixels(x-sampleModelTranslateX, - y-sampleModelTranslateY, - w, h, fArray, dataBuffer); + sampleModel.setPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, + w, h, fArray, dataBuffer); } + /** + * Sets the sample values for the pixels in the region specified by + * (x, y, w, h) in the raster. The array is ordered by pixels (that is, all + * the samples for the first pixel are grouped together, followed by all the + * samples for the second pixel, and so on). + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param dArray the pixel sample values (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>dArray</code> is <code>null</code>. + */ public void setPixels(int x, int y, int w, int h, double[] dArray) { - sampleModel.setPixels(x-sampleModelTranslateX, - y-sampleModelTranslateY, - w, h, dArray, dataBuffer); + sampleModel.setPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, + w, h, dArray, dataBuffer); } + /** + * Sets the sample value for a band for the pixel at (x, y) in the raster. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param s the sample value. + */ public void setSample(int x, int y, int b, int s) { - sampleModel.setSample(x-sampleModelTranslateX, - y-sampleModelTranslateY, - b, s, dataBuffer); + sampleModel.setSample(x - sampleModelTranslateX, y - sampleModelTranslateY, + b, s, dataBuffer); } + /** + * Sets the sample value for a band for the pixel at (x, y) in the raster. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param s the sample value. + */ public void setSample(int x, int y, int b, float s) { - sampleModel.setSample(x-sampleModelTranslateX, - y-sampleModelTranslateY, - b, s, dataBuffer); + sampleModel.setSample(x - sampleModelTranslateX, y - sampleModelTranslateY, + b, s, dataBuffer); } + /** + * Sets the sample value for a band for the pixel at (x, y) in the raster. + * + * @param x the x-coordinate of the pixel. + * @param y the y-coordinate of the pixel. + * @param b the band (in the range <code>0</code> to + * <code>getNumBands() - 1</code>). + * @param s the sample value. + */ public void setSample(int x, int y, int b, double s) { - sampleModel.setSample(x-sampleModelTranslateX, - y-sampleModelTranslateY, - b, s, dataBuffer); + sampleModel.setSample(x - sampleModelTranslateX, y - sampleModelTranslateY, + b, s, dataBuffer); } + /** + * Sets the sample values for one band for the pixels in the region + * specified by (x, y, w, h) in the raster. + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param iArray the sample values (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>iArray</code> is <code>null</code>. + */ public void setSamples(int x, int y, int w, int h, int b, - int[] iArray) + int[] iArray) { - sampleModel.setSamples(x-sampleModelTranslateX, - y-sampleModelTranslateY, - w, h, b, iArray, dataBuffer); + sampleModel.setSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, + w, h, b, iArray, dataBuffer); } + /** + * Sets the sample values for one band for the pixels in the region + * specified by (x, y, w, h) in the raster. + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param fArray the sample values (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>fArray</code> is <code>null</code>. + */ public void setSamples(int x, int y, int w, int h, int b, - float[] fArray) + float[] fArray) { - sampleModel.setSamples(x-sampleModelTranslateX, - y-sampleModelTranslateY, - w, h, b, fArray, dataBuffer); + sampleModel.setSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, + w, h, b, fArray, dataBuffer); } + /** + * Sets the sample values for one band for the pixels in the region + * specified by (x, y, w, h) in the raster. + * + * @param x the x-coordinate of the top-left pixel. + * @param y the y-coordinate of the top-left pixel. + * @param w the width of the region of pixels. + * @param h the height of the region of pixels. + * @param b the band (in the range <code>0</code> to + * </code>getNumBands() - 1</code>). + * @param dArray the sample values (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>dArray</code> is <code>null</code>. + */ public void setSamples(int x, int y, int w, int h, int b, - double[] dArray) + double[] dArray) { - sampleModel.setSamples(x-sampleModelTranslateX, - y-sampleModelTranslateY, - w, h, b, dArray, dataBuffer); + sampleModel.setSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, + w, h, b, dArray, dataBuffer); } } diff --git a/libjava/classpath/java/awt/peer/ComponentPeer.java b/libjava/classpath/java/awt/peer/ComponentPeer.java index 97b96f49cdb..bc6e3a457f3 100644 --- a/libjava/classpath/java/awt/peer/ComponentPeer.java +++ b/libjava/classpath/java/awt/peer/ComponentPeer.java @@ -153,6 +153,12 @@ public interface ComponentPeer * {@link Component#getMinimumSize()}. * * @return the minimum size for the component + * + * @specnote Presumably this method got added to replace minimumSize(). + * However, testing shows that this is never called in the RI + * (tested with JDK5), but instead minimumSize() is called + * directly. It is advisable to implement this method to delegate + * to minimumSize() and put the real implementation in there. */ Dimension getMinimumSize(); @@ -161,6 +167,12 @@ public interface ComponentPeer * {@link Component#getPreferredSize()}. * * @return the preferred size for the component + * + * @specnote Presumably this method got added to replace preferredSize(). + * However, testing shows that this is never called in the RI + * (tested with JDK5), but instead preferredSize() is called + * directly. It is advisable to implement this method to delegate + * to preferredSize() and put the real implementation in there. */ Dimension getPreferredSize(); @@ -262,12 +274,21 @@ public interface ComponentPeer * Requests that this component receives the focus. This is called from * {@link Component#requestFocus()}. * - * @param source TODO - * @param bool1 TODO - * @param bool2 TODO - * @param x TODO - */ - boolean requestFocus(Component source, boolean bool1, boolean bool2, long x); + * This method is only called for heavyweight component's peers. Lightweight + * components ask their nearest heavyweight component to request focus. + * It's up to the heavyweight peer to decide if any of it's lightweight + * descendants are allowed to receive keyboard input focus or not. If the + * focus request is finally approved, then the peer must post a FOCUS_GAINED + * event for the requested component. + * + * @param request the component for which the focus is requested + * @param temporary indicates if the focus change is temporary (true) or + * permanent (false) + * @param allowWindowFocus indicates if it's allowed to change window focus + * @param time the timestamp + */ + boolean requestFocus(Component request, boolean temporary, + boolean allowWindowFocus, long time); /** * Notifies the peer that the bounds of this component have changed. This diff --git a/libjava/classpath/java/awt/peer/MouseInfoPeer.java b/libjava/classpath/java/awt/peer/MouseInfoPeer.java new file mode 100644 index 00000000000..e9923a653aa --- /dev/null +++ b/libjava/classpath/java/awt/peer/MouseInfoPeer.java @@ -0,0 +1,61 @@ +/* MouseInfoPeer.java -- peer interface for MouseInfo + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.peer; + +import java.awt.Point; +import java.awt.Window; + +/** + * MouseInfoPeer is the peer interface java.awt.MouseInfo. + * + * @author Sven de Marothy + * @since 1.5 + */ +public interface MouseInfoPeer +{ + /** + * Get the mouse pointer coordinates and store them in p (obviously non-null) + * returns the index of the current screen device of the mouse. + */ + public int fillPointWithCoords(Point p); + + /** + * Returns whether a given Window is under the mouse. + */ + public boolean isWindowUnderMouse(Window w); +} diff --git a/libjava/classpath/java/awt/peer/WindowPeer.java b/libjava/classpath/java/awt/peer/WindowPeer.java index 6c014de0b99..00d1035791a 100644 --- a/libjava/classpath/java/awt/peer/WindowPeer.java +++ b/libjava/classpath/java/awt/peer/WindowPeer.java @@ -1,5 +1,5 @@ /* WindowPeer.java -- Interface for window peers - Copyright (C) 1999 Free Software Foundation, Inc. + Copyright (C) 1999, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -44,7 +44,8 @@ public interface WindowPeer extends ContainerPeer void toFront(); /** - * FIXME: unknown. + * Update the always-on-top status of the Window. + * * @since 1.5 */ void updateAlwaysOnTop(); |