Merged gcj-eclipse branch to trunk.
From-SVN: r120621
This commit is contained in:
parent
c648dedbde
commit
97b8365caf
17478 changed files with 606493 additions and 100744 deletions
|
@ -96,6 +96,11 @@ public abstract class AWTEvent extends EventObject
|
|||
*/
|
||||
protected boolean consumed;
|
||||
|
||||
/**
|
||||
* Used for implementing a simple linked list in EventQueue.
|
||||
*/
|
||||
transient AWTEvent queueNext;
|
||||
|
||||
/**
|
||||
* Who knows? It's in the serial version.
|
||||
*
|
||||
|
|
|
@ -1175,16 +1175,17 @@ public class AWTEventMulticaster
|
|||
* @throws IllegalArgumentException if type is Void.TYPE
|
||||
* @since 1.4
|
||||
*/
|
||||
public static EventListener[] getListeners(EventListener l, Class type)
|
||||
public static <T extends EventListener> T[] getListeners(EventListener l,
|
||||
Class<T> type)
|
||||
{
|
||||
ArrayList list = new ArrayList();
|
||||
ArrayList<EventListener> list = new ArrayList<EventListener>();
|
||||
if (l instanceof AWTEventMulticaster)
|
||||
((AWTEventMulticaster) l).getListeners(list, type);
|
||||
else if (type.isInstance(l))
|
||||
list.add(l);
|
||||
EventListener[] r = (EventListener[]) Array.newInstance(type, list.size());
|
||||
list.toArray(r);
|
||||
return r;
|
||||
return (T[]) r;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* AWTKeyStroke.java -- an immutable key stroke
|
||||
Copyright (C) 2002, 2004, 2005 Free Software Foundation
|
||||
Copyright (C) 2002, 2004, 2005 Free Software Foundation
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -65,6 +65,7 @@ import java.util.StringTokenizer;
|
|||
* no-arg constructor (of any accessibility).
|
||||
*
|
||||
* @author Eric Blake (ebb9@email.byu.edu)
|
||||
* @author Andrew John Hughes (gnu_andrew@member.fsf.org)
|
||||
* @see #getAWTKeyStroke(char)
|
||||
* @since 1.4
|
||||
* @status updated to 1.4
|
||||
|
@ -85,13 +86,15 @@ public class AWTKeyStroke implements Serializable
|
|||
* under the assumption that garbage collection of a new keystroke is
|
||||
* easy when we find the old one that it matches in the cache.
|
||||
*/
|
||||
private static final LinkedHashMap cache = new LinkedHashMap(11, 0.75f, true)
|
||||
private static final LinkedHashMap<AWTKeyStroke,AWTKeyStroke> cache =
|
||||
new LinkedHashMap<AWTKeyStroke,AWTKeyStroke>(11, 0.75f, true)
|
||||
{
|
||||
/** The largest the keystroke cache can grow. */
|
||||
private static final int MAX_CACHE_SIZE = 2048;
|
||||
|
||||
/** Prune stale entries. */
|
||||
protected boolean removeEldestEntry(Map.Entry eldest)
|
||||
protected boolean removeEldestEntry(Map.Entry<AWTKeyStroke,AWTKeyStroke>
|
||||
eldest)
|
||||
{ // XXX - FIXME Use Map.Entry, not just Entry as gcj 3.1 workaround.
|
||||
return size() > MAX_CACHE_SIZE;
|
||||
}
|
||||
|
@ -114,7 +117,7 @@ public class AWTKeyStroke implements Serializable
|
|||
*
|
||||
* @see #getAWTKeyStroke(String)
|
||||
*/
|
||||
static final HashMap vktable = new HashMap();
|
||||
static final HashMap<String,Object> vktable = new HashMap<String,Object>();
|
||||
static
|
||||
{
|
||||
// Using reflection saves the hassle of keeping this in sync with KeyEvent,
|
||||
|
@ -229,7 +232,7 @@ public class AWTKeyStroke implements Serializable
|
|||
* @throws IllegalArgumentException subclass doesn't have no-arg constructor
|
||||
* @throws ClassCastException subclass doesn't extend AWTKeyStroke
|
||||
*/
|
||||
protected static void registerSubclass(final Class subclass)
|
||||
protected static void registerSubclass(final Class<?> subclass)
|
||||
{
|
||||
if (subclass == null)
|
||||
throw new IllegalArgumentException();
|
||||
|
@ -252,7 +255,8 @@ public class AWTKeyStroke implements Serializable
|
|||
throws NoSuchMethodException, InstantiationException,
|
||||
IllegalAccessException, InvocationTargetException
|
||||
{
|
||||
Constructor c = subclass.getDeclaredConstructor(null);
|
||||
Constructor<?> c =
|
||||
subclass.getDeclaredConstructor((Class<?>[])null);
|
||||
c.setAccessible(true);
|
||||
// Create a new instance, to make sure that we can, and
|
||||
// to cause any ClassCastException.
|
||||
|
@ -595,7 +599,7 @@ public class AWTKeyStroke implements Serializable
|
|||
*/
|
||||
protected Object readResolve() throws ObjectStreamException
|
||||
{
|
||||
AWTKeyStroke s = (AWTKeyStroke) cache.get(this);
|
||||
AWTKeyStroke s = cache.get(this);
|
||||
if (s != null)
|
||||
return s;
|
||||
cache.put(this, this);
|
||||
|
|
|
@ -43,6 +43,7 @@ import gnu.java.awt.java2d.LineSegment;
|
|||
import gnu.java.awt.java2d.QuadSegment;
|
||||
import gnu.java.awt.java2d.Segment;
|
||||
|
||||
import java.awt.geom.FlatteningPathIterator;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.geom.PathIterator;
|
||||
import java.awt.geom.Point2D;
|
||||
|
@ -486,8 +487,157 @@ public class BasicStroke implements Stroke
|
|||
|
||||
private Shape dashedStroke(PathIterator pi)
|
||||
{
|
||||
GeneralPath out = new GeneralPath();
|
||||
return out;
|
||||
// The choice of (flatnessSq == width / 3) is made to be consistent with
|
||||
// the flattening in CubicSegment.getDisplacedSegments
|
||||
FlatteningPathIterator flat = new FlatteningPathIterator(pi,
|
||||
Math.sqrt(width / 3));
|
||||
|
||||
// Holds the endpoint of the current segment (or piece of a segment)
|
||||
double[] coords = new double[2];
|
||||
|
||||
// Holds end of the last segment
|
||||
double x, y, x0, y0;
|
||||
x = x0 = y = y0 = 0;
|
||||
|
||||
// Various useful flags
|
||||
boolean pathOpen = false;
|
||||
boolean dashOn = true;
|
||||
boolean offsetting = (phase != 0);
|
||||
|
||||
// How far we are into the current dash
|
||||
double distance = 0;
|
||||
int dashIndex = 0;
|
||||
|
||||
// And variables to hold the final output
|
||||
GeneralPath output = new GeneralPath();
|
||||
Segment[] p;
|
||||
|
||||
// Iterate over the FlatteningPathIterator
|
||||
while (! flat.isDone())
|
||||
{
|
||||
switch (flat.currentSegment(coords))
|
||||
{
|
||||
case PathIterator.SEG_MOVETO:
|
||||
x0 = x = coords[0];
|
||||
y0 = y = coords[1];
|
||||
|
||||
if (pathOpen)
|
||||
{
|
||||
capEnds();
|
||||
convertPath(output, start);
|
||||
start = end = null;
|
||||
pathOpen = false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PathIterator.SEG_LINETO:
|
||||
boolean segmentConsumed = false;
|
||||
|
||||
while (! segmentConsumed)
|
||||
{
|
||||
// Find the total remaining length of this segment
|
||||
double segLength = Math.sqrt((x - coords[0]) * (x - coords[0])
|
||||
+ (y - coords[1])
|
||||
* (y - coords[1]));
|
||||
boolean spanBoundary = true;
|
||||
double[] segmentEnd = null;
|
||||
|
||||
// The current segment fits entirely inside the current dash
|
||||
if ((offsetting && distance + segLength <= phase)
|
||||
|| distance + segLength <= dash[dashIndex])
|
||||
{
|
||||
spanBoundary = false;
|
||||
}
|
||||
|
||||
// Otherwise, we need to split the segment in two, as this
|
||||
// segment spans a dash boundry
|
||||
else
|
||||
{
|
||||
segmentEnd = (double[]) coords.clone();
|
||||
|
||||
// Calculate the remaining distance in this dash,
|
||||
// and coordinates of the dash boundary
|
||||
double reqLength;
|
||||
if (offsetting)
|
||||
reqLength = phase - distance;
|
||||
else
|
||||
reqLength = dash[dashIndex] - distance;
|
||||
|
||||
coords[0] = x + ((coords[0] - x) * reqLength / segLength);
|
||||
coords[1] = y + ((coords[1] - y) * reqLength / segLength);
|
||||
}
|
||||
|
||||
if (offsetting || ! dashOn)
|
||||
{
|
||||
// Dash is off, or we are in offset - treat this as a
|
||||
// moveTo
|
||||
x0 = x = coords[0];
|
||||
y0 = y = coords[1];
|
||||
|
||||
if (pathOpen)
|
||||
{
|
||||
capEnds();
|
||||
convertPath(output, start);
|
||||
start = end = null;
|
||||
pathOpen = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Dash is on - treat this as a lineTo
|
||||
p = (new LineSegment(x, y, coords[0], coords[1])).getDisplacedSegments(width / 2.0);
|
||||
|
||||
if (! pathOpen)
|
||||
{
|
||||
start = p[0];
|
||||
end = p[1];
|
||||
pathOpen = true;
|
||||
}
|
||||
else
|
||||
addSegments(p);
|
||||
|
||||
x = coords[0];
|
||||
y = coords[1];
|
||||
}
|
||||
|
||||
// Update variables depending on whether we spanned a
|
||||
// dash boundary or not
|
||||
if (! spanBoundary)
|
||||
{
|
||||
distance += segLength;
|
||||
segmentConsumed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (offsetting)
|
||||
offsetting = false;
|
||||
dashOn = ! dashOn;
|
||||
distance = 0;
|
||||
coords = segmentEnd;
|
||||
|
||||
if (dashIndex + 1 == dash.length)
|
||||
dashIndex = 0;
|
||||
else
|
||||
dashIndex++;
|
||||
|
||||
// Since the value of segmentConsumed is still false,
|
||||
// the next run of the while loop will complete the segment
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// This is a flattened path, so we don't need to deal with curves
|
||||
}
|
||||
flat.next();
|
||||
}
|
||||
|
||||
if (pathOpen)
|
||||
{
|
||||
capEnds();
|
||||
convertPath(output, start);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -611,9 +761,13 @@ public class BasicStroke implements Stroke
|
|||
p1 = new double[]{a.last.P2.getX(), a.last.P2.getY()};
|
||||
dx = p1[0] - p0[0];
|
||||
dy = p1[1] - p0[1];
|
||||
l = Math.sqrt(dx * dx + dy * dy);
|
||||
dx = (2.0/3.0)*width*dx/l;
|
||||
dy = (2.0/3.0)*width*dy/l;
|
||||
if (dx != 0 && dy != 0)
|
||||
{
|
||||
l = Math.sqrt(dx * dx + dy * dy);
|
||||
dx = (2.0/3.0)*width*dx/l;
|
||||
dy = (2.0/3.0)*width*dy/l;
|
||||
}
|
||||
|
||||
c1 = new Point2D.Double(p1[0] + dx, p1[1] + dy);
|
||||
c2 = new Point2D.Double(b.P1.getX() + dx, b.P1.getY() + dy);
|
||||
a.add(new CubicSegment(a.last.P2, c1, c2, b.P1));
|
||||
|
|
|
@ -352,11 +352,11 @@ removeActionListener(ActionListener listener)
|
|||
*
|
||||
* @since 1.3
|
||||
*/
|
||||
public EventListener[] getListeners(Class listenerType)
|
||||
public <T extends EventListener> T[] getListeners(Class<T> listenerType)
|
||||
{
|
||||
if (listenerType == ActionListener.class)
|
||||
return getActionListeners();
|
||||
return (EventListener[]) Array.newInstance(listenerType, 0);
|
||||
return (T[]) getActionListeners();
|
||||
return (T[]) Array.newInstance(listenerType, 0);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
|
|
@ -225,6 +225,8 @@ public class CardLayout implements LayoutManager2, Serializable
|
|||
*/
|
||||
public Dimension maximumLayoutSize (Container target)
|
||||
{
|
||||
if (target == null)
|
||||
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
// The JCL says that this returns Integer.MAX_VALUE for both
|
||||
// dimensions. But that just seems wrong to me.
|
||||
return getSize (target, MAX);
|
||||
|
@ -361,7 +363,7 @@ public class CardLayout implements LayoutManager2, Serializable
|
|||
*/
|
||||
public String toString ()
|
||||
{
|
||||
return getClass ().getName () + "[" + hgap + "," + vgap + "]";
|
||||
return getClass ().getName () + "[hgap=" + hgap + ",vgap=" + vgap + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -401,11 +403,11 @@ public class CardLayout implements LayoutManager2, Serializable
|
|||
{
|
||||
if (comps[i].isVisible ())
|
||||
{
|
||||
if (what == NEXT)
|
||||
if (choice == i)
|
||||
{
|
||||
choice = i + 1;
|
||||
if (choice == num)
|
||||
choice = 0;
|
||||
// Do nothing if we're already looking at the right
|
||||
// component.
|
||||
return;
|
||||
}
|
||||
else if (what == PREV)
|
||||
{
|
||||
|
@ -413,17 +415,20 @@ public class CardLayout implements LayoutManager2, Serializable
|
|||
if (choice < 0)
|
||||
choice = num - 1;
|
||||
}
|
||||
else if (choice == i)
|
||||
else if (what == NEXT)
|
||||
{
|
||||
// Do nothing if we're already looking at the right
|
||||
// component.
|
||||
return;
|
||||
choice = i + 1;
|
||||
if (choice == num)
|
||||
choice = 0;
|
||||
}
|
||||
comps[i].setVisible (false);
|
||||
|
||||
if (choice >= 0)
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
comps[i].setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (choice >= 0 && choice < num)
|
||||
|
|
|
@ -318,11 +318,11 @@ paramString()
|
|||
* @exception ClassCastException If listenerType doesn't specify a class or
|
||||
* interface that implements java.util.EventListener.
|
||||
*/
|
||||
public EventListener[] getListeners (Class listenerType)
|
||||
public <T extends EventListener> T[] getListeners (Class<T> listenerType)
|
||||
{
|
||||
if (listenerType == ItemListener.class)
|
||||
return AWTEventMulticaster.getListeners (item_listeners, listenerType);
|
||||
|
||||
|
||||
return super.getListeners (listenerType);
|
||||
}
|
||||
|
||||
|
|
|
@ -255,8 +255,8 @@ public class Choice extends Component
|
|||
/**
|
||||
* Adds the specified item to this choice box.
|
||||
*
|
||||
* This method is oboslete since Java 2 platform 1.1. Please use @see add
|
||||
* instead.
|
||||
* This method is oboslete since Java 2 platform 1.1. Please use
|
||||
* {@link #add(String)} instead.
|
||||
*
|
||||
* @param item The item to add.
|
||||
*
|
||||
|
@ -320,9 +320,6 @@ public class Choice extends Component
|
|||
*/
|
||||
public synchronized void remove(int index)
|
||||
{
|
||||
if ((index < 0) || (index > getItemCount()))
|
||||
throw new IllegalArgumentException("Bad index: " + index);
|
||||
|
||||
pItems.removeElementAt(index);
|
||||
|
||||
if (peer != null)
|
||||
|
@ -332,14 +329,14 @@ public class Choice extends Component
|
|||
selectedIndex = -1;
|
||||
else
|
||||
{
|
||||
if( selectedIndex > index )
|
||||
selectedIndex--;
|
||||
else if( selectedIndex == index )
|
||||
selectedIndex = 0;
|
||||
if( selectedIndex > index )
|
||||
selectedIndex--;
|
||||
else if( selectedIndex == index )
|
||||
selectedIndex = 0;
|
||||
|
||||
if( peer != null )
|
||||
((ChoicePeer)peer).select( selectedIndex );
|
||||
}
|
||||
if( peer != null )
|
||||
((ChoicePeer)peer).select( selectedIndex );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -523,11 +520,11 @@ public class Choice extends Component
|
|||
*
|
||||
* @since 1.3
|
||||
*/
|
||||
public EventListener[] getListeners (Class listenerType)
|
||||
public <T extends EventListener> T[] getListeners (Class<T> listenerType)
|
||||
{
|
||||
if (listenerType == ItemListener.class)
|
||||
return AWTEventMulticaster.getListeners (item_listeners, listenerType);
|
||||
|
||||
|
||||
return super.getListeners (listenerType);
|
||||
}
|
||||
|
||||
|
|
|
@ -534,14 +534,31 @@ public class Color implements Paint, Serializable
|
|||
{
|
||||
// Do not inline getRGB() to this.value, because of SystemColor.
|
||||
int value = getRGB();
|
||||
int red = (value & RED_MASK) >> 16;
|
||||
int green = (value & GREEN_MASK) >> 8;
|
||||
int blue = value & BLUE_MASK;
|
||||
// We have to special case 0-2 because they won't scale by division.
|
||||
red = red < 3 ? 3 : (int) Math.min(255, red / BRIGHT_SCALE);
|
||||
green = green < 3 ? 3 : (int) Math.min(255, green / BRIGHT_SCALE);
|
||||
blue = blue < 3 ? 3 : (int) Math.min(255, blue / BRIGHT_SCALE);
|
||||
return new Color(red, green, blue, 255);
|
||||
int[] hues = new int[3];
|
||||
hues[0] = (value & RED_MASK) >> 16;
|
||||
hues[1] = (value & GREEN_MASK) >> 8;
|
||||
hues[2] = value & BLUE_MASK;
|
||||
|
||||
// (0,0,0) is a special case.
|
||||
if (hues[0] == 0 && hues[1] == 0 && hues[2] ==0)
|
||||
{
|
||||
hues[0] = 3;
|
||||
hues[1] = 3;
|
||||
hues[2] = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int index = 0; index < 3; index++)
|
||||
{
|
||||
|
||||
if (hues[index] > 2)
|
||||
hues[index] = (int) Math.min(255, hues[index]/0.7f);
|
||||
if (hues[index] == 1 || hues[index] == 2)
|
||||
hues[index] = 4;
|
||||
}
|
||||
}
|
||||
|
||||
return new Color(hues[0], hues[1], hues[2], 255);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -39,11 +39,11 @@ exception statement from your version. */
|
|||
|
||||
package java.awt;
|
||||
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.awt.event.ContainerEvent;
|
||||
import java.awt.event.ContainerListener;
|
||||
import java.awt.event.HierarchyEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.peer.ComponentPeer;
|
||||
import java.awt.peer.ContainerPeer;
|
||||
import java.awt.peer.LightweightPeer;
|
||||
|
@ -69,10 +69,11 @@ import javax.accessibility.Accessible;
|
|||
*
|
||||
* @author original author unknown
|
||||
* @author Eric Blake (ebb9@email.byu.edu)
|
||||
* @author Andrew John Hughes (gnu_andrew@member.fsf.org)
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @status still missing 1.4 support
|
||||
* @status still missing 1.4 support, some generics from 1.5
|
||||
*/
|
||||
public class Container extends Component
|
||||
{
|
||||
|
@ -86,8 +87,6 @@ public class Container extends Component
|
|||
Component[] component;
|
||||
LayoutManager layoutMgr;
|
||||
|
||||
Dimension maxSize;
|
||||
|
||||
/**
|
||||
* @since 1.4
|
||||
*/
|
||||
|
@ -208,10 +207,12 @@ public class Container extends Component
|
|||
*/
|
||||
public Insets insets()
|
||||
{
|
||||
if (peer == null)
|
||||
return new Insets (0, 0, 0, 0);
|
||||
|
||||
return ((ContainerPeer) peer).getInsets ();
|
||||
Insets i;
|
||||
if (peer == null || peer instanceof LightweightPeer)
|
||||
i = new Insets (0, 0, 0, 0);
|
||||
else
|
||||
i = ((ContainerPeer) peer).getInsets ();
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -324,23 +325,6 @@ public class Container extends Component
|
|||
// we are.
|
||||
if (comp.parent != null)
|
||||
comp.parent.remove(comp);
|
||||
comp.parent = this;
|
||||
|
||||
if (peer != null)
|
||||
{
|
||||
// Notify the component that it has a new parent.
|
||||
comp.addNotify();
|
||||
|
||||
if (comp.isLightweight ())
|
||||
{
|
||||
enableEvents (comp.eventMask);
|
||||
if (!isLightweight ())
|
||||
enableEvents (AWTEvent.PAINT_EVENT_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
// Invalidate the layout of the added component and its ancestors.
|
||||
comp.invalidate();
|
||||
|
||||
if (component == null)
|
||||
component = new Component[4]; // FIXME, better initial size?
|
||||
|
@ -365,6 +349,9 @@ public class Container extends Component
|
|||
++ncomponents;
|
||||
}
|
||||
|
||||
// Give the new component a parent.
|
||||
comp.parent = this;
|
||||
|
||||
// Update the counter for Hierarchy(Bounds)Listeners.
|
||||
int childHierarchyListeners = comp.numHierarchyListeners;
|
||||
if (childHierarchyListeners > 0)
|
||||
|
@ -375,6 +362,18 @@ public class Container extends Component
|
|||
updateHierarchyListenerCount(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
|
||||
childHierarchyListeners);
|
||||
|
||||
// Invalidate the layout of this container.
|
||||
if (valid)
|
||||
invalidate();
|
||||
|
||||
// Create the peer _after_ the component has been added, so that
|
||||
// the peer gets to know about the component hierarchy.
|
||||
if (peer != null)
|
||||
{
|
||||
// Notify the component that it has a new parent.
|
||||
comp.addNotify();
|
||||
}
|
||||
|
||||
// Notify the layout manager.
|
||||
if (layoutMgr != null)
|
||||
{
|
||||
|
@ -394,13 +393,15 @@ public class Container extends Component
|
|||
// We previously only sent an event when this container is showing.
|
||||
// Also, the event was posted to the event queue. A Mauve test shows
|
||||
// that this event is not delivered using the event queue and it is
|
||||
// also sent when the container is not showing.
|
||||
ContainerEvent ce = new ContainerEvent(this,
|
||||
ContainerEvent.COMPONENT_ADDED,
|
||||
comp);
|
||||
ContainerListener[] listeners = getContainerListeners();
|
||||
for (int i = 0; i < listeners.length; i++)
|
||||
listeners[i].componentAdded(ce);
|
||||
// also sent when the container is not showing.
|
||||
if (containerListener != null
|
||||
|| (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0)
|
||||
{
|
||||
ContainerEvent ce = new ContainerEvent(this,
|
||||
ContainerEvent.COMPONENT_ADDED,
|
||||
comp);
|
||||
dispatchEvent(ce);
|
||||
}
|
||||
|
||||
// Notify hierarchy listeners.
|
||||
comp.fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, comp,
|
||||
|
@ -417,17 +418,15 @@ public class Container extends Component
|
|||
{
|
||||
synchronized (getTreeLock ())
|
||||
{
|
||||
if (index < 0 || index >= ncomponents)
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
|
||||
Component r = component[index];
|
||||
if (peer != null)
|
||||
r.removeNotify();
|
||||
|
||||
ComponentListener[] list = r.getComponentListeners();
|
||||
for (int j = 0; j < list.length; j++)
|
||||
r.removeComponentListener(list[j]);
|
||||
|
||||
r.removeNotify();
|
||||
|
||||
System.arraycopy(component, index + 1, component, index,
|
||||
ncomponents - index - 1);
|
||||
component[--ncomponents] = null;
|
||||
if (layoutMgr != null)
|
||||
layoutMgr.removeLayoutComponent(r);
|
||||
|
||||
// Update the counter for Hierarchy(Bounds)Listeners.
|
||||
int childHierarchyListeners = r.numHierarchyListeners;
|
||||
|
@ -439,20 +438,23 @@ public class Container extends Component
|
|||
updateHierarchyListenerCount(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
|
||||
-childHierarchyListeners);
|
||||
|
||||
invalidate();
|
||||
|
||||
if (layoutMgr != null)
|
||||
layoutMgr.removeLayoutComponent(r);
|
||||
|
||||
r.parent = null;
|
||||
|
||||
if (isShowing ())
|
||||
System.arraycopy(component, index + 1, component, index,
|
||||
ncomponents - index - 1);
|
||||
component[--ncomponents] = null;
|
||||
|
||||
if (valid)
|
||||
invalidate();
|
||||
|
||||
if (containerListener != null
|
||||
|| (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0)
|
||||
{
|
||||
// Post event to notify of removing the component.
|
||||
ContainerEvent ce = new ContainerEvent(this,
|
||||
ContainerEvent.COMPONENT_REMOVED,
|
||||
r);
|
||||
getToolkit().getSystemEventQueue().postEvent(ce);
|
||||
ContainerEvent.COMPONENT_REMOVED,
|
||||
r);
|
||||
dispatchEvent(ce);
|
||||
}
|
||||
|
||||
// Notify hierarchy listeners.
|
||||
|
@ -496,36 +498,51 @@ public class Container extends Component
|
|||
// super.removeAll() ).
|
||||
// By doing it this way, user code cannot prevent the correct
|
||||
// removal of components.
|
||||
for ( int index = 0; index < ncomponents; index++)
|
||||
while (ncomponents > 0)
|
||||
{
|
||||
Component r = component[index];
|
||||
ncomponents--;
|
||||
Component r = component[ncomponents];
|
||||
component[ncomponents] = null;
|
||||
|
||||
ComponentListener[] list = r.getComponentListeners();
|
||||
for (int j = 0; j < list.length; j++)
|
||||
r.removeComponentListener(list[j]);
|
||||
|
||||
r.removeNotify();
|
||||
if (peer != null)
|
||||
r.removeNotify();
|
||||
|
||||
if (layoutMgr != null)
|
||||
layoutMgr.removeLayoutComponent(r);
|
||||
|
||||
r.parent = null;
|
||||
|
||||
if (isShowing ())
|
||||
// Send ContainerEvent if necessary.
|
||||
if (containerListener != null
|
||||
|| (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0)
|
||||
{
|
||||
// Post event to notify of removing the component.
|
||||
ContainerEvent ce
|
||||
= new ContainerEvent(this,
|
||||
ContainerEvent.COMPONENT_REMOVED,
|
||||
r);
|
||||
|
||||
getToolkit().getSystemEventQueue().postEvent(ce);
|
||||
dispatchEvent(ce);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Update the counter for Hierarchy(Bounds)Listeners.
|
||||
int childHierarchyListeners = r.numHierarchyListeners;
|
||||
if (childHierarchyListeners > 0)
|
||||
updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK,
|
||||
-childHierarchyListeners);
|
||||
int childHierarchyBoundsListeners = r.numHierarchyBoundsListeners;
|
||||
if (childHierarchyBoundsListeners > 0)
|
||||
updateHierarchyListenerCount(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
|
||||
-childHierarchyListeners);
|
||||
|
||||
|
||||
// Send HierarchyEvent if necessary.
|
||||
fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, r, this,
|
||||
HierarchyEvent.PARENT_CHANGED);
|
||||
|
||||
}
|
||||
|
||||
if (valid)
|
||||
invalidate();
|
||||
|
||||
ncomponents = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -590,11 +607,20 @@ public class Container extends Component
|
|||
*/
|
||||
public void validate()
|
||||
{
|
||||
synchronized (getTreeLock ())
|
||||
ComponentPeer p = peer;
|
||||
if (! valid && p != null)
|
||||
{
|
||||
if (! isValid() && peer != null)
|
||||
ContainerPeer cPeer = null;
|
||||
if (p instanceof ContainerPeer)
|
||||
cPeer = (ContainerPeer) peer;
|
||||
synchronized (getTreeLock ())
|
||||
{
|
||||
if (cPeer != null)
|
||||
cPeer.beginValidate();
|
||||
validateTree();
|
||||
valid = true;
|
||||
if (cPeer != null)
|
||||
cPeer.endValidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -602,24 +628,20 @@ public class Container extends Component
|
|||
/**
|
||||
* Recursively invalidates the container tree.
|
||||
*/
|
||||
void invalidateTree()
|
||||
private final void invalidateTree()
|
||||
{
|
||||
synchronized (getTreeLock())
|
||||
{
|
||||
super.invalidate(); // Clean cached layout state.
|
||||
for (int i = 0; i < ncomponents; i++)
|
||||
{
|
||||
Component comp = component[i];
|
||||
comp.invalidate();
|
||||
if (comp instanceof Container)
|
||||
((Container) comp).invalidateTree();
|
||||
else if (comp.valid)
|
||||
comp.invalidate();
|
||||
}
|
||||
|
||||
if (layoutMgr != null && layoutMgr instanceof LayoutManager2)
|
||||
{
|
||||
LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
|
||||
lm2.invalidateLayout(this);
|
||||
}
|
||||
if (valid)
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -629,40 +651,36 @@ public class Container extends Component
|
|||
*/
|
||||
protected void validateTree()
|
||||
{
|
||||
if (valid)
|
||||
return;
|
||||
|
||||
ContainerPeer cPeer = null;
|
||||
if (peer != null && ! (peer instanceof LightweightPeer))
|
||||
if (!valid)
|
||||
{
|
||||
cPeer = (ContainerPeer) peer;
|
||||
cPeer.beginValidate();
|
||||
}
|
||||
|
||||
for (int i = 0; i < ncomponents; ++i)
|
||||
{
|
||||
Component comp = component[i];
|
||||
|
||||
if (comp.getPeer () == null)
|
||||
comp.addNotify();
|
||||
}
|
||||
|
||||
doLayout ();
|
||||
for (int i = 0; i < ncomponents; ++i)
|
||||
{
|
||||
Component comp = component[i];
|
||||
|
||||
if (! comp.isValid())
|
||||
ContainerPeer cPeer = null;
|
||||
if (peer instanceof ContainerPeer)
|
||||
{
|
||||
if (comp instanceof Container)
|
||||
cPeer = (ContainerPeer) peer;
|
||||
cPeer.beginLayout();
|
||||
}
|
||||
|
||||
doLayout ();
|
||||
for (int i = 0; i < ncomponents; ++i)
|
||||
{
|
||||
Component comp = component[i];
|
||||
|
||||
if (comp instanceof Container && ! (comp instanceof Window)
|
||||
&& ! comp.valid)
|
||||
{
|
||||
((Container) comp).validateTree();
|
||||
}
|
||||
else
|
||||
{
|
||||
component[i].validate();
|
||||
comp.validate();
|
||||
}
|
||||
}
|
||||
|
||||
if (cPeer != null)
|
||||
{
|
||||
cPeer = (ContainerPeer) peer;
|
||||
cPeer.endLayout();
|
||||
}
|
||||
}
|
||||
|
||||
/* children will call invalidate() when they are layed out. It
|
||||
|
@ -670,19 +688,15 @@ public class Container extends Component
|
|||
until after the children have been layed out. */
|
||||
valid = true;
|
||||
|
||||
if (cPeer != null)
|
||||
cPeer.endValidate();
|
||||
}
|
||||
|
||||
public void setFont(Font f)
|
||||
{
|
||||
if( (f != null && (font == null || !font.equals(f)))
|
||||
|| f == null)
|
||||
Font oldFont = getFont();
|
||||
super.setFont(f);
|
||||
Font newFont = getFont();
|
||||
if (newFont != oldFont && (oldFont == null || ! oldFont.equals(newFont)))
|
||||
{
|
||||
super.setFont(f);
|
||||
// FIXME: Although it might make more sense to invalidate only
|
||||
// those children whose font == null, Sun invalidates all children.
|
||||
// So we'll do the same.
|
||||
invalidateTree();
|
||||
}
|
||||
}
|
||||
|
@ -784,8 +798,9 @@ public class Container extends Component
|
|||
LayoutManager l = layoutMgr;
|
||||
if (l instanceof LayoutManager2)
|
||||
maxSize = ((LayoutManager2) l).maximumLayoutSize(this);
|
||||
else
|
||||
else {
|
||||
maxSize = super.maximumSizeImpl();
|
||||
}
|
||||
size = maxSize;
|
||||
}
|
||||
}
|
||||
|
@ -920,8 +935,8 @@ public class Container extends Component
|
|||
*/
|
||||
public void paintComponents(Graphics g)
|
||||
{
|
||||
paint(g);
|
||||
visitChildren(g, GfxPaintAllVisitor.INSTANCE, true);
|
||||
if (isShowing())
|
||||
visitChildren(g, GfxPaintAllVisitor.INSTANCE, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -943,7 +958,12 @@ public class Container extends Component
|
|||
*/
|
||||
public synchronized void addContainerListener(ContainerListener listener)
|
||||
{
|
||||
containerListener = AWTEventMulticaster.add(containerListener, listener);
|
||||
if (listener != null)
|
||||
{
|
||||
containerListener = AWTEventMulticaster.add(containerListener,
|
||||
listener);
|
||||
newEventsOnly = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -985,10 +1005,10 @@ public class Container extends Component
|
|||
*
|
||||
* @since 1.3
|
||||
*/
|
||||
public EventListener[] getListeners(Class listenerType)
|
||||
public <T extends EventListener> T[] getListeners(Class<T> listenerType)
|
||||
{
|
||||
if (listenerType == ContainerListener.class)
|
||||
return getContainerListeners();
|
||||
return (T[]) getContainerListeners();
|
||||
return super.getListeners(listenerType);
|
||||
}
|
||||
|
||||
|
@ -1247,8 +1267,14 @@ public class Container extends Component
|
|||
{
|
||||
synchronized (getTreeLock ())
|
||||
{
|
||||
for (int i = 0; i < ncomponents; ++i)
|
||||
component[i].removeNotify();
|
||||
int ncomps = ncomponents;
|
||||
Component[] comps = component;
|
||||
for (int i = ncomps - 1; i >= 0; --i)
|
||||
{
|
||||
Component comp = comps[i];
|
||||
if (comp != null)
|
||||
comp.removeNotify();
|
||||
}
|
||||
super.removeNotify();
|
||||
}
|
||||
}
|
||||
|
@ -1345,7 +1371,8 @@ public class Container extends Component
|
|||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
public void setFocusTraversalKeys(int id, Set keystrokes)
|
||||
public void setFocusTraversalKeys(int id,
|
||||
Set<? extends AWTKeyStroke> keystrokes)
|
||||
{
|
||||
if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
|
||||
id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
|
||||
|
@ -1433,7 +1460,8 @@ public class Container extends Component
|
|||
if (focusTraversalKeys == null)
|
||||
focusTraversalKeys = new Set[4];
|
||||
|
||||
keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes));
|
||||
keystrokes =
|
||||
Collections.unmodifiableSet(new HashSet<AWTKeyStroke>(keystrokes));
|
||||
firePropertyChange (name, focusTraversalKeys[id], keystrokes);
|
||||
|
||||
focusTraversalKeys[id] = keystrokes;
|
||||
|
@ -1451,7 +1479,7 @@ public class Container extends Component
|
|||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
public Set getFocusTraversalKeys (int id)
|
||||
public Set<AWTKeyStroke> getFocusTraversalKeys (int id)
|
||||
{
|
||||
if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
|
||||
id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
|
||||
|
@ -1866,6 +1894,7 @@ public class Container extends Component
|
|||
bounds.height);
|
||||
try
|
||||
{
|
||||
g2.setFont(comp.getFont());
|
||||
visitor.visit(comp, g2);
|
||||
}
|
||||
finally
|
||||
|
@ -1874,20 +1903,40 @@ public class Container extends Component
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to dispatch events to lightweight descendents.
|
||||
*
|
||||
* @param e the event to dispatch.
|
||||
*/
|
||||
void dispatchEventImpl(AWTEvent e)
|
||||
{
|
||||
boolean dispatched =
|
||||
LightweightDispatcher.getInstance().dispatchEvent(e);
|
||||
if (! dispatched)
|
||||
LightweightDispatcher dispatcher = LightweightDispatcher.getInstance();
|
||||
if (! isLightweight() && dispatcher.dispatchEvent(e))
|
||||
{
|
||||
if ((e.id <= ContainerEvent.CONTAINER_LAST
|
||||
&& e.id >= ContainerEvent.CONTAINER_FIRST)
|
||||
&& (containerListener != null
|
||||
|| (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0))
|
||||
processEvent(e);
|
||||
else
|
||||
super.dispatchEventImpl(e);
|
||||
// Some lightweight descendent got this event dispatched. Consume
|
||||
// it and let the peer handle it.
|
||||
e.consume();
|
||||
ComponentPeer p = peer;
|
||||
if (p != null)
|
||||
p.handleEvent(e);
|
||||
}
|
||||
else
|
||||
{
|
||||
super.dispatchEventImpl(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called by the lightweight dispatcher to avoid recursivly
|
||||
* calling into the lightweight dispatcher.
|
||||
*
|
||||
* @param e the event to dispatch
|
||||
*
|
||||
* @see LightweightDispatcher#redispatch(MouseEvent, Component, int)
|
||||
*/
|
||||
void dispatchNoLightweight(AWTEvent e)
|
||||
{
|
||||
super.dispatchEventImpl(e);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2004,6 +2053,43 @@ public class Container extends Component
|
|||
parent.updateHierarchyListenerCount(type, delta);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies interested listeners about resizing or moving the container.
|
||||
* This performs the super behaviour (sending component events) and
|
||||
* additionally notifies any hierarchy bounds listeners on child components.
|
||||
*
|
||||
* @param resized true if the component has been resized, false otherwise
|
||||
* @param moved true if the component has been moved, false otherwise
|
||||
*/
|
||||
void notifyReshape(boolean resized, boolean moved)
|
||||
{
|
||||
// Notify component listeners.
|
||||
super.notifyReshape(resized, moved);
|
||||
|
||||
if (ncomponents > 0)
|
||||
{
|
||||
// Notify hierarchy bounds listeners.
|
||||
if (resized)
|
||||
{
|
||||
for (int i = 0; i < getComponentCount(); i++)
|
||||
{
|
||||
Component child = getComponent(i);
|
||||
child.fireHierarchyEvent(HierarchyEvent.ANCESTOR_RESIZED,
|
||||
this, parent, 0);
|
||||
}
|
||||
}
|
||||
if (moved)
|
||||
{
|
||||
for (int i = 0; i < getComponentCount(); i++)
|
||||
{
|
||||
Component child = getComponent(i);
|
||||
child.fireHierarchyEvent(HierarchyEvent.ANCESTOR_MOVED,
|
||||
this, parent, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addNotifyContainerChildren()
|
||||
{
|
||||
synchronized (getTreeLock ())
|
||||
|
@ -2011,12 +2097,6 @@ public class Container extends Component
|
|||
for (int i = ncomponents; --i >= 0; )
|
||||
{
|
||||
component[i].addNotify();
|
||||
if (component[i].isLightweight ())
|
||||
{
|
||||
enableEvents(component[i].eventMask);
|
||||
if (peer != null && !isLightweight ())
|
||||
enableEvents (AWTEvent.PAINT_EVENT_MASK);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,6 +96,11 @@ public class Dialog extends Window
|
|||
*/
|
||||
private EventQueue eq2 = null;
|
||||
|
||||
/**
|
||||
* The number used to generate the name returned by getName.
|
||||
*/
|
||||
private static transient long next_dialog_number;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of <code>Dialog</code> with the specified
|
||||
* parent, that is resizable and not modal, and which has no title.
|
||||
|
@ -190,6 +195,7 @@ public class Dialog extends Window
|
|||
visible = false;
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -273,6 +279,7 @@ public class Dialog extends Window
|
|||
visible = false;
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -530,5 +537,19 @@ public class Dialog extends Window
|
|||
accessibleContext = new AccessibleAWTDialog();
|
||||
return accessibleContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a unique name for this <code>Dialog</code>.
|
||||
*
|
||||
* @return A unique name for this <code>Dialog</code>.
|
||||
*/
|
||||
String generateName()
|
||||
{
|
||||
return "dialog" + getUniqueLong();
|
||||
}
|
||||
|
||||
private static synchronized long getUniqueLong()
|
||||
{
|
||||
return next_dialog_number++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,10 +38,16 @@ exception statement from your version. */
|
|||
|
||||
package java.awt;
|
||||
|
||||
import gnu.java.awt.LowPriorityEvent;
|
||||
import gnu.java.awt.peer.NativeEventLoopRunningEvent;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.InputMethodEvent;
|
||||
import java.awt.event.InvocationEvent;
|
||||
import java.awt.event.PaintEvent;
|
||||
import java.awt.peer.ComponentPeer;
|
||||
import java.awt.peer.LightweightPeer;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.EmptyStackException;
|
||||
|
||||
|
@ -61,11 +67,47 @@ import java.util.EmptyStackException;
|
|||
*/
|
||||
public class EventQueue
|
||||
{
|
||||
private static final int INITIAL_QUEUE_DEPTH = 8;
|
||||
private AWTEvent[] queue = new AWTEvent[INITIAL_QUEUE_DEPTH];
|
||||
/**
|
||||
* Indicates events that are processed with normal priority. This is normally
|
||||
* all events except PaintEvents.
|
||||
*/
|
||||
private static final int NORM_PRIORITY = 0;
|
||||
|
||||
private int next_in = 0; // Index where next event will be added to queue
|
||||
private int next_out = 0; // Index of next event to be removed from queue
|
||||
/**
|
||||
* Indicates events that are processed with lowes priority. This is normally
|
||||
* all PaintEvents and LowPriorityEvents.
|
||||
*/
|
||||
private static final int LOW_PRIORITY = 1;
|
||||
|
||||
/**
|
||||
* Implements the actual queue. EventQueue has 2 internal queues for
|
||||
* different priorities:
|
||||
* 1 PaintEvents are always dispatched with low priority.
|
||||
* 2. All other events are dispatched with normal priority.
|
||||
*
|
||||
* This makes sure that the actual painting (output) is performed _after_ all
|
||||
* available input has been processed and that the paint regions are
|
||||
* coalesced as much as possible.
|
||||
*/
|
||||
private class Queue
|
||||
{
|
||||
/**
|
||||
* The first item in the queue. This is where events are popped from.
|
||||
*/
|
||||
AWTEvent queueHead;
|
||||
|
||||
/**
|
||||
* The last item. This is where events are posted to.
|
||||
*/
|
||||
AWTEvent queueTail;
|
||||
}
|
||||
|
||||
/**
|
||||
* The three internal event queues.
|
||||
*
|
||||
* @see Queue
|
||||
*/
|
||||
private Queue[] queues;
|
||||
|
||||
private EventQueue next;
|
||||
private EventQueue prev;
|
||||
|
@ -73,31 +115,25 @@ public class EventQueue
|
|||
private long lastWhen = System.currentTimeMillis();
|
||||
|
||||
private EventDispatchThread dispatchThread = new EventDispatchThread(this);
|
||||
private boolean shutdown = false;
|
||||
private boolean nativeLoopRunning = false;
|
||||
|
||||
synchronized private void setShutdown (boolean b)
|
||||
private boolean isShutdown ()
|
||||
{
|
||||
shutdown = b;
|
||||
}
|
||||
|
||||
synchronized boolean isShutdown ()
|
||||
{
|
||||
if (shutdown)
|
||||
return true;
|
||||
|
||||
// This is the exact self-shutdown condition specified in J2SE:
|
||||
// http://java.sun.com/j2se/1.4.2/docs/api/java/awt/doc-files/AWTThreadIssues.html
|
||||
|
||||
// FIXME: check somewhere that the native queue is empty
|
||||
if (peekEvent() == null)
|
||||
{
|
||||
Frame[] frames = Frame.getFrames();
|
||||
for (int i = 0; i < frames.length; ++i)
|
||||
if (frames[i].isDisplayable())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
if (nativeLoopRunning)
|
||||
return false;
|
||||
|
||||
if (peekEvent() != null)
|
||||
return false;
|
||||
|
||||
Frame[] frames = Frame.getFrames();
|
||||
for (int i = 0; i < frames.length; ++i)
|
||||
if (frames[i].isDisplayable())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,6 +141,9 @@ public class EventQueue
|
|||
*/
|
||||
public EventQueue()
|
||||
{
|
||||
queues = new Queue[2];
|
||||
queues[NORM_PRIORITY] = new Queue();
|
||||
queues[LOW_PRIORITY] = new Queue();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -122,30 +161,66 @@ public class EventQueue
|
|||
if (next != null)
|
||||
return next.getNextEvent();
|
||||
|
||||
while (next_in == next_out)
|
||||
{
|
||||
// We are not allowed to return null from this method, yet it
|
||||
// is possible that we actually have run out of native events
|
||||
// in the enclosing while() loop, and none of the native events
|
||||
// happened to cause AWT events. We therefore ought to check
|
||||
// the isShutdown() condition here, before risking a "native
|
||||
// wait". If we check it before entering this function we may
|
||||
// wait forever for events after the shutdown condition has
|
||||
// arisen.
|
||||
AWTEvent res = getNextEventImpl(true);
|
||||
|
||||
while (res == null)
|
||||
{
|
||||
if (isShutdown())
|
||||
throw new InterruptedException();
|
||||
{
|
||||
// Explicitly set dispathThread to null. If we don't do
|
||||
// this, there is a race condition where dispatchThread
|
||||
// can be != null even after the event dispatch thread has
|
||||
// stopped running. If that happens, then the
|
||||
// dispatchThread == null check in postEventImpl will
|
||||
// fail, and a new event dispatch thread will not be
|
||||
// created, leaving invokeAndWaits waiting indefinitely.
|
||||
dispatchThread = null;
|
||||
|
||||
// Interrupt the event dispatch thread.
|
||||
throw new InterruptedException();
|
||||
}
|
||||
|
||||
wait();
|
||||
res = getNextEventImpl(true);
|
||||
}
|
||||
|
||||
AWTEvent res = queue[next_out];
|
||||
|
||||
if (++next_out == queue.length)
|
||||
next_out = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches and possibly removes the next event from the internal queues.
|
||||
* This method returns immediately. When all queues are empty, this returns
|
||||
* <code>null</code>:
|
||||
*
|
||||
* @param remove <true> when the event should be removed from the queue,
|
||||
* <code>false</code> otherwise
|
||||
*
|
||||
* @return the next event or <code>null</code> when all internal queues
|
||||
* are empty
|
||||
*/
|
||||
private AWTEvent getNextEventImpl(boolean remove)
|
||||
{
|
||||
AWTEvent next = null;
|
||||
for (int i = 0; i < queues.length && next == null; i++)
|
||||
{
|
||||
Queue q = queues[i];
|
||||
if (q.queueHead != null)
|
||||
{
|
||||
// Got an event, remove it.
|
||||
next = q.queueHead;
|
||||
if (remove)
|
||||
{
|
||||
// Unlink event from the queue.
|
||||
q.queueHead = next.queueNext;
|
||||
if (q.queueHead == null)
|
||||
q.queueTail = null;
|
||||
next.queueNext = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next event in the queue without removing it from the queue.
|
||||
* This method will block until an event is available or until the thread
|
||||
|
@ -160,10 +235,7 @@ public class EventQueue
|
|||
if (next != null)
|
||||
return next.peekEvent();
|
||||
|
||||
if (next_in != next_out)
|
||||
return queue[next_out];
|
||||
else
|
||||
return null;
|
||||
return getNextEventImpl(false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -184,14 +256,18 @@ public class EventQueue
|
|||
if (next != null)
|
||||
return next.peekEvent(id);
|
||||
|
||||
int i = next_out;
|
||||
while (i != next_in)
|
||||
AWTEvent evt = null;
|
||||
for (int i = 0; i < queues.length && evt == null; i++)
|
||||
{
|
||||
AWTEvent qevt = queue[i];
|
||||
if (qevt.id == id)
|
||||
return qevt;
|
||||
Queue q = queues[i];
|
||||
evt = q.queueHead;
|
||||
while (evt != null && evt.id != id)
|
||||
evt = evt.queueNext;
|
||||
// At this point we either have found an event (evt != null -> exit
|
||||
// for loop), or we have found no event (evt == null -> search next
|
||||
// internal queue).
|
||||
}
|
||||
return null;
|
||||
return evt;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -201,7 +277,42 @@ public class EventQueue
|
|||
*
|
||||
* @exception NullPointerException If event is null.
|
||||
*/
|
||||
public synchronized void postEvent(AWTEvent evt)
|
||||
public void postEvent(AWTEvent evt)
|
||||
{
|
||||
postEventImpl(evt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts events to their priority and calls
|
||||
* {@link #postEventImpl(AWTEvent, int)}.
|
||||
*
|
||||
* @param evt the event to post
|
||||
*/
|
||||
private synchronized final void postEventImpl(AWTEvent evt)
|
||||
{
|
||||
int priority = NORM_PRIORITY;
|
||||
if (evt instanceof PaintEvent || evt instanceof LowPriorityEvent)
|
||||
priority = LOW_PRIORITY;
|
||||
// TODO: Maybe let Swing RepaintManager events also be processed with
|
||||
// low priority.
|
||||
if (evt instanceof NativeEventLoopRunningEvent)
|
||||
{
|
||||
nativeLoopRunning = ((NativeEventLoopRunningEvent) evt).isRunning();
|
||||
notify();
|
||||
return;
|
||||
}
|
||||
postEventImpl(evt, priority);
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually performs the event posting. This is needed because the
|
||||
* RI doesn't use the public postEvent() method when transferring events
|
||||
* between event queues in push() and pop().
|
||||
*
|
||||
* @param evt the event to post
|
||||
* @param priority the priority of the event
|
||||
*/
|
||||
private final void postEventImpl(AWTEvent evt, int priority)
|
||||
{
|
||||
if (evt == null)
|
||||
throw new NullPointerException();
|
||||
|
@ -212,52 +323,71 @@ public class EventQueue
|
|||
return;
|
||||
}
|
||||
|
||||
/* Check for any events already on the queue with the same source
|
||||
and ID. */
|
||||
int i = next_out;
|
||||
while (i != next_in)
|
||||
Object source = evt.getSource();
|
||||
|
||||
Queue q = queues[priority];
|
||||
if (source instanceof Component)
|
||||
{
|
||||
AWTEvent qevt = queue[i];
|
||||
Object src;
|
||||
if (qevt.id == evt.id
|
||||
&& (src = qevt.getSource()) == evt.getSource()
|
||||
&& src instanceof Component)
|
||||
// For PaintEvents, ask the ComponentPeer to coalesce the event
|
||||
// when the component is heavyweight.
|
||||
Component comp = (Component) source;
|
||||
ComponentPeer peer = comp.peer;
|
||||
if (peer != null && evt instanceof PaintEvent
|
||||
&& ! (peer instanceof LightweightPeer))
|
||||
peer.coalescePaintEvent((PaintEvent) evt);
|
||||
|
||||
// Check for any events already on the queue with the same source
|
||||
// and ID.
|
||||
AWTEvent previous = null;
|
||||
for (AWTEvent qevt = q.queueHead; qevt != null; qevt = qevt.queueNext)
|
||||
{
|
||||
/* If there are, call coalesceEvents on the source component
|
||||
to see if they can be combined. */
|
||||
Component srccmp = (Component) src;
|
||||
AWTEvent coalesced_evt = srccmp.coalesceEvents(qevt, evt);
|
||||
if (coalesced_evt != null)
|
||||
Object src = qevt.getSource();
|
||||
if (qevt.id == evt.id && src == comp)
|
||||
{
|
||||
/* Yes. Replace the existing event with the combined event. */
|
||||
queue[i] = coalesced_evt;
|
||||
return;
|
||||
// If there are, call coalesceEvents on the source component
|
||||
// to see if they can be combined.
|
||||
Component srccmp = (Component) src;
|
||||
AWTEvent coalescedEvt = srccmp.coalesceEvents(qevt, evt);
|
||||
if (coalescedEvt != null)
|
||||
{
|
||||
// Yes. Replace the existing event with the combined event.
|
||||
if (qevt != coalescedEvt)
|
||||
{
|
||||
if (previous != null)
|
||||
{
|
||||
assert previous.queueNext == qevt;
|
||||
previous.queueNext = coalescedEvt;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert q.queueHead == qevt;
|
||||
q.queueHead = coalescedEvt;
|
||||
}
|
||||
coalescedEvt.queueNext = qevt.queueNext;
|
||||
if (q.queueTail == qevt)
|
||||
q.queueTail = coalescedEvt;
|
||||
qevt.queueNext = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
previous = qevt;
|
||||
}
|
||||
if (++i == queue.length)
|
||||
i = 0;
|
||||
}
|
||||
|
||||
queue[next_in] = evt;
|
||||
if (++next_in == queue.length)
|
||||
next_in = 0;
|
||||
|
||||
if (next_in == next_out)
|
||||
if (q.queueHead == null)
|
||||
{
|
||||
/* Queue is full. Extend it. */
|
||||
AWTEvent[] oldQueue = queue;
|
||||
queue = new AWTEvent[queue.length * 2];
|
||||
|
||||
int len = oldQueue.length - next_out;
|
||||
System.arraycopy(oldQueue, next_out, queue, 0, len);
|
||||
if (next_out != 0)
|
||||
System.arraycopy(oldQueue, 0, queue, len, next_out);
|
||||
|
||||
next_out = 0;
|
||||
next_in = oldQueue.length;
|
||||
// We have an empty queue. Set this event both as head and as tail.
|
||||
q.queueHead = evt;
|
||||
q.queueTail = evt;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// Note: queueTail should not be null here.
|
||||
q.queueTail.queueNext = evt;
|
||||
q.queueTail = evt;
|
||||
}
|
||||
|
||||
if (dispatchThread == null || !dispatchThread.isAlive())
|
||||
{
|
||||
dispatchThread = new EventDispatchThread(this);
|
||||
|
@ -287,15 +417,15 @@ public class EventQueue
|
|||
throw new Error("Can't call invokeAndWait from event dispatch thread");
|
||||
|
||||
EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
|
||||
Thread current = Thread.currentThread();
|
||||
Object notifyObject = new Object();
|
||||
|
||||
InvocationEvent ie =
|
||||
new InvocationEvent(eq, runnable, current, true);
|
||||
InvocationEvent ie =
|
||||
new InvocationEvent(eq, runnable, notifyObject, true);
|
||||
|
||||
synchronized (current)
|
||||
synchronized (notifyObject)
|
||||
{
|
||||
eq.postEvent(ie);
|
||||
current.wait();
|
||||
notifyObject.wait();
|
||||
}
|
||||
|
||||
Exception exception;
|
||||
|
@ -387,17 +517,26 @@ public class EventQueue
|
|||
if (dispatchThread == null)
|
||||
dispatchThread = new EventDispatchThread(this);
|
||||
|
||||
int i = next_out;
|
||||
while (i != next_in)
|
||||
synchronized (newEventQueue)
|
||||
{
|
||||
newEventQueue.postEvent(queue[i]);
|
||||
next_out = i;
|
||||
if (++i == queue.length)
|
||||
i = 0;
|
||||
// The RI transfers the events without calling the new eventqueue's
|
||||
// push(), but using getNextEvent().
|
||||
while (peekEvent() != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
newEventQueue.postEventImpl(getNextEvent());
|
||||
}
|
||||
catch (InterruptedException ex)
|
||||
{
|
||||
// What should we do with this?
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
newEventQueue.prev = this;
|
||||
}
|
||||
|
||||
next = newEventQueue;
|
||||
newEventQueue.prev = this;
|
||||
}
|
||||
|
||||
/** Transfer any pending events from this queue back to the parent queue that
|
||||
|
@ -408,36 +547,49 @@ public class EventQueue
|
|||
*/
|
||||
protected void pop() throws EmptyStackException
|
||||
{
|
||||
if (prev == null)
|
||||
throw new EmptyStackException();
|
||||
|
||||
/* The order is important here, we must get the prev lock first,
|
||||
or deadlock could occur as callers usually get here following
|
||||
prev's next pointer, and thus obtain prev's lock before trying
|
||||
to get this lock. */
|
||||
synchronized (prev)
|
||||
EventQueue previous = prev;
|
||||
if (previous == null)
|
||||
throw new EmptyStackException();
|
||||
synchronized (previous)
|
||||
{
|
||||
prev.next = next;
|
||||
if (next != null)
|
||||
next.prev = prev;
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
int i = next_out;
|
||||
while (i != next_in)
|
||||
EventQueue nextQueue = next;
|
||||
if (nextQueue != null)
|
||||
{
|
||||
prev.postEvent(queue[i]);
|
||||
next_out = i;
|
||||
if (++i == queue.length)
|
||||
i = 0;
|
||||
nextQueue.pop();
|
||||
}
|
||||
// Empty the queue so it can be reused
|
||||
next_in = 0;
|
||||
next_out = 0;
|
||||
else
|
||||
{
|
||||
previous.next = null;
|
||||
|
||||
setShutdown(true);
|
||||
dispatchThread = null;
|
||||
this.notifyAll();
|
||||
// The RI transfers the events without calling the new eventqueue's
|
||||
// push(), so this should be OK and most effective.
|
||||
while (peekEvent() != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
previous.postEventImpl(getNextEvent());
|
||||
}
|
||||
catch (InterruptedException ex)
|
||||
{
|
||||
// What should we do with this?
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
prev = null;
|
||||
// Tell our EventDispatchThread that it can end
|
||||
// execution.
|
||||
if (dispatchThread != null)
|
||||
{
|
||||
dispatchThread.interrupt();
|
||||
dispatchThread = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,6 +95,11 @@ private FilenameFilter filter;
|
|||
*/
|
||||
private int mode;
|
||||
|
||||
/**
|
||||
* The number used to generate the name returned by getName.
|
||||
*/
|
||||
private static transient long next_file_dialog_number;
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
|
@ -300,7 +305,11 @@ getFile()
|
|||
public synchronized void
|
||||
setFile(String file)
|
||||
{
|
||||
this.file = file;
|
||||
if ("".equals(file))
|
||||
this.file = null;
|
||||
else
|
||||
this.file = file;
|
||||
|
||||
if (peer != null)
|
||||
{
|
||||
FileDialogPeer f = (FileDialogPeer) peer;
|
||||
|
@ -366,5 +375,22 @@ paramString()
|
|||
",mode=" + mode + "," + super.paramString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a unique name for this <code>FileDialog</code>.
|
||||
*
|
||||
* @return A unique name for this <code>FileDialog</code>.
|
||||
*/
|
||||
String
|
||||
generateName()
|
||||
{
|
||||
return "filedlg" + getUniqueLong();
|
||||
}
|
||||
|
||||
private static synchronized long
|
||||
getUniqueLong()
|
||||
{
|
||||
return next_file_dialog_number++;
|
||||
}
|
||||
|
||||
} // class FileDialog
|
||||
|
||||
|
|
|
@ -337,7 +337,10 @@ public class FlowLayout implements LayoutManager, Serializable
|
|||
|
||||
Insets ins = parent.getInsets ();
|
||||
|
||||
w += (num + 1) * hgap + ins.left + ins.right;
|
||||
if (num == 0)
|
||||
w += 2 * hgap + ins.left + ins.right;
|
||||
else
|
||||
w += (num + 1) * hgap + ins.left + ins.right;
|
||||
h += 2 * vgap + ins.top + ins.bottom;
|
||||
|
||||
return new Dimension (w, h);
|
||||
|
|
|
@ -44,6 +44,7 @@ import gnu.java.awt.peer.ClasspathFontPeer;
|
|||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.GlyphVector;
|
||||
import java.awt.font.LineMetrics;
|
||||
import java.awt.font.TextAttribute;
|
||||
import java.awt.font.TextLayout;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
@ -351,7 +352,7 @@ public class Font implements Serializable
|
|||
this.name = peer.getName(this);
|
||||
}
|
||||
|
||||
public Font(Map attrs)
|
||||
public Font(Map<? extends AttributedCharacterIterator.Attribute, ?> attrs)
|
||||
{
|
||||
this(null, attrs);
|
||||
}
|
||||
|
@ -797,7 +798,7 @@ public class Font implements Serializable
|
|||
*
|
||||
* @since 1.2
|
||||
*/
|
||||
public Font deriveFont(Map attributes)
|
||||
public Font deriveFont(Map<? extends AttributedCharacterIterator.Attribute, ?> attributes)
|
||||
{
|
||||
return peer.deriveFont(this, attributes);
|
||||
}
|
||||
|
@ -811,7 +812,7 @@ public class Font implements Serializable
|
|||
* @see java.text.AttributedCharacterIterator.Attribute
|
||||
* @see java.awt.font.TextAttribute
|
||||
*/
|
||||
public Map getAttributes()
|
||||
public Map<TextAttribute, ?> getAttributes()
|
||||
{
|
||||
return peer.getAttributes(this);
|
||||
}
|
||||
|
@ -890,7 +891,7 @@ public class Font implements Serializable
|
|||
*
|
||||
* @see java.awt.font.TextAttribute
|
||||
*/
|
||||
public static Font getFont(Map attributes)
|
||||
public static Font getFont(Map<? extends AttributedCharacterIterator.Attribute, ?> attributes)
|
||||
{
|
||||
return getFontFromToolkit(null, attributes);
|
||||
}
|
||||
|
@ -1086,7 +1087,8 @@ public class Font implements Serializable
|
|||
*/
|
||||
public Rectangle2D getStringBounds(String str, FontRenderContext frc)
|
||||
{
|
||||
return getStringBounds(str, 0, str.length() - 1, frc);
|
||||
char[] chars = str.toCharArray();
|
||||
return getStringBounds(chars, 0, chars.length, frc);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1114,8 +1116,8 @@ public class Font implements Serializable
|
|||
public Rectangle2D getStringBounds(String str, int begin,
|
||||
int limit, FontRenderContext frc)
|
||||
{
|
||||
return peer.getStringBounds(this, new StringCharacterIterator(str), begin,
|
||||
limit, frc);
|
||||
String sub = str.substring(begin, limit);
|
||||
return getStringBounds(sub, frc);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1143,7 +1145,16 @@ public class Font implements Serializable
|
|||
public Rectangle2D getStringBounds(CharacterIterator ci, int begin,
|
||||
int limit, FontRenderContext frc)
|
||||
{
|
||||
return peer.getStringBounds(this, ci, begin, limit, frc);
|
||||
int start = ci.getBeginIndex();
|
||||
int end = ci.getEndIndex();
|
||||
char[] chars = new char[limit - start];
|
||||
ci.setIndex(start);
|
||||
for (int index = 0; index < chars.length; index++)
|
||||
{
|
||||
chars[index] = ci.current();
|
||||
ci.next();
|
||||
}
|
||||
return getStringBounds(chars, 0, chars.length, frc);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1171,9 +1182,10 @@ public class Font implements Serializable
|
|||
public Rectangle2D getStringBounds(char[] chars, int begin,
|
||||
int limit, FontRenderContext frc)
|
||||
{
|
||||
return peer.getStringBounds(this,
|
||||
new StringCharacterIterator(new String(chars)),
|
||||
begin, limit, frc);
|
||||
String str = new String(chars, begin, limit - begin);
|
||||
TextLayout layout = new TextLayout(str, this, frc);
|
||||
return new Rectangle2D.Float(0, -layout.getAscent(), layout.getAdvance(),
|
||||
layout.getDescent() + layout.getLeading());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -340,13 +340,16 @@ public class Frame extends Window implements MenuContainer
|
|||
parent.remove(menuBar);
|
||||
menuBar.setParent(this);
|
||||
|
||||
if (peer != null)
|
||||
{
|
||||
if (menuBar != null)
|
||||
menuBar.addNotify();
|
||||
invalidateTree();
|
||||
((FramePeer) peer).setMenuBar(menuBar);
|
||||
}
|
||||
// Create local copy for thread safety.
|
||||
FramePeer p = (FramePeer) peer;
|
||||
if (p != null)
|
||||
{
|
||||
if (menuBar != null)
|
||||
menuBar.addNotify();
|
||||
if (valid)
|
||||
invalidate();
|
||||
p.setMenuBar(menuBar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -485,7 +488,10 @@ public class Frame extends Window implements MenuContainer
|
|||
|
||||
private static void noteFrame(Frame f)
|
||||
{
|
||||
weakFrames.add(new WeakReference(f));
|
||||
synchronized (weakFrames)
|
||||
{
|
||||
weakFrames.add(new WeakReference(f));
|
||||
}
|
||||
}
|
||||
|
||||
public static Frame[] getFrames()
|
||||
|
@ -533,8 +539,7 @@ public class Frame extends Window implements MenuContainer
|
|||
|
||||
public int getState()
|
||||
{
|
||||
// FIXME: State might have changed in the peer... Must check.
|
||||
return (state & ICONIFIED) != 0 ? ICONIFIED : NORMAL;
|
||||
return (getExtendedState() & ICONIFIED) != 0 ? ICONIFIED : NORMAL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -542,7 +547,13 @@ public class Frame extends Window implements MenuContainer
|
|||
*/
|
||||
public void setExtendedState(int state)
|
||||
{
|
||||
this.state = state;
|
||||
if (getToolkit().isFrameStateSupported(state))
|
||||
{
|
||||
this.state = state;
|
||||
FramePeer p = (FramePeer) peer;
|
||||
if (p != null)
|
||||
p.setState(state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -550,6 +561,9 @@ public class Frame extends Window implements MenuContainer
|
|||
*/
|
||||
public int getExtendedState()
|
||||
{
|
||||
FramePeer p = (FramePeer) peer;
|
||||
if (p != null)
|
||||
state = p.getState();
|
||||
return state;
|
||||
}
|
||||
|
||||
|
|
|
@ -183,7 +183,7 @@ public abstract class Graphics2D extends Graphics
|
|||
* @see #getComposite()
|
||||
*/
|
||||
public abstract void setComposite(Composite comp);
|
||||
|
||||
|
||||
/**
|
||||
* Sets the paint to be used for subsequent drawing operations.
|
||||
*
|
||||
|
@ -227,14 +227,14 @@ public abstract class Graphics2D extends Graphics
|
|||
*
|
||||
* @see #addRenderingHints(Map)
|
||||
*/
|
||||
public abstract void setRenderingHints(Map hints);
|
||||
public abstract void setRenderingHints(Map<?,?> hints);
|
||||
|
||||
/**
|
||||
* Adds/updates the rendering hint.
|
||||
*
|
||||
* @param hints the hints to add or update.
|
||||
*/
|
||||
public abstract void addRenderingHints(Map hints);
|
||||
public abstract void addRenderingHints(Map<?,?> hints);
|
||||
|
||||
/**
|
||||
* Returns the current rendering hints.
|
||||
|
|
|
@ -46,6 +46,7 @@ import java.util.Hashtable;
|
|||
/**
|
||||
* @author Michael Koch (konqueror@gmx.de)
|
||||
* @author Jeroen Frijters (jeroen@frijters.net)
|
||||
* @author Andrew John Hughes (gnu_andrew@member.fsf.org)
|
||||
*/
|
||||
public class GridBagLayout
|
||||
implements Serializable, LayoutManager2
|
||||
|
@ -62,8 +63,8 @@ public class GridBagLayout
|
|||
// REMAINDER constraints.
|
||||
// Constraints kept in comptable are never modified, and constraints
|
||||
// kept in internalcomptable can be modified internally only.
|
||||
protected Hashtable comptable;
|
||||
private Hashtable internalcomptable;
|
||||
protected Hashtable<Component,GridBagConstraints> comptable;
|
||||
private Hashtable<Component,GridBagConstraints> internalcomptable;
|
||||
protected GridBagLayoutInfo layoutInfo;
|
||||
protected GridBagConstraints defaultConstraints;
|
||||
|
||||
|
@ -74,8 +75,8 @@ public class GridBagLayout
|
|||
|
||||
public GridBagLayout ()
|
||||
{
|
||||
this.comptable = new Hashtable();
|
||||
this.internalcomptable = new Hashtable();
|
||||
this.comptable = new Hashtable<Component,GridBagConstraints>();
|
||||
this.internalcomptable = new Hashtable<Component,GridBagConstraints>();
|
||||
this.defaultConstraints= new GridBagConstraints();
|
||||
}
|
||||
|
||||
|
@ -319,6 +320,16 @@ public class GridBagLayout
|
|||
return new Point (col, row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string representation of this GridBagLayout.
|
||||
*
|
||||
* @return a string representation
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Move and resize a rectangle according to a set of grid bag
|
||||
* constraints. The x, y, width and height fields of the
|
||||
|
@ -489,16 +500,18 @@ public class GridBagLayout
|
|||
|
||||
// Guaranteed to contain the last component added to the given row
|
||||
// or column, whose gridwidth/height is not REMAINDER.
|
||||
HashMap lastInRow = new HashMap();
|
||||
HashMap lastInCol = new HashMap();
|
||||
HashMap<Integer,Component> lastInRow = new HashMap<Integer,Component>();
|
||||
HashMap<Integer,Component> lastInCol = new HashMap<Integer,Component>();
|
||||
|
||||
Component[] components = parent.getComponents();
|
||||
|
||||
// Components sorted by gridwidths/heights,
|
||||
// smallest to largest, with REMAINDER and RELATIVE at the end.
|
||||
// These are useful when determining sizes and weights.
|
||||
ArrayList sortedByWidth = new ArrayList(components.length);
|
||||
ArrayList sortedByHeight = new ArrayList(components.length);
|
||||
ArrayList<Component> sortedByWidth =
|
||||
new ArrayList<Component>(components.length);
|
||||
ArrayList<Component> sortedByHeight =
|
||||
new ArrayList<Component>(components.length);
|
||||
|
||||
// STEP 1: first we figure out how many rows/columns
|
||||
for (int i = 0; i < components.length; i++)
|
||||
|
@ -763,7 +776,7 @@ public class GridBagLayout
|
|||
// STEP 3: Determine sizes and weights for columns.
|
||||
for (int i = 0; i < sortedByWidth.size(); i++)
|
||||
{
|
||||
Component component = (Component) sortedByWidth.get(i);
|
||||
Component component = sortedByWidth.get(i);
|
||||
|
||||
// If component is not visible we dont have to care about it.
|
||||
if (!component.isVisible())
|
||||
|
@ -877,7 +890,8 @@ public class GridBagLayout
|
|||
* width. Otherwise, sort by height.
|
||||
* FIXME: Use a better sorting algorithm.
|
||||
*/
|
||||
private void sortBySpan (Component component, int span, ArrayList list, boolean sortByWidth)
|
||||
private void sortBySpan (Component component, int span,
|
||||
ArrayList<Component> list, boolean sortByWidth)
|
||||
{
|
||||
if (span == GridBagConstraints.REMAINDER
|
||||
|| span == GridBagConstraints.RELATIVE)
|
||||
|
|
|
@ -289,7 +289,7 @@ public class GridLayout implements LayoutManager, Serializable
|
|||
public String toString ()
|
||||
{
|
||||
return (getClass ().getName () + "["
|
||||
+ ",hgap=" + hgap + ",vgap=" + vgap
|
||||
+ "hgap=" + hgap + ",vgap=" + vgap
|
||||
+ ",rows=" + rows + ",cols=" + cols
|
||||
+ "]");
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* KeyboardFocusManager.java -- manage component focusing via the keyboard
|
||||
Copyright (C) 2002, 2004 Free Software Foundation
|
||||
Copyright (C) 2002, 2004, 2005 Free Software Foundation
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -555,7 +555,9 @@ public abstract class KeyboardFocusManager
|
|||
* @see #UP_CYCLE_TRAVERSAL_KEYS
|
||||
* @see #DOWN_CYCLE_TRAVERSAL_KEYS
|
||||
*/
|
||||
public void setDefaultFocusTraversalKeys (int id, Set keystrokes)
|
||||
public void setDefaultFocusTraversalKeys (int id,
|
||||
Set<? extends AWTKeyStroke>
|
||||
keystrokes)
|
||||
{
|
||||
if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
|
||||
id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
|
||||
|
@ -627,7 +629,7 @@ public abstract class KeyboardFocusManager
|
|||
* @see #UP_CYCLE_TRAVERSAL_KEYS
|
||||
* @see #DOWN_CYCLE_TRAVERSAL_KEYS
|
||||
*/
|
||||
public Set getDefaultFocusTraversalKeys (int id)
|
||||
public Set<AWTKeyStroke> getDefaultFocusTraversalKeys (int id)
|
||||
{
|
||||
if (id < FORWARD_TRAVERSAL_KEYS || id > DOWN_CYCLE_TRAVERSAL_KEYS)
|
||||
throw new IllegalArgumentException ();
|
||||
|
@ -989,9 +991,9 @@ public abstract class KeyboardFocusManager
|
|||
* @return A list of explicitly registered key event dispatchers.
|
||||
* @see KeyboardFocusManager#addKeyEventDispatcher(java.awt.KeyEventDispatcher)
|
||||
*/
|
||||
protected List getKeyEventDispatchers ()
|
||||
protected List<KeyEventDispatcher> getKeyEventDispatchers ()
|
||||
{
|
||||
return (List) keyEventDispatchers.clone ();
|
||||
return (List<KeyEventDispatcher>) keyEventDispatchers.clone ();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1046,9 +1048,9 @@ public abstract class KeyboardFocusManager
|
|||
* @return A list of explicitly registered key event post processors.
|
||||
* @see KeyboardFocusManager#addKeyEventPostProcessor(java.awt.KeyEventPostProcessor)
|
||||
*/
|
||||
protected List getKeyEventPostProcessors ()
|
||||
protected List<KeyEventPostProcessor> getKeyEventPostProcessors ()
|
||||
{
|
||||
return (List) keyEventPostProcessors.clone ();
|
||||
return (List<KeyEventPostProcessor>) keyEventPostProcessors.clone ();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -38,7 +38,10 @@ exception statement from your version. */
|
|||
|
||||
package java.awt;
|
||||
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.awt.peer.LightweightPeer;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
|
@ -49,7 +52,7 @@ import java.util.WeakHashMap;
|
|||
*
|
||||
* @author Roman Kennke (kennke@aicas.com)
|
||||
*/
|
||||
class LightweightDispatcher
|
||||
final class LightweightDispatcher
|
||||
{
|
||||
|
||||
/**
|
||||
|
@ -59,26 +62,17 @@ class LightweightDispatcher
|
|||
*/
|
||||
private static WeakHashMap instances = new WeakHashMap();
|
||||
|
||||
/**
|
||||
* The component that is the start of a mouse dragging. All MOUSE_DRAGGED
|
||||
* events that follow the initial press must have the source set to this,
|
||||
* as well as the MOUSE_RELEASED event following the dragging.
|
||||
*/
|
||||
private Component dragTarget;
|
||||
|
||||
/**
|
||||
* Stores the button number which started the drag operation. This is needed
|
||||
* because we want to handle only one drag operation and only the button that
|
||||
* started the dragging should be able to stop it (by a button release).
|
||||
*/
|
||||
private int dragButton;
|
||||
|
||||
/**
|
||||
* The last mouse event target. If the target changes, additional
|
||||
* MOUSE_ENTERED and MOUSE_EXITED events must be dispatched.
|
||||
*/
|
||||
private Component lastTarget;
|
||||
|
||||
/**
|
||||
* The current mouseEventTarget.
|
||||
*/
|
||||
private Component mouseEventTarget;
|
||||
|
||||
/**
|
||||
* Returns an instance of LightweightDispatcher for the current thread's
|
||||
* thread group.
|
||||
|
@ -113,9 +107,9 @@ class LightweightDispatcher
|
|||
*
|
||||
* @param event the event
|
||||
*/
|
||||
public boolean dispatchEvent(AWTEvent event)
|
||||
public boolean dispatchEvent(final AWTEvent event)
|
||||
{
|
||||
if (event instanceof MouseEvent && event.getSource() instanceof Window)
|
||||
if (event instanceof MouseEvent)
|
||||
{
|
||||
MouseEvent mouseEvent = (MouseEvent) event;
|
||||
return handleMouseEvent(mouseEvent);
|
||||
|
@ -130,151 +124,49 @@ class LightweightDispatcher
|
|||
* @param ev the mouse event
|
||||
* @return whether or not we found a lightweight that handled the event.
|
||||
*/
|
||||
private boolean handleMouseEvent(MouseEvent ev)
|
||||
private boolean handleMouseEvent(final MouseEvent ev)
|
||||
{
|
||||
Window window = (Window) ev.getSource();
|
||||
// Find the target for the mouse event. We first seach the deepest
|
||||
// component at the specified location. The we go up to its parent and
|
||||
// try to find a neighbor of the deepest component that is suitable as
|
||||
// mouse event target (it must be showing, at that location and have either
|
||||
// a MouseListener or MouseMotionListener installed). If no such component
|
||||
// is found, then we walk up the container hierarchy and find the next
|
||||
// container that has a MouseListener or MouseMotionListener installed.
|
||||
Component deepest = window.findComponentAt(ev.getX(), ev.getY());
|
||||
if (deepest == null)
|
||||
return false;
|
||||
Container parent = deepest.getParent();
|
||||
Point loc = ev.getPoint();
|
||||
loc = convertPointToChild(window, loc, parent);
|
||||
Component target = null;
|
||||
if (parent != null)
|
||||
Container container = (Container) ev.getSource();
|
||||
Component target = findTarget(container, ev.getX(), ev.getY());
|
||||
trackEnterExit(target, ev);
|
||||
int id = ev.getID();
|
||||
|
||||
// Dont update the mouseEventTarget when dragging. Also, MOUSE_CLICKED
|
||||
// must be dispatched to the original target of MOUSE_PRESSED, so don't
|
||||
// update in this case either.
|
||||
if (! isDragging(ev) && id != MouseEvent.MOUSE_CLICKED)
|
||||
mouseEventTarget = (target != container) ? target : null;
|
||||
|
||||
if (mouseEventTarget != null)
|
||||
{
|
||||
target = findTarget(parent, loc);
|
||||
while (target == null && parent != null)
|
||||
switch (id)
|
||||
{
|
||||
if (parent.mouseListener != null
|
||||
|| parent.mouseMotionListener != null
|
||||
|| (parent.eventMask
|
||||
& (AWTEvent.MOUSE_EVENT_MASK
|
||||
| AWTEvent.MOUSE_MOTION_EVENT_MASK)) != 0)
|
||||
{
|
||||
target = parent;
|
||||
}
|
||||
else
|
||||
parent = parent.getParent();
|
||||
}
|
||||
}
|
||||
if (target == null || target.isLightweight())
|
||||
{
|
||||
// Dispatch additional MOUSE_EXITED and MOUSE_ENTERED if event target
|
||||
// is different from the last event target.
|
||||
if (target != lastTarget)
|
||||
{
|
||||
if (lastTarget != null)
|
||||
{
|
||||
Point p1 = convertPointToChild(window, ev.getPoint(),
|
||||
lastTarget);
|
||||
MouseEvent mouseExited =
|
||||
new MouseEvent(lastTarget, MouseEvent.MOUSE_EXITED,
|
||||
ev.getWhen(), ev.getModifiers(), p1.x, p1.y,
|
||||
ev.getClickCount(), ev.isPopupTrigger());
|
||||
//System.err.println("event: " + mouseExited);
|
||||
lastTarget.dispatchEvent(mouseExited);
|
||||
}
|
||||
|
||||
// If a target exists dispatch the MOUSE_ENTERED event.
|
||||
// Experimenting shows that the MOUSE_ENTERED is also dispatched
|
||||
// when the mouse is dragging.
|
||||
if (target != null)
|
||||
{
|
||||
Point p = convertPointToChild(window, ev.getPoint(), target);
|
||||
MouseEvent mouseEntered =
|
||||
new MouseEvent(target,
|
||||
MouseEvent.MOUSE_ENTERED, ev.getWhen(),
|
||||
ev.getModifiers(), p.x, p.y, ev.getClickCount(),
|
||||
ev.isPopupTrigger());
|
||||
//System.err.println("event: " + mouseEntered);
|
||||
target.dispatchEvent(mouseEntered);
|
||||
}
|
||||
}
|
||||
|
||||
switch (ev.getID())
|
||||
{
|
||||
case MouseEvent.MOUSE_PRESSED:
|
||||
// Handle the start of a drag operation or discard the event if
|
||||
// one is already in progress. This prevents focus changes with the
|
||||
// other mouse buttons when one is used for dragging.
|
||||
if (dragTarget == null)
|
||||
{
|
||||
lastTarget = dragTarget = target;
|
||||
|
||||
// Save the button that started the drag operation.
|
||||
dragButton = ev.getButton();
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
case MouseEvent.MOUSE_ENTERED:
|
||||
case MouseEvent.MOUSE_EXITED:
|
||||
// This is already handled in trackEnterExit().
|
||||
break;
|
||||
case MouseEvent.MOUSE_PRESSED:
|
||||
case MouseEvent.MOUSE_RELEASED:
|
||||
// Stop the drag operation only when the button that started
|
||||
// it was released.
|
||||
if (dragTarget != null && dragButton == ev.getButton())
|
||||
{
|
||||
// Only post MOUSE_RELEASED to dragTarget (set in
|
||||
// MOUSE_PRESSED) when the dragTarget is actually visible.
|
||||
// Otherwise post the event to the normal target.
|
||||
if (dragTarget.isVisible())
|
||||
target = dragTarget;
|
||||
dragTarget = null;
|
||||
}
|
||||
|
||||
lastTarget = target;
|
||||
case MouseEvent.MOUSE_MOVED:
|
||||
redispatch(ev, mouseEventTarget, id);
|
||||
break;
|
||||
case MouseEvent.MOUSE_CLICKED:
|
||||
// When we receive a MOUSE_CLICKED, we set the target to the
|
||||
// previous target, which must have been a MOUSE_RELEASED event.
|
||||
// This is necessary for the case when the MOUSE_RELEASED has
|
||||
// caused the original target (like an internal component) go
|
||||
// away.
|
||||
// This line is the reason why it is not possible to move the
|
||||
// 'lastTarget = target' assignment before the switch-statement.
|
||||
target = lastTarget;
|
||||
// MOUSE_CLICKED must be dispatched to the original target of
|
||||
// MOUSE_PRESSED.
|
||||
if (target == mouseEventTarget)
|
||||
redispatch(ev, mouseEventTarget, id);
|
||||
break;
|
||||
case MouseEvent.MOUSE_DRAGGED:
|
||||
// We consider only dragTarget for redispatching the event still
|
||||
// we have to act in a way that the newly found target component
|
||||
// was handled.
|
||||
lastTarget = target;
|
||||
target = dragTarget;
|
||||
if (isDragging(ev))
|
||||
redispatch(ev, mouseEventTarget, id);
|
||||
break;
|
||||
default:
|
||||
// Only declare current target as the old value in all other
|
||||
// cases.
|
||||
lastTarget = target;
|
||||
break;
|
||||
}
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
Point targetCoordinates = convertPointToChild(window,
|
||||
ev.getPoint(),
|
||||
target);
|
||||
int dx = targetCoordinates.x - ev.getX();
|
||||
int dy = targetCoordinates.y - ev.getY();
|
||||
ev.translatePoint(dx, dy);
|
||||
ev.setSource(target);
|
||||
target.dispatchEvent(ev);
|
||||
|
||||
// We reset the event, so that the normal event dispatching is not
|
||||
// influenced by this modified event.
|
||||
ev.setSource(window);
|
||||
ev.translatePoint(-dx, -dy);
|
||||
case MouseEvent.MOUSE_WHEEL:
|
||||
redispatch(ev, mouseEventTarget, id);
|
||||
}
|
||||
|
||||
return true;
|
||||
ev.consume();
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return ev.isConsumed();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -290,58 +182,180 @@ class LightweightDispatcher
|
|||
* @return the actual receiver of the mouse event, or null, if no such
|
||||
* component has been found
|
||||
*/
|
||||
private Component findTarget(Container c, Point loc)
|
||||
private Component findTarget(final Container c, final int x, final int y)
|
||||
{
|
||||
int numComponents = c.getComponentCount();
|
||||
Component target = null;
|
||||
if (c != null)
|
||||
|
||||
// First we check the children of the container.
|
||||
|
||||
// Note: It is important that we use the package private Container
|
||||
// fields ncomponents and component here. There are applications
|
||||
// that override getComponentCount()
|
||||
// and getComponent() to hide internal components, which makes
|
||||
// the LightweightDispatcher not work correctly in these cases.
|
||||
// As a positive sideeffect this is slightly more efficient.
|
||||
int nChildren = c.ncomponents;
|
||||
for (int i = 0; i < nChildren && target == null; i++)
|
||||
{
|
||||
for (int i = 0; i < numComponents; i++)
|
||||
Component child = c.component[i];
|
||||
int childX = x - child.x;
|
||||
int childY = y - child.y;
|
||||
if (child != null && child.visible
|
||||
&& child.peer instanceof LightweightPeer
|
||||
&& child.contains(childX, childY))
|
||||
{
|
||||
Component child = c.getComponent(i);
|
||||
if (child.isShowing())
|
||||
// Check if there's a deeper possible target.
|
||||
if (child instanceof Container)
|
||||
{
|
||||
if (child.contains(loc.x - child.getX(), loc.y - child.getY())
|
||||
&& (child.mouseListener != null
|
||||
|| child.mouseMotionListener != null
|
||||
|| (child.eventMask
|
||||
& (AWTEvent.MOUSE_EVENT_MASK
|
||||
| AWTEvent.MOUSE_MOTION_EVENT_MASK)) != 0))
|
||||
{
|
||||
target = child;
|
||||
break;
|
||||
}
|
||||
Component deeper = findTarget((Container) child,
|
||||
childX, childY);
|
||||
if (deeper != null)
|
||||
target = deeper;
|
||||
}
|
||||
// Check if the child itself is interested in mouse events.
|
||||
else if (isMouseListening(child))
|
||||
target = child;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the container itself, if we didn't find a target yet.
|
||||
if (target == null && c.contains(x, y) && isMouseListening(c))
|
||||
target = c;
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a point in the parent's coordinate system to a child coordinate
|
||||
* system. The resulting point is stored in the same Point object and
|
||||
* returned.
|
||||
* Checks if the specified component would be interested in a mouse event.
|
||||
*
|
||||
* @param parent the parent component
|
||||
* @param p the point
|
||||
* @param child the child component
|
||||
* @param c the component to check
|
||||
*
|
||||
* @return the translated point
|
||||
* @return <code>true</code> if the component has mouse listeners installed,
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
private Point convertPointToChild(Component parent, Point p,
|
||||
Component child)
|
||||
private boolean isMouseListening(final Component c)
|
||||
{
|
||||
int offX = 0;
|
||||
int offY = 0;
|
||||
Component comp = child;
|
||||
while (comp != null && comp != parent)
|
||||
// Note: It is important to NOT check if the component is listening
|
||||
// for a specific event (for instance, mouse motion events). The event
|
||||
// gets dispatched to the component if the component is listening
|
||||
// for ANY mouse event, even when the component is not listening for the
|
||||
// specific type of event. There are applications that depend on this
|
||||
// (sadly).
|
||||
return c.mouseListener != null
|
||||
|| c.mouseMotionListener != null
|
||||
|| c.mouseWheelListener != null
|
||||
|| (c.eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0
|
||||
|| (c.eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0
|
||||
|| (c.eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks MOUSE_ENTERED and MOUSE_EXIT as well as MOUSE_MOVED and
|
||||
* MOUSE_DRAGGED and creates synthetic MOUSE_ENTERED and MOUSE_EXITED for
|
||||
* lightweight component.s
|
||||
*
|
||||
* @param target the current mouse event target
|
||||
* @param ev the mouse event
|
||||
*/
|
||||
private void trackEnterExit(final Component target, final MouseEvent ev)
|
||||
{
|
||||
int id = ev.getID();
|
||||
if (target != lastTarget)
|
||||
{
|
||||
offX += comp.getX();
|
||||
offY += comp.getY();
|
||||
comp = comp.getParent();
|
||||
if (lastTarget != null)
|
||||
redispatch(ev, lastTarget, MouseEvent.MOUSE_EXITED);
|
||||
if (id == MouseEvent.MOUSE_EXITED)
|
||||
ev.consume();
|
||||
if (target != null)
|
||||
redispatch(ev, target, MouseEvent.MOUSE_ENTERED);
|
||||
if (id == MouseEvent.MOUSE_ENTERED)
|
||||
ev.consume();
|
||||
lastTarget = target;
|
||||
}
|
||||
p.x -= offX;
|
||||
p.y -= offY;
|
||||
return p;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Redispatches the specified mouse event to the specified target with the
|
||||
* specified id.
|
||||
*
|
||||
* @param ev the mouse event
|
||||
* @param target the new target
|
||||
* @param id the new id
|
||||
*/
|
||||
private void redispatch(MouseEvent ev, Component target, int id)
|
||||
{
|
||||
Component source = ev.getComponent();
|
||||
if (target != null)
|
||||
{
|
||||
// Translate coordinates.
|
||||
int x = ev.getX();
|
||||
int y = ev.getY();
|
||||
for (Component c = target; c != null && c != source; c = c.getParent())
|
||||
{
|
||||
x -= c.x;
|
||||
y -= c.y;
|
||||
}
|
||||
|
||||
// Retarget event.
|
||||
MouseEvent retargeted;
|
||||
if (id == MouseEvent.MOUSE_WHEEL)
|
||||
{
|
||||
MouseWheelEvent mwe = (MouseWheelEvent) ev;
|
||||
retargeted = new MouseWheelEvent(target, id, ev.getWhen(),
|
||||
ev.getModifiers()
|
||||
| ev.getModifiersEx(), x, y,
|
||||
ev.getClickCount(),
|
||||
ev.isPopupTrigger(),
|
||||
mwe.getScrollType(),
|
||||
mwe.getScrollAmount(),
|
||||
mwe.getWheelRotation());
|
||||
}
|
||||
else
|
||||
{
|
||||
retargeted = new MouseEvent(target, id, ev.getWhen(),
|
||||
ev.getModifiers() | ev.getModifiersEx(),
|
||||
x, y, ev.getClickCount(),
|
||||
ev.isPopupTrigger(), ev.getButton());
|
||||
}
|
||||
|
||||
if (target == source)
|
||||
((Container) target).dispatchNoLightweight(retargeted);
|
||||
else
|
||||
target.dispatchEvent(retargeted);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if we are in the middle of a drag operation, that is, if
|
||||
* any of the buttons is held down.
|
||||
*
|
||||
* @param ev the mouse event to check
|
||||
*
|
||||
* @return <code>true</code> if we are in the middle of a drag operation,
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
private boolean isDragging(MouseEvent ev)
|
||||
{
|
||||
int mods = ev.getModifiersEx();
|
||||
int id = ev.getID();
|
||||
if (id == MouseEvent.MOUSE_PRESSED || id == MouseEvent.MOUSE_RELEASED)
|
||||
{
|
||||
switch (ev.getButton())
|
||||
{
|
||||
case MouseEvent.BUTTON1:
|
||||
mods ^= InputEvent.BUTTON1_DOWN_MASK;
|
||||
break;
|
||||
case MouseEvent.BUTTON2:
|
||||
mods ^= InputEvent.BUTTON2_DOWN_MASK;
|
||||
break;
|
||||
case MouseEvent.BUTTON3:
|
||||
mods ^= InputEvent.BUTTON3_DOWN_MASK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (mods & (InputEvent.BUTTON1_DOWN_MASK
|
||||
| InputEvent.BUTTON2_DOWN_MASK
|
||||
| InputEvent.BUTTON3_DOWN_MASK)) != 0;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -54,38 +54,28 @@ import javax.accessibility.AccessibleRole;
|
|||
public class Menu extends MenuItem implements MenuContainer, Serializable
|
||||
{
|
||||
|
||||
/*
|
||||
* Static Variables
|
||||
*/
|
||||
/**
|
||||
* The number used to generate the name returned by getName.
|
||||
*/
|
||||
private static transient long next_menu_number;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
// Serialization Constant
|
||||
private static final long serialVersionUID = -8809584163345499784L;
|
||||
/**
|
||||
* @serial The actual items in the menu
|
||||
*/
|
||||
private Vector items = new Vector();
|
||||
|
||||
/*************************************************************************/
|
||||
/**
|
||||
* @serial Flag indicating whether or not this menu is a tear off
|
||||
*/
|
||||
private boolean tearOff;
|
||||
|
||||
/*
|
||||
* Instance Variables
|
||||
*/
|
||||
|
||||
/**
|
||||
* @serial The actual items in the menu
|
||||
*/
|
||||
private Vector items = new Vector();
|
||||
|
||||
/**
|
||||
* @serial Flag indicating whether or not this menu is a tear off
|
||||
*/
|
||||
private boolean tearOff;
|
||||
|
||||
/**
|
||||
* @serial Indicates whether or not this is a help menu.
|
||||
*/
|
||||
private boolean isHelpMenu;
|
||||
/**
|
||||
* @serial Indicates whether or not this is a help menu.
|
||||
*/
|
||||
private boolean isHelpMenu;
|
||||
|
||||
/*
|
||||
* @serial Unused in this implementation, but present in Sun's
|
||||
|
@ -93,371 +83,316 @@ private boolean isHelpMenu;
|
|||
*/
|
||||
private int menuSerializedDataVersion = 1;
|
||||
|
||||
static final transient String separatorLabel = "-";
|
||||
static final transient String separatorLabel = "-";
|
||||
|
||||
/*************************************************************************/
|
||||
/**
|
||||
* Initializes a new instance of <code>Menu</code> with no label and that
|
||||
* is not a tearoff;
|
||||
*
|
||||
* @exception HeadlessException If GraphicsEnvironment.isHeadless() is true.
|
||||
*/
|
||||
public Menu()
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructors
|
||||
*/
|
||||
/**
|
||||
* Initializes a new instance of <code>Menu</code> that is not a tearoff and
|
||||
* that has the specified label.
|
||||
*
|
||||
* @param label The menu label.
|
||||
*
|
||||
* @exception HeadlessException If GraphicsEnvironment.isHeadless() is true.
|
||||
*/
|
||||
public Menu(String label)
|
||||
{
|
||||
this(label, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new instance of <code>Menu</code> with no label and that
|
||||
* is not a tearoff;
|
||||
*
|
||||
* @exception HeadlessException If GraphicsEnvironment.isHeadless() is true.
|
||||
*/
|
||||
public
|
||||
Menu()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* Initializes a new instance of <code>Menu</code> with the specified
|
||||
* label and tearoff status.
|
||||
*
|
||||
* @param label The label for this menu
|
||||
* @param isTearOff <code>true</code> if this menu is a tear off menu,
|
||||
* <code>false</code> otherwise.
|
||||
*
|
||||
* @exception HeadlessException If GraphicsEnvironment.isHeadless() is true.
|
||||
*/
|
||||
public Menu(String label, boolean isTearOff)
|
||||
{
|
||||
super(label);
|
||||
|
||||
/*************************************************************************/
|
||||
tearOff = isTearOff;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of <code>Menu</code> that is not a tearoff and
|
||||
* that has the specified label.
|
||||
*
|
||||
* @param label The menu label.
|
||||
*
|
||||
* @exception HeadlessException If GraphicsEnvironment.isHeadless() is true.
|
||||
*/
|
||||
public
|
||||
Menu(String label)
|
||||
{
|
||||
this(label, false);
|
||||
}
|
||||
if (label.equals("Help"))
|
||||
isHelpMenu = true;
|
||||
|
||||
/*************************************************************************/
|
||||
if (GraphicsEnvironment.isHeadless())
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new instance of <code>Menu</code> with the specified
|
||||
* label and tearoff status.
|
||||
*
|
||||
* @param label The label for this menu
|
||||
* @param isTearOff <code>true</code> if this menu is a tear off menu,
|
||||
* <code>false</code> otherwise.
|
||||
*
|
||||
* @exception HeadlessException If GraphicsEnvironment.isHeadless() is true.
|
||||
*/
|
||||
public
|
||||
Menu(String label, boolean isTearOff)
|
||||
{
|
||||
super(label);
|
||||
/**
|
||||
* Tests whether or not this menu is a tearoff.
|
||||
*
|
||||
* @return <code>true</code> if this menu is a tearoff, <code>false</code>
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean isTearOff()
|
||||
{
|
||||
return(tearOff);
|
||||
}
|
||||
|
||||
tearOff = isTearOff;
|
||||
/**
|
||||
* Returns the number of items in this menu.
|
||||
*
|
||||
* @return The number of items in this menu.
|
||||
*/
|
||||
public int getItemCount()
|
||||
{
|
||||
return countItems();
|
||||
}
|
||||
|
||||
if (label.equals("Help"))
|
||||
isHelpMenu = true;
|
||||
|
||||
if (GraphicsEnvironment.isHeadless())
|
||||
throw new HeadlessException ();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
* Instance Methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tests whether or not this menu is a tearoff.
|
||||
*
|
||||
* @return <code>true</code> if this menu is a tearoff, <code>false</code>
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean
|
||||
isTearOff()
|
||||
{
|
||||
return(tearOff);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/**
|
||||
* Returns the number of items in this menu.
|
||||
*
|
||||
* @return The number of items in this menu.
|
||||
*/
|
||||
public int
|
||||
getItemCount()
|
||||
{
|
||||
return countItems ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of items in this menu.
|
||||
*
|
||||
* @return The number of items in this menu.
|
||||
*
|
||||
* @deprecated As of JDK 1.1, replaced by getItemCount().
|
||||
*/
|
||||
public int countItems ()
|
||||
{
|
||||
return items.size ();
|
||||
}
|
||||
/**
|
||||
* Returns the number of items in this menu.
|
||||
*
|
||||
* @return The number of items in this menu.
|
||||
*
|
||||
* @deprecated As of JDK 1.1, replaced by getItemCount().
|
||||
*/
|
||||
public int countItems()
|
||||
{
|
||||
return items.size();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/**
|
||||
* Returns the item at the specified index.
|
||||
*
|
||||
* @param index the item index.
|
||||
*
|
||||
* @return The item at the specified index.
|
||||
*
|
||||
* @exception ArrayIndexOutOfBoundsException If the index value is not valid.
|
||||
*/
|
||||
public MenuItem getItem(int index)
|
||||
{
|
||||
return((MenuItem) items.elementAt(index));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the item at the specified index.
|
||||
*
|
||||
* @return The item at the specified index.
|
||||
*
|
||||
* @exception ArrayIndexOutOfBoundsException If the index value is not valid.
|
||||
*/
|
||||
public MenuItem
|
||||
getItem(int index)
|
||||
{
|
||||
return((MenuItem)items.elementAt(index));
|
||||
}
|
||||
/**
|
||||
* Adds the specified item to this menu. If it was previously part of
|
||||
* another menu, it is first removed from that menu.
|
||||
*
|
||||
* @param item The new item to add.
|
||||
*
|
||||
* @return The item that was added.
|
||||
*/
|
||||
public MenuItem add(MenuItem item)
|
||||
{
|
||||
MenuContainer parent = item.getParent();
|
||||
if (parent != null)
|
||||
parent.remove(item);
|
||||
|
||||
/*************************************************************************/
|
||||
items.addElement(item);
|
||||
item.setParent(this);
|
||||
|
||||
/**
|
||||
* Adds the specified item to this menu. If it was previously part of
|
||||
* another menu, it is first removed from that menu.
|
||||
*
|
||||
* @param item The new item to add.
|
||||
*
|
||||
* @return The item that was added.
|
||||
*/
|
||||
public MenuItem
|
||||
add(MenuItem item)
|
||||
{
|
||||
MenuContainer parent = item.getParent();
|
||||
if (parent != null)
|
||||
parent.remove(item);
|
||||
if (peer != null)
|
||||
{
|
||||
item.addNotify();
|
||||
MenuPeer mp = (MenuPeer) peer;
|
||||
mp.addItem(item);
|
||||
}
|
||||
|
||||
items.addElement(item);
|
||||
item.setParent(this);
|
||||
return item;
|
||||
}
|
||||
|
||||
if (peer != null)
|
||||
{
|
||||
item.addNotify();
|
||||
MenuPeer mp = (MenuPeer) peer;
|
||||
mp.addItem(item);
|
||||
}
|
||||
/**
|
||||
* Add an item with the specified label to this menu.
|
||||
*
|
||||
* @param label The label of the menu item to add.
|
||||
*/
|
||||
public void add(String label)
|
||||
{
|
||||
add(new MenuItem(label));
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
/**
|
||||
* Inserts the specified menu item into this menu at the specified index. If
|
||||
* the index is greater than or equal to the number of items already in the
|
||||
* menu, the new item is added as the last item in the menu.
|
||||
*
|
||||
* @param item The menu item to add (<code>null</code> not permitted).
|
||||
* @param index The index of the menu item (>= 0).
|
||||
*
|
||||
* @throws IllegalArgumentException if the index is less than zero.
|
||||
* @throws NullPointerException if <code>item</code> is <code>null</code>.
|
||||
*/
|
||||
public void insert(MenuItem item, int index)
|
||||
{
|
||||
if (index < 0)
|
||||
throw new IllegalArgumentException("Index is less than zero");
|
||||
|
||||
/*************************************************************************/
|
||||
int count = getItemCount();
|
||||
|
||||
/**
|
||||
* Add an item with the specified label to this menu.
|
||||
*
|
||||
* @param label The label of the menu item to add.
|
||||
*/
|
||||
public void
|
||||
add(String label)
|
||||
{
|
||||
add(new MenuItem(label));
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/**
|
||||
* Inserts the specified menu item into this menu at the specified index.
|
||||
*
|
||||
* @param item The menu item to add.
|
||||
* @param index The index of the menu item.
|
||||
*
|
||||
* @exception IllegalArgumentException If the index is less than zero.
|
||||
* @exception ArrayIndexOutOfBoundsException If the index is otherwise invalid.
|
||||
*/
|
||||
public void
|
||||
insert(MenuItem item, int index)
|
||||
{
|
||||
if (index < 0)
|
||||
throw new IllegalArgumentException("Index is less than zero");
|
||||
|
||||
int count = getItemCount ();
|
||||
|
||||
if (index >= count)
|
||||
add(item);
|
||||
else
|
||||
{
|
||||
MenuContainer parent = item.getParent();
|
||||
if (parent != null)
|
||||
parent.remove(item);
|
||||
if (index >= count)
|
||||
add(item);
|
||||
else
|
||||
{
|
||||
MenuContainer parent = item.getParent();
|
||||
if (parent != null)
|
||||
parent.remove(item);
|
||||
|
||||
items.insertElementAt(item, index);
|
||||
item.setParent(this);
|
||||
items.insertElementAt(item, index);
|
||||
item.setParent(this);
|
||||
|
||||
MenuPeer peer = (MenuPeer) getPeer();
|
||||
if (peer == null)
|
||||
return;
|
||||
MenuPeer peer = (MenuPeer) getPeer();
|
||||
if (peer == null)
|
||||
return;
|
||||
|
||||
for (int i = count - 1; i >= index; i--)
|
||||
peer.delItem(i);
|
||||
for (int i = count - 1; i >= index; i--)
|
||||
peer.delItem(i);
|
||||
|
||||
item.addNotify();
|
||||
peer.addItem(item);
|
||||
item.addNotify();
|
||||
peer.addItem(item);
|
||||
|
||||
for (int i = index; i < count; i++)
|
||||
peer.addItem((MenuItem) items.elementAt (i));
|
||||
}
|
||||
// bear in mind that count is the number of items *before* the new
|
||||
// item was added
|
||||
for (int i = index + 1; i <= count; i++)
|
||||
peer.addItem((MenuItem) items.elementAt(i));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/**
|
||||
* Inserts an item with the specified label into this menu at the specified index.
|
||||
*
|
||||
* @param label The label of the item to add.
|
||||
* @param index The index of the menu item.
|
||||
*
|
||||
* @exception IllegalArgumentException If the index is less than zero.
|
||||
* @exception ArrayIndexOutOfBoundsException If the index is otherwise invalid.
|
||||
*/
|
||||
public void
|
||||
insert(String label, int index)
|
||||
{
|
||||
insert(new MenuItem(label), index);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/**
|
||||
* Adds a separator bar at the current menu location.
|
||||
*/
|
||||
public void
|
||||
addSeparator()
|
||||
{
|
||||
add(new MenuItem(separatorLabel));
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/**
|
||||
* Inserts a separator bar at the specified index value.
|
||||
*
|
||||
* @param index The index at which to insert a separator bar.
|
||||
*
|
||||
* @exception IllegalArgumentException If the index is less than zero.
|
||||
* @exception ArrayIndexOutOfBoundsException If the index is otherwise invalid.
|
||||
*/
|
||||
public void
|
||||
insertSeparator(int index)
|
||||
{
|
||||
insert(new MenuItem(separatorLabel), index);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/**
|
||||
* Deletes the item at the specified index from this menu.
|
||||
*
|
||||
* @param index The index of the item to remove.
|
||||
*
|
||||
* @exception ArrayIndexOutOfBoundsException If the index is otherwise invalid.
|
||||
*/
|
||||
public synchronized void
|
||||
remove(int index)
|
||||
{
|
||||
MenuItem item = (MenuItem) items.remove(index);
|
||||
|
||||
MenuPeer mp = (MenuPeer) getPeer();
|
||||
if (mp != null)
|
||||
{
|
||||
mp.delItem(index);
|
||||
item.removeNotify();
|
||||
}
|
||||
item.setParent(null);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/**
|
||||
* Removes the specifed item from the menu. If the specified component
|
||||
* does not exist, this method does nothing.
|
||||
*
|
||||
* @param item The component to remove.
|
||||
*/
|
||||
public void
|
||||
remove(MenuComponent item)
|
||||
{
|
||||
int index = items.indexOf(item);
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
remove(index);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/**
|
||||
* Removes all the elements from this menu.
|
||||
*/
|
||||
public synchronized void
|
||||
removeAll()
|
||||
{
|
||||
int count = getItemCount();
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
// We must always remove item 0.
|
||||
remove(0);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/**
|
||||
* Creates the native peer for this object.
|
||||
*/
|
||||
public void
|
||||
addNotify()
|
||||
{
|
||||
MenuPeer peer = (MenuPeer) getPeer();
|
||||
if (peer == null)
|
||||
{
|
||||
peer = getToolkit().createMenu(this);
|
||||
setPeer(peer);
|
||||
}
|
||||
|
||||
Enumeration e = items.elements();
|
||||
while (e.hasMoreElements())
|
||||
{
|
||||
MenuItem mi = (MenuItem)e.nextElement();
|
||||
mi.addNotify();
|
||||
peer.addItem(mi);
|
||||
}
|
||||
|
||||
super.addNotify ();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/**
|
||||
* Destroys the native peer for this object.
|
||||
*/
|
||||
public void
|
||||
removeNotify()
|
||||
{
|
||||
Enumeration e = items.elements();
|
||||
while (e.hasMoreElements())
|
||||
/**
|
||||
* Inserts an item with the specified label into this menu at the specified
|
||||
* index. If the index is greater than or equal to the number of items
|
||||
* already in the menu, the new item is added as the last item in the menu.
|
||||
*
|
||||
* @param label The label of the item to add.
|
||||
* @param index The index of the menu item (>= 0).
|
||||
*
|
||||
* @throws IllegalArgumentException If the index is less than zero.
|
||||
*/
|
||||
public void insert(String label, int index)
|
||||
{
|
||||
MenuItem mi = (MenuItem) e.nextElement();
|
||||
mi.removeNotify();
|
||||
insert(new MenuItem(label), index);
|
||||
}
|
||||
super.removeNotify();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/**
|
||||
* Adds a separator bar at the current menu location.
|
||||
*/
|
||||
public void addSeparator()
|
||||
{
|
||||
add(new MenuItem(separatorLabel));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a debugging string for this menu.
|
||||
*
|
||||
* @return A debugging string for this menu.
|
||||
*/
|
||||
public String
|
||||
paramString()
|
||||
{
|
||||
return (",tearOff=" + tearOff + ",isHelpMenu=" + isHelpMenu
|
||||
+ super.paramString());
|
||||
}
|
||||
/**
|
||||
* Inserts a separator bar at the specified index value.
|
||||
*
|
||||
* @param index The index at which to insert a separator bar.
|
||||
*
|
||||
* @exception IllegalArgumentException If the index is less than zero.
|
||||
* @exception ArrayIndexOutOfBoundsException If the index is otherwise invalid.
|
||||
*/
|
||||
public void insertSeparator(int index)
|
||||
{
|
||||
insert(new MenuItem(separatorLabel), index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the item at the specified index from this menu.
|
||||
*
|
||||
* @param index The index of the item to remove.
|
||||
*
|
||||
* @exception ArrayIndexOutOfBoundsException If the index is otherwise invalid.
|
||||
*/
|
||||
public synchronized void remove(int index)
|
||||
{
|
||||
MenuItem item = (MenuItem) items.remove(index);
|
||||
|
||||
MenuPeer mp = (MenuPeer) getPeer();
|
||||
if (mp != null)
|
||||
{
|
||||
mp.delItem(index);
|
||||
item.removeNotify();
|
||||
}
|
||||
item.setParent(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specifed item from the menu. If the specified component
|
||||
* does not exist, this method does nothing.
|
||||
*
|
||||
* @param item The component to remove.
|
||||
*/
|
||||
public void remove(MenuComponent item)
|
||||
{
|
||||
int index = items.indexOf(item);
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
remove(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all the elements from this menu.
|
||||
*/
|
||||
public synchronized void removeAll()
|
||||
{
|
||||
int count = getItemCount();
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
// We must always remove item 0.
|
||||
remove(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the native peer for this object.
|
||||
*/
|
||||
public void addNotify()
|
||||
{
|
||||
MenuPeer peer = (MenuPeer) getPeer();
|
||||
if (peer == null)
|
||||
{
|
||||
peer = getToolkit().createMenu(this);
|
||||
setPeer(peer);
|
||||
}
|
||||
|
||||
Enumeration e = items.elements();
|
||||
while (e.hasMoreElements())
|
||||
{
|
||||
MenuItem mi = (MenuItem)e.nextElement();
|
||||
mi.addNotify();
|
||||
peer.addItem(mi);
|
||||
}
|
||||
|
||||
super.addNotify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the native peer for this object.
|
||||
*/
|
||||
public void removeNotify()
|
||||
{
|
||||
Enumeration e = items.elements();
|
||||
while (e.hasMoreElements())
|
||||
{
|
||||
MenuItem mi = (MenuItem) e.nextElement();
|
||||
mi.removeNotify();
|
||||
}
|
||||
super.removeNotify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a debugging string for this menu.
|
||||
*
|
||||
* @return A debugging string for this menu.
|
||||
*/
|
||||
public String paramString()
|
||||
{
|
||||
return (",tearOff=" + tearOff + ",isHelpMenu=" + isHelpMenu
|
||||
+ super.paramString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic Accessibility class for Menu. Details get provided in derived
|
||||
|
|
|
@ -272,7 +272,7 @@ public class MenuBar extends MenuComponent
|
|||
*
|
||||
* @return a list of all shortcuts for the menus in this menu bar
|
||||
*/
|
||||
public synchronized Enumeration shortcuts()
|
||||
public synchronized Enumeration<MenuShortcut> shortcuts()
|
||||
{
|
||||
Vector shortcuts = new Vector();
|
||||
Enumeration e = menus.elements();
|
||||
|
|
|
@ -523,11 +523,11 @@ removeActionListener(ActionListener l)
|
|||
* ClassClassException is thrown.
|
||||
* @since 1.3
|
||||
*/
|
||||
public EventListener[] getListeners(Class listenerType)
|
||||
public <T extends EventListener> T[] getListeners(Class<T> listenerType)
|
||||
{
|
||||
if (listenerType == ActionListener.class)
|
||||
return getActionListeners();
|
||||
return (EventListener[]) Array.newInstance(listenerType, 0);
|
||||
return (T[]) getActionListeners();
|
||||
return (T[]) Array.newInstance(listenerType, 0);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
|
|
@ -38,6 +38,8 @@ exception statement from your version. */
|
|||
|
||||
package java.awt;
|
||||
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
/**
|
||||
* This class implements a keyboard accelerator for a menu item.
|
||||
*
|
||||
|
@ -70,6 +72,8 @@ private int key;
|
|||
*/
|
||||
private boolean usesShift;
|
||||
|
||||
private String keyName;
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/**
|
||||
|
@ -99,6 +103,7 @@ MenuShortcut(int key, boolean usesShift)
|
|||
{
|
||||
this.key = key;
|
||||
this.usesShift = usesShift;
|
||||
setKeyName(key);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
@ -181,7 +186,11 @@ equals(Object obj)
|
|||
public String
|
||||
toString()
|
||||
{
|
||||
return(getClass().getName() + "[" + paramString () + "]");
|
||||
String temp = "Ctrl+";
|
||||
if (usesShift)
|
||||
temp = temp + "Shift+";
|
||||
temp = temp + keyName;
|
||||
return temp;
|
||||
}
|
||||
|
||||
public int
|
||||
|
@ -204,4 +213,224 @@ paramString()
|
|||
return "key=" + key + ",usesShift=" + usesShift;
|
||||
}
|
||||
|
||||
} // class MenuShortcut
|
||||
private void
|
||||
setKeyName(int key)
|
||||
{
|
||||
if (key == '\n')
|
||||
keyName = "Enter";
|
||||
else if (key == '\b')
|
||||
keyName = "Backspace";
|
||||
else if (key == '\t')
|
||||
keyName = "Tab";
|
||||
else if (key == ' ')
|
||||
keyName = "Space";
|
||||
else if (key == ',')
|
||||
keyName = "Comma";
|
||||
else if (key == '.')
|
||||
keyName = "Period";
|
||||
else if (key == '/')
|
||||
keyName = "Slash";
|
||||
else if (key == '\\')
|
||||
keyName = "Back Slash";
|
||||
else if (key == ';')
|
||||
keyName = "Semicolon";
|
||||
else if (key == '=')
|
||||
keyName = "Equals";
|
||||
else if (key == '[')
|
||||
keyName = "Open Bracket";
|
||||
else if (key == ']')
|
||||
keyName = "Close Bracket";
|
||||
else if (key == '0')
|
||||
keyName = "0";
|
||||
else if (key == '1')
|
||||
keyName = "1";
|
||||
else if (key == '2')
|
||||
keyName = "2";
|
||||
else if (key == '3')
|
||||
keyName = "3";
|
||||
else if (key == '4')
|
||||
keyName = "4";
|
||||
else if (key == '5')
|
||||
keyName = "5";
|
||||
else if (key == '6')
|
||||
keyName = "6";
|
||||
else if (key == '7')
|
||||
keyName = "7";
|
||||
else if (key == '8')
|
||||
keyName = "8";
|
||||
else if (key == '9')
|
||||
keyName = "9";
|
||||
else if (key == 'A')
|
||||
keyName = "A";
|
||||
else if (key == 'B')
|
||||
keyName = "B";
|
||||
else if (key == 'C')
|
||||
keyName = "C";
|
||||
else if (key == 'D')
|
||||
keyName = "D";
|
||||
else if (key == 'E')
|
||||
keyName = "E";
|
||||
else if (key == 'F')
|
||||
keyName = "F";
|
||||
else if (key == 'G')
|
||||
keyName = "G";
|
||||
else if (key == 'H')
|
||||
keyName = "H";
|
||||
else if (key == 'I')
|
||||
keyName = "I";
|
||||
else if (key == 'J')
|
||||
keyName = "J";
|
||||
else if (key == 'K')
|
||||
keyName = "K";
|
||||
else if (key == 'L')
|
||||
keyName = "L";
|
||||
else if (key == 'M')
|
||||
keyName = "M";
|
||||
else if (key == 'N')
|
||||
keyName = "N";
|
||||
else if (key == 'O')
|
||||
keyName = "O";
|
||||
else if (key == 'P')
|
||||
keyName = "P";
|
||||
else if (key == 'Q')
|
||||
keyName = "Q";
|
||||
else if (key == 'R')
|
||||
keyName = "R";
|
||||
else if (key == 'S')
|
||||
keyName = "S";
|
||||
else if (key == 'T')
|
||||
keyName = "T";
|
||||
else if (key == 'U')
|
||||
keyName = "U";
|
||||
else if (key == 'V')
|
||||
keyName = "V";
|
||||
else if (key == 'W')
|
||||
keyName = "W";
|
||||
else if (key == 'X')
|
||||
keyName = "X";
|
||||
else if (key == 'Y')
|
||||
keyName = "Y";
|
||||
else if (key == 'Z')
|
||||
keyName = "Z";
|
||||
else if (key == 3)
|
||||
keyName = "Cancel";
|
||||
else if (key == 12)
|
||||
keyName = "Clear";
|
||||
else if (key == 16)
|
||||
keyName = "Shift";
|
||||
else if (key == 17)
|
||||
keyName = "Ctrl";
|
||||
else if (key == 18)
|
||||
keyName = "Alt";
|
||||
else if (key == 19)
|
||||
keyName = "Pause";
|
||||
else if (key == 20)
|
||||
keyName = "Caps Lock";
|
||||
else if (key == 21)
|
||||
keyName = "Kana";
|
||||
else if (key == 24)
|
||||
keyName = "Final";
|
||||
else if (key == 25)
|
||||
keyName = "Kanji";
|
||||
else if (key == 27)
|
||||
keyName = "Escape";
|
||||
else if (key == 28)
|
||||
keyName = "Convert";
|
||||
else if (key == 29)
|
||||
keyName = "No Convert";
|
||||
else if (key == 30)
|
||||
keyName = "Accept";
|
||||
else if (key == 31)
|
||||
keyName = "Mode Change";
|
||||
else if (key == 33)
|
||||
keyName = "Page Up";
|
||||
else if (key == 34)
|
||||
keyName = "Page Down";
|
||||
else if (key == 35)
|
||||
keyName = "End";
|
||||
else if (key == 36)
|
||||
keyName = "Home";
|
||||
else if (key == 37)
|
||||
keyName = "Left";
|
||||
else if (key == 38)
|
||||
keyName = "Up";
|
||||
else if (key == 39)
|
||||
keyName = "Right";
|
||||
else if (key == 40)
|
||||
keyName = "Down";
|
||||
else if (key == 96)
|
||||
keyName = "NumPad-0";
|
||||
else if (key == 97)
|
||||
keyName = "NumPad-1";
|
||||
else if (key == 98)
|
||||
keyName = "NumPad-2";
|
||||
else if (key == 99)
|
||||
keyName = "NumPad-3";
|
||||
else if (key == 100)
|
||||
keyName = "NumPad-4";
|
||||
else if (key == 101)
|
||||
keyName = "NumPad-5";
|
||||
else if (key == 102)
|
||||
keyName = "NumPad-6";
|
||||
else if (key == 103)
|
||||
keyName = "NumPad-7";
|
||||
else if (key == 104)
|
||||
keyName = "NumPad-8";
|
||||
else if (key == 105)
|
||||
keyName = "NumPad-9";
|
||||
else if (key == 106)
|
||||
keyName = "NumPad *";
|
||||
else if (key == 107)
|
||||
keyName = "NumPad +";
|
||||
else if (key == 108)
|
||||
keyName = "NumPad ,";
|
||||
else if (key == 109)
|
||||
keyName = "NumPad -";
|
||||
else if (key == 110)
|
||||
keyName = "NumPad .";
|
||||
else if (key == 111)
|
||||
keyName = "NumPad /";
|
||||
else if (key == 112)
|
||||
keyName = "F1";
|
||||
else if (key == 113)
|
||||
keyName = "F2";
|
||||
else if (key == 114)
|
||||
keyName = "F3";
|
||||
else if (key == 115)
|
||||
keyName = "F4";
|
||||
else if (key == 116)
|
||||
keyName = "F5";
|
||||
else if (key == 117)
|
||||
keyName = "F6";
|
||||
else if (key == 118)
|
||||
keyName = "F7";
|
||||
else if (key == 119)
|
||||
keyName = "F8";
|
||||
else if (key == 120)
|
||||
keyName = "F9";
|
||||
else if (key == 121)
|
||||
keyName = "F10";
|
||||
else if (key == 122)
|
||||
keyName = "F11";
|
||||
else if (key == 123)
|
||||
keyName = "F12";
|
||||
else if (key == 127)
|
||||
keyName = "Delete";
|
||||
else if (key == 144)
|
||||
keyName = "Num Lock";
|
||||
else if (key == 145)
|
||||
keyName = "Scroll Lock";
|
||||
else if (key == 154)
|
||||
keyName = "Print Screen";
|
||||
else if (key == 155)
|
||||
keyName = "Insert";
|
||||
else if (key == 156)
|
||||
keyName = "Help";
|
||||
else if (key == 157)
|
||||
keyName = "Meta";
|
||||
else if (key == 192)
|
||||
keyName = "Back Quote";
|
||||
else if (key == 222)
|
||||
keyName = "Quote";
|
||||
}
|
||||
} // class MenuShortcut
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* Rectangle.java -- represents a graphics rectangle
|
||||
Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2006, Free Software Foundation
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -119,7 +119,6 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable
|
|||
* coordinates of the specified rectangle.
|
||||
*
|
||||
* @param r the rectangle to copy from
|
||||
* @throws NullPointerException if r is null
|
||||
* @since 1.1
|
||||
*/
|
||||
public Rectangle(Rectangle r)
|
||||
|
@ -168,7 +167,6 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable
|
|||
*
|
||||
* @param p the upper left corner of the rectangle
|
||||
* @param d the width and height of the rectangle
|
||||
* @throws NullPointerException if p or d is null
|
||||
*/
|
||||
public Rectangle(Point p, Dimension d)
|
||||
{
|
||||
|
@ -185,7 +183,7 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable
|
|||
* @param p the upper left corner of the rectangle
|
||||
*/
|
||||
public Rectangle(Point p)
|
||||
{
|
||||
{
|
||||
x = p.x;
|
||||
y = p.y;
|
||||
}
|
||||
|
@ -198,7 +196,7 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable
|
|||
* @param d the width and height of the rectangle
|
||||
*/
|
||||
public Rectangle(Dimension d)
|
||||
{
|
||||
{
|
||||
width = d.width;
|
||||
height = d.height;
|
||||
}
|
||||
|
@ -299,8 +297,10 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable
|
|||
}
|
||||
|
||||
/**
|
||||
* Updates this rectangle to have the specified dimensions, as rounded to
|
||||
* integers.
|
||||
* Updates this rectangle to have the specified dimensions, rounded to the
|
||||
* integer precision used by this class (the values are rounded "outwards" so
|
||||
* that the stored rectangle completely encloses the specified double
|
||||
* precision rectangle).
|
||||
*
|
||||
* @param x the new X coordinate of the upper left hand corner
|
||||
* @param y the new Y coordinate of the upper left hand corner
|
||||
|
@ -310,10 +310,10 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable
|
|||
*/
|
||||
public void setRect(double x, double y, double width, double height)
|
||||
{
|
||||
this.x = (int) x;
|
||||
this.y = (int) y;
|
||||
this.width = (int) width;
|
||||
this.height = (int) height;
|
||||
this.x = (int) Math.floor(x);
|
||||
this.y = (int) Math.floor(y);
|
||||
this.width = (int) Math.ceil(x + width) - this.x;
|
||||
this.height = (int) Math.ceil(y + height) - this.y;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -54,7 +54,8 @@ import java.util.Set;
|
|||
* @author Rolf W. Rasmussen (rolfwr@ii.uib.no)
|
||||
* @author Eric Blake (ebb9@email.byu.edu)
|
||||
*/
|
||||
public class RenderingHints implements Map, Cloneable
|
||||
public class RenderingHints
|
||||
implements Map<Object,Object>, Cloneable
|
||||
{
|
||||
/**
|
||||
* The base class used to represent keys.
|
||||
|
@ -550,7 +551,7 @@ public class RenderingHints implements Map, Cloneable
|
|||
* @param init a map containing a collection of hints (<code>null</code>
|
||||
* permitted).
|
||||
*/
|
||||
public RenderingHints(Map init)
|
||||
public RenderingHints(Map<Key,?> init)
|
||||
{
|
||||
if (init != null)
|
||||
putAll(init);
|
||||
|
@ -704,7 +705,7 @@ public class RenderingHints implements Map, Cloneable
|
|||
* @throws IllegalArgumentException if the map contains a value that is
|
||||
* not compatible with its key.
|
||||
*/
|
||||
public void putAll(Map m)
|
||||
public void putAll(Map<?,?> m)
|
||||
{
|
||||
// preprocess map to generate appropriate exceptions
|
||||
Iterator iterator = m.keySet().iterator();
|
||||
|
@ -723,7 +724,7 @@ public class RenderingHints implements Map, Cloneable
|
|||
*
|
||||
* @return A set of keys.
|
||||
*/
|
||||
public Set keySet()
|
||||
public Set<Object> keySet()
|
||||
{
|
||||
return hintMap.keySet();
|
||||
}
|
||||
|
@ -735,7 +736,7 @@ public class RenderingHints implements Map, Cloneable
|
|||
*
|
||||
* @return A collection of values.
|
||||
*/
|
||||
public Collection values()
|
||||
public Collection<Object> values()
|
||||
{
|
||||
return hintMap.values();
|
||||
}
|
||||
|
@ -745,7 +746,7 @@ public class RenderingHints implements Map, Cloneable
|
|||
*
|
||||
* @return A set of entries.
|
||||
*/
|
||||
public Set entrySet()
|
||||
public Set<Map.Entry<Object,Object>> entrySet()
|
||||
{
|
||||
return Collections.unmodifiableSet(hintMap.entrySet());
|
||||
}
|
||||
|
|
|
@ -338,10 +338,15 @@ getVScrollbarWidth()
|
|||
* Returns the current scroll position of the viewport.
|
||||
*
|
||||
* @return The current scroll position of the viewport.
|
||||
*
|
||||
* @throws NullPointerException if the scrollpane does have a child.
|
||||
*/
|
||||
public Point
|
||||
getScrollPosition()
|
||||
{
|
||||
if (getComponentCount() == 0)
|
||||
throw new NullPointerException();
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
|
@ -380,20 +385,35 @@ setScrollPosition(Point scrollPosition) throws IllegalArgumentException
|
|||
* @param x The new X coordinate of the scroll position.
|
||||
* @param y The new Y coordinate of the scroll position.
|
||||
*
|
||||
* @throws NullPointerException if scrollpane does not have a child.
|
||||
*
|
||||
* @exception IllegalArgumentException If the specified value is outside
|
||||
* the legal scrolling range.
|
||||
*/
|
||||
public void
|
||||
setScrollPosition(int x, int y)
|
||||
{
|
||||
if (getComponentCount() == 0)
|
||||
throw new NullPointerException("child is null");
|
||||
|
||||
if (x > (int) (getComponent(0).getWidth() - getViewportSize().getWidth()))
|
||||
x = (int) (getComponent(0).getWidth() - getViewportSize().getWidth());
|
||||
if (y > (int) (getComponent(0).getHeight() - getViewportSize().getHeight()))
|
||||
y = (int) (getComponent(0).getHeight() - getViewportSize().getHeight());
|
||||
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
if (y < 0)
|
||||
y = 0;
|
||||
|
||||
Adjustable h = getHAdjustable();
|
||||
Adjustable v = getVAdjustable();
|
||||
|
||||
|
||||
if (h != null)
|
||||
h.setValue(x);
|
||||
if (v != null)
|
||||
v.setValue(y);
|
||||
|
||||
|
||||
ScrollPanePeer spp = (ScrollPanePeer)getPeer();
|
||||
if (spp != null)
|
||||
spp.setScrollPosition(x, y);
|
||||
|
@ -414,7 +434,7 @@ addNotify()
|
|||
super.addNotify();
|
||||
|
||||
Component[] list = getComponents();
|
||||
if (list != null && list.length > 0 && ! (list[0] instanceof Panel))
|
||||
if (list != null && list.length > 0 && list[0].isLightweight())
|
||||
{
|
||||
Panel panel = new Panel();
|
||||
panel.setLayout(new BorderLayout());
|
||||
|
@ -453,9 +473,7 @@ removeNotify()
|
|||
if ((list != null) && (list.length > 0))
|
||||
remove(list[0]);
|
||||
|
||||
super.addImpl(component, constraints, -1);
|
||||
|
||||
doLayout();
|
||||
super.addImpl(component, constraints, index);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
@ -507,6 +525,8 @@ layout()
|
|||
p.y = dim.height;
|
||||
|
||||
setScrollPosition (p);
|
||||
|
||||
list[0].setLocation(new Point());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -518,11 +538,12 @@ layout()
|
|||
* not have layout managers.
|
||||
*
|
||||
* @param layoutManager Ignored
|
||||
* @throws AWTError Always throws this error when called.
|
||||
*/
|
||||
public final void
|
||||
setLayout(LayoutManager layoutManager)
|
||||
{
|
||||
return;
|
||||
throw new AWTError("ScrollPane controls layout");
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
@ -553,16 +574,37 @@ paramString()
|
|||
+ getX() + ","
|
||||
+ getY() + ","
|
||||
+ getWidth() + "x" + getHeight() + ","
|
||||
+ "ScrollPosition=(" + scrollPosition.getX() + ","
|
||||
+ scrollPosition.getY() + "),"
|
||||
+ getIsValidString() + ","
|
||||
+ "ScrollPosition=(" + scrollPosition.x + ","
|
||||
+ scrollPosition.y + "),"
|
||||
+ "Insets=(" + insets.top + ","
|
||||
+ insets.left + ","
|
||||
+ insets.bottom + ","
|
||||
+ insets.right + "),"
|
||||
+ "ScrollbarDisplayPolicy=" + getScrollbarDisplayPolicy() + ","
|
||||
+ "ScrollbarDisplayPolicy=" + getScrollbarDisplayPolicyString() + ","
|
||||
+ "wheelScrollingEnabled=" + isWheelScrollingEnabled();
|
||||
}
|
||||
|
||||
private String
|
||||
getScrollbarDisplayPolicyString()
|
||||
{
|
||||
if (getScrollbarDisplayPolicy() == 0)
|
||||
return "as-needed";
|
||||
else if (getScrollbarDisplayPolicy() == 1)
|
||||
return "always";
|
||||
else
|
||||
return "never";
|
||||
}
|
||||
|
||||
private String
|
||||
getIsValidString()
|
||||
{
|
||||
if (isValid())
|
||||
return "valid";
|
||||
else
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether or not an event is enabled.
|
||||
*
|
||||
|
|
|
@ -145,14 +145,26 @@ public class ScrollPaneAdjustable
|
|||
this.blockIncrement = blockIncrement;
|
||||
}
|
||||
|
||||
public void setMaximum (int maximum)
|
||||
/**
|
||||
* This method should never be called.
|
||||
*
|
||||
* @param maximum The maximum value to be set.
|
||||
* @throws AWTError Always throws this error when called.
|
||||
*/
|
||||
public void setMaximum (int maximum) throws AWTError
|
||||
{
|
||||
this.maximum = maximum;
|
||||
throw new AWTError("Can be set by scrollpane only");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
*
|
||||
* @param minimum The minimum value to be set.
|
||||
* @throws AWTError Always throws this error when called.
|
||||
*/
|
||||
public void setMinimum (int minimum)
|
||||
{
|
||||
this.minimum = minimum;
|
||||
throw new AWTError("Can be set by scrollpane only");
|
||||
}
|
||||
|
||||
public void setUnitIncrement (int unitIncrement)
|
||||
|
@ -171,20 +183,36 @@ public class ScrollPaneAdjustable
|
|||
maximum = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
*
|
||||
* @param visibleAmount The visible amount to be set.
|
||||
* @throws AWTError Always throws this error when called.
|
||||
*/
|
||||
public void setVisibleAmount (int visibleAmount)
|
||||
{
|
||||
this.visibleAmount = visibleAmount;
|
||||
throw new AWTError("Can be set by scrollpane only");
|
||||
}
|
||||
|
||||
public String paramString ()
|
||||
{
|
||||
return ("scrollpane=" + sp + ", orientation=" + orientation
|
||||
+ ", value=" + value + ", minimum=" + minimum
|
||||
+ ", maximum=" + maximum + ", visibleAmount=" + visibleAmount
|
||||
+ ", unitIncrement=" + unitIncrement
|
||||
+ ", blockIncrement=" + blockIncrement);
|
||||
return paramStringHelper()
|
||||
+ ",[" + getMinimum() + ".." + getMaximum()
|
||||
+ "],val=" + getValue()
|
||||
+ ",vis=" + getVisibleAmount()
|
||||
+ ",unit=" + getUnitIncrement()
|
||||
+ ",block=" + getBlockIncrement()
|
||||
+ ",isAdjusting=" + valueIsAdjusting;
|
||||
}
|
||||
|
||||
private String paramStringHelper()
|
||||
{
|
||||
if (getOrientation() == HORIZONTAL)
|
||||
return "horizontal";
|
||||
else
|
||||
return "vertical";
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return getClass().getName() + "[" + paramString() + "]";
|
||||
|
@ -209,5 +237,6 @@ public class ScrollPaneAdjustable
|
|||
{
|
||||
this.valueIsAdjusting = valueIsAdjusting;
|
||||
}
|
||||
|
||||
} // class ScrollPaneAdjustable
|
||||
|
||||
|
|
|
@ -341,17 +341,22 @@ public class Scrollbar extends Component implements Accessible, Adjustable
|
|||
public synchronized void setValues(int value, int visibleAmount,
|
||||
int minimum, int maximum)
|
||||
{
|
||||
if (maximum < minimum)
|
||||
maximum = minimum;
|
||||
if (visibleAmount <= 0)
|
||||
visibleAmount = 1;
|
||||
|
||||
if (maximum <= minimum)
|
||||
maximum = minimum + 1;
|
||||
|
||||
if (value < minimum)
|
||||
value = minimum;
|
||||
|
||||
if (value > maximum)
|
||||
value = maximum;
|
||||
|
||||
if (visibleAmount > maximum - minimum)
|
||||
visibleAmount = maximum - minimum;
|
||||
|
||||
// According to documentation, the actual maximum
|
||||
// value is (maximum - visibleAmount)
|
||||
if (value > maximum - visibleAmount)
|
||||
value = maximum - visibleAmount;
|
||||
|
||||
ScrollbarPeer peer = (ScrollbarPeer) getPeer();
|
||||
if (peer != null
|
||||
|
@ -362,30 +367,7 @@ public class Scrollbar extends Component implements Accessible, Adjustable
|
|||
this.value = value;
|
||||
this.visibleAmount = visibleAmount;
|
||||
this.minimum = minimum;
|
||||
this.maximum = maximum;
|
||||
|
||||
int range = maximum - minimum;
|
||||
if (lineIncrement > range)
|
||||
{
|
||||
if (range == 0)
|
||||
lineIncrement = 1;
|
||||
else
|
||||
lineIncrement = range;
|
||||
|
||||
if (peer != null)
|
||||
peer.setLineIncrement(lineIncrement);
|
||||
}
|
||||
|
||||
if (pageIncrement > range)
|
||||
{
|
||||
if (range == 0)
|
||||
pageIncrement = 1;
|
||||
else
|
||||
pageIncrement = range;
|
||||
|
||||
if (peer != null)
|
||||
peer.setPageIncrement(pageIncrement);
|
||||
}
|
||||
this.maximum = maximum;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -437,19 +419,13 @@ public class Scrollbar extends Component implements Accessible, Adjustable
|
|||
{
|
||||
if (lineIncrement < 0)
|
||||
throw new IllegalArgumentException("Unit increment less than zero.");
|
||||
|
||||
int range = maximum - minimum;
|
||||
if (lineIncrement > range)
|
||||
{
|
||||
if (range == 0)
|
||||
lineIncrement = 1;
|
||||
else
|
||||
lineIncrement = range;
|
||||
}
|
||||
|
||||
if (lineIncrement == this.lineIncrement)
|
||||
|
||||
if (lineIncrement == 0)
|
||||
lineIncrement = 1;
|
||||
|
||||
if (lineIncrement == this.lineIncrement)
|
||||
return;
|
||||
|
||||
|
||||
this.lineIncrement = lineIncrement;
|
||||
|
||||
ScrollbarPeer peer = (ScrollbarPeer) getPeer();
|
||||
|
@ -507,15 +483,9 @@ public class Scrollbar extends Component implements Accessible, Adjustable
|
|||
if (pageIncrement < 0)
|
||||
throw new IllegalArgumentException("Block increment less than zero.");
|
||||
|
||||
int range = maximum - minimum;
|
||||
if (pageIncrement > range)
|
||||
{
|
||||
if (range == 0)
|
||||
pageIncrement = 1;
|
||||
else
|
||||
pageIncrement = range;
|
||||
}
|
||||
|
||||
if (pageIncrement == 0)
|
||||
pageIncrement = 1;
|
||||
|
||||
if (pageIncrement == this.pageIncrement)
|
||||
return;
|
||||
|
||||
|
@ -647,7 +617,7 @@ public class Scrollbar extends Component implements Accessible, Adjustable
|
|||
* @exception ClassCastException If listenerType doesn't specify a class or
|
||||
* interface that implements java.util.EventListener.
|
||||
*/
|
||||
public EventListener[] getListeners(Class listenerType)
|
||||
public <T extends EventListener> T[] getListeners(Class<T> listenerType)
|
||||
{
|
||||
if (listenerType == AdjustmentListener.class)
|
||||
return AWTEventMulticaster.getListeners(adjustment_listeners,
|
||||
|
|
|
@ -284,11 +284,7 @@ public class TextArea extends TextComponent implements java.io.Serializable
|
|||
}
|
||||
|
||||
/**
|
||||
* Retrieve the minimum size for this text area, considering the
|
||||
* text area's current row and column values. A text area's minimum
|
||||
* size depends on the number of rows and columns of text it would
|
||||
* prefer to display, and on the size of the font in which the text
|
||||
* would be displayed.
|
||||
* Retrieve the minimum size for this text area.
|
||||
*
|
||||
* @return The minimum size for this text field.
|
||||
*/
|
||||
|
@ -298,11 +294,8 @@ public class TextArea extends TextComponent implements java.io.Serializable
|
|||
}
|
||||
|
||||
/**
|
||||
* Retrieve the minimum size that this text area would have if its
|
||||
* row and column values were equal to those specified. A text
|
||||
* area's minimum size depends on the number of rows and columns of
|
||||
* text it would prefer to display, and on the size of the font in
|
||||
* which the text would be displayed.
|
||||
* Retrieve the minimum size for this text area. If the minimum
|
||||
* size has been set, then rows and columns are used in the calculation.
|
||||
*
|
||||
* @param rows The number of rows to use in the minimum size
|
||||
* calculation.
|
||||
|
@ -317,12 +310,8 @@ public class TextArea extends TextComponent implements java.io.Serializable
|
|||
}
|
||||
|
||||
/**
|
||||
* Retrieve the minimum size for this text area, considering the
|
||||
* text area's current row and column values. A text area's minimum
|
||||
* size depends on the number of rows and columns of text it would
|
||||
* prefer to display, and on the size of the font in which the text
|
||||
* would be displayed.
|
||||
*
|
||||
* Retrieve the minimum size for this text area.
|
||||
*
|
||||
* @return The minimum size for this text area.
|
||||
*
|
||||
* @deprecated This method is deprecated in favor of
|
||||
|
@ -334,11 +323,8 @@ public class TextArea extends TextComponent implements java.io.Serializable
|
|||
}
|
||||
|
||||
/**
|
||||
* Retrieve the minimum size that this text area would have if its
|
||||
* row and column values were equal to those specified. A text
|
||||
* area's minimum size depends on the number of rows and columns of
|
||||
* text it would prefer to display, and on the size of the font in
|
||||
* which the text would be displayed.
|
||||
* Retrieve the minimum size for this text area. If the minimum
|
||||
* size has been set, then rows and columns are used in the calculation.
|
||||
*
|
||||
* @param rows The number of rows to use in the minimum size
|
||||
* calculation.
|
||||
|
@ -352,21 +338,18 @@ public class TextArea extends TextComponent implements java.io.Serializable
|
|||
*/
|
||||
public Dimension minimumSize (int rows, int columns)
|
||||
{
|
||||
if (isMinimumSizeSet())
|
||||
return new Dimension(minSize);
|
||||
|
||||
TextAreaPeer peer = (TextAreaPeer) getPeer ();
|
||||
|
||||
// Sun returns Dimension (0,0) in this case.
|
||||
if (peer == null)
|
||||
return new Dimension (0, 0);
|
||||
return new Dimension (getWidth(), getHeight());
|
||||
|
||||
return peer.getMinimumSize (rows, columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the preferred size for this text area, considering the
|
||||
* text area's current row and column values. A text area's preferred
|
||||
* size depends on the number of rows and columns of text it would
|
||||
* prefer to display, and on the size of the font in which the text
|
||||
* would be displayed.
|
||||
* Retrieve the preferred size for this text area.
|
||||
*
|
||||
* @return The preferred size for this text field.
|
||||
*/
|
||||
|
@ -376,11 +359,8 @@ public class TextArea extends TextComponent implements java.io.Serializable
|
|||
}
|
||||
|
||||
/**
|
||||
* Retrieve the preferred size that this text area would have if its
|
||||
* row and column values were equal to those specified. A text
|
||||
* area's preferred size depends on the number of rows and columns
|
||||
* of text it would prefer to display, and on the size of the font
|
||||
* in which the text would be displayed.
|
||||
* Retrieve the preferred size for this text area. If the preferred
|
||||
* size has been set, then rows and columns are used in the calculation.
|
||||
*
|
||||
* @param rows The number of rows to use in the preferred size
|
||||
* calculation.
|
||||
|
@ -395,11 +375,7 @@ public class TextArea extends TextComponent implements java.io.Serializable
|
|||
}
|
||||
|
||||
/**
|
||||
* Retrieve the preferred size for this text area, considering the
|
||||
* text area's current row and column values. A text area's preferred
|
||||
* size depends on the number of rows and columns of text it would
|
||||
* prefer to display, and on the size of the font in which the text
|
||||
* would be displayed.
|
||||
* Retrieve the preferred size for this text area.
|
||||
*
|
||||
* @return The preferred size for this text field.
|
||||
*
|
||||
|
@ -412,11 +388,8 @@ public class TextArea extends TextComponent implements java.io.Serializable
|
|||
}
|
||||
|
||||
/**
|
||||
* Retrieve the preferred size that this text area would have if its
|
||||
* row and column values were equal to those specified. A text
|
||||
* area's preferred size depends on the number of rows and columns
|
||||
* of text it would prefer to display, and on the size of the font
|
||||
* in which the text would be displayed.
|
||||
* Retrieve the preferred size for this text area. If the preferred
|
||||
* size has been set, then rows and columns are used in the calculation.
|
||||
*
|
||||
* @param rows The number of rows to use in the preferred size
|
||||
* calculation.
|
||||
|
@ -430,11 +403,12 @@ public class TextArea extends TextComponent implements java.io.Serializable
|
|||
*/
|
||||
public Dimension preferredSize (int rows, int columns)
|
||||
{
|
||||
if (isPreferredSizeSet())
|
||||
return new Dimension(prefSize);
|
||||
|
||||
TextAreaPeer peer = (TextAreaPeer) getPeer ();
|
||||
|
||||
// Sun returns Dimension (0,0) in this case.
|
||||
if (peer == null)
|
||||
return new Dimension (0, 0);
|
||||
return new Dimension (getWidth(), getHeight());
|
||||
|
||||
return peer.getPreferredSize (rows, columns);
|
||||
}
|
||||
|
|
|
@ -391,7 +391,9 @@ public class TextComponent extends Component
|
|||
*/
|
||||
public synchronized void setSelectionStart(int selectionStart)
|
||||
{
|
||||
select(selectionStart, getSelectionEnd());
|
||||
select(selectionStart,
|
||||
(getSelectionEnd() < selectionStart)
|
||||
? selectionStart : getSelectionEnd());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -610,7 +612,7 @@ public class TextComponent extends Component
|
|||
* @exception ClassCastException If listenerType doesn't specify a class or
|
||||
* interface that implements java.util.EventListener.
|
||||
*/
|
||||
public EventListener[] getListeners(Class listenerType)
|
||||
public <T extends EventListener> T[] getListeners(Class<T> listenerType)
|
||||
{
|
||||
if (listenerType == TextListener.class)
|
||||
return AWTEventMulticaster.getListeners(textListener, listenerType);
|
||||
|
|
|
@ -264,9 +264,12 @@ public class TextField extends TextComponent
|
|||
*/
|
||||
public Dimension minimumSize(int columns)
|
||||
{
|
||||
if (isMinimumSizeSet())
|
||||
return new Dimension(minSize);
|
||||
|
||||
TextFieldPeer peer = (TextFieldPeer) getPeer ();
|
||||
if (peer == null)
|
||||
return null; // FIXME: What do we do if there is no peer?
|
||||
return new Dimension(getWidth(), getHeight());
|
||||
|
||||
return peer.getMinimumSize (columns);
|
||||
}
|
||||
|
@ -316,10 +319,13 @@ public class TextField extends TextComponent
|
|||
*/
|
||||
public Dimension preferredSize(int columns)
|
||||
{
|
||||
if (isPreferredSizeSet())
|
||||
return new Dimension(prefSize);
|
||||
|
||||
TextFieldPeer peer = (TextFieldPeer) getPeer ();
|
||||
if (peer == null)
|
||||
return new Dimension (0, 0);
|
||||
|
||||
return new Dimension (getWidth(), getHeight());
|
||||
|
||||
return peer.getPreferredSize (columns);
|
||||
}
|
||||
|
||||
|
@ -422,7 +428,7 @@ public class TextField extends TextComponent
|
|||
*
|
||||
* @since 1.3
|
||||
*/
|
||||
public EventListener[] getListeners (Class listenerType)
|
||||
public <T extends EventListener> T[] getListeners (Class<T> listenerType)
|
||||
{
|
||||
if (listenerType == ActionListener.class)
|
||||
return AWTEventMulticaster.getListeners (action_listeners, listenerType);
|
||||
|
|
|
@ -41,6 +41,7 @@ package java.awt;
|
|||
|
||||
import gnu.classpath.SystemProperties;
|
||||
import gnu.java.awt.peer.GLightweightPeer;
|
||||
import gnu.java.awt.peer.headless.HeadlessToolkit;
|
||||
|
||||
import java.awt.datatransfer.Clipboard;
|
||||
import java.awt.dnd.DragGestureEvent;
|
||||
|
@ -51,6 +52,7 @@ import java.awt.dnd.peer.DragSourceContextPeer;
|
|||
import java.awt.event.AWTEventListener;
|
||||
import java.awt.event.AWTEventListenerProxy;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.font.TextAttribute;
|
||||
import java.awt.im.InputMethodHighlight;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.ImageObserver;
|
||||
|
@ -86,6 +88,7 @@ import java.net.URL;
|
|||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
@ -119,7 +122,8 @@ public abstract class Toolkit
|
|||
/** The toolkit properties. */
|
||||
private static Properties props = new Properties();
|
||||
|
||||
protected final Map desktopProperties = new Properties();
|
||||
protected final Map<String,Object> desktopProperties =
|
||||
new Hashtable<String,Object>();
|
||||
|
||||
protected final PropertyChangeSupport desktopPropsSupport
|
||||
= new PropertyChangeSupport(this);
|
||||
|
@ -130,6 +134,11 @@ public abstract class Toolkit
|
|||
*/
|
||||
AWTEventListenerProxy[] awtEventListeners;
|
||||
|
||||
/**
|
||||
* The shared peer for all lightweight components.
|
||||
*/
|
||||
private GLightweightPeer lightweightPeer;
|
||||
|
||||
/**
|
||||
* Default constructor for subclasses.
|
||||
*/
|
||||
|
@ -379,7 +388,9 @@ public abstract class Toolkit
|
|||
*/
|
||||
protected LightweightPeer createComponent(Component target)
|
||||
{
|
||||
return new GLightweightPeer(target);
|
||||
if (lightweightPeer == null)
|
||||
lightweightPeer = new GLightweightPeer();
|
||||
return lightweightPeer;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -540,10 +551,11 @@ public abstract class Toolkit
|
|||
*
|
||||
* @throws AWTError If the toolkit cannot be loaded.
|
||||
*/
|
||||
public static Toolkit getDefaultToolkit()
|
||||
public static synchronized Toolkit getDefaultToolkit()
|
||||
{
|
||||
if (toolkit != null)
|
||||
return toolkit;
|
||||
|
||||
String toolkit_name = SystemProperties.getProperty("awt.toolkit",
|
||||
default_toolkit_name);
|
||||
try
|
||||
|
@ -573,8 +585,18 @@ public abstract class Toolkit
|
|||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
AWTError e = new AWTError("Cannot load AWT toolkit: " + toolkit_name);
|
||||
throw (AWTError) e.initCause(t);
|
||||
// Check for the headless property.
|
||||
if (GraphicsEnvironment.isHeadless())
|
||||
{
|
||||
toolkit = new HeadlessToolkit();
|
||||
return toolkit;
|
||||
}
|
||||
else
|
||||
{
|
||||
AWTError e = new AWTError("Cannot load AWT toolkit: "
|
||||
+ toolkit_name);
|
||||
throw (AWTError) e.initCause(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -964,8 +986,8 @@ public abstract class Toolkit
|
|||
/**
|
||||
* @since 1.3
|
||||
*/
|
||||
public DragGestureRecognizer
|
||||
createDragGestureRecognizer(Class recognizer, DragSource ds,
|
||||
public <T extends DragGestureRecognizer> T
|
||||
createDragGestureRecognizer(Class<T> recognizer, DragSource ds,
|
||||
Component comp, int actions,
|
||||
DragGestureListener l)
|
||||
{
|
||||
|
@ -1252,7 +1274,8 @@ public abstract class Toolkit
|
|||
/**
|
||||
* @since 1.3
|
||||
*/
|
||||
public abstract Map mapInputMethodHighlight(InputMethodHighlight highlight);
|
||||
public abstract Map<TextAttribute,?>
|
||||
mapInputMethodHighlight(InputMethodHighlight highlight);
|
||||
|
||||
/**
|
||||
* Initializes the accessibility framework. In particular, this loads the
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* Window.java --
|
||||
Copyright (C) 1999, 2000, 2002, 2003, 2004, 2006 Free Software Foundation
|
||||
Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005 Free Software Foundation
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -140,7 +140,7 @@ public class Window extends Container implements Accessible
|
|||
this();
|
||||
graphicsConfiguration = gc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initializes a new instance of <code>Window</code> with the specified
|
||||
* parent. The window will initially be invisible.
|
||||
|
@ -250,13 +250,13 @@ public class Window extends Container implements Accessible
|
|||
/**
|
||||
* Shows on-screen this window and any of its owned windows for whom
|
||||
* isVisible returns true.
|
||||
* @specnote: Deprecated starting in 1.5.
|
||||
*/
|
||||
@Deprecated
|
||||
public void show()
|
||||
{
|
||||
synchronized (getTreeLock())
|
||||
{
|
||||
if (parent != null && ! parent.isDisplayable())
|
||||
parent.addNotify();
|
||||
if (peer == null)
|
||||
addNotify();
|
||||
|
||||
|
@ -298,11 +298,24 @@ public class Window extends Container implements Accessible
|
|||
if (initialFocusOwner != null)
|
||||
initialFocusOwner.requestFocusInWindow();
|
||||
|
||||
// Post WINDOW_OPENED from here.
|
||||
if (windowListener != null
|
||||
|| (eventMask & AWTEvent.WINDOW_EVENT_MASK) != 0)
|
||||
{
|
||||
WindowEvent ev = new WindowEvent(this,
|
||||
WindowEvent.WINDOW_OPENED);
|
||||
Toolkit tk = Toolkit.getDefaultToolkit();
|
||||
tk.getSystemEventQueue().postEvent(ev);
|
||||
}
|
||||
shown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @specnote: Deprecated starting in 1.5.
|
||||
*/
|
||||
@Deprecated
|
||||
public void hide()
|
||||
{
|
||||
// Hide visible owned windows.
|
||||
|
@ -349,9 +362,15 @@ public class Window extends Container implements Accessible
|
|||
component[i].removeNotify();
|
||||
this.removeNotify();
|
||||
|
||||
// Post a WINDOW_CLOSED event.
|
||||
WindowEvent we = new WindowEvent(this, WindowEvent.WINDOW_CLOSED);
|
||||
getToolkit().getSystemEventQueue().postEvent(we);
|
||||
// Post WINDOW_CLOSED from here.
|
||||
if (windowListener != null
|
||||
|| (eventMask & AWTEvent.WINDOW_EVENT_MASK) != 0)
|
||||
{
|
||||
WindowEvent ev = new WindowEvent(this,
|
||||
WindowEvent.WINDOW_CLOSED);
|
||||
Toolkit tk = Toolkit.getDefaultToolkit();
|
||||
tk.getSystemEventQueue().postEvent(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -479,7 +498,11 @@ public class Window extends Container implements Accessible
|
|||
*/
|
||||
public synchronized void addWindowListener(WindowListener listener)
|
||||
{
|
||||
windowListener = AWTEventMulticaster.add(windowListener, listener);
|
||||
if (listener != null)
|
||||
{
|
||||
newEventsOnly = true;
|
||||
windowListener = AWTEventMulticaster.add(windowListener, listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -536,7 +559,12 @@ public class Window extends Container implements Accessible
|
|||
*/
|
||||
public void addWindowFocusListener (WindowFocusListener wfl)
|
||||
{
|
||||
windowFocusListener = AWTEventMulticaster.add (windowFocusListener, wfl);
|
||||
if (wfl != null)
|
||||
{
|
||||
newEventsOnly = true;
|
||||
windowFocusListener = AWTEventMulticaster.add (windowFocusListener,
|
||||
wfl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -546,7 +574,12 @@ public class Window extends Container implements Accessible
|
|||
*/
|
||||
public void addWindowStateListener (WindowStateListener wsl)
|
||||
{
|
||||
windowStateListener = AWTEventMulticaster.add (windowStateListener, wsl);
|
||||
if (wsl != null)
|
||||
{
|
||||
newEventsOnly = true;
|
||||
windowStateListener = AWTEventMulticaster.add (windowStateListener,
|
||||
wsl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -577,42 +610,21 @@ public class Window extends Container implements Accessible
|
|||
*
|
||||
* @since 1.3
|
||||
*/
|
||||
public EventListener[] getListeners(Class listenerType)
|
||||
public <T extends EventListener> T[] getListeners(Class<T> listenerType)
|
||||
{
|
||||
if (listenerType == WindowListener.class)
|
||||
return getWindowListeners();
|
||||
return (T[]) getWindowListeners();
|
||||
return super.getListeners(listenerType);
|
||||
}
|
||||
|
||||
void dispatchEventImpl(AWTEvent e)
|
||||
{
|
||||
// Make use of event id's in order to avoid multiple instanceof tests.
|
||||
if (e.id <= WindowEvent.WINDOW_LAST
|
||||
&& e.id >= WindowEvent.WINDOW_FIRST
|
||||
&& (windowListener != null
|
||||
|| windowFocusListener != null
|
||||
|| windowStateListener != null
|
||||
|| (eventMask & AWTEvent.WINDOW_EVENT_MASK) != 0))
|
||||
processEvent(e);
|
||||
else
|
||||
if (e.getID() == ComponentEvent.COMPONENT_RESIZED)
|
||||
{
|
||||
if (peer != null && (e.id == ComponentEvent.COMPONENT_RESIZED
|
||||
|| e.id == ComponentEvent.COMPONENT_MOVED))
|
||||
{
|
||||
Rectangle bounds = peer.getBounds();
|
||||
x = bounds.x;
|
||||
y = bounds.y;
|
||||
height = bounds.height;
|
||||
width = bounds.width;
|
||||
|
||||
if (e.id == ComponentEvent.COMPONENT_RESIZED)
|
||||
{
|
||||
invalidate();
|
||||
validate();
|
||||
}
|
||||
}
|
||||
super.dispatchEventImpl(e);
|
||||
invalidate();
|
||||
validate();
|
||||
}
|
||||
super.dispatchEventImpl(e);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -626,7 +638,28 @@ public class Window extends Container implements Accessible
|
|||
protected void processEvent(AWTEvent evt)
|
||||
{
|
||||
if (evt instanceof WindowEvent)
|
||||
processWindowEvent((WindowEvent) evt);
|
||||
{
|
||||
WindowEvent we = (WindowEvent) evt;
|
||||
switch (evt.getID())
|
||||
{
|
||||
case WindowEvent.WINDOW_OPENED:
|
||||
case WindowEvent.WINDOW_CLOSED:
|
||||
case WindowEvent.WINDOW_CLOSING:
|
||||
case WindowEvent.WINDOW_ICONIFIED:
|
||||
case WindowEvent.WINDOW_DEICONIFIED:
|
||||
case WindowEvent.WINDOW_ACTIVATED:
|
||||
case WindowEvent.WINDOW_DEACTIVATED:
|
||||
processWindowEvent(we);
|
||||
break;
|
||||
case WindowEvent.WINDOW_GAINED_FOCUS:
|
||||
case WindowEvent.WINDOW_LOST_FOCUS:
|
||||
processWindowFocusEvent(we);
|
||||
break;
|
||||
case WindowEvent.WINDOW_STATE_CHANGED:
|
||||
processWindowStateEvent(we);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
super.processEvent(evt);
|
||||
}
|
||||
|
@ -641,54 +674,35 @@ public class Window extends Container implements Accessible
|
|||
*/
|
||||
protected void processWindowEvent(WindowEvent evt)
|
||||
{
|
||||
int id = evt.getID();
|
||||
|
||||
if (id == WindowEvent.WINDOW_GAINED_FOCUS
|
||||
|| id == WindowEvent.WINDOW_LOST_FOCUS)
|
||||
processWindowFocusEvent (evt);
|
||||
else if (id == WindowEvent.WINDOW_STATE_CHANGED)
|
||||
processWindowStateEvent (evt);
|
||||
else
|
||||
if (windowListener != null)
|
||||
{
|
||||
if (windowListener != null)
|
||||
{
|
||||
switch (evt.getID())
|
||||
{
|
||||
case WindowEvent.WINDOW_ACTIVATED:
|
||||
windowListener.windowActivated(evt);
|
||||
break;
|
||||
|
||||
case WindowEvent.WINDOW_CLOSED:
|
||||
windowListener.windowClosed(evt);
|
||||
break;
|
||||
|
||||
case WindowEvent.WINDOW_CLOSING:
|
||||
windowListener.windowClosing(evt);
|
||||
break;
|
||||
|
||||
case WindowEvent.WINDOW_DEACTIVATED:
|
||||
windowListener.windowDeactivated(evt);
|
||||
break;
|
||||
|
||||
case WindowEvent.WINDOW_DEICONIFIED:
|
||||
windowListener.windowDeiconified(evt);
|
||||
break;
|
||||
|
||||
case WindowEvent.WINDOW_ICONIFIED:
|
||||
windowListener.windowIconified(evt);
|
||||
break;
|
||||
|
||||
case WindowEvent.WINDOW_OPENED:
|
||||
windowListener.windowOpened(evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (evt.getID())
|
||||
{
|
||||
case WindowEvent.WINDOW_ACTIVATED:
|
||||
windowListener.windowActivated(evt);
|
||||
break;
|
||||
case WindowEvent.WINDOW_CLOSED:
|
||||
windowListener.windowClosed(evt);
|
||||
break;
|
||||
case WindowEvent.WINDOW_CLOSING:
|
||||
windowListener.windowClosing(evt);
|
||||
break;
|
||||
case WindowEvent.WINDOW_DEACTIVATED:
|
||||
windowListener.windowDeactivated(evt);
|
||||
break;
|
||||
case WindowEvent.WINDOW_DEICONIFIED:
|
||||
windowListener.windowDeiconified(evt);
|
||||
break;
|
||||
case WindowEvent.WINDOW_ICONIFIED:
|
||||
windowListener.windowIconified(evt);
|
||||
break;
|
||||
case WindowEvent.WINDOW_OPENED:
|
||||
windowListener.windowOpened(evt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Identifies if this window is active. The active window is a Frame or
|
||||
* Dialog that has focus or owns the active window.
|
||||
|
@ -1233,6 +1247,42 @@ public class Window extends Container implements Accessible
|
|||
return "win" + getUniqueLong();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to handle WindowEvents.
|
||||
*
|
||||
* @return <code>true</code> when the specified event type is enabled,
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
boolean eventTypeEnabled(int type)
|
||||
{
|
||||
boolean enabled = false;
|
||||
switch (type)
|
||||
{
|
||||
case WindowEvent.WINDOW_OPENED:
|
||||
case WindowEvent.WINDOW_CLOSED:
|
||||
case WindowEvent.WINDOW_CLOSING:
|
||||
case WindowEvent.WINDOW_ICONIFIED:
|
||||
case WindowEvent.WINDOW_DEICONIFIED:
|
||||
case WindowEvent.WINDOW_ACTIVATED:
|
||||
case WindowEvent.WINDOW_DEACTIVATED:
|
||||
enabled = ((eventMask & AWTEvent.WINDOW_EVENT_MASK) != 0)
|
||||
|| windowListener != null;
|
||||
break;
|
||||
case WindowEvent.WINDOW_GAINED_FOCUS:
|
||||
case WindowEvent.WINDOW_LOST_FOCUS:
|
||||
enabled = ((eventMask & AWTEvent.WINDOW_FOCUS_EVENT_MASK) != 0)
|
||||
|| windowFocusListener != null;
|
||||
break;
|
||||
case WindowEvent.WINDOW_STATE_CHANGED:
|
||||
enabled = ((eventMask & AWTEvent.WINDOW_STATE_EVENT_MASK) != 0)
|
||||
|| windowStateListener != null;
|
||||
break;
|
||||
default:
|
||||
enabled = super.eventTypeEnabled(type);
|
||||
}
|
||||
return enabled;
|
||||
}
|
||||
|
||||
private static synchronized long getUniqueLong()
|
||||
{
|
||||
return next_window_number++;
|
||||
|
|
|
@ -38,14 +38,13 @@ exception statement from your version. */
|
|||
|
||||
package java.awt.datatransfer;
|
||||
|
||||
import gnu.classpath.NotImplementedException;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.OptionalDataException;
|
||||
import java.io.Reader;
|
||||
import java.io.Serializable;
|
||||
import java.io.StringReader;
|
||||
|
@ -76,8 +75,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
* deals with bytes not chars. Use <code>getRederForText()</code>.
|
||||
*/
|
||||
public static final DataFlavor plainTextFlavor =
|
||||
new DataFlavor(java.io.InputStream.class,
|
||||
"text/plain; charset=unicode",
|
||||
new DataFlavor("text/plain; charset=unicode; class=java.io.InputStream",
|
||||
"plain unicode text");
|
||||
|
||||
/**
|
||||
|
@ -94,8 +92,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
* element of the list being a <code>java.io.File</code>.
|
||||
*/
|
||||
public static final DataFlavor javaFileListFlavor =
|
||||
new DataFlavor(java.util.List.class,
|
||||
"application/x-java-file-list; class=java.util.List",
|
||||
new DataFlavor("application/x-java-file-list; class=java.util.List",
|
||||
"Java File List");
|
||||
|
||||
/**
|
||||
|
@ -132,10 +129,10 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
*/
|
||||
|
||||
// The MIME type for this flavor
|
||||
private final String mimeType;
|
||||
private MimeType mimeType;
|
||||
|
||||
// The representation class for this flavor
|
||||
private final Class representationClass;
|
||||
private Class<?> representationClass;
|
||||
|
||||
// The human readable name of this flavor
|
||||
private String humanPresentableName;
|
||||
|
@ -156,8 +153,8 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
*
|
||||
* @exception ClassNotFoundException If the class cannot be loaded.
|
||||
*/
|
||||
protected static final Class tryToLoadClass(String className,
|
||||
ClassLoader classLoader)
|
||||
protected static final Class<?> tryToLoadClass(String className,
|
||||
ClassLoader classLoader)
|
||||
throws ClassNotFoundException
|
||||
{
|
||||
// Bootstrap
|
||||
|
@ -198,62 +195,6 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
throw new ClassNotFoundException(className);
|
||||
}
|
||||
|
||||
private static Class getRepresentationClassFromMimeThrows(String mimeString,
|
||||
ClassLoader classLoader)
|
||||
throws ClassNotFoundException
|
||||
{
|
||||
String classname = getParameter("class", mimeString);
|
||||
if (classname != null)
|
||||
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
|
||||
* string.
|
||||
*
|
||||
* @param paramName The name of the parameter.
|
||||
* @param mimeString The mime string from where the name should be found.
|
||||
*
|
||||
* @return The value of the parameter or null.
|
||||
*/
|
||||
private static String getParameter(String paramName, String mimeString)
|
||||
{
|
||||
int idx = mimeString.indexOf(paramName + "=");
|
||||
if (idx == -1)
|
||||
return(null);
|
||||
|
||||
String value = mimeString.substring(idx + paramName.length() + 1);
|
||||
|
||||
idx = value.indexOf(";");
|
||||
if (idx == -1)
|
||||
return(value);
|
||||
else
|
||||
return(value.substring(0, idx));
|
||||
}
|
||||
|
||||
/**
|
||||
* XXX - Currently returns <code>plainTextFlavor</code>.
|
||||
*/
|
||||
|
@ -321,32 +262,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
*/
|
||||
public DataFlavor()
|
||||
{
|
||||
mimeType = null;
|
||||
representationClass = null;
|
||||
humanPresentableName = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor.
|
||||
*/
|
||||
private DataFlavor(Class representationClass,
|
||||
String mimeType,
|
||||
String humanPresentableName)
|
||||
{
|
||||
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
|
||||
this.humanPresentableName = mimeType;
|
||||
// Used for deserialization only, nothing to do here.
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -359,13 +275,23 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
* @param representationClass The representation class for this object.
|
||||
* @param humanPresentableName The display name of the object.
|
||||
*/
|
||||
public DataFlavor(Class representationClass, String humanPresentableName)
|
||||
public DataFlavor(Class<?> representationClass, String humanPresentableName)
|
||||
{
|
||||
this(representationClass,
|
||||
"application/x-java-serialized-object"
|
||||
+ "; class="
|
||||
+ representationClass.getName(),
|
||||
humanPresentableName);
|
||||
if (representationClass == null)
|
||||
throw new NullPointerException("representationClass must not be null");
|
||||
try
|
||||
{
|
||||
mimeType = new MimeType(javaSerializedObjectMimeType);
|
||||
}
|
||||
catch (MimeTypeParseException ex)
|
||||
{
|
||||
// Must not happen as we use a constant string.
|
||||
assert false;
|
||||
}
|
||||
if (humanPresentableName == null)
|
||||
humanPresentableName = javaSerializedObjectMimeType;
|
||||
this.humanPresentableName = humanPresentableName;
|
||||
this.representationClass = representationClass;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -390,8 +316,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
ClassLoader classLoader)
|
||||
throws ClassNotFoundException
|
||||
{
|
||||
this(getRepresentationClassFromMimeThrows(mimeType, classLoader),
|
||||
mimeType, humanPresentableName);
|
||||
init(mimeType, humanPresentableName, classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -412,8 +337,17 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
*/
|
||||
public DataFlavor(String mimeType, String humanPresentableName)
|
||||
{
|
||||
this(getRepresentationClassFromMime (mimeType, null),
|
||||
mimeType, humanPresentableName);
|
||||
try
|
||||
{
|
||||
init(mimeType, humanPresentableName, getClass().getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex)
|
||||
{
|
||||
IllegalArgumentException iae =
|
||||
new IllegalArgumentException("Class not found: " + ex.getMessage());
|
||||
iae.initCause(ex);
|
||||
throw iae;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -432,8 +366,54 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
*/
|
||||
public DataFlavor(String mimeType) throws ClassNotFoundException
|
||||
{
|
||||
this(getRepresentationClassFromMimeThrows(mimeType, null),
|
||||
mimeType, null);
|
||||
init(mimeType, null, getClass().getClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by various constructors to initialize this object.
|
||||
*
|
||||
* @param mime the mime string
|
||||
* @param humanPresentableName the human presentable name
|
||||
* @param loader the class loader to use for loading the representation
|
||||
* class
|
||||
*/
|
||||
private void init(String mime, String humanPresentableName,
|
||||
ClassLoader loader)
|
||||
throws ClassNotFoundException
|
||||
{
|
||||
if (mime == null)
|
||||
throw new NullPointerException("The mime type must not be null");
|
||||
try
|
||||
{
|
||||
mimeType = new MimeType(mime);
|
||||
}
|
||||
catch (MimeTypeParseException ex)
|
||||
{
|
||||
IllegalArgumentException iae =
|
||||
new IllegalArgumentException("Invalid mime type");
|
||||
iae.initCause(ex);
|
||||
throw iae;
|
||||
}
|
||||
String className = mimeType.getParameter("class");
|
||||
if (className == null)
|
||||
{
|
||||
if (mimeType.getBaseType().equals(javaSerializedObjectMimeType))
|
||||
throw new IllegalArgumentException("Serialized object type must have"
|
||||
+ " a representation class parameter");
|
||||
else
|
||||
representationClass = java.io.InputStream.class;
|
||||
}
|
||||
else
|
||||
representationClass = tryToLoadClass(className, loader);
|
||||
mimeType.addParameter("class", representationClass.getName());
|
||||
|
||||
if (humanPresentableName == null)
|
||||
{
|
||||
humanPresentableName = mimeType.getParameter("humanPresentableName");
|
||||
if (humanPresentableName == null)
|
||||
humanPresentableName = mimeType.getBaseType();
|
||||
}
|
||||
this.humanPresentableName = humanPresentableName;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -443,7 +423,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
*/
|
||||
public String getMimeType()
|
||||
{
|
||||
return(mimeType);
|
||||
return(mimeType.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -451,7 +431,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
*
|
||||
* @return The representation class for this flavor.
|
||||
*/
|
||||
public Class getRepresentationClass()
|
||||
public Class<?> getRepresentationClass()
|
||||
{
|
||||
return(representationClass);
|
||||
}
|
||||
|
@ -473,11 +453,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
*/
|
||||
public String getPrimaryType()
|
||||
{
|
||||
int idx = mimeType.indexOf("/");
|
||||
if (idx == -1)
|
||||
return(mimeType);
|
||||
|
||||
return(mimeType.substring(0, idx));
|
||||
return(mimeType.getPrimaryType());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -487,15 +463,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
*/
|
||||
public String getSubType()
|
||||
{
|
||||
int start = mimeType.indexOf("/");
|
||||
if (start == -1)
|
||||
return "";
|
||||
|
||||
int end = mimeType.indexOf(";", start + 1);
|
||||
if (end == -1)
|
||||
return mimeType.substring(start + 1);
|
||||
else
|
||||
return mimeType.substring(start + 1, end);
|
||||
return mimeType.getSubType();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -511,7 +479,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
if ("humanPresentableName".equals(paramName))
|
||||
return getHumanPresentableName();
|
||||
|
||||
return getParameter(paramName, mimeType);
|
||||
return mimeType.getParameter(paramName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -537,16 +505,22 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
*/
|
||||
public boolean isMimeTypeEqual(String mimeType)
|
||||
{
|
||||
String mime = getMimeType();
|
||||
int i = mime.indexOf(";");
|
||||
if (i != -1)
|
||||
mime = mime.substring(0, i);
|
||||
|
||||
i = mimeType.indexOf(";");
|
||||
if (i != -1)
|
||||
mimeType = mimeType.substring(0, i);
|
||||
|
||||
return mime.equals(mimeType);
|
||||
if (mimeType == null)
|
||||
throw new NullPointerException("mimeType must not be null");
|
||||
boolean equal = false;
|
||||
try
|
||||
{
|
||||
if (this.mimeType != null)
|
||||
{
|
||||
MimeType other = new MimeType(mimeType);
|
||||
equal = this.mimeType.matches(other);
|
||||
}
|
||||
}
|
||||
catch (MimeTypeParseException ex)
|
||||
{
|
||||
// Return false in this case.
|
||||
}
|
||||
return equal;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -571,7 +545,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
*/
|
||||
public boolean isMimeTypeSerializedObject()
|
||||
{
|
||||
return mimeType.startsWith(javaSerializedObjectMimeType);
|
||||
return isMimeTypeEqual(javaSerializedObjectMimeType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -617,8 +591,8 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
*/
|
||||
public boolean isFlavorSerializedObjectType()
|
||||
{
|
||||
// FIXME: What is the diff between this and isMimeTypeSerializedObject?
|
||||
return(mimeType.startsWith(javaSerializedObjectMimeType));
|
||||
return isRepresentationClassSerializable()
|
||||
&& isMimeTypeEqual(javaSerializedObjectMimeType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -629,7 +603,9 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
*/
|
||||
public boolean isFlavorRemoteObjectType()
|
||||
{
|
||||
return(mimeType.startsWith(javaRemoteObjectMimeType));
|
||||
return isRepresentationClassRemote()
|
||||
&& isRepresentationClassSerializable()
|
||||
&& isMimeTypeEqual(javaRemoteObjectMimeType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -770,7 +746,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
*/
|
||||
public int hashCode()
|
||||
{
|
||||
return mimeType.toLowerCase().hashCode() ^ representationClass.hashCode();
|
||||
return mimeType.toString().hashCode() ^ representationClass.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -822,9 +798,17 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
* @exception IOException If an error occurs.
|
||||
*/
|
||||
public void writeExternal(ObjectOutput stream)
|
||||
throws IOException, NotImplementedException
|
||||
throws IOException
|
||||
{
|
||||
// FIXME: Implement me
|
||||
if (mimeType != null)
|
||||
{
|
||||
mimeType.addParameter("humanPresentableName", humanPresentableName);
|
||||
stream.writeObject(mimeType);
|
||||
mimeType.removeParameter("humanPresentableName");
|
||||
}
|
||||
else
|
||||
stream.writeObject(null);
|
||||
stream.writeObject(representationClass);
|
||||
}
|
||||
|
||||
|
||||
|
@ -838,9 +822,34 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
* cannot be found.
|
||||
*/
|
||||
public void readExternal(ObjectInput stream)
|
||||
throws IOException, ClassNotFoundException, NotImplementedException
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
// FIXME: Implement me
|
||||
mimeType = (MimeType) stream.readObject();
|
||||
String className = null;
|
||||
if (mimeType != null)
|
||||
{
|
||||
humanPresentableName =
|
||||
mimeType.getParameter("humanPresentableName");
|
||||
mimeType.removeParameter("humanPresentableName");
|
||||
className = mimeType.getParameter("class");
|
||||
if (className == null)
|
||||
throw new IOException("No class in mime type");
|
||||
}
|
||||
try
|
||||
{
|
||||
representationClass = (Class) stream.readObject();
|
||||
}
|
||||
catch (OptionalDataException ex)
|
||||
{
|
||||
if (ex.eof && ex.length == 0)
|
||||
{
|
||||
if (className != null)
|
||||
representationClass = tryToLoadClass(className,
|
||||
getClass().getClassLoader());
|
||||
}
|
||||
else
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -861,7 +870,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
|
|||
*
|
||||
* @since 1.3
|
||||
*/
|
||||
public final Class getDefaultRepresentationClass()
|
||||
public final Class<?> getDefaultRepresentationClass()
|
||||
{
|
||||
return java.io.InputStream.class;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ public interface FlavorMap
|
|||
*
|
||||
* @return A <code>Map</code> of native data types.
|
||||
*/
|
||||
Map getNativesForFlavors (DataFlavor[] flavors);
|
||||
Map<DataFlavor, String> getNativesForFlavors (DataFlavor[] flavors);
|
||||
|
||||
/**
|
||||
* Maps the specified native type names to <code>DataFlavor</code>'s.
|
||||
|
@ -71,5 +71,5 @@ public interface FlavorMap
|
|||
*
|
||||
* @return A <code>Map</code> of data flavors.
|
||||
*/
|
||||
Map getFlavorsForNatives (String[] natives);
|
||||
Map<String, DataFlavor> getFlavorsForNatives (String[] natives);
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ public interface FlavorTable extends FlavorMap
|
|||
* @param flavor the flavor to look up, or null to return all natives
|
||||
* @return the sorted list of natives
|
||||
*/
|
||||
List getNativesForFlavor(DataFlavor flavor);
|
||||
List<String> getNativesForFlavor(DataFlavor flavor);
|
||||
|
||||
/**
|
||||
* Returns a list of flavors corresponding to the given String native. The
|
||||
|
@ -69,5 +69,5 @@ public interface FlavorTable extends FlavorMap
|
|||
* @param name the native name to look up, or null to return all flavors
|
||||
* @return the sorted list of flavors
|
||||
*/
|
||||
List getFlavorsForNative(String name);
|
||||
List<DataFlavor> getFlavorsForNative(String name);
|
||||
}
|
||||
|
|
281
libjava/classpath/java/awt/datatransfer/MimeType.java
Normal file
281
libjava/classpath/java/awt/datatransfer/MimeType.java
Normal file
|
@ -0,0 +1,281 @@
|
|||
/* MimeType.java -- A helper class for mime handling in DataFlavor
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
GNU Classpath is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Classpath is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Classpath; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA.
|
||||
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent
|
||||
modules, and to copy and distribute the resulting executable under
|
||||
terms of your choice, provided that you also meet, for each linked
|
||||
independent module, the terms and conditions of the license of that
|
||||
module. An independent module is a module which is not derived from
|
||||
or based on this library. If you modify this library, you may extend
|
||||
this exception to your version of the library, but you are not
|
||||
obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. */
|
||||
|
||||
|
||||
package java.awt.datatransfer;
|
||||
|
||||
import java.io.Externalizable;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* A helper class for mime handling in DataFlavor.
|
||||
*
|
||||
* A Mauve test for DataFlavor.writeExternal() shows that a non-public
|
||||
* class java.awt.datatransfer.MimeType gets serialized. This class
|
||||
* is mainly here for serialization compatibility. Of course,
|
||||
* now that we have it here, we can just as well implement some
|
||||
* mime handling facility here.
|
||||
*/
|
||||
class MimeType
|
||||
implements Externalizable
|
||||
{
|
||||
|
||||
/**
|
||||
* The primary type.
|
||||
*/
|
||||
private String primaryType;
|
||||
|
||||
/**
|
||||
* The subtype.
|
||||
*/
|
||||
private String subType;
|
||||
|
||||
/**
|
||||
* Additional parameters to be appended to the mime string.
|
||||
*/
|
||||
private HashMap parameters;
|
||||
|
||||
/**
|
||||
* This is only here for deserialization.
|
||||
*/
|
||||
public MimeType()
|
||||
{
|
||||
parameters = new HashMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new MimeType object.
|
||||
*
|
||||
* @param mime the mime type
|
||||
*/
|
||||
MimeType(String mime)
|
||||
throws MimeTypeParseException
|
||||
{
|
||||
this();
|
||||
parse(mime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a mime parameter.
|
||||
*
|
||||
* @param param the parameter key
|
||||
* @param value the parameter value
|
||||
*/
|
||||
void addParameter(String param, String value)
|
||||
{
|
||||
parameters.put(param, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the parameter with the specified key.
|
||||
*
|
||||
* @param param the parameter to remove
|
||||
*/
|
||||
void removeParameter(String param)
|
||||
{
|
||||
parameters.remove(param);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameter for the <code>key</code>.
|
||||
*
|
||||
* @param key the parameter key
|
||||
*
|
||||
* @return the parameter for the <code>key</code>
|
||||
*/
|
||||
String getParameter(String key)
|
||||
{
|
||||
return (String) parameters.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the primary type.
|
||||
*
|
||||
* @return the primary type
|
||||
*/
|
||||
String getPrimaryType()
|
||||
{
|
||||
return primaryType;
|
||||
}
|
||||
|
||||
String getSubType()
|
||||
{
|
||||
return subType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the base type of this mime type. This is the primary
|
||||
* type plus the subtype, separated by '/'.
|
||||
*
|
||||
* @return the base type of this mime type
|
||||
*/
|
||||
String getBaseType()
|
||||
{
|
||||
return primaryType + '/' + subType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if this mime type and another mime type
|
||||
* match. This will be true when their primary types are equal, and their
|
||||
* subtypes are equal (or when either subtype is * ).
|
||||
*
|
||||
* @param other the other mime type
|
||||
*
|
||||
* @return <code>true</code> if the mime types match, <code>false</code>
|
||||
* otherwise
|
||||
*/
|
||||
boolean matches(MimeType other)
|
||||
{
|
||||
boolean match = false;
|
||||
if (other != null)
|
||||
{
|
||||
match = primaryType.equals(other.primaryType)
|
||||
&& (subType.equals("*") || other.subType.equals("*")
|
||||
|| subType.equals(other.subType));
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the mime type.
|
||||
*
|
||||
* @param in the input stream to read from
|
||||
*
|
||||
* @throws ClassNotFoundException not thrown here
|
||||
* @throws IOException when something goes wrong on the input stream,
|
||||
* or when the mime type can't be parsed
|
||||
*/
|
||||
public void readExternal(ObjectInput in)
|
||||
throws ClassNotFoundException, IOException
|
||||
{
|
||||
String mime = in.readUTF();
|
||||
parameters.clear();
|
||||
try
|
||||
{
|
||||
parse(mime);
|
||||
}
|
||||
catch (MimeTypeParseException ex)
|
||||
{
|
||||
IOException ioEx = new IOException();
|
||||
ioEx.initCause(ex);
|
||||
throw ioEx;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes this mime type.
|
||||
*
|
||||
* @param out the output stream
|
||||
*
|
||||
* @throws IOException when something goes wrong on the output stream
|
||||
*/
|
||||
public void writeExternal(ObjectOutput out)
|
||||
throws IOException
|
||||
{
|
||||
out.writeUTF(toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string representation of this mime type.
|
||||
*
|
||||
* @return a string representation of this mime type
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append(primaryType);
|
||||
s.append('/');
|
||||
s.append(subType);
|
||||
if (parameters.size() > 0)
|
||||
{
|
||||
Set entries = parameters.entrySet();
|
||||
for (Iterator i = entries.iterator(); i.hasNext();)
|
||||
{
|
||||
s.append("; ");
|
||||
Map.Entry entry = (Map.Entry) i.next();
|
||||
s.append(entry.getKey());
|
||||
s.append('=');
|
||||
s.append(entry.getValue());
|
||||
}
|
||||
}
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the specified mime type string and initializes the fields
|
||||
* of this object.
|
||||
*
|
||||
* @param mime the mime type string
|
||||
*/
|
||||
private void parse(String mime)
|
||||
throws MimeTypeParseException
|
||||
{
|
||||
// FIXME: Maybe implement more sophisticated mime string parsing according
|
||||
// to RFC 2045 and 2046.
|
||||
StringTokenizer tokenizer = new StringTokenizer(mime);
|
||||
try
|
||||
{
|
||||
primaryType = tokenizer.nextToken("/");
|
||||
subType = tokenizer.nextToken("/;");
|
||||
}
|
||||
catch (NoSuchElementException ex)
|
||||
{
|
||||
throw new MimeTypeParseException("Expected / separator");
|
||||
}
|
||||
|
||||
// Add any parameters.
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
String keyValuePair = tokenizer.nextToken(";");
|
||||
int i = keyValuePair.indexOf('=');
|
||||
if (i == -1)
|
||||
throw new MimeTypeParseException("Expected = as parameter separator");
|
||||
String key = keyValuePair.substring(0, i).trim();
|
||||
String value = keyValuePair.substring(i + 1).trim();
|
||||
parameters.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -98,9 +98,9 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable
|
|||
*
|
||||
* @return A <code>Map</code> of native data types to data flavors.
|
||||
*/
|
||||
public Map getNativesForFlavors (DataFlavor[] flavors)
|
||||
public Map<DataFlavor, String> getNativesForFlavors (DataFlavor[] flavors)
|
||||
{
|
||||
return new HashMap();
|
||||
return new HashMap<DataFlavor, String>();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -114,9 +114,9 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable
|
|||
*
|
||||
* @return A <code>Map</code> of data flavors to native type names.
|
||||
*/
|
||||
public Map getFlavorsForNatives (String[] natives)
|
||||
public Map<String, DataFlavor> getFlavorsForNatives (String[] natives)
|
||||
{
|
||||
return new HashMap();
|
||||
return new HashMap<String, DataFlavor>();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -263,13 +263,13 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable
|
|||
* specified native and a DataFlavor whose MIME type is a decoded
|
||||
* version of the native.
|
||||
*/
|
||||
public List getFlavorsForNative (String nat)
|
||||
public List<DataFlavor> getFlavorsForNative (String nat)
|
||||
throws NotImplementedException
|
||||
{
|
||||
throw new Error ("Not implemented");
|
||||
}
|
||||
|
||||
public List getNativesForFlavor (DataFlavor flav)
|
||||
public List<String> getNativesForFlavor (DataFlavor flav)
|
||||
throws NotImplementedException
|
||||
{
|
||||
throw new Error ("Not implemented");
|
||||
|
|
|
@ -59,7 +59,7 @@ public class DragGestureEvent extends EventObject
|
|||
private Component component;
|
||||
private final Point origin;
|
||||
private final int action;
|
||||
private List events;
|
||||
private List<InputEvent> events;
|
||||
private DragGestureRecognizer dgr;
|
||||
|
||||
/**
|
||||
|
@ -71,15 +71,15 @@ public class DragGestureEvent extends EventObject
|
|||
* @throws IllegalArgumentException - if input parameters are null
|
||||
*/
|
||||
public DragGestureEvent(DragGestureRecognizer dgr, int action, Point origin,
|
||||
List events)
|
||||
{
|
||||
List<? extends InputEvent> events)
|
||||
{
|
||||
super(dgr);
|
||||
if (origin == null || events == null || dgr == null)
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
|
||||
this.origin = origin;
|
||||
this.action = action;
|
||||
this.events = events;
|
||||
this.events = (List<InputEvent>) events;
|
||||
this.dgr = dgr;
|
||||
this.component = dgr.getComponent();
|
||||
this.dragSource = dgr.getDragSource();
|
||||
|
@ -130,7 +130,7 @@ public class DragGestureEvent extends EventObject
|
|||
*
|
||||
* @return an iterator representation of the List of events.
|
||||
*/
|
||||
public Iterator iterator()
|
||||
public Iterator<InputEvent> iterator()
|
||||
{
|
||||
return events.iterator();
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ public class DragGestureEvent extends EventObject
|
|||
{
|
||||
return events.toArray(array);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the user's preferred action.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* DragGestureRecognizer.java --
|
||||
Copyright (C) 2002,2006 Free Software Foundation, Inc.
|
||||
Copyright (C) 2002, 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.dnd;
|
||||
|
||||
import gnu.classpath.NotImplementedException;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Point;
|
||||
import java.awt.event.InputEvent;
|
||||
|
@ -52,6 +50,8 @@ import java.util.TooManyListenersException;
|
|||
|
||||
/**
|
||||
* STUBBED
|
||||
* @author Michael Koch (konqueror@gmx.de)
|
||||
* @author Andrew John Hughes (gnu_andrew@member.fsf.org)
|
||||
* @since 1.2
|
||||
*/
|
||||
public abstract class DragGestureRecognizer implements Serializable
|
||||
|
@ -65,7 +65,7 @@ public abstract class DragGestureRecognizer implements Serializable
|
|||
protected Component component;
|
||||
protected transient DragGestureListener dragGestureListener;
|
||||
protected int sourceActions;
|
||||
protected ArrayList events = new ArrayList();
|
||||
protected ArrayList<InputEvent> events = new ArrayList<InputEvent>();
|
||||
|
||||
protected DragGestureRecognizer(DragSource ds, Component c, int sa,
|
||||
DragGestureListener dgl)
|
||||
|
@ -127,11 +127,12 @@ public abstract class DragGestureRecognizer implements Serializable
|
|||
return events.size() > 0 ? (InputEvent) events.get(0) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the recognizer. If a gesture is currently recognize, discard it.
|
||||
*/
|
||||
public void resetRecognizer()
|
||||
throws NotImplementedException
|
||||
{
|
||||
events = new ArrayList();
|
||||
// FIXME: Not implemented fully.
|
||||
events.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -164,6 +165,7 @@ public abstract class DragGestureRecognizer implements Serializable
|
|||
if(dragGestureListener != null)
|
||||
dragGestureListener.dragGestureRecognized
|
||||
(new DragGestureEvent(this, dragAction, p, events));
|
||||
resetRecognizer();
|
||||
}
|
||||
|
||||
protected void appendEvent(InputEvent e)
|
||||
|
|
|
@ -105,16 +105,15 @@ public class DragSource implements Serializable
|
|||
ds = null;
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
|
||||
if (ds == null)
|
||||
ds = new DragSource();
|
||||
return ds;
|
||||
}
|
||||
|
||||
public static boolean isDragImageSupported()
|
||||
throws NotImplementedException
|
||||
{
|
||||
// FIXME: Implement this
|
||||
// In all cases, Sun returns false here.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -140,8 +139,6 @@ public class DragSource implements Serializable
|
|||
// 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
|
||||
{
|
||||
|
@ -228,15 +225,16 @@ public class DragSource implements Serializable
|
|||
{
|
||||
return flavorMap;
|
||||
}
|
||||
|
||||
public DragGestureRecognizer createDragGestureRecognizer(Class recognizer,
|
||||
Component c,
|
||||
int actions,
|
||||
DragGestureListener dgl)
|
||||
|
||||
public <T extends DragGestureRecognizer> T
|
||||
createDragGestureRecognizer(Class<T> recognizer,
|
||||
Component c,
|
||||
int actions,
|
||||
DragGestureListener dgl)
|
||||
{
|
||||
return Toolkit.getDefaultToolkit().createDragGestureRecognizer(recognizer,
|
||||
this, c,
|
||||
actions, dgl);
|
||||
return (T) Toolkit.getDefaultToolkit().createDragGestureRecognizer(recognizer,
|
||||
this, c,
|
||||
actions, dgl);
|
||||
}
|
||||
|
||||
public DragGestureRecognizer createDefaultDragGestureRecognizer(Component c,
|
||||
|
@ -299,23 +297,23 @@ public class DragSource implements Serializable
|
|||
/**
|
||||
* @since 1.4
|
||||
*/
|
||||
public EventListener[] getListeners (Class listenerType)
|
||||
public <T extends EventListener> T[] getListeners (Class<T> listenerType)
|
||||
{
|
||||
if (listenerType == DragSourceListener.class)
|
||||
return DnDEventMulticaster.getListeners (dragSourceListener,
|
||||
listenerType);
|
||||
listenerType);
|
||||
|
||||
if (listenerType == DragSourceMotionListener.class)
|
||||
return DnDEventMulticaster.getListeners (dragSourceMotionListener,
|
||||
listenerType);
|
||||
listenerType);
|
||||
|
||||
// Return an empty EventListener array.
|
||||
return new EventListener [0];
|
||||
return (T[]) new EventListener [0];
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @return
|
||||
* @return TODO
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
|
@ -323,6 +321,6 @@ public class DragSource implements Serializable
|
|||
throws NotImplementedException
|
||||
{
|
||||
// FIXME: Not implemented.
|
||||
return 4;
|
||||
return 8;
|
||||
}
|
||||
} // class DragSource
|
||||
|
|
|
@ -38,8 +38,6 @@ exception statement from your version. */
|
|||
|
||||
package java.awt.dnd;
|
||||
|
||||
import gnu.classpath.NotImplementedException;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Image;
|
||||
|
@ -268,7 +266,8 @@ public class DragSourceContext
|
|||
for (int i = 0; i < dsl.length; i++)
|
||||
dsl[i].dragExit(e);
|
||||
|
||||
updateCurrentCursor(0, 0, DEFAULT);
|
||||
updateCurrentCursor(DnDConstants.ACTION_NONE, DnDConstants.ACTION_NONE,
|
||||
DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -340,26 +339,45 @@ public class DragSourceContext
|
|||
* @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)
|
||||
if (! useCustomCursor)
|
||||
{
|
||||
Cursor cursor = null;
|
||||
Cursor newCursor = null;
|
||||
switch (status)
|
||||
{
|
||||
case ENTER:
|
||||
break;
|
||||
case CHANGED:
|
||||
break;
|
||||
case OVER:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
targetAct = DnDConstants.ACTION_NONE;
|
||||
case ENTER:
|
||||
case CHANGED:
|
||||
case OVER:
|
||||
int action = dropOp & targetAct;
|
||||
if (action == DnDConstants.ACTION_NONE)
|
||||
{
|
||||
if ((dropOp & DnDConstants.ACTION_LINK) != 0)
|
||||
newCursor = DragSource.DefaultLinkNoDrop;
|
||||
else if ((dropOp & DnDConstants.ACTION_MOVE) != 0)
|
||||
newCursor = DragSource.DefaultMoveNoDrop;
|
||||
else
|
||||
newCursor = DragSource.DefaultCopyNoDrop;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((dropOp & DnDConstants.ACTION_LINK) != 0)
|
||||
newCursor = DragSource.DefaultLinkDrop;
|
||||
else if ((dropOp & DnDConstants.ACTION_MOVE) != 0)
|
||||
newCursor = DragSource.DefaultMoveDrop;
|
||||
else
|
||||
newCursor = DragSource.DefaultCopyDrop;
|
||||
}
|
||||
}
|
||||
|
||||
this.cursor = cursor;
|
||||
peer.setCursor(cursor);
|
||||
if (cursor == null || ! cursor.equals(newCursor))
|
||||
{
|
||||
cursor = newCursor;
|
||||
DragSourceContextPeer p = peer;
|
||||
if (p != null)
|
||||
p.setCursor(cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // class DragSourceContext
|
||||
|
|
|
@ -38,13 +38,14 @@ 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.Insets;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.datatransfer.FlavorMap;
|
||||
import java.awt.datatransfer.SystemFlavorMap;
|
||||
import java.awt.dnd.peer.DropTargetPeer;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
@ -54,6 +55,8 @@ import java.io.Serializable;
|
|||
import java.util.EventListener;
|
||||
import java.util.TooManyListenersException;
|
||||
|
||||
import javax.swing.Timer;
|
||||
|
||||
/**
|
||||
* @author Michael Koch
|
||||
* @since 1.2
|
||||
|
@ -69,30 +72,87 @@ public class DropTarget
|
|||
protected static class DropTargetAutoScroller
|
||||
implements ActionListener
|
||||
{
|
||||
/**
|
||||
* The threshold that keeps the autoscroller running.
|
||||
*/
|
||||
private static final int HYSTERESIS = 10;
|
||||
|
||||
/**
|
||||
* The initial timer delay.
|
||||
*/
|
||||
private static final int DELAY = 100;
|
||||
|
||||
private Component component;
|
||||
private Point point;
|
||||
|
||||
|
||||
/**
|
||||
* The timer that triggers autoscrolling.
|
||||
*/
|
||||
private Timer timer;
|
||||
|
||||
/**
|
||||
* The outer region of the scroller. This is the component's size.
|
||||
*/
|
||||
private Rectangle outer;
|
||||
|
||||
/**
|
||||
* The inner region of the scroller. This is the component size without
|
||||
* the autoscroll insets.
|
||||
*/
|
||||
private Rectangle inner;
|
||||
|
||||
protected DropTargetAutoScroller (Component c, Point p)
|
||||
{
|
||||
component = c;
|
||||
point = p;
|
||||
timer = new Timer(DELAY, this);
|
||||
timer.setCoalesce(true);
|
||||
timer.start();
|
||||
}
|
||||
|
||||
protected void updateLocation (Point newLocn)
|
||||
{
|
||||
Point previous = point;
|
||||
point = newLocn;
|
||||
if (Math.abs(point.x - previous.x) > HYSTERESIS
|
||||
|| Math.abs(point.y - previous.y) > HYSTERESIS)
|
||||
{
|
||||
if (timer.isRunning())
|
||||
timer.stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! timer.isRunning())
|
||||
timer.start();
|
||||
}
|
||||
}
|
||||
|
||||
protected void stop ()
|
||||
throws NotImplementedException
|
||||
{
|
||||
// FIXME: implement this
|
||||
timer.start();
|
||||
}
|
||||
|
||||
public void actionPerformed (ActionEvent e)
|
||||
throws NotImplementedException
|
||||
{
|
||||
// FIXME: implement this
|
||||
Autoscroll autoScroll = (Autoscroll) component;
|
||||
|
||||
// First synchronize the inner and outer rectangles.
|
||||
Insets i = autoScroll.getAutoscrollInsets();
|
||||
int width = component.getWidth();
|
||||
int height = component.getHeight();
|
||||
if (width != outer.width || height != outer.height)
|
||||
outer.setBounds(0, 0, width, height);
|
||||
if (inner.x != i.left || inner.y != i.top)
|
||||
inner.setLocation(i.left, i.top);
|
||||
int inWidth = width - i.left - i.right;
|
||||
int inHeight = height - i.top - i.bottom;
|
||||
if (inWidth != inner.width || inHeight != inner.height)
|
||||
inner.setSize(inWidth, inHeight);
|
||||
|
||||
// Scroll if the outer rectangle contains the location, but the
|
||||
// inner doesn't.
|
||||
if (outer.contains(point) && ! inner.contains(point))
|
||||
autoScroll.autoscroll(point);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,7 +173,7 @@ public class DropTarget
|
|||
*/
|
||||
public DropTarget ()
|
||||
{
|
||||
this (null, 0, null, true, null);
|
||||
this (null, DnDConstants.ACTION_COPY_OR_MOVE, null, true, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,7 +184,7 @@ public class DropTarget
|
|||
*/
|
||||
public DropTarget (Component c, DropTargetListener dtl)
|
||||
{
|
||||
this (c, 0, dtl, true, null);
|
||||
this (c, DnDConstants.ACTION_COPY_OR_MOVE, dtl, true, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -164,7 +224,11 @@ public class DropTarget
|
|||
setComponent(c);
|
||||
setDefaultActions(i);
|
||||
dropTargetListener = dtl;
|
||||
flavorMap = fm;
|
||||
|
||||
if (fm == null)
|
||||
flavorMap = SystemFlavorMap.getDefaultFlavorMap();
|
||||
else
|
||||
flavorMap = fm;
|
||||
|
||||
setActive (b);
|
||||
|
||||
|
@ -177,6 +241,8 @@ public class DropTarget
|
|||
*/
|
||||
public void setComponent (Component c)
|
||||
{
|
||||
if (component != null)
|
||||
clearAutoscroll();
|
||||
component = c;
|
||||
}
|
||||
|
||||
|
@ -207,6 +273,8 @@ public class DropTarget
|
|||
public void setActive (boolean active)
|
||||
{
|
||||
this.active = active;
|
||||
if (! active)
|
||||
clearAutoscroll();
|
||||
}
|
||||
|
||||
public boolean isActive()
|
||||
|
@ -225,8 +293,14 @@ public class DropTarget
|
|||
public void addDropTargetListener (DropTargetListener dtl)
|
||||
throws TooManyListenersException
|
||||
{
|
||||
if (dtl == null)
|
||||
return;
|
||||
|
||||
if (dtl.equals(this))
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
if (dropTargetListener != null)
|
||||
throw new TooManyListenersException ();
|
||||
throw new TooManyListenersException();
|
||||
|
||||
dropTargetListener = dtl;
|
||||
}
|
||||
|
@ -239,30 +313,47 @@ public class DropTarget
|
|||
|
||||
public void dragEnter(DropTargetDragEvent dtde)
|
||||
{
|
||||
if (dropTargetListener != null)
|
||||
dropTargetListener.dragEnter(dtde);
|
||||
if (active)
|
||||
{
|
||||
if (dropTargetListener != null)
|
||||
dropTargetListener.dragEnter(dtde);
|
||||
initializeAutoscrolling(dtde.getLocation());
|
||||
}
|
||||
}
|
||||
|
||||
public void dragOver(DropTargetDragEvent dtde)
|
||||
{
|
||||
if (dropTargetListener != null)
|
||||
dropTargetListener.dragOver(dtde);
|
||||
if (active)
|
||||
{
|
||||
if (dropTargetListener != null)
|
||||
dropTargetListener.dragOver(dtde);
|
||||
updateAutoscroll(dtde.getLocation());
|
||||
}
|
||||
}
|
||||
|
||||
public void dropActionChanged(DropTargetDragEvent dtde)
|
||||
{
|
||||
if (dropTargetListener != null)
|
||||
dropTargetListener.dropActionChanged(dtde);
|
||||
if (active)
|
||||
{
|
||||
if (dropTargetListener != null)
|
||||
dropTargetListener.dropActionChanged(dtde);
|
||||
updateAutoscroll(dtde.getLocation());
|
||||
}
|
||||
}
|
||||
|
||||
public void dragExit(DropTargetEvent dte)
|
||||
{
|
||||
if (dropTargetListener != null)
|
||||
dropTargetListener.dragExit(dte);
|
||||
if (active)
|
||||
{
|
||||
if (dropTargetListener != null)
|
||||
dropTargetListener.dragExit(dte);
|
||||
clearAutoscroll();
|
||||
}
|
||||
}
|
||||
|
||||
public void drop(DropTargetDropEvent dtde)
|
||||
{
|
||||
clearAutoscroll();
|
||||
if (dropTargetListener != null)
|
||||
dropTargetListener.drop(dtde);
|
||||
}
|
||||
|
@ -321,15 +412,13 @@ public class DropTarget
|
|||
protected DropTarget.DropTargetAutoScroller createDropTargetAutoScroller
|
||||
(Component c, Point p)
|
||||
{
|
||||
if (autoscroller == null)
|
||||
autoscroller = new DropTarget.DropTargetAutoScroller (c, p);
|
||||
|
||||
return autoscroller;
|
||||
return new DropTarget.DropTargetAutoScroller (c, p);
|
||||
}
|
||||
|
||||
protected void initializeAutoscrolling(Point p)
|
||||
{
|
||||
createDropTargetAutoScroller (component, p);
|
||||
if (component instanceof Autoscroll) // Checks for null too.
|
||||
autoscroller = createDropTargetAutoScroller (component, p);
|
||||
}
|
||||
|
||||
protected void updateAutoscroll(Point dragCursorLocn)
|
||||
|
@ -340,6 +429,10 @@ public class DropTarget
|
|||
|
||||
protected void clearAutoscroll()
|
||||
{
|
||||
autoscroller = null;
|
||||
if (autoscroller != null)
|
||||
{
|
||||
autoscroller.stop();
|
||||
autoscroller = null;
|
||||
}
|
||||
}
|
||||
} // class DropTarget
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* DropTargetContext.java --
|
||||
Copyright (C) 2002, 2003, 2004, 2006, Free Software Foundation
|
||||
Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -49,6 +49,7 @@ import java.util.List;
|
|||
|
||||
/**
|
||||
* @author Michael Koch (konqueror@gmx.de)
|
||||
* @author Andrew John Hughes (gnu_andrew@member.fsf.org)
|
||||
* @since 1.2
|
||||
*/
|
||||
public class DropTargetContext implements Serializable
|
||||
|
@ -128,51 +129,51 @@ public class DropTargetContext implements Serializable
|
|||
*
|
||||
* @exception InvalidDnDOperationException If a drop is not outstanding.
|
||||
*/
|
||||
public void dropComplete(boolean success)
|
||||
public void dropComplete (boolean success)
|
||||
{
|
||||
if (dtcp != null)
|
||||
dtcp.dropComplete(success);
|
||||
}
|
||||
|
||||
protected void acceptDrag(int dragOperation)
|
||||
protected void acceptDrag (int dragOperation)
|
||||
{
|
||||
if (dtcp != null)
|
||||
dtcp.acceptDrag(dragOperation);
|
||||
}
|
||||
|
||||
protected void rejectDrag()
|
||||
protected void rejectDrag ()
|
||||
{
|
||||
if (dtcp != null)
|
||||
dtcp.rejectDrag();
|
||||
}
|
||||
|
||||
protected void acceptDrop(int dropOperation)
|
||||
protected void acceptDrop (int dropOperation)
|
||||
{
|
||||
if (dtcp != null)
|
||||
dtcp.acceptDrop(dropOperation);
|
||||
}
|
||||
|
||||
protected void rejectDrop()
|
||||
protected void rejectDrop ()
|
||||
{
|
||||
if (dtcp != null)
|
||||
dtcp.rejectDrop();
|
||||
}
|
||||
|
||||
protected DataFlavor[] getCurrentDataFlavors()
|
||||
protected DataFlavor[] getCurrentDataFlavors ()
|
||||
{
|
||||
if (dtcp != null)
|
||||
dtcp.getTransferDataFlavors();
|
||||
return null;
|
||||
}
|
||||
|
||||
protected List getCurrentDataFlavorsAsList()
|
||||
protected List<DataFlavor> getCurrentDataFlavorsAsList ()
|
||||
{
|
||||
return Arrays.asList(getCurrentDataFlavors());
|
||||
return Arrays.asList(getCurrentDataFlavors ());
|
||||
}
|
||||
|
||||
protected boolean isDataFlavorSupported(DataFlavor flavor)
|
||||
protected boolean isDataFlavorSupported (DataFlavor flavor)
|
||||
{
|
||||
return getCurrentDataFlavorsAsList().contains(flavor);
|
||||
return getCurrentDataFlavorsAsList().contains (flavor);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -108,7 +108,7 @@ public class DropTargetDragEvent extends DropTargetEvent
|
|||
return context.getCurrentDataFlavors ();
|
||||
}
|
||||
|
||||
public List getCurrentDataFlavorsAsList ()
|
||||
public List<DataFlavor> getCurrentDataFlavorsAsList ()
|
||||
{
|
||||
return context.getCurrentDataFlavorsAsList ();
|
||||
}
|
||||
|
@ -147,7 +147,6 @@ public class DropTargetDragEvent extends DropTargetEvent
|
|||
*/
|
||||
public Transferable getTransferable()
|
||||
{
|
||||
// FIXME: Not implemented
|
||||
return null;
|
||||
return context.getTransferable();
|
||||
}
|
||||
} // class DropTargetDragEvent
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* DropTargetDropEvent.java --
|
||||
Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
Copyright (C) 2002, 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -123,7 +123,7 @@ public class DropTargetDropEvent extends DropTargetEvent
|
|||
return context.getCurrentDataFlavors();
|
||||
}
|
||||
|
||||
public List getCurrentDataFlavorsAsList()
|
||||
public List<DataFlavor> getCurrentDataFlavorsAsList()
|
||||
{
|
||||
return context.getCurrentDataFlavorsAsList();
|
||||
}
|
||||
|
|
|
@ -41,6 +41,10 @@ import java.util.EventObject;
|
|||
|
||||
public class DropTargetEvent extends EventObject
|
||||
{
|
||||
|
||||
/**
|
||||
* Serialization identifier for Sun 1.5 compatability
|
||||
*/
|
||||
private static final long serialVersionUID = 2821229066521922993L;
|
||||
|
||||
protected DropTargetContext context;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* ComponentEvent.java -- notification of events for components
|
||||
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.
|
||||
|
||||
|
@ -114,24 +114,27 @@ public class ComponentEvent extends AWTEvent
|
|||
*/
|
||||
public String paramString()
|
||||
{
|
||||
StringBuffer s = new StringBuffer();
|
||||
|
||||
// Unlike Sun, we don't throw NullPointerException or ClassCastException
|
||||
// when source was illegally changed.
|
||||
switch (id)
|
||||
{
|
||||
case COMPONENT_MOVED:
|
||||
return "COMPONENT_MOVED "
|
||||
+ (source instanceof Component
|
||||
? ((Component) source).getBounds() : (Object) "");
|
||||
case COMPONENT_RESIZED:
|
||||
return "COMPONENT_RESIZED "
|
||||
+ (source instanceof Component
|
||||
? ((Component) source).getBounds() : (Object) "");
|
||||
case COMPONENT_SHOWN:
|
||||
return "COMPONENT_SHOWN";
|
||||
case COMPONENT_HIDDEN:
|
||||
return "COMPONENT_HIDDEN";
|
||||
default:
|
||||
return "unknown type";
|
||||
}
|
||||
if (id == COMPONENT_MOVED)
|
||||
s.append("COMPONENT_MOVED ");
|
||||
else if (id == COMPONENT_RESIZED)
|
||||
s.append("COMPONENT_RESIZED ");
|
||||
else if (id == COMPONENT_SHOWN)
|
||||
s.append("COMPONENT_SHOWN ");
|
||||
else if (id == COMPONENT_HIDDEN)
|
||||
s.append("COMPONENT_HIDDEN ");
|
||||
else
|
||||
return "unknown type";
|
||||
|
||||
s.append("(").append(getComponent().getX()).append(",")
|
||||
.append(getComponent().getY()).append(" ")
|
||||
.append(getComponent().getWidth()).append("x")
|
||||
.append(getComponent().getHeight()).append(")");
|
||||
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
} // class ComponentEvent
|
||||
|
|
|
@ -117,8 +117,12 @@ public class FontRenderContext
|
|||
*/
|
||||
public int hashCode ()
|
||||
{
|
||||
// FIXME: check what SUN does here.
|
||||
return affineTransform == null ? 0 : affineTransform.hashCode ();
|
||||
int code = ( isAntiAliased ? 1 : 0 ) + ( usesFractionalMetrics ? 2 : 0 );
|
||||
|
||||
if( affineTransform != null && !affineTransform.isIdentity() )
|
||||
code ^= affineTransform.hashCode();
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
public boolean isAntiAliased ()
|
||||
|
|
|
@ -81,6 +81,9 @@ public final class TextHitInfo
|
|||
|
||||
public boolean equals(TextHitInfo hitInfo)
|
||||
{
|
||||
if (hitInfo == null)
|
||||
return false;
|
||||
|
||||
return (charIndex == hitInfo.getCharIndex ())
|
||||
&& (leadingEdge == hitInfo.isLeadingEdge ());
|
||||
}
|
||||
|
@ -97,7 +100,7 @@ public final class TextHitInfo
|
|||
|
||||
public static TextHitInfo beforeOffset(int offset)
|
||||
{
|
||||
return new TextHitInfo (offset, false);
|
||||
return new TextHitInfo ((offset - 1), false);
|
||||
}
|
||||
|
||||
public static TextHitInfo afterOffset(int offset)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1401,10 +1401,10 @@ public class AffineTransform implements Cloneable, Serializable
|
|||
* documented, but appears to be the same as:
|
||||
* <pre>
|
||||
* long l = Double.doubleToLongBits(getScaleX());
|
||||
* l = l * 31 + Double.doubleToLongBits(getShearY());
|
||||
* l = l * 31 + Double.doubleToLongBits(getShearX());
|
||||
* l = l * 31 + Double.doubleToLongBits(getScaleY());
|
||||
* l = l * 31 + Double.doubleToLongBits(getTranslateX());
|
||||
* l = l * 31 + Double.doubleToLongBits(getShearY());
|
||||
* l = l * 31 + Double.doubleToLongBits(getScaleY());
|
||||
* l = l * 31 + Double.doubleToLongBits(getTranslateY());
|
||||
* return (int) ((l >> 32) ^ l);
|
||||
* </pre>
|
||||
|
@ -1413,12 +1413,12 @@ public class AffineTransform implements Cloneable, Serializable
|
|||
*/
|
||||
public int hashCode()
|
||||
{
|
||||
long l = Double.doubleToLongBits(m00);
|
||||
l = l * 31 + Double.doubleToLongBits(m10);
|
||||
l = l * 31 + Double.doubleToLongBits(m01);
|
||||
l = l * 31 + Double.doubleToLongBits(m11);
|
||||
l = l * 31 + Double.doubleToLongBits(m02);
|
||||
l = l * 31 + Double.doubleToLongBits(m12);
|
||||
long l = Double.doubleToLongBits(m00);
|
||||
l = l * 31 + Double.doubleToLongBits(m01);
|
||||
l = l * 31 + Double.doubleToLongBits(m02);
|
||||
l = l * 31 + Double.doubleToLongBits(m10);
|
||||
l = l * 31 + Double.doubleToLongBits(m11);
|
||||
l = l * 31 + Double.doubleToLongBits(m12);
|
||||
return (int) ((l >> 32) ^ l);
|
||||
}
|
||||
|
||||
|
|
|
@ -774,14 +774,9 @@ public abstract class Arc2D extends RectangularShape
|
|||
y = a.getY();
|
||||
w = a.getWidth();
|
||||
h = a.getHeight();
|
||||
double start = a.getAngleStart() * (Math.PI / 180);
|
||||
double extent = a.getAngleExtent() * (Math.PI / 180);
|
||||
double start = Math.toRadians(a.getAngleStart());
|
||||
double extent = Math.toRadians(a.getAngleExtent());
|
||||
|
||||
if (extent < 0)
|
||||
{
|
||||
extent = -extent;
|
||||
start = 2 * Math.PI - extent + start;
|
||||
}
|
||||
this.start = start;
|
||||
this.extent = extent;
|
||||
|
||||
|
@ -790,11 +785,11 @@ public abstract class Arc2D extends RectangularShape
|
|||
limit = -1;
|
||||
else if (extent == 0)
|
||||
limit = type;
|
||||
else if (extent <= Math.PI / 2.0)
|
||||
else if (Math.abs(extent) <= Math.PI / 2.0)
|
||||
limit = type + 1;
|
||||
else if (extent <= Math.PI)
|
||||
else if (Math.abs(extent) <= Math.PI)
|
||||
limit = type + 2;
|
||||
else if (extent <= 3.0 * (Math.PI / 2.0))
|
||||
else if (Math.abs(extent) <= 3.0 * (Math.PI / 2.0))
|
||||
limit = type + 3;
|
||||
else
|
||||
limit = type + 4;
|
||||
|
@ -909,9 +904,20 @@ public abstract class Arc2D extends RectangularShape
|
|||
double kappa = (Math.sqrt(2.0) - 1.0) * (4.0 / 3.0);
|
||||
double quad = (Math.PI / 2.0);
|
||||
|
||||
double curr_begin = start + (current - 1) * quad;
|
||||
double curr_extent = Math.min((start + extent) - curr_begin, quad);
|
||||
double portion_of_a_quadrant = curr_extent / quad;
|
||||
double curr_begin;
|
||||
double curr_extent;
|
||||
if (extent > 0)
|
||||
{
|
||||
curr_begin = start + (current - 1) * quad;
|
||||
curr_extent = Math.min((start + extent) - curr_begin, quad);
|
||||
}
|
||||
else
|
||||
{
|
||||
curr_begin = start - (current - 1) * quad;
|
||||
curr_extent = Math.max((start + extent) - curr_begin, -quad);
|
||||
}
|
||||
|
||||
double portion_of_a_quadrant = Math.abs(curr_extent / quad);
|
||||
|
||||
double x0 = xmid + rx * Math.cos(curr_begin);
|
||||
double y0 = ymid - ry * Math.sin(curr_begin);
|
||||
|
@ -932,7 +938,11 @@ public abstract class Arc2D extends RectangularShape
|
|||
// will *subtract* the y value of this control vector from our first
|
||||
// point.
|
||||
cvec[0] = 0;
|
||||
cvec[1] = len;
|
||||
if (extent > 0)
|
||||
cvec[1] = len;
|
||||
else
|
||||
cvec[1] = -len;
|
||||
|
||||
trans.scale(rx, ry);
|
||||
trans.rotate(angle);
|
||||
trans.transform(cvec, 0, cvec, 0, 1);
|
||||
|
@ -942,7 +952,11 @@ public abstract class Arc2D extends RectangularShape
|
|||
// control vector #2 would, ideally, be sticking out and to the
|
||||
// right, in a first quadrant arc segment. again, subtraction of y.
|
||||
cvec[0] = 0;
|
||||
cvec[1] = -len;
|
||||
if (extent > 0)
|
||||
cvec[1] = -len;
|
||||
else
|
||||
cvec[1] = len;
|
||||
|
||||
trans.rotate(curr_extent);
|
||||
trans.transform(cvec, 0, cvec, 0, 1);
|
||||
coords[2] = x1 + cvec[0];
|
||||
|
|
|
@ -86,7 +86,7 @@ public final class GeneralPath implements Shape, Cloneable
|
|||
public static final int WIND_EVEN_ODD
|
||||
= java.awt.geom.PathIterator.WIND_EVEN_ODD;
|
||||
|
||||
/** Same constant as {@link PathIterator.WIND_NON_ZERO}. */
|
||||
/** Same constant as {@link PathIterator#WIND_NON_ZERO}. */
|
||||
public static final int WIND_NON_ZERO
|
||||
= java.awt.geom.PathIterator.WIND_NON_ZERO;
|
||||
|
||||
|
@ -140,7 +140,11 @@ public final class GeneralPath implements Shape, Cloneable
|
|||
/**
|
||||
* Constructs a GeneralPath with a specific winding rule
|
||||
* and the default initial capacity (20).
|
||||
* @param rule the winding rule (WIND_NON_ZERO or WIND_EVEN_ODD)
|
||||
* @param rule the winding rule ({@link #WIND_NON_ZERO} or
|
||||
* {@link #WIND_EVEN_ODD})
|
||||
*
|
||||
* @throws IllegalArgumentException if <code>rule</code> is not one of the
|
||||
* listed values.
|
||||
*/
|
||||
public GeneralPath(int rule)
|
||||
{
|
||||
|
@ -151,8 +155,12 @@ public final class GeneralPath implements Shape, Cloneable
|
|||
* Constructs a GeneralPath with a specific winding rule
|
||||
* and the initial capacity. The initial capacity should be
|
||||
* the approximate number of path segments to be used.
|
||||
* @param rule the winding rule (WIND_NON_ZERO or WIND_EVEN_ODD)
|
||||
* @param rule the winding rule ({@link #WIND_NON_ZERO} or
|
||||
* {@link #WIND_EVEN_ODD})
|
||||
* @param capacity the inital capacity, in path segments
|
||||
*
|
||||
* @throws IllegalArgumentException if <code>rule</code> is not one of the
|
||||
* listed values.
|
||||
*/
|
||||
public GeneralPath(int rule, int capacity)
|
||||
{
|
||||
|
@ -169,7 +177,10 @@ public final class GeneralPath implements Shape, Cloneable
|
|||
/**
|
||||
* Constructs a GeneralPath from an arbitrary shape object.
|
||||
* The Shapes PathIterator path and winding rule will be used.
|
||||
* @param s the shape
|
||||
*
|
||||
* @param s the shape (<code>null</code> not permitted).
|
||||
*
|
||||
* @throws NullPointerException if <code>shape</code> is <code>null</code>.
|
||||
*/
|
||||
public GeneralPath(Shape s)
|
||||
{
|
||||
|
@ -183,6 +194,9 @@ public final class GeneralPath implements Shape, Cloneable
|
|||
|
||||
/**
|
||||
* Adds a new point to a path.
|
||||
*
|
||||
* @param x the x-coordinate.
|
||||
* @param y the y-coordinate.
|
||||
*/
|
||||
public void moveTo(float x, float y)
|
||||
{
|
||||
|
@ -263,6 +277,11 @@ public final class GeneralPath implements Shape, Cloneable
|
|||
* Appends the segments of a Shape to the path. If <code>connect</code> is
|
||||
* true, the new path segments are connected to the existing one with a line.
|
||||
* The winding rule of the Shape is ignored.
|
||||
*
|
||||
* @param s the shape (<code>null</code> not permitted).
|
||||
* @param connect whether to connect the new shape to the existing path.
|
||||
*
|
||||
* @throws NullPointerException if <code>s</code> is <code>null</code>.
|
||||
*/
|
||||
public void append(Shape s, boolean connect)
|
||||
{
|
||||
|
@ -276,7 +295,7 @@ public final class GeneralPath implements Shape, Cloneable
|
|||
* PathIterator#SEG_LINETO} segment.
|
||||
*
|
||||
* @param iter the PathIterator specifying which segments shall be
|
||||
* appended.
|
||||
* appended (<code>null</code> not permitted).
|
||||
*
|
||||
* @param connect <code>true</code> for substituting the initial
|
||||
* {@link PathIterator#SEG_MOVETO} segment by a {@link
|
||||
|
@ -327,6 +346,8 @@ public final class GeneralPath implements Shape, Cloneable
|
|||
|
||||
/**
|
||||
* Returns the path’s current winding rule.
|
||||
*
|
||||
* @return {@link #WIND_EVEN_ODD} or {@link #WIND_NON_ZERO}.
|
||||
*/
|
||||
public int getWindingRule()
|
||||
{
|
||||
|
@ -338,6 +359,8 @@ public final class GeneralPath implements Shape, Cloneable
|
|||
* considered ’inside’ or ’outside’ the path
|
||||
* on drawing. Valid rules are WIND_EVEN_ODD for an even-odd winding rule,
|
||||
* or WIND_NON_ZERO for a non-zero winding rule.
|
||||
*
|
||||
* @param rule the rule ({@link #WIND_EVEN_ODD} or {@link #WIND_NON_ZERO}).
|
||||
*/
|
||||
public void setWindingRule(int rule)
|
||||
{
|
||||
|
@ -348,6 +371,8 @@ public final class GeneralPath implements Shape, Cloneable
|
|||
|
||||
/**
|
||||
* Returns the current appending point of the path.
|
||||
*
|
||||
* @return The point.
|
||||
*/
|
||||
public Point2D getCurrentPoint()
|
||||
{
|
||||
|
@ -367,6 +392,8 @@ public final class GeneralPath implements Shape, Cloneable
|
|||
|
||||
/**
|
||||
* Applies a transform to the path.
|
||||
*
|
||||
* @param xform the transform (<code>null</code> not permitted).
|
||||
*/
|
||||
public void transform(AffineTransform xform)
|
||||
{
|
||||
|
@ -706,6 +733,8 @@ public final class GeneralPath implements Shape, Cloneable
|
|||
/**
|
||||
* Helper method - ensure the size of the data arrays,
|
||||
* otherwise, reallocate new ones twice the size
|
||||
*
|
||||
* @param size the minimum array size.
|
||||
*/
|
||||
private void ensureSize(int size)
|
||||
{
|
||||
|
|
|
@ -326,15 +326,12 @@ public abstract class RectangularShape implements Shape, Cloneable
|
|||
|
||||
/**
|
||||
* Returns a bounding box for this shape, in integer format. Notice that you
|
||||
* may get a tighter bound with getBounds2D. If the frame is empty, the
|
||||
* box is the default empty box at the origin.
|
||||
* may get a tighter bound with getBounds2D.
|
||||
*
|
||||
* @return a bounding box
|
||||
*/
|
||||
public Rectangle getBounds()
|
||||
{
|
||||
if (isEmpty())
|
||||
return new Rectangle();
|
||||
double x = getX();
|
||||
double y = getY();
|
||||
double maxx = Math.ceil(x + getWidth());
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* RoundRectangle2D.java -- represents a rectangle with rounded corners
|
||||
Copyright (C) 2000, 2002, 2003, 2004 Free Software Foundation
|
||||
Copyright (C) 2000, 2002, 2003, 2004, 2006, Free Software Foundation
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -37,7 +37,6 @@ exception statement from your version. */
|
|||
|
||||
package java.awt.geom;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
|
||||
/** This class implements a rectangle with rounded corners.
|
||||
|
@ -46,13 +45,29 @@ import java.util.NoSuchElementException;
|
|||
*/
|
||||
public abstract class RoundRectangle2D extends RectangularShape
|
||||
{
|
||||
/** Return the arc height of this round rectangle. */
|
||||
/**
|
||||
* Return the arc height of this round rectangle. The arc height and width
|
||||
* control the roundness of the corners of the rectangle.
|
||||
*
|
||||
* @return The arc height.
|
||||
*
|
||||
* @see #getArcWidth()
|
||||
*/
|
||||
public abstract double getArcHeight();
|
||||
|
||||
/** Return the arc width of this round rectangle. */
|
||||
/**
|
||||
* Return the arc width of this round rectangle. The arc width and height
|
||||
* control the roundness of the corners of the rectangle.
|
||||
*
|
||||
* @return The arc width.
|
||||
*
|
||||
* @see #getArcHeight()
|
||||
*/
|
||||
public abstract double getArcWidth();
|
||||
|
||||
/** Set the values of this round rectangle
|
||||
/**
|
||||
* Set the values of this round rectangle.
|
||||
*
|
||||
* @param x The x coordinate
|
||||
* @param y The y coordinate
|
||||
* @param w The width
|
||||
|
@ -63,14 +78,16 @@ public abstract class RoundRectangle2D extends RectangularShape
|
|||
public abstract void setRoundRect(double x, double y, double w, double h,
|
||||
double arcWidth, double arcHeight);
|
||||
|
||||
/** Create a RoundRectangle2D. This is protected because this class
|
||||
/**
|
||||
* Create a RoundRectangle2D. This is protected because this class
|
||||
* is abstract and cannot be instantiated.
|
||||
*/
|
||||
protected RoundRectangle2D()
|
||||
{
|
||||
}
|
||||
|
||||
/** Return true if this object contains the specified point.
|
||||
/**
|
||||
* Return true if this object contains the specified point.
|
||||
* @param x The x coordinate
|
||||
* @param y The y coordinate
|
||||
*/
|
||||
|
@ -106,7 +123,8 @@ public abstract class RoundRectangle2D extends RectangularShape
|
|||
return dx * dx + dy * dy <= 1.0;
|
||||
}
|
||||
|
||||
/** Return true if this object contains the specified rectangle
|
||||
/**
|
||||
* Return true if this object contains the specified rectangle
|
||||
* @param x The x coordinate
|
||||
* @param y The y coordinate
|
||||
* @param w The width
|
||||
|
@ -120,176 +138,185 @@ public abstract class RoundRectangle2D extends RectangularShape
|
|||
&& contains(x + w, y));
|
||||
}
|
||||
|
||||
/** Return a new path iterator which iterates over this rectangle.
|
||||
/**
|
||||
* Return a new path iterator which iterates over this rectangle.
|
||||
*
|
||||
* @param at An affine transform to apply to the object
|
||||
*/
|
||||
public PathIterator getPathIterator(final AffineTransform at)
|
||||
public PathIterator getPathIterator(final AffineTransform at)
|
||||
{
|
||||
final double minx = getX();
|
||||
final double miny = getY();
|
||||
final double maxx = minx + getWidth();
|
||||
final double maxy = miny + getHeight();
|
||||
final double arcwidth = getArcWidth();
|
||||
final double archeight = getArcHeight();
|
||||
return new PathIterator()
|
||||
double arcW = Math.min(getArcWidth(), getWidth());
|
||||
double arcH = Math.min(getArcHeight(), getHeight());
|
||||
|
||||
// check for special cases...
|
||||
if (arcW <= 0 || arcH <= 0)
|
||||
{
|
||||
/** We iterate counterclockwise around the rectangle, starting in the
|
||||
* upper right. This variable tracks our current point, which
|
||||
* can be on either side of a given corner. */
|
||||
private int current = 0;
|
||||
Rectangle2D r = new Rectangle2D.Double(getX(), getY(), getWidth(),
|
||||
getHeight());
|
||||
return r.getPathIterator(at);
|
||||
}
|
||||
else if (arcW >= getWidth() && arcH >= getHeight())
|
||||
{
|
||||
Ellipse2D e = new Ellipse2D.Double(getX(), getY(), getWidth(),
|
||||
getHeight());
|
||||
return e.getPathIterator(at);
|
||||
}
|
||||
|
||||
// otherwise return the standard case...
|
||||
return new PathIterator()
|
||||
{
|
||||
double x = getX();
|
||||
double y = getY();
|
||||
double w = getWidth();
|
||||
double h = getHeight();
|
||||
double arcW = Math.min(getArcWidth(), w);
|
||||
double arcH = Math.min(getArcHeight(), h);
|
||||
Arc2D.Double arc = new Arc2D.Double();
|
||||
PathIterator corner;
|
||||
int step = -1;
|
||||
|
||||
/** Child path iterator, used for corners. */
|
||||
private PathIterator corner;
|
||||
public int currentSegment(double[] coords)
|
||||
{
|
||||
if (corner != null) // steps 1, 3, 5 and 7
|
||||
{
|
||||
int r = corner.currentSegment(coords);
|
||||
if (r == SEG_MOVETO)
|
||||
r = SEG_LINETO;
|
||||
return r;
|
||||
}
|
||||
if (step == -1)
|
||||
{
|
||||
// move to the start position
|
||||
coords[0] = x + w - arcW / 2;
|
||||
coords[1] = y;
|
||||
}
|
||||
else if (step == 0)
|
||||
{
|
||||
// top line
|
||||
coords[0] = x + arcW / 2;
|
||||
coords[1] = y;
|
||||
}
|
||||
else if (step == 2)
|
||||
{
|
||||
// left line
|
||||
coords[0] = x;
|
||||
coords[1] = y + h - arcH / 2;
|
||||
}
|
||||
else if (step == 4)
|
||||
{
|
||||
// bottom line
|
||||
coords[0] = x + w - arcW / 2;
|
||||
coords[1] = y + h;
|
||||
}
|
||||
else if (step == 6)
|
||||
{
|
||||
// right line
|
||||
coords[0] = x + w;
|
||||
coords[1] = y + arcH / 2;
|
||||
}
|
||||
if (at != null)
|
||||
at.transform(coords, 0, coords, 0, 1);
|
||||
return step == -1 ? SEG_MOVETO : SEG_LINETO;
|
||||
}
|
||||
|
||||
/** This is used when rendering the corners. We re-use the arc
|
||||
* for each corner. */
|
||||
private Arc2D arc = new Arc2D.Double();
|
||||
public int currentSegment(float[] coords) {
|
||||
if (corner != null) // steps 1, 3, 5 and 7
|
||||
{
|
||||
int r = corner.currentSegment(coords);
|
||||
if (r == SEG_MOVETO)
|
||||
r = SEG_LINETO;
|
||||
return r;
|
||||
}
|
||||
if (step == -1)
|
||||
{
|
||||
// move to the start position
|
||||
coords[0] = (float) (x + w - arcW / 2);
|
||||
coords[1] = (float) y;
|
||||
}
|
||||
else if (step == 0)
|
||||
{
|
||||
// top line
|
||||
coords[0] = (float) (x + arcW / 2);
|
||||
coords[1] = (float) y;
|
||||
}
|
||||
else if (step == 2)
|
||||
{
|
||||
// left line
|
||||
coords[0] = (float) x;
|
||||
coords[1] = (float) (y + h - arcH / 2);
|
||||
}
|
||||
else if (step == 4)
|
||||
{
|
||||
// bottom line
|
||||
coords[0] = (float) (x + w - arcW / 2);
|
||||
coords[1] = (float) (y + h);
|
||||
}
|
||||
else if (step == 6)
|
||||
{
|
||||
// right line
|
||||
coords[0] = (float) (x + w);
|
||||
coords[1] = (float) (y + arcH / 2);
|
||||
}
|
||||
if (at != null)
|
||||
at.transform(coords, 0, coords, 0, 1);
|
||||
return step == -1 ? SEG_MOVETO : SEG_LINETO;
|
||||
}
|
||||
|
||||
/** Temporary array used by getPoint. */
|
||||
private double[] temp = new double[2];
|
||||
public int getWindingRule() {
|
||||
return WIND_NON_ZERO;
|
||||
}
|
||||
|
||||
public int getWindingRule()
|
||||
{
|
||||
return WIND_NON_ZERO;
|
||||
}
|
||||
public boolean isDone() {
|
||||
return step >= 8;
|
||||
}
|
||||
|
||||
public boolean isDone()
|
||||
{
|
||||
return current > 9;
|
||||
}
|
||||
|
||||
private void getPoint(int val)
|
||||
{
|
||||
switch (val)
|
||||
{
|
||||
case 0:
|
||||
case 8:
|
||||
temp[0] = maxx;
|
||||
temp[1] = miny + archeight;
|
||||
break;
|
||||
case 7:
|
||||
temp[0] = maxx;
|
||||
temp[1] = maxy - archeight;
|
||||
break;
|
||||
case 6:
|
||||
temp[0] = maxx - arcwidth;
|
||||
temp[1] = maxy;
|
||||
break;
|
||||
case 5:
|
||||
temp[0] = minx + arcwidth;
|
||||
temp[1] = maxy;
|
||||
break;
|
||||
case 4:
|
||||
temp[0] = minx;
|
||||
temp[1] = maxy - archeight;
|
||||
break;
|
||||
case 3:
|
||||
temp[0] = minx;
|
||||
temp[1] = miny + archeight;
|
||||
break;
|
||||
case 2:
|
||||
temp[0] = minx + arcwidth;
|
||||
temp[1] = miny;
|
||||
break;
|
||||
case 1:
|
||||
temp[0] = maxx - arcwidth;
|
||||
temp[1] = miny;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void next()
|
||||
{
|
||||
if (current >= 8)
|
||||
++current;
|
||||
else if (corner != null)
|
||||
{
|
||||
// We're iterating through the corner. Work on the child
|
||||
// iterator; if it finishes, reset and move to the next
|
||||
// point along the rectangle.
|
||||
corner.next();
|
||||
if (corner.isDone())
|
||||
{
|
||||
corner = null;
|
||||
++current;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make an arc between this point on the rectangle and
|
||||
// the next one, and then iterate over this arc.
|
||||
getPoint(current);
|
||||
double x1 = temp[0];
|
||||
double y1 = temp[1];
|
||||
getPoint(current + 1);
|
||||
Rectangle2D.Double r = new Rectangle2D.Double(Math.min(x1,
|
||||
temp[0]),
|
||||
Math.min(y1,
|
||||
temp[1]),
|
||||
Math.abs(x1
|
||||
- temp[0]),
|
||||
Math.abs(y1
|
||||
- temp[1]));
|
||||
arc.setArc(r, (current >> 1) * 90.0, 90.0, Arc2D.OPEN);
|
||||
corner = arc.getPathIterator(at);
|
||||
}
|
||||
}
|
||||
|
||||
public int currentSegment(float[] coords)
|
||||
{
|
||||
if (corner != null)
|
||||
{
|
||||
int r = corner.currentSegment(coords);
|
||||
if (r == SEG_MOVETO)
|
||||
r = SEG_LINETO;
|
||||
return r;
|
||||
}
|
||||
|
||||
if (current < 9)
|
||||
{
|
||||
getPoint(current);
|
||||
coords[0] = (float) temp[0];
|
||||
coords[1] = (float) temp[1];
|
||||
}
|
||||
else if (current == 9)
|
||||
return SEG_CLOSE;
|
||||
else
|
||||
throw new NoSuchElementException("rect iterator out of bounds");
|
||||
|
||||
if (at != null)
|
||||
at.transform(coords, 0, coords, 0, 1);
|
||||
return current == 0 ? SEG_MOVETO : SEG_LINETO;
|
||||
}
|
||||
|
||||
public int currentSegment(double[] coords)
|
||||
{
|
||||
if (corner != null)
|
||||
{
|
||||
int r = corner.currentSegment(coords);
|
||||
if (r == SEG_MOVETO)
|
||||
r = SEG_LINETO;
|
||||
return r;
|
||||
}
|
||||
|
||||
if (current < 9)
|
||||
{
|
||||
getPoint(current);
|
||||
coords[0] = temp[0];
|
||||
coords[1] = temp[1];
|
||||
}
|
||||
else if (current == 9)
|
||||
return SEG_CLOSE;
|
||||
else
|
||||
throw new NoSuchElementException("rect iterator out of bounds");
|
||||
|
||||
if (at != null)
|
||||
at.transform(coords, 0, coords, 0, 1);
|
||||
return current == 0 ? SEG_MOVETO : SEG_LINETO;
|
||||
}
|
||||
};
|
||||
public void next()
|
||||
{
|
||||
if (corner != null)
|
||||
{
|
||||
corner.next();
|
||||
if (corner.isDone())
|
||||
{
|
||||
corner = null;
|
||||
step++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
step++;
|
||||
if (step == 1)
|
||||
{
|
||||
// create top left corner
|
||||
arc.setArc(x, y, arcW, arcH, 90, 90, Arc2D.OPEN);
|
||||
corner = arc.getPathIterator(at);
|
||||
}
|
||||
else if (step == 3)
|
||||
{
|
||||
// create bottom left corner
|
||||
arc.setArc(x, y + h - arcH, arcW, arcH, 180, 90,
|
||||
Arc2D.OPEN);
|
||||
corner = arc.getPathIterator(at);
|
||||
}
|
||||
else if (step == 5)
|
||||
{
|
||||
// create bottom right corner
|
||||
arc.setArc(x + w - arcW, y + h - arcH, arcW, arcH, 270, 90,
|
||||
Arc2D.OPEN);
|
||||
corner = arc.getPathIterator(at);
|
||||
}
|
||||
else if (step == 7)
|
||||
{
|
||||
// create top right corner
|
||||
arc.setArc(x + w - arcW, y, arcW, arcH, 0, 90, Arc2D.OPEN);
|
||||
corner = arc.getPathIterator(at);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** Return true if the given rectangle intersects this shape.
|
||||
/**
|
||||
* Return true if the given rectangle intersects this shape.
|
||||
* @param x The x coordinate
|
||||
* @param y The y coordinate
|
||||
* @param w The width
|
||||
|
@ -302,7 +329,8 @@ public abstract class RoundRectangle2D extends RectangularShape
|
|||
|| contains(x + w, y));
|
||||
}
|
||||
|
||||
/** Set the boundary of this round rectangle.
|
||||
/**
|
||||
* Set the boundary of this round rectangle.
|
||||
* @param x The x coordinate
|
||||
* @param y The y coordinate
|
||||
* @param w The width
|
||||
|
@ -314,7 +342,8 @@ public abstract class RoundRectangle2D extends RectangularShape
|
|||
setRoundRect(x, y, w, h, getArcWidth(), getArcHeight());
|
||||
}
|
||||
|
||||
/** Set the values of this round rectangle to be the same as those
|
||||
/**
|
||||
* Set the values of this round rectangle to be the same as those
|
||||
* of the argument.
|
||||
* @param rr The round rectangle to copy
|
||||
*/
|
||||
|
@ -324,8 +353,10 @@ public abstract class RoundRectangle2D extends RectangularShape
|
|||
rr.getArcWidth(), rr.getArcHeight());
|
||||
}
|
||||
|
||||
/** A subclass of RoundRectangle which keeps its parameters as
|
||||
* doubles. */
|
||||
/**
|
||||
* A subclass of RoundRectangle which keeps its parameters as
|
||||
* doubles.
|
||||
*/
|
||||
public static class Double extends RoundRectangle2D
|
||||
{
|
||||
/** The height of the corner arc. */
|
||||
|
@ -346,12 +377,15 @@ public abstract class RoundRectangle2D extends RectangularShape
|
|||
/** The height of this object. */
|
||||
public double height;
|
||||
|
||||
/** Construct a new instance, with all parameters set to 0. */
|
||||
/**
|
||||
* Construct a new instance, with all parameters set to 0.
|
||||
*/
|
||||
public Double()
|
||||
{
|
||||
}
|
||||
|
||||
/** Construct a new instance with the given arguments.
|
||||
/**
|
||||
* Construct a new instance with the given arguments.
|
||||
* @param x The x coordinate
|
||||
* @param y The y coordinate
|
||||
* @param w The width
|
||||
|
@ -422,8 +456,10 @@ public abstract class RoundRectangle2D extends RectangularShape
|
|||
}
|
||||
} // class Double
|
||||
|
||||
/** A subclass of RoundRectangle which keeps its parameters as
|
||||
* floats. */
|
||||
/**
|
||||
* A subclass of RoundRectangle which keeps its parameters as
|
||||
* floats.
|
||||
*/
|
||||
public static class Float extends RoundRectangle2D
|
||||
{
|
||||
/** The height of the corner arc. */
|
||||
|
@ -444,12 +480,15 @@ public abstract class RoundRectangle2D extends RectangularShape
|
|||
/** The height of this object. */
|
||||
public float height;
|
||||
|
||||
/** Construct a new instance, with all parameters set to 0. */
|
||||
/**
|
||||
* Construct a new instance, with all parameters set to 0.
|
||||
*/
|
||||
public Float()
|
||||
{
|
||||
}
|
||||
|
||||
/** Construct a new instance with the given arguments.
|
||||
/**
|
||||
* Construct a new instance with the given arguments.
|
||||
* @param x The x coordinate
|
||||
* @param y The y coordinate
|
||||
* @param w The width
|
||||
|
@ -508,6 +547,18 @@ public abstract class RoundRectangle2D extends RectangularShape
|
|||
return width <= 0 || height <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the dimensions for this rounded rectangle.
|
||||
*
|
||||
* @param x the x-coordinate of the top left corner.
|
||||
* @param y the y-coordinate of the top left corner.
|
||||
* @param w the width of the rectangle.
|
||||
* @param h the height of the rectangle.
|
||||
* @param arcWidth the arc width.
|
||||
* @param arcHeight the arc height.
|
||||
*
|
||||
* @see #setRoundRect(double, double, double, double, double, double)
|
||||
*/
|
||||
public void setRoundRect(float x, float y, float w, float h,
|
||||
float arcWidth, float arcHeight)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* InputContext.java -- provides the context for text input
|
||||
Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -76,6 +76,7 @@ import java.util.Locale;
|
|||
* java.awt.im.spi.InputMethodDescriptor.
|
||||
*
|
||||
* @author Eric Blake (ebb9@email.byu.edu)
|
||||
* @author Andrew John Hughes (gnu_andrew@member.fsf.org)
|
||||
* @see Component#getInputContext()
|
||||
* @see Component#enableInputMethods(boolean)
|
||||
* @since 1.2
|
||||
|
@ -86,7 +87,9 @@ public class InputContext
|
|||
/**
|
||||
* The list of installed input method descriptors.
|
||||
*/
|
||||
private static final ArrayList descriptors = new ArrayList();
|
||||
private static final ArrayList<InputMethodDescriptor> descriptors
|
||||
= new ArrayList<InputMethodDescriptor>();
|
||||
|
||||
static
|
||||
{
|
||||
Enumeration e;
|
||||
|
@ -123,7 +126,7 @@ public class InputContext
|
|||
{
|
||||
if (line.charAt(0) != '#')
|
||||
{
|
||||
Class c = Class.forName(line);
|
||||
Class<?> c = Class.forName(line);
|
||||
descriptors.add((InputMethodDescriptor) c.newInstance());
|
||||
}
|
||||
line = in.readLine().trim();
|
||||
|
@ -143,7 +146,8 @@ public class InputContext
|
|||
private InputMethod im;
|
||||
|
||||
/** Map of locales to the most recently selected input method. */
|
||||
private final HashMap recent = new HashMap();
|
||||
private final HashMap<Locale,InputMethod> recent
|
||||
= new HashMap<Locale,InputMethod>();
|
||||
|
||||
/** The list of acceptable character subsets. */
|
||||
private Character.Subset[] subsets;
|
||||
|
|
|
@ -41,6 +41,7 @@ import java.awt.Toolkit;
|
|||
import java.text.Annotation;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import java.util.Map;
|
||||
import java.awt.font.TextAttribute;
|
||||
|
||||
/**
|
||||
* This describes the highlight attributes of text composed in an input method.
|
||||
|
@ -95,7 +96,7 @@ public class InputMethodHighlight
|
|||
private final int variation;
|
||||
|
||||
/** The unmodifiable map of rendering styles. */
|
||||
private final Map style;
|
||||
private final Map<TextAttribute, ?> style;
|
||||
|
||||
/**
|
||||
* Create an input method highlight style, with variation 0 and null style
|
||||
|
@ -134,7 +135,7 @@ public class InputMethodHighlight
|
|||
* @since 1.3
|
||||
*/
|
||||
public InputMethodHighlight(boolean selected, int state, int variation,
|
||||
Map style)
|
||||
Map<TextAttribute, ?> style)
|
||||
{
|
||||
if (state != RAW_TEXT && state != CONVERTED_TEXT)
|
||||
throw new IllegalArgumentException();
|
||||
|
@ -181,7 +182,7 @@ public class InputMethodHighlight
|
|||
* @return the style map
|
||||
* @since 1.3
|
||||
*/
|
||||
public Map getStyle()
|
||||
public Map<TextAttribute, ?> getStyle()
|
||||
{
|
||||
return style;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* InputMethodContext.java -- communication between an input method and client
|
||||
Copyright (C) 2002, 2004 Free Software Foundation, Inc.
|
||||
Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -53,6 +53,7 @@ import javax.swing.JFrame;
|
|||
* {@link InputMethod#setInputMethodContext(InputMethodContext)}.
|
||||
*
|
||||
* @author Eric Blake (ebb9@email.byu.edu)
|
||||
* @author Andrew John Hughes (gnu_andrew@member.fsf.org)
|
||||
* @since 1.3
|
||||
* @status updated to 1.4
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* AffineTransformOp.java -- This class performs affine
|
||||
transformation between two images or rasters in 2 dimensions.
|
||||
Copyright (C) 2004 Free Software Foundation
|
||||
Copyright (C) 2004, 2006 Free Software Foundation
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -39,6 +39,7 @@ exception statement from your version. */
|
|||
package java.awt.image;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.geom.AffineTransform;
|
||||
|
@ -48,10 +49,14 @@ import java.awt.geom.Rectangle2D;
|
|||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* This class performs affine transformation between two images or
|
||||
* rasters in 2 dimensions.
|
||||
* AffineTransformOp performs matrix-based transformations (translations,
|
||||
* scales, flips, rotations, and shears).
|
||||
*
|
||||
* If interpolation is required, nearest neighbour, bilinear, and bicubic
|
||||
* methods are available.
|
||||
*
|
||||
* @author Olga Rodimina (rodimina@redhat.com)
|
||||
* @author Francis Kung (fkung@redhat.com)
|
||||
*/
|
||||
public class AffineTransformOp implements BufferedImageOp, RasterOp
|
||||
{
|
||||
|
@ -74,6 +79,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
|
|||
*
|
||||
* @param xform AffineTransform that will applied to the source image
|
||||
* @param interpolationType type of interpolation used
|
||||
* @throws ImagingOpException if the transform matrix is noninvertible
|
||||
*/
|
||||
public AffineTransformOp (AffineTransform xform, int interpolationType)
|
||||
{
|
||||
|
@ -102,6 +108,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
|
|||
*
|
||||
* @param xform AffineTransform that will applied to the source image
|
||||
* @param hints rendering hints that will be used during transformation
|
||||
* @throws ImagingOpException if the transform matrix is noninvertible
|
||||
*/
|
||||
public AffineTransformOp (AffineTransform xform, RenderingHints hints)
|
||||
{
|
||||
|
@ -112,185 +119,165 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates empty BufferedImage with the size equal to that of the
|
||||
* transformed image and correct number of bands. The newly created
|
||||
* Creates a new BufferedImage with the size equal to that of the
|
||||
* transformed image and the correct number of bands. The newly created
|
||||
* image is created with the specified ColorModel.
|
||||
* If the ColorModel is equal to null, then image is created
|
||||
* with the ColorModel of the source image.
|
||||
* If a ColorModel is not specified, an appropriate ColorModel is used.
|
||||
*
|
||||
* @param src source image
|
||||
* @param destCM color model for the destination image
|
||||
* @return new compatible destination image
|
||||
* @param src the source image.
|
||||
* @param destCM color model for the destination image (can be null).
|
||||
* @return a new compatible destination image.
|
||||
*/
|
||||
public BufferedImage createCompatibleDestImage (BufferedImage src,
|
||||
ColorModel destCM)
|
||||
{
|
||||
if (destCM != null)
|
||||
return new BufferedImage(destCM,
|
||||
createCompatibleDestRaster(src.getRaster()),
|
||||
src.isAlphaPremultiplied(), null);
|
||||
|
||||
// if destCm is not specified, use color model of the source image
|
||||
|
||||
if (destCM == null)
|
||||
destCM = src.getColorModel ();
|
||||
|
||||
return new BufferedImage (destCM,
|
||||
createCompatibleDestRaster (src.getRaster ()),
|
||||
src.isAlphaPremultiplied (),
|
||||
null);
|
||||
// This behaviour was determined by Mauve testcases, and is compatible
|
||||
// with the reference implementation
|
||||
if (src.getType() == BufferedImage.TYPE_INT_ARGB_PRE
|
||||
|| src.getType() == BufferedImage.TYPE_4BYTE_ABGR
|
||||
|| src.getType() == BufferedImage.TYPE_4BYTE_ABGR_PRE)
|
||||
return new BufferedImage(src.getWidth(), src.getHeight(), src.getType());
|
||||
|
||||
else
|
||||
return new BufferedImage(src.getWidth(), src.getHeight(),
|
||||
BufferedImage.TYPE_INT_ARGB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates empty WritableRaster with the size equal to the transformed
|
||||
* source raster and correct number of bands
|
||||
* Creates a new WritableRaster with the size equal to the transformed
|
||||
* source raster and correct number of bands .
|
||||
*
|
||||
* @param src source raster
|
||||
* @throws RasterFormatException if resulting width or height of raster is 0
|
||||
* @return new compatible raster
|
||||
* @param src the source raster.
|
||||
* @throws RasterFormatException if resulting width or height of raster is 0.
|
||||
* @return a new compatible raster.
|
||||
*/
|
||||
public WritableRaster createCompatibleDestRaster (Raster src)
|
||||
{
|
||||
Rectangle rect = (Rectangle) getBounds2D (src);
|
||||
Rectangle2D rect = getBounds2D(src);
|
||||
|
||||
// throw RasterFormatException if resulting width or height of the
|
||||
// transformed raster is 0
|
||||
|
||||
if (rect.getWidth () == 0 || rect.getHeight () == 0)
|
||||
if (rect.getWidth() == 0 || rect.getHeight() == 0)
|
||||
throw new RasterFormatException("width or height is 0");
|
||||
|
||||
return src.createCompatibleWritableRaster ((int) rect.getWidth (),
|
||||
(int) rect.getHeight ());
|
||||
return src.createCompatibleWritableRaster((int) rect.getWidth(),
|
||||
(int) rect.getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms source image using transform specified at the constructor.
|
||||
* The resulting transformed image is stored in the destination image.
|
||||
* The resulting transformed image is stored in the destination image if one
|
||||
* is provided; otherwise a new BufferedImage is created and returned.
|
||||
*
|
||||
* @param src source image
|
||||
* @param dst destination image
|
||||
* @return transformed source image
|
||||
* @throws IllegalArgumentException if the source and destination image are
|
||||
* the same
|
||||
* @return transformed source image.
|
||||
*/
|
||||
public final BufferedImage filter (BufferedImage src, BufferedImage dst)
|
||||
{
|
||||
|
||||
if (dst == src)
|
||||
throw new IllegalArgumentException ("src image cannot be the same as the dst image");
|
||||
|
||||
// If the destination image is null, then BufferedImage is
|
||||
// created with ColorModel of the source image
|
||||
throw new IllegalArgumentException("src image cannot be the same as "
|
||||
+ "the dst image");
|
||||
|
||||
// If the destination image is null, then use a compatible BufferedImage
|
||||
if (dst == null)
|
||||
dst = createCompatibleDestImage(src, src.getColorModel ());
|
||||
dst = createCompatibleDestImage(src, null);
|
||||
|
||||
// FIXME: Must check if color models of src and dst images are the same.
|
||||
// If it is not, then source image should be converted to color model
|
||||
// of the destination image
|
||||
|
||||
Graphics2D gr = (Graphics2D) dst.createGraphics ();
|
||||
gr.setRenderingHints (hints);
|
||||
gr.drawImage (src, transform, null);
|
||||
Graphics2D gr = (Graphics2D) dst.createGraphics();
|
||||
gr.setRenderingHints(hints);
|
||||
gr.drawImage(src, transform, null);
|
||||
return dst;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms source raster using transform specified at the constructor.
|
||||
* The resulting raster is stored in the destination raster.
|
||||
* The resulting raster is stored in the destination raster if it is not
|
||||
* null, otherwise a new raster is created and returned.
|
||||
*
|
||||
* @param src source raster
|
||||
* @param dst destination raster
|
||||
* @return transformed raster
|
||||
* @throws IllegalArgumentException if the source and destination are not
|
||||
* compatible
|
||||
* @return transformed raster.
|
||||
*/
|
||||
public final WritableRaster filter (Raster src, WritableRaster dst)
|
||||
public final WritableRaster filter(Raster src, WritableRaster dst)
|
||||
{
|
||||
// Initial checks
|
||||
if (dst == src)
|
||||
throw new IllegalArgumentException("src image cannot be the same as"
|
||||
+ " the dst image");
|
||||
+ " the dst image");
|
||||
|
||||
if (dst == null)
|
||||
dst = createCompatibleDestRaster(src);
|
||||
|
||||
if (src.getNumBands() != dst.getNumBands())
|
||||
throw new IllegalArgumentException("src and dst must have same number"
|
||||
+ " of bands");
|
||||
+ " of bands");
|
||||
|
||||
double[] dpts = new double[dst.getWidth() * 2];
|
||||
double[] pts = new double[dst.getWidth() * 2];
|
||||
for (int x = 0; x < dst.getWidth(); x++)
|
||||
{
|
||||
dpts[2 * x] = x + dst.getMinX();
|
||||
dpts[2 * x + 1] = x;
|
||||
}
|
||||
Rectangle srcbounds = src.getBounds();
|
||||
if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR))
|
||||
{
|
||||
for (int y = dst.getMinY(); y < dst.getMinY() + dst.getHeight(); y++)
|
||||
{
|
||||
try {
|
||||
transform.inverseTransform(dpts, 0, pts, 0, dst.getWidth() * 2);
|
||||
} catch (NoninvertibleTransformException e) {
|
||||
// Can't happen since the constructor traps this
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
for (int x = 0; x < dst.getWidth(); x++)
|
||||
{
|
||||
if (!srcbounds.contains(pts[2 * x], pts[2 * x + 1]))
|
||||
continue;
|
||||
dst.setDataElements(x + dst.getMinX(), y,
|
||||
src.getDataElements((int)pts[2 * x],
|
||||
(int)pts[2 * x + 1],
|
||||
null));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
|
||||
{
|
||||
double[] tmp = new double[4 * src.getNumBands()];
|
||||
for (int y = dst.getMinY(); y < dst.getMinY() + dst.getHeight(); y++)
|
||||
// Optimization for rasters that can be represented in the RGB colormodel:
|
||||
// wrap the rasters in images, and let Cairo do the transformation
|
||||
if (ColorModel.getRGBdefault().isCompatibleSampleModel(src.getSampleModel())
|
||||
&& ColorModel.getRGBdefault().isCompatibleSampleModel(dst.getSampleModel()))
|
||||
{
|
||||
try {
|
||||
transform.inverseTransform(dpts, 0, pts, 0, dst.getWidth() * 2);
|
||||
} catch (NoninvertibleTransformException e) {
|
||||
// Can't happen since the constructor traps this
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
for (int x = 0; x < dst.getWidth(); x++)
|
||||
{
|
||||
if (!srcbounds.contains(pts[2 * x], pts[2 * x + 1]))
|
||||
continue;
|
||||
int xx = (int)pts[2 * x];
|
||||
int yy = (int)pts[2 * x + 1];
|
||||
double dx = (pts[2 * x] - xx);
|
||||
double dy = (pts[2 * x + 1] - yy);
|
||||
|
||||
// TODO write this more intelligently
|
||||
if (xx == src.getMinX() + src.getWidth() - 1 ||
|
||||
yy == src.getMinY() + src.getHeight() - 1)
|
||||
{
|
||||
// bottom or right edge
|
||||
Arrays.fill(tmp, 0);
|
||||
src.getPixel(xx, yy, tmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal case
|
||||
src.getPixels(xx, yy, 2, 2, tmp);
|
||||
for (int b = 0; b < src.getNumBands(); b++)
|
||||
tmp[b] = dx * dy * tmp[b]
|
||||
+ (1 - dx) * dy * tmp[b + src.getNumBands()]
|
||||
+ dx * (1 - dy) * tmp[b + 2 * src.getNumBands()]
|
||||
+ (1 - dx) * (1 - dy) * tmp[b + 3 * src.getNumBands()];
|
||||
}
|
||||
dst.setPixel(x, y, tmp);
|
||||
}
|
||||
WritableRaster src2 = Raster.createWritableRaster(src.getSampleModel(),
|
||||
src.getDataBuffer(),
|
||||
new Point(src.getMinX(),
|
||||
src.getMinY()));
|
||||
BufferedImage iSrc = new BufferedImage(ColorModel.getRGBdefault(),
|
||||
src2, false, null);
|
||||
BufferedImage iDst = new BufferedImage(ColorModel.getRGBdefault(), dst,
|
||||
false, null);
|
||||
|
||||
return filter(iSrc, iDst).getRaster();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Bicubic
|
||||
throw new UnsupportedOperationException("not implemented yet");
|
||||
}
|
||||
|
||||
// Otherwise, we need to do the transformation in java code...
|
||||
// Create arrays to hold all the points
|
||||
double[] dstPts = new double[dst.getHeight() * dst.getWidth() * 2];
|
||||
double[] srcPts = new double[dst.getHeight() * dst.getWidth() * 2];
|
||||
|
||||
// Populate array with all points in the *destination* raster
|
||||
int i = 0;
|
||||
for (int x = 0; x < dst.getWidth(); x++)
|
||||
{
|
||||
for (int y = 0; y < dst.getHeight(); y++)
|
||||
{
|
||||
dstPts[i++] = x;
|
||||
dstPts[i++] = y;
|
||||
}
|
||||
}
|
||||
Rectangle srcbounds = src.getBounds();
|
||||
|
||||
// Use an inverse transform to map each point in the destination to
|
||||
// a point in the source. Note that, while all points in the destination
|
||||
// matrix are integers, this is not necessarily true for points in the
|
||||
// source (hence why interpolation is required)
|
||||
try
|
||||
{
|
||||
AffineTransform inverseTx = transform.createInverse();
|
||||
inverseTx.transform(dstPts, 0, srcPts, 0, dstPts.length / 2);
|
||||
}
|
||||
catch (NoninvertibleTransformException e)
|
||||
{
|
||||
// Shouldn't happen since the constructor traps this
|
||||
throw new ImagingOpException(e.getMessage());
|
||||
}
|
||||
|
||||
// Different interpolation methods...
|
||||
if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR))
|
||||
filterNearest(src, dst, dstPts, srcPts);
|
||||
|
||||
else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
|
||||
filterBilinear(src, dst, dstPts, srcPts);
|
||||
|
||||
else // bicubic
|
||||
filterBicubic(src, dst, dstPts, srcPts);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
@ -314,27 +301,22 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
|
|||
*/
|
||||
public final Rectangle2D getBounds2D (Raster src)
|
||||
{
|
||||
// determine new size for the transformed raster.
|
||||
// Need to calculate transformed coordinates of the lower right
|
||||
// corner of the raster. The upper left corner is always (0,0)
|
||||
|
||||
double x2 = (double) src.getWidth () + src.getMinX ();
|
||||
double y2 = (double) src.getHeight () + src.getMinY ();
|
||||
Point2D p2 = getPoint2D (new Point2D.Double (x2,y2), null);
|
||||
|
||||
Rectangle2D rect = new Rectangle (0, 0, (int) p2.getX (), (int) p2.getY ());
|
||||
return rect.getBounds ();
|
||||
return transform.createTransformedShape(src.getBounds()).getBounds2D();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns interpolation type used during transformations
|
||||
* Returns interpolation type used during transformations.
|
||||
*
|
||||
* @return interpolation type
|
||||
*/
|
||||
public final int getInterpolationType ()
|
||||
{
|
||||
if(hints.containsValue (RenderingHints.VALUE_INTERPOLATION_BILINEAR))
|
||||
if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
|
||||
return TYPE_BILINEAR;
|
||||
|
||||
else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BICUBIC))
|
||||
return TYPE_BICUBIC;
|
||||
|
||||
else
|
||||
return TYPE_NEAREST_NEIGHBOR;
|
||||
}
|
||||
|
@ -355,7 +337,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
|
|||
/**
|
||||
* Returns rendering hints that are used during transformation.
|
||||
*
|
||||
* @return rendering hints
|
||||
* @return the rendering hints used in this Op.
|
||||
*/
|
||||
public final RenderingHints getRenderingHints ()
|
||||
{
|
||||
|
@ -366,10 +348,261 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp
|
|||
* Returns transform used in transformation between source and destination
|
||||
* image.
|
||||
*
|
||||
* @return transform
|
||||
* @return the transform used in this Op.
|
||||
*/
|
||||
public final AffineTransform getTransform ()
|
||||
{
|
||||
return transform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform nearest-neighbour filtering
|
||||
*
|
||||
* @param src the source raster
|
||||
* @param dst the destination raster
|
||||
* @param dpts array of points on the destination raster
|
||||
* @param pts array of corresponding points on the source raster
|
||||
*/
|
||||
private void filterNearest(Raster src, WritableRaster dst, double[] dpts,
|
||||
double[] pts)
|
||||
{
|
||||
Rectangle srcbounds = src.getBounds();
|
||||
|
||||
// For all points on the destination raster, copy the value from the
|
||||
// corrosponding (rounded) source point
|
||||
for (int i = 0; i < dpts.length; i += 2)
|
||||
{
|
||||
int srcX = (int) Math.round(pts[i]) + src.getMinX();
|
||||
int srcY = (int) Math.round(pts[i + 1]) + src.getMinY();
|
||||
|
||||
if (srcbounds.contains(srcX, srcY))
|
||||
dst.setDataElements((int) dpts[i] + dst.getMinX(),
|
||||
(int) dpts[i + 1] + dst.getMinY(),
|
||||
src.getDataElements(srcX, srcY, null));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform bilinear filtering
|
||||
*
|
||||
* @param src the source raster
|
||||
* @param dst the destination raster
|
||||
* @param dpts array of points on the destination raster
|
||||
* @param pts array of corresponding points on the source raster
|
||||
*/
|
||||
private void filterBilinear(Raster src, WritableRaster dst, double[] dpts,
|
||||
double[] pts)
|
||||
{
|
||||
Rectangle srcbounds = src.getBounds();
|
||||
|
||||
Object xyarr = null;
|
||||
Object xp1arr = null;
|
||||
Object yp1arr = null;
|
||||
Object xyp1arr = null;
|
||||
|
||||
double xy;
|
||||
double xp1;
|
||||
double yp1;
|
||||
double xyp1;
|
||||
|
||||
double[] result = new double[src.getNumBands()];
|
||||
|
||||
// For all points in the destination raster, use bilinear interpolation
|
||||
// to find the value from the corrosponding source points
|
||||
for (int i = 0; i < dpts.length; i += 2)
|
||||
{
|
||||
int srcX = (int) Math.round(pts[i]) + src.getMinX();
|
||||
int srcY = (int) Math.round(pts[i + 1]) + src.getMinY();
|
||||
|
||||
if (srcbounds.contains(srcX, srcY))
|
||||
{
|
||||
// Corner case at the bottom or right edge; use nearest neighbour
|
||||
if (pts[i] >= src.getWidth() - 1
|
||||
|| pts[i + 1] >= src.getHeight() - 1)
|
||||
dst.setDataElements((int) dpts[i] + dst.getMinX(),
|
||||
(int) dpts[i + 1] + dst.getMinY(),
|
||||
src.getDataElements(srcX, srcY, null));
|
||||
|
||||
// Standard case, apply the bilinear formula
|
||||
else
|
||||
{
|
||||
int x = (int) Math.floor(pts[i] + src.getMinX());
|
||||
int y = (int) Math.floor(pts[i + 1] + src.getMinY());
|
||||
double xdiff = pts[i] + src.getMinX() - x;
|
||||
double ydiff = pts[i + 1] + src.getMinY() - y;
|
||||
|
||||
// Get surrounding pixels used in interpolation... optimized
|
||||
// to use the smallest datatype possible.
|
||||
if (src.getTransferType() == DataBuffer.TYPE_DOUBLE
|
||||
|| src.getTransferType() == DataBuffer.TYPE_FLOAT)
|
||||
{
|
||||
xyarr = src.getPixel(x, y, (double[])xyarr);
|
||||
xp1arr = src.getPixel(x+1, y, (double[])xp1arr);
|
||||
yp1arr = src.getPixel(x, y+1, (double[])yp1arr);
|
||||
xyp1arr = src.getPixel(x+1, y+1, (double[])xyp1arr);
|
||||
}
|
||||
else
|
||||
{
|
||||
xyarr = src.getPixel(x, y, (int[])xyarr);
|
||||
xp1arr = src.getPixel(x+1, y, (int[])xp1arr);
|
||||
yp1arr = src.getPixel(x, y+1, (int[])yp1arr);
|
||||
xyp1arr = src.getPixel(x+1, y+1, (int[])xyp1arr);
|
||||
}
|
||||
// using
|
||||
// array[] pixels = src.getPixels(x, y, 2, 2, pixels);
|
||||
// instead of doing four individual src.getPixel() calls
|
||||
// should be faster, but benchmarking shows that it's not...
|
||||
|
||||
// Run interpolation for each band
|
||||
for (int j = 0; j < src.getNumBands(); j++)
|
||||
{
|
||||
// Pull individual sample values out of array
|
||||
if (src.getTransferType() == DataBuffer.TYPE_DOUBLE
|
||||
|| src.getTransferType() == DataBuffer.TYPE_FLOAT)
|
||||
{
|
||||
xy = ((double[])xyarr)[j];
|
||||
xp1 = ((double[])xp1arr)[j];
|
||||
yp1 = ((double[])yp1arr)[j];
|
||||
xyp1 = ((double[])xyp1arr)[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
xy = ((int[])xyarr)[j];
|
||||
xp1 = ((int[])xp1arr)[j];
|
||||
yp1 = ((int[])yp1arr)[j];
|
||||
xyp1 = ((int[])xyp1arr)[j];
|
||||
}
|
||||
|
||||
// If all four samples are identical, there's no need to
|
||||
// calculate anything
|
||||
if (xy == xp1 && xy == yp1 && xy == xyp1)
|
||||
result[j] = xy;
|
||||
|
||||
// Run bilinear interpolation formula
|
||||
else
|
||||
result[j] = (xy * (1-xdiff) + xp1 * xdiff)
|
||||
* (1-ydiff)
|
||||
+ (yp1 * (1-xdiff) + xyp1 * xdiff)
|
||||
* ydiff;
|
||||
}
|
||||
|
||||
dst.setPixel((int)dpts[i] + dst.getMinX(),
|
||||
(int)dpts[i+1] + dst.getMinY(),
|
||||
result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform bicubic filtering
|
||||
* based on http://local.wasp.uwa.edu.au/~pbourke/colour/bicubic/
|
||||
*
|
||||
* @param src the source raster
|
||||
* @param dst the destination raster
|
||||
* @param dpts array of points on the destination raster
|
||||
* @param pts array of corresponding points on the source raster
|
||||
*/
|
||||
private void filterBicubic(Raster src, WritableRaster dst, double[] dpts,
|
||||
double[] pts)
|
||||
{
|
||||
Rectangle srcbounds = src.getBounds();
|
||||
double[] result = new double[src.getNumBands()];
|
||||
Object pixels = null;
|
||||
|
||||
// For all points on the destination raster, perform bicubic interpolation
|
||||
// from corrosponding source points
|
||||
for (int i = 0; i < dpts.length; i += 2)
|
||||
{
|
||||
if (srcbounds.contains((int) Math.round(pts[i]) + src.getMinX(),
|
||||
(int) Math.round(pts[i + 1]) + src.getMinY()))
|
||||
{
|
||||
int x = (int) Math.floor(pts[i] + src.getMinX());
|
||||
int y = (int) Math.floor(pts[i + 1] + src.getMinY());
|
||||
double dx = pts[i] + src.getMinX() - x;
|
||||
double dy = pts[i + 1] + src.getMinY() - y;
|
||||
Arrays.fill(result, 0);
|
||||
|
||||
for (int m = - 1; m < 3; m++)
|
||||
for (int n = - 1; n < 3; n++)
|
||||
{
|
||||
// R(x) = ( P(x+2)^3 - 4 P(x+1)^3 + 6 P(x)^3 - 4 P(x-1)^3 ) / 6
|
||||
double r1 = 0;
|
||||
double r2 = 0;
|
||||
|
||||
// Calculate R(m - dx)
|
||||
double rx = m - dx + 2;
|
||||
r1 += rx * rx * rx;
|
||||
|
||||
rx = m - dx + 1;
|
||||
if (rx > 0)
|
||||
r1 -= 4 * rx * rx * rx;
|
||||
|
||||
rx = m - dx;
|
||||
if (rx > 0)
|
||||
r1 += 6 * rx * rx * rx;
|
||||
|
||||
rx = m - dx - 1;
|
||||
if (rx > 0)
|
||||
r1 -= 4 * rx * rx * rx;
|
||||
|
||||
r1 /= 6;
|
||||
|
||||
// Calculate R(dy - n);
|
||||
rx = dy - n + 2;
|
||||
if (rx > 0)
|
||||
r2 += rx * rx * rx;
|
||||
|
||||
rx = dy - n + 1;
|
||||
if (rx > 0)
|
||||
r2 -= 4 * rx * rx * rx;
|
||||
|
||||
rx = dy - n;
|
||||
if (rx > 0)
|
||||
r2 += 6 * rx * rx * rx;
|
||||
|
||||
rx = dy - n - 1;
|
||||
if (rx > 0)
|
||||
r2 -= 4 * rx * rx * rx;
|
||||
|
||||
r2 /= 6;
|
||||
|
||||
// Calculate F(i+m, j+n) R(m - dx) R(dy - n)
|
||||
// Check corner cases
|
||||
int srcX = x + m;
|
||||
if (srcX >= src.getMinX() + src.getWidth())
|
||||
srcX = src.getMinX() + src.getWidth() - 1;
|
||||
else if (srcX < src.getMinX())
|
||||
srcX = src.getMinX();
|
||||
|
||||
int srcY = y + n;
|
||||
if (srcY >= src.getMinY() + src.getHeight())
|
||||
srcY = src.getMinY() + src.getHeight() - 1;
|
||||
else if (srcY < src.getMinY())
|
||||
srcY = src.getMinY();
|
||||
|
||||
// Calculate once for each band, using the smallest
|
||||
// datatype possible
|
||||
if (src.getTransferType() == DataBuffer.TYPE_DOUBLE
|
||||
|| src.getTransferType() == DataBuffer.TYPE_FLOAT)
|
||||
{
|
||||
pixels = src.getPixel(srcX, srcY, (double[])pixels);
|
||||
for (int j = 0; j < result.length; j++)
|
||||
result[j] += ((double[])pixels)[j] * r1 * r2;
|
||||
}
|
||||
else
|
||||
{
|
||||
pixels = src.getPixel(srcX, srcY, (int[])pixels);
|
||||
for (int j = 0; j < result.length; j++)
|
||||
result[j] += ((int[])pixels)[j] * r1 * r2;
|
||||
}
|
||||
}
|
||||
|
||||
// Put it all together
|
||||
dst.setPixel((int)dpts[i] + dst.getMinX(),
|
||||
(int)dpts[i+1] + dst.getMinY(),
|
||||
result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* Copyright (C) 2004 Free Software Foundation
|
||||
/* BandCombineOp.java - perform a combination on the bands of a raster
|
||||
Copyright (C) 2004, 2006 Free Software Foundation
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -36,10 +37,10 @@ exception statement from your version. */
|
|||
|
||||
package java.awt.image;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Filter Raster pixels by applying a matrix.
|
||||
|
@ -53,6 +54,9 @@ import java.awt.geom.Rectangle2D;
|
|||
* for the destination. Therefore the destination Raster must contain the
|
||||
* same number of bands as the number of rows in the filter matrix.
|
||||
*
|
||||
* This Op assumes that samples are integers; floating point sample types will
|
||||
* be rounded to their nearest integer value during filtering.
|
||||
*
|
||||
* @author Jerry Quinn (jlquinn@optonline.net)
|
||||
*/
|
||||
public class BandCombineOp implements RasterOp
|
||||
|
@ -65,52 +69,74 @@ public class BandCombineOp implements RasterOp
|
|||
*
|
||||
* @param matrix The matrix to filter pixels with.
|
||||
* @param hints Rendering hints to apply. Ignored.
|
||||
* @throws ArrayIndexOutOfBoundsException if the matrix is invalid
|
||||
*/
|
||||
public BandCombineOp(float[][] matrix, RenderingHints hints)
|
||||
{
|
||||
this.matrix = matrix;
|
||||
this.matrix = new float[matrix.length][];
|
||||
int width = matrix[0].length;
|
||||
for (int i = 0; i < matrix.length; i++)
|
||||
{
|
||||
this.matrix[i] = new float[width + 1];
|
||||
for (int j = 0; j < width; j++)
|
||||
this.matrix[i][j] = matrix[i][j];
|
||||
|
||||
// The reference implementation pads the array with a trailing zero...
|
||||
this.matrix[i][width] = 0;
|
||||
}
|
||||
|
||||
this.hints = hints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter Raster pixels through a matrix.
|
||||
*
|
||||
* Applies the Op matrix to source pixes to produce dest pixels. Each row
|
||||
* of the matrix is multiplied by the src pixel components to produce the
|
||||
* dest pixel. If matrix is one more than the number of bands in the src,
|
||||
* the last element is implicitly multiplied by 1, i.e. added to the sum
|
||||
* for that dest component.
|
||||
*
|
||||
* If dest is null, a suitable Raster is created. This implementation uses
|
||||
* createCompatibleDestRaster.
|
||||
* Filter Raster pixels through a matrix. Applies the Op matrix to source
|
||||
* pixes to produce dest pixels. Each row of the matrix is multiplied by the
|
||||
* src pixel components to produce the dest pixel. If matrix is one more than
|
||||
* the number of bands in the src, the last element is implicitly multiplied
|
||||
* by 1, i.e. added to the sum for that dest component. If dest is null, a
|
||||
* suitable Raster is created. This implementation uses
|
||||
* createCompatibleDestRaster.
|
||||
*
|
||||
* @param src The source Raster.
|
||||
* @param dest The destination Raster, or null.
|
||||
* @returns The destination Raster or an allocated Raster.
|
||||
* @param dest The destination Raster, or null.
|
||||
* @throws IllegalArgumentException if the destination raster is incompatible
|
||||
* with the source raster.
|
||||
* @return The filtered Raster.
|
||||
* @see java.awt.image.RasterOp#filter(java.awt.image.Raster,
|
||||
*java.awt.image.WritableRaster)
|
||||
* java.awt.image.WritableRaster)
|
||||
*/
|
||||
public WritableRaster filter(Raster src, WritableRaster dest) {
|
||||
if (dest == null)
|
||||
dest = createCompatibleDestRaster(src);
|
||||
|
||||
else if (dest.getNumBands() != src.getNumBands()
|
||||
|| dest.getTransferType() != src.getTransferType())
|
||||
throw new IllegalArgumentException("Destination raster is incompatible with source raster");
|
||||
|
||||
// Filter the pixels
|
||||
float[] spix = new float[matrix[0].length];
|
||||
float[] dpix = new float[matrix.length];
|
||||
int[] spix = new int[matrix[0].length - 1];
|
||||
int[] spix2 = new int[matrix[0].length - 1];
|
||||
int[] dpix = new int[matrix.length];
|
||||
for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++)
|
||||
for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++)
|
||||
{
|
||||
// In case matrix rows have implicit translation
|
||||
spix[spix.length - 1] = 1.0f;
|
||||
src.getPixel(x, y, spix);
|
||||
for (int i = 0; i < matrix.length; i++)
|
||||
{
|
||||
dpix[i] = 0;
|
||||
for (int j = 0; j < matrix[0].length; j++)
|
||||
dpix[i] += spix[j] * matrix[i][j];
|
||||
// In case matrix rows have implicit translation
|
||||
spix[spix.length - 1] = 1;
|
||||
src.getPixel(x, y, spix);
|
||||
|
||||
// Do not re-calculate if pixel is identical to the last one
|
||||
// (ie, blocks of the same colour)
|
||||
if (!Arrays.equals(spix, spix2))
|
||||
{
|
||||
System.arraycopy(spix, 0, spix2, 0, spix.length);
|
||||
for (int i = 0; i < matrix.length; i++)
|
||||
{
|
||||
dpix[i] = 0;
|
||||
for (int j = 0; j < matrix[0].length - 1; j++)
|
||||
dpix[i] += spix[j] * (int)matrix[i][j];
|
||||
}
|
||||
}
|
||||
dest.setPixel(x, y, dpix);
|
||||
}
|
||||
dest.setPixel(x, y, dpix);
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
@ -125,28 +151,48 @@ public class BandCombineOp implements RasterOp
|
|||
|
||||
/**
|
||||
* Creates a new WritableRaster that can be used as the destination for this
|
||||
* Op. This implementation creates a Banded Raster with data type FLOAT.
|
||||
* @see
|
||||
*java.awt.image.RasterOp#createCompatibleDestRaster(java.awt.image.Raster)
|
||||
* Op. The number of bands in the source raster must equal the number of rows
|
||||
* in the op matrix, which must also be equal to either the number of columns
|
||||
* or (columns - 1) in the matrix.
|
||||
*
|
||||
* @param src The source raster.
|
||||
* @return A compatible raster.
|
||||
* @see java.awt.image.RasterOp#createCompatibleDestRaster(java.awt.image.Raster)
|
||||
* @throws IllegalArgumentException if the raster is incompatible with the
|
||||
* matrix.
|
||||
*/
|
||||
public WritableRaster createCompatibleDestRaster(Raster src)
|
||||
{
|
||||
return Raster.createBandedRaster(DataBuffer.TYPE_FLOAT, src.getWidth(),
|
||||
src.getHeight(), matrix.length,
|
||||
new Point(src.getMinX(), src.getMinY()));
|
||||
// Destination raster must have same number of bands as source
|
||||
if (src.getNumBands() != matrix.length)
|
||||
throw new IllegalArgumentException("Number of rows in matrix specifies an "
|
||||
+ "incompatible number of bands");
|
||||
|
||||
// We use -1 and -2 because we previously padded the rows with a trailing 0
|
||||
if (src.getNumBands() != matrix[0].length - 1
|
||||
&& src.getNumBands() != matrix[0].length - 2)
|
||||
throw new IllegalArgumentException("Incompatible number of bands: "
|
||||
+ "the number of bands in the raster must equal the number of "
|
||||
+ "columns in the matrix, optionally minus one");
|
||||
|
||||
return src.createCompatibleWritableRaster();
|
||||
}
|
||||
|
||||
/** Return corresponding destination point for source point.
|
||||
/**
|
||||
* Return corresponding destination point for source point. Because this is
|
||||
* not a geometric operation, it simply returns a copy of the source.
|
||||
*
|
||||
* LookupOp will return the value of src unchanged.
|
||||
* @param src The source point.
|
||||
* @param dst The destination point.
|
||||
* @return dst The destination point.
|
||||
* @see java.awt.image.RasterOp#getPoint2D(java.awt.geom.Point2D,
|
||||
*java.awt.geom.Point2D)
|
||||
*/
|
||||
public final Point2D getPoint2D(Point2D src, Point2D dst)
|
||||
{
|
||||
if (dst == null) return (Point2D)src.clone();
|
||||
if (dst == null)
|
||||
return (Point2D)src.clone();
|
||||
|
||||
dst.setLocation(src);
|
||||
return dst;
|
||||
}
|
||||
|
@ -159,7 +205,11 @@ public class BandCombineOp implements RasterOp
|
|||
return hints;
|
||||
}
|
||||
|
||||
/** Return the matrix for this Op. */
|
||||
/**
|
||||
* Return the matrix used in this operation.
|
||||
*
|
||||
* @return The matrix used in this operation.
|
||||
*/
|
||||
public final float[][] getMatrix()
|
||||
{
|
||||
return matrix;
|
||||
|
|
|
@ -38,6 +38,7 @@ exception statement from your version. */
|
|||
|
||||
package java.awt.image;
|
||||
|
||||
import gnu.java.awt.Buffers;
|
||||
import gnu.java.awt.ComponentDataBlitOp;
|
||||
|
||||
import java.awt.Graphics;
|
||||
|
@ -79,26 +80,36 @@ public class BufferedImage extends Image
|
|||
TYPE_BYTE_BINARY = 12,
|
||||
TYPE_BYTE_INDEXED = 13;
|
||||
|
||||
static final int[] bits3 = { 8, 8, 8 };
|
||||
static final int[] bits4 = { 8, 8, 8, 8 };
|
||||
static final int[] bits1byte = { 8 };
|
||||
static final int[] bits1ushort = { 16 };
|
||||
/**
|
||||
* Vector of TileObservers (or null)
|
||||
*/
|
||||
Vector tileObservers;
|
||||
|
||||
static final int[] masks_int = { 0x00ff0000,
|
||||
0x0000ff00,
|
||||
0x000000ff,
|
||||
DataBuffer.TYPE_INT };
|
||||
static final int[] masks_565 = { 0xf800,
|
||||
0x07e0,
|
||||
0x001f,
|
||||
DataBuffer.TYPE_USHORT};
|
||||
static final int[] masks_555 = { 0x7c00,
|
||||
0x03e0,
|
||||
0x001f,
|
||||
DataBuffer.TYPE_USHORT};
|
||||
/**
|
||||
* The image's WritableRaster
|
||||
*/
|
||||
WritableRaster raster;
|
||||
|
||||
/**
|
||||
* The associated ColorModel
|
||||
*/
|
||||
ColorModel colorModel;
|
||||
|
||||
/**
|
||||
* The image's properties (or null)
|
||||
*/
|
||||
Hashtable properties;
|
||||
|
||||
/**
|
||||
* Whether alpha is premultiplied
|
||||
*/
|
||||
boolean isPremultiplied;
|
||||
|
||||
/**
|
||||
* The predefined type, if any.
|
||||
*/
|
||||
int type;
|
||||
|
||||
Vector observers;
|
||||
|
||||
/**
|
||||
* Creates a new <code>BufferedImage</code> with the specified width, height
|
||||
* and type. Valid <code>type</code> values are:
|
||||
|
@ -119,155 +130,181 @@ public class BufferedImage extends Image
|
|||
* <li>{@link #TYPE_BYTE_INDEXED}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param w the width (must be > 0).
|
||||
* @param h the height (must be > 0).
|
||||
* @param width the width (must be > 0).
|
||||
* @param height the height (must be > 0).
|
||||
* @param type the image type (see the list of valid types above).
|
||||
*
|
||||
* @throws IllegalArgumentException if <code>w</code> or <code>h</code> is
|
||||
* less than or equal to zero.
|
||||
* @throws IllegalArgumentException if <code>width</code> or
|
||||
* <code>height</code> is less than or equal to zero.
|
||||
* @throws IllegalArgumentException if <code>type</code> is not one of the
|
||||
* specified values.
|
||||
*/
|
||||
public BufferedImage(int w, int h, int type)
|
||||
public BufferedImage(int width, int height, int type)
|
||||
{
|
||||
SampleModel sm = null;
|
||||
ColorModel cm = null;
|
||||
|
||||
boolean alpha = false;
|
||||
boolean premultiplied = false;
|
||||
switch (type)
|
||||
boolean premultiplied = (type == BufferedImage.TYPE_INT_ARGB_PRE ||
|
||||
type == BufferedImage.TYPE_4BYTE_ABGR_PRE);
|
||||
|
||||
switch( type )
|
||||
{
|
||||
case TYPE_4BYTE_ABGR_PRE:
|
||||
case TYPE_INT_ARGB_PRE:
|
||||
premultiplied = true;
|
||||
// fall through
|
||||
case TYPE_INT_ARGB:
|
||||
case TYPE_4BYTE_ABGR:
|
||||
alpha = true;
|
||||
}
|
||||
|
||||
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
|
||||
switch (type)
|
||||
{
|
||||
case TYPE_INT_RGB:
|
||||
case TYPE_INT_ARGB:
|
||||
case TYPE_INT_ARGB_PRE:
|
||||
case TYPE_USHORT_565_RGB:
|
||||
case TYPE_USHORT_555_RGB:
|
||||
int[] masks = null;
|
||||
switch (type)
|
||||
{
|
||||
case TYPE_INT_RGB:
|
||||
case TYPE_INT_ARGB:
|
||||
case TYPE_INT_ARGB_PRE:
|
||||
masks = masks_int;
|
||||
break;
|
||||
case TYPE_USHORT_565_RGB:
|
||||
masks = masks_565;
|
||||
break;
|
||||
case TYPE_USHORT_555_RGB:
|
||||
masks = masks_555;
|
||||
break;
|
||||
}
|
||||
|
||||
cm = new DirectColorModel(cs,
|
||||
32, // 32 bits in an int
|
||||
masks[0], // r
|
||||
masks[1], // g
|
||||
masks[2], // b
|
||||
alpha ? 0xff000000 : 0,
|
||||
premultiplied,
|
||||
masks[3] // data type
|
||||
);
|
||||
case BufferedImage.TYPE_INT_RGB:
|
||||
sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_INT,
|
||||
width, height,
|
||||
new int[]{ 0x00FF0000,
|
||||
0x0000FF00,
|
||||
0x000000FF } ) ;
|
||||
cm = new DirectColorModel( 24, 0xff0000, 0xff00, 0xff );
|
||||
break;
|
||||
|
||||
case TYPE_INT_BGR:
|
||||
String msg =
|
||||
"FIXME: Programmer is confused. Why (and how) does a " +
|
||||
"TYPE_INT_BGR image use ComponentColorModel to store " +
|
||||
"8-bit values? Is data type TYPE_INT or TYPE_BYTE. What " +
|
||||
"is the difference between TYPE_INT_BGR and TYPE_3BYTE_BGR?";
|
||||
throw new UnsupportedOperationException(msg);
|
||||
|
||||
case TYPE_3BYTE_BGR:
|
||||
case TYPE_4BYTE_ABGR:
|
||||
case TYPE_4BYTE_ABGR_PRE:
|
||||
case TYPE_BYTE_GRAY:
|
||||
case TYPE_USHORT_GRAY:
|
||||
int[] bits = null;
|
||||
int dataType = DataBuffer.TYPE_BYTE;
|
||||
switch (type) {
|
||||
case TYPE_3BYTE_BGR:
|
||||
bits = bits3;
|
||||
break;
|
||||
case TYPE_4BYTE_ABGR:
|
||||
case TYPE_4BYTE_ABGR_PRE:
|
||||
bits = bits4;
|
||||
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 ?
|
||||
Transparency.TRANSLUCENT:
|
||||
Transparency.OPAQUE,
|
||||
dataType);
|
||||
case BufferedImage.TYPE_3BYTE_BGR:
|
||||
sm = new PixelInterleavedSampleModel( DataBuffer.TYPE_BYTE,
|
||||
width, height,
|
||||
3, width * 3,
|
||||
new int[]{ 2, 1, 0 } );
|
||||
cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
|
||||
false, false,
|
||||
BufferedImage.OPAQUE,
|
||||
DataBuffer.TYPE_BYTE);
|
||||
break;
|
||||
|
||||
case BufferedImage.TYPE_INT_ARGB:
|
||||
case BufferedImage.TYPE_INT_ARGB_PRE:
|
||||
sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_INT,
|
||||
width, height,
|
||||
new int[]{ 0x00FF0000,
|
||||
0x0000FF00,
|
||||
0x000000FF,
|
||||
0xFF000000 } );
|
||||
if (premultiplied)
|
||||
cm = new DirectColorModel( ColorSpace.getInstance(ColorSpace.CS_sRGB),
|
||||
32, 0xff0000, 0xff00, 0xff, 0xff000000,
|
||||
true,
|
||||
Buffers.smallestAppropriateTransferType(32));
|
||||
else
|
||||
cm = new DirectColorModel( 32, 0xff0000, 0xff00, 0xff, 0xff000000 );
|
||||
break;
|
||||
case TYPE_BYTE_BINARY:
|
||||
byte[] vals = { 0, (byte) 0xff };
|
||||
cm = new IndexColorModel(8, 2, vals, vals, vals);
|
||||
|
||||
case BufferedImage.TYPE_4BYTE_ABGR:
|
||||
case BufferedImage.TYPE_4BYTE_ABGR_PRE:
|
||||
sm = new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
|
||||
width, height,
|
||||
4, 4*width,
|
||||
new int[]{3, 2, 1, 0});
|
||||
cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
|
||||
true, premultiplied,
|
||||
BufferedImage.TRANSLUCENT,
|
||||
DataBuffer.TYPE_BYTE);
|
||||
break;
|
||||
case TYPE_BYTE_INDEXED:
|
||||
String msg2 = "type not implemented yet";
|
||||
throw new UnsupportedOperationException(msg2);
|
||||
// FIXME: build color-cube and create color model
|
||||
|
||||
case BufferedImage.TYPE_INT_BGR:
|
||||
sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_INT,
|
||||
width, height,
|
||||
new int[]{ 0x000000FF,
|
||||
0x0000FF00,
|
||||
0x00FF0000 } ) ;
|
||||
cm = new DirectColorModel( 24, 0xff, 0xff00, 0xff0000 );
|
||||
break;
|
||||
|
||||
case BufferedImage.TYPE_USHORT_565_RGB:
|
||||
sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_USHORT,
|
||||
width, height,
|
||||
new int[]{ 0xF800,
|
||||
0x7E0,
|
||||
0x1F } ) ;
|
||||
cm = new DirectColorModel( 16, 0xF800, 0x7E0, 0x1F );
|
||||
break;
|
||||
case BufferedImage.TYPE_USHORT_555_RGB:
|
||||
sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_USHORT,
|
||||
width, height,
|
||||
new int[]{ 0x7C00,
|
||||
0x3E0,
|
||||
0x1F } ) ;
|
||||
cm = new DirectColorModel( 15, 0x7C00, 0x3E0, 0x1F );
|
||||
break;
|
||||
|
||||
case BufferedImage.TYPE_BYTE_INDEXED:
|
||||
cm = createDefaultIndexedColorModel( false );
|
||||
|
||||
case BufferedImage.TYPE_BYTE_GRAY:
|
||||
sm = new PixelInterleavedSampleModel( DataBuffer.TYPE_BYTE,
|
||||
width, height,
|
||||
1, width, new int[]{ 0 } );
|
||||
break;
|
||||
|
||||
case BufferedImage.TYPE_USHORT_GRAY:
|
||||
sm = new PixelInterleavedSampleModel( DataBuffer.TYPE_USHORT,
|
||||
width, height,
|
||||
1, width, new int[]{ 0 } );
|
||||
break;
|
||||
|
||||
case BufferedImage.TYPE_BYTE_BINARY:
|
||||
cm = createDefaultIndexedColorModel( true );
|
||||
sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
|
||||
width, height, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown image type " + type);
|
||||
sm = null;
|
||||
}
|
||||
|
||||
if( sm == null )
|
||||
throw new IllegalArgumentException("Unknown predefined image type.");
|
||||
|
||||
init(cm,
|
||||
cm.createCompatibleWritableRaster(w, h),
|
||||
premultiplied,
|
||||
null, // no properties
|
||||
type
|
||||
);
|
||||
if( cm == null ) // only for the grayscale types
|
||||
{
|
||||
int buftype;
|
||||
int[] bits = new int[1];
|
||||
if( type == BufferedImage.TYPE_BYTE_GRAY )
|
||||
{
|
||||
buftype = DataBuffer.TYPE_BYTE;
|
||||
bits[0] = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
buftype = DataBuffer.TYPE_USHORT;
|
||||
bits[0] = 16;
|
||||
}
|
||||
ColorSpace graySpace = ColorSpace.getInstance( ColorSpace.CS_GRAY );
|
||||
|
||||
cm = new ComponentColorModel( graySpace, bits, false, false,
|
||||
Transparency.OPAQUE, buftype );
|
||||
}
|
||||
|
||||
init( cm,
|
||||
Raster.createWritableRaster(sm, new Point( 0, 0 ) ),
|
||||
premultiplied,
|
||||
null, // no properties
|
||||
type );
|
||||
}
|
||||
|
||||
public BufferedImage(int w, int h, int type,
|
||||
IndexColorModel indexcolormodel)
|
||||
{
|
||||
if ((type != TYPE_BYTE_BINARY) && (type != TYPE_BYTE_INDEXED))
|
||||
throw new IllegalArgumentException("type must be binary or indexed");
|
||||
throw new IllegalArgumentException("Type must be TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED");
|
||||
if( indexcolormodel.getMapSize() > 16 && type == TYPE_BYTE_BINARY )
|
||||
throw new IllegalArgumentException("Type TYPE_BYTE_BINARY cannot have a larger than 16-color palette.");
|
||||
if( indexcolormodel.getMapSize() > 256 )
|
||||
throw new IllegalArgumentException("Byte type cannot have a larger than 256-color palette.");
|
||||
|
||||
init(indexcolormodel,
|
||||
indexcolormodel.createCompatibleWritableRaster(w, h),
|
||||
false, // not premultiplied (guess)
|
||||
null, // no properties
|
||||
type);
|
||||
init( indexcolormodel,
|
||||
indexcolormodel.createCompatibleWritableRaster(w, h),
|
||||
indexcolormodel.isAlphaPremultiplied(),
|
||||
null, // no properties
|
||||
type );
|
||||
}
|
||||
|
||||
public BufferedImage(ColorModel colormodel,
|
||||
WritableRaster writableraster,
|
||||
boolean premultiplied,
|
||||
Hashtable properties)
|
||||
Hashtable<?,?> properties)
|
||||
{
|
||||
init(colormodel, writableraster, premultiplied, properties,
|
||||
TYPE_CUSTOM);
|
||||
// TODO: perhaps try to identify type?
|
||||
}
|
||||
|
||||
WritableRaster raster;
|
||||
ColorModel colorModel;
|
||||
Hashtable properties;
|
||||
boolean isPremultiplied;
|
||||
int type;
|
||||
|
||||
|
||||
private void init(ColorModel cm,
|
||||
WritableRaster writableraster,
|
||||
boolean premultiplied,
|
||||
|
@ -280,12 +317,48 @@ public class BufferedImage extends Image
|
|||
isPremultiplied = premultiplied;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
//public void addTileObserver(TileObserver tileobserver) {}
|
||||
|
||||
/**
|
||||
* Creates the default palettes for the predefined indexed color types
|
||||
* (256-color or black-and-white)
|
||||
*
|
||||
* @param binary - If <code>true</code>, a black and white palette,
|
||||
* otherwise a default 256-color palette is returned.
|
||||
*/
|
||||
private IndexColorModel createDefaultIndexedColorModel( boolean binary )
|
||||
{
|
||||
if( binary )
|
||||
{
|
||||
byte[] t = new byte[]{ 0, (byte)255 };
|
||||
return new IndexColorModel( 1, 2, t, t, t );
|
||||
}
|
||||
|
||||
byte[] r = new byte[256];
|
||||
byte[] g = new byte[256];
|
||||
byte[] b = new byte[256];
|
||||
int index = 0;
|
||||
for( int i = 0; i < 6; i++ )
|
||||
for( int j = 0; j < 6; j++ )
|
||||
for( int k = 0; k < 6; k++ )
|
||||
{
|
||||
r[ index ] = (byte)(i * 51);
|
||||
g[ index ] = (byte)(j * 51);
|
||||
b[ index ] = (byte)(k * 51);
|
||||
index++;
|
||||
}
|
||||
while( index < 256 )
|
||||
{
|
||||
r[ index ] = g[ index ] = b[ index ] =
|
||||
(byte)(18 + (index - 216) * 6);
|
||||
index++;
|
||||
}
|
||||
return new IndexColorModel( 8, 256, r, g, b );
|
||||
}
|
||||
|
||||
public void coerceData(boolean premultiplied)
|
||||
{
|
||||
colorModel = colorModel.coerceData(raster, premultiplied);
|
||||
isPremultiplied = premultiplied;
|
||||
}
|
||||
|
||||
public WritableRaster copyData(WritableRaster dest)
|
||||
|
@ -555,7 +628,7 @@ public class BufferedImage extends Image
|
|||
};
|
||||
}
|
||||
|
||||
public Vector getSources()
|
||||
public Vector<RenderedImage> getSources()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
@ -726,10 +799,10 @@ public class BufferedImage extends Image
|
|||
*/
|
||||
public void addTileObserver (TileObserver to)
|
||||
{
|
||||
if (observers == null)
|
||||
observers = new Vector ();
|
||||
if (tileObservers == null)
|
||||
tileObservers = new Vector ();
|
||||
|
||||
observers.add (to);
|
||||
tileObservers.add (to);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -741,10 +814,10 @@ public class BufferedImage extends Image
|
|||
*/
|
||||
public void removeTileObserver (TileObserver to)
|
||||
{
|
||||
if (observers == null)
|
||||
if (tileObservers == null)
|
||||
return;
|
||||
|
||||
observers.remove (to);
|
||||
tileObservers.remove (to);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -38,7 +38,10 @@ exception statement from your version. */
|
|||
|
||||
package java.awt.image;
|
||||
|
||||
import gnu.java.awt.Buffers;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.color.ICC_ColorSpace;
|
||||
|
@ -47,9 +50,9 @@ import java.awt.geom.Point2D;
|
|||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
/**
|
||||
* ColorConvertOp is a filter for converting an image from one colorspace to
|
||||
* another colorspace. The filter can convert the image through a sequence
|
||||
* of colorspaces or just from source to destination.
|
||||
* ColorConvertOp is a filter for converting images or rasters between
|
||||
* colorspaces, either through a sequence of colorspaces or just from source to
|
||||
* destination.
|
||||
*
|
||||
* Color conversion is done on the color components without alpha. Thus
|
||||
* if a BufferedImage has alpha premultiplied, this is divided out before
|
||||
|
@ -63,24 +66,22 @@ import java.awt.geom.Rectangle2D;
|
|||
*/
|
||||
public class ColorConvertOp implements BufferedImageOp, RasterOp
|
||||
{
|
||||
private ColorSpace srccs;
|
||||
private ColorSpace dstcs;
|
||||
private RenderingHints hints;
|
||||
private ICC_Profile[] profiles;
|
||||
private ICC_Profile[] profiles = null;
|
||||
private ColorSpace[] spaces;
|
||||
private boolean rasterValid;
|
||||
|
||||
|
||||
/**
|
||||
* Convert BufferedImage through a ColorSpace.
|
||||
* Convert a BufferedImage through a ColorSpace.
|
||||
*
|
||||
* This filter version is only valid for BufferedImages. The source image
|
||||
* is converted to cspace. If the destination is not null, it is then
|
||||
* converted to the destination colorspace. Normally this filter will only
|
||||
* be used with a null destination.
|
||||
* Objects created with this constructor can be used to convert
|
||||
* BufferedImage's to a destination ColorSpace. Attempts to convert Rasters
|
||||
* with this constructor will result in an IllegalArgumentException when the
|
||||
* filter(Raster, WritableRaster) method is called.
|
||||
*
|
||||
* @param cspace The target color space.
|
||||
* @param hints Rendering hints to use in conversion, or null.
|
||||
* @param hints Rendering hints to use in conversion, if any (may be null)
|
||||
* @throws NullPointerException if the ColorSpace is null.
|
||||
*/
|
||||
public ColorConvertOp(ColorSpace cspace, RenderingHints hints)
|
||||
{
|
||||
|
@ -88,9 +89,27 @@ public class ColorConvertOp implements BufferedImageOp, RasterOp
|
|||
throw new NullPointerException();
|
||||
spaces = new ColorSpace[]{cspace};
|
||||
this.hints = hints;
|
||||
rasterValid = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from a source colorspace to a destination colorspace.
|
||||
*
|
||||
* This constructor takes two ColorSpace arguments as the source and
|
||||
* destination color spaces. It is usually used with the
|
||||
* filter(Raster, WritableRaster) method, in which case the source colorspace
|
||||
* is assumed to correspond to the source Raster, and the destination
|
||||
* colorspace with the destination Raster.
|
||||
*
|
||||
* If used with BufferedImages that do not match the source or destination
|
||||
* colorspaces specified here, there is an implicit conversion from the
|
||||
* source image to the source ColorSpace, or the destination ColorSpace to
|
||||
* the destination image.
|
||||
*
|
||||
* @param srcCspace The source ColorSpace.
|
||||
* @param dstCspace The destination ColorSpace.
|
||||
* @param hints Rendering hints to use in conversion, if any (may be null).
|
||||
* @throws NullPointerException if any ColorSpace is null.
|
||||
*/
|
||||
public ColorConvertOp(ColorSpace srcCspace, ColorSpace dstCspace,
|
||||
RenderingHints hints)
|
||||
{
|
||||
|
@ -101,61 +120,77 @@ public class ColorConvertOp implements BufferedImageOp, RasterOp
|
|||
}
|
||||
|
||||
/**
|
||||
* Convert from a source image destination image color space.
|
||||
* Convert from a source colorspace to a destinatino colorspace.
|
||||
*
|
||||
* This constructor builds a ColorConvertOp from an array of ICC_Profiles.
|
||||
* The source image will be converted through the sequence of color spaces
|
||||
* The source will be converted through the sequence of color spaces
|
||||
* defined by the profiles. If the sequence of profiles doesn't give a
|
||||
* well-defined conversion, throws IllegalArgumentException.
|
||||
* well-defined conversion, an IllegalArgumentException is thrown.
|
||||
*
|
||||
* NOTE: Sun's docs don't clearly define what a well-defined conversion is
|
||||
* - or perhaps someone smarter can come along and sort it out.
|
||||
*
|
||||
* For BufferedImages, when the first and last profiles match the
|
||||
* requirements of the source and destination color space respectively, the
|
||||
* corresponding conversion is unnecessary. TODO: code this up. I don't
|
||||
* yet understand how you determine this.
|
||||
* If used with BufferedImages that do not match the source or destination
|
||||
* colorspaces specified here, there is an implicit conversion from the
|
||||
* source image to the source ColorSpace, or the destination ColorSpace to
|
||||
* the destination image.
|
||||
*
|
||||
* For Rasters, the first and last profiles must have the same number of
|
||||
* bands as the source and destination Rasters, respectively. If this is
|
||||
* not the case, or there fewer than 2 profiles, an IllegalArgumentException
|
||||
* will be thrown.
|
||||
*
|
||||
* @param profiles
|
||||
* @param hints
|
||||
* @param profiles An array of ICC_Profile's to convert through.
|
||||
* @param hints Rendering hints to use in conversion, if any (may be null).
|
||||
* @throws NullPointerException if the profile array is null.
|
||||
* @throws IllegalArgumentException if the array is not a well-defined
|
||||
* conversion.
|
||||
*/
|
||||
public ColorConvertOp(ICC_Profile[] profiles, RenderingHints hints)
|
||||
{
|
||||
if (profiles == null)
|
||||
throw new NullPointerException();
|
||||
|
||||
this.hints = hints;
|
||||
this.profiles = profiles;
|
||||
// TODO: Determine if this is well-defined.
|
||||
|
||||
// Create colorspace array with space for src and dest colorspace
|
||||
// Note that the ICC_ColorSpace constructor will throw an
|
||||
// IllegalArgumentException if the profile is invalid; thus we check
|
||||
// for a "well defined conversion"
|
||||
spaces = new ColorSpace[profiles.length];
|
||||
for (int i = 0; i < profiles.length; i++)
|
||||
spaces[i] = new ICC_ColorSpace(profiles[i]);
|
||||
}
|
||||
|
||||
/** Convert from source image color space to destination image color space.
|
||||
/**
|
||||
* Convert from source color space to destination color space.
|
||||
*
|
||||
* Only valid for BufferedImage objects, this Op converts from the source
|
||||
* color space to the destination color space. The destination can't be
|
||||
* null for this operation.
|
||||
* image's color space to the destination image's color space.
|
||||
*
|
||||
* @param hints Rendering hints to use during conversion, or null.
|
||||
* The destination in the filter(BufferedImage, BufferedImage) method cannot
|
||||
* be null for this operation, and it also cannot be used with the
|
||||
* filter(Raster, WritableRaster) method.
|
||||
*
|
||||
* @param hints Rendering hints to use in conversion, if any (may be null).
|
||||
*/
|
||||
public ColorConvertOp(RenderingHints hints)
|
||||
{
|
||||
this.hints = hints;
|
||||
srccs = null;
|
||||
dstcs = null;
|
||||
rasterValid = false;
|
||||
this.hints = hints;
|
||||
spaces = new ColorSpace[0];
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.awt.image.BufferedImageOp#filter(java.awt.image.BufferedImage,
|
||||
java.awt.image.BufferedImage)
|
||||
/**
|
||||
* Converts the source image using the conversion path specified in the
|
||||
* constructor. The resulting image is stored in the destination image if one
|
||||
* is provided; otherwise a new BufferedImage is created and returned.
|
||||
*
|
||||
* The source and destination BufferedImage (if one is supplied) must have
|
||||
* the same dimensions.
|
||||
*
|
||||
* @param src The source image.
|
||||
* @param dst The destination image.
|
||||
* @throws IllegalArgumentException if the rasters and/or color spaces are
|
||||
* incompatible.
|
||||
* @return The transformed image.
|
||||
*/
|
||||
public final BufferedImage filter(BufferedImage src, BufferedImage dst)
|
||||
{
|
||||
|
@ -163,129 +198,241 @@ public class ColorConvertOp implements BufferedImageOp, RasterOp
|
|||
// For now we just suck it up and create intermediate buffers.
|
||||
|
||||
if (dst == null && spaces.length == 0)
|
||||
throw new IllegalArgumentException();
|
||||
throw new IllegalArgumentException("Not enough color space information "
|
||||
+ "to complete conversion.");
|
||||
|
||||
if (dst != null
|
||||
&& (src.getHeight() != dst.getHeight() || src.getWidth() != dst.getWidth()))
|
||||
throw new IllegalArgumentException("Source and destination images have "
|
||||
+ "different dimensions");
|
||||
|
||||
// Make sure input isn't premultiplied by alpha
|
||||
if (src.isAlphaPremultiplied())
|
||||
{
|
||||
BufferedImage tmp = createCompatibleDestImage(src, src.getColorModel());
|
||||
copyimage(src, tmp);
|
||||
tmp.coerceData(false);
|
||||
src = tmp;
|
||||
}
|
||||
{
|
||||
BufferedImage tmp = createCompatibleDestImage(src, src.getColorModel());
|
||||
copyimage(src, tmp);
|
||||
tmp.coerceData(false);
|
||||
src = tmp;
|
||||
}
|
||||
|
||||
ColorModel scm = src.getColorModel();
|
||||
// Convert through defined intermediate conversions
|
||||
BufferedImage tmp;
|
||||
for (int i = 0; i < spaces.length; i++)
|
||||
{
|
||||
BufferedImage tmp = createCompatibleDestImage(src, scm);
|
||||
copyimage(src, tmp);
|
||||
src = tmp;
|
||||
}
|
||||
{
|
||||
if (src.getColorModel().getColorSpace().getType() != spaces[i].getType())
|
||||
{
|
||||
tmp = createCompatibleDestImage(src,
|
||||
createCompatibleColorModel(src,
|
||||
spaces[i]));
|
||||
copyimage(src, tmp);
|
||||
src = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
// Intermediate conversions leave result in src
|
||||
// No implicit conversion to destination type needed; return result from the
|
||||
// last intermediate conversions (which was left in src)
|
||||
if (dst == null)
|
||||
return src;
|
||||
|
||||
// Apply final conversion
|
||||
copyimage(src, dst);
|
||||
|
||||
dst = src;
|
||||
|
||||
// Implicit conversion to destination image's color space
|
||||
else
|
||||
copyimage(src, dst);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.awt.image.BufferedImageOp#createCompatibleDestImage(java.awt.image.BufferedImage, java.awt.image.ColorModel)
|
||||
/**
|
||||
* Converts the source raster using the conversion path specified in the
|
||||
* constructor. The resulting raster is stored in the destination raster if
|
||||
* one is provided; otherwise a new WritableRaster is created and returned.
|
||||
*
|
||||
* This operation is not valid with every constructor of this class; see
|
||||
* the constructors for details. Further, the source raster must have the
|
||||
* same number of bands as the source ColorSpace, and the destination raster
|
||||
* must have the same number of bands as the destination ColorSpace.
|
||||
*
|
||||
* The source and destination raster (if one is supplied) must also have the
|
||||
* same dimensions.
|
||||
*
|
||||
* @param src The source raster.
|
||||
* @param dest The destination raster.
|
||||
* @throws IllegalArgumentException if the rasters and/or color spaces are
|
||||
* incompatible.
|
||||
* @return The transformed raster.
|
||||
*/
|
||||
public final WritableRaster filter(Raster src, WritableRaster dest)
|
||||
{
|
||||
// Various checks to ensure that the rasters and color spaces are compatible
|
||||
if (spaces.length < 2)
|
||||
throw new IllegalArgumentException("Not enough information about " +
|
||||
"source and destination colorspaces.");
|
||||
|
||||
if (spaces[0].getNumComponents() != src.getNumBands()
|
||||
|| (dest != null && spaces[spaces.length - 1].getNumComponents() != dest.getNumBands()))
|
||||
throw new IllegalArgumentException("Source or destination raster " +
|
||||
"contains the wrong number of bands.");
|
||||
|
||||
if (dest != null
|
||||
&& (src.getHeight() != dest.getHeight() || src.getWidth() != dest.getWidth()))
|
||||
throw new IllegalArgumentException("Source and destination rasters " +
|
||||
"have different dimensions");
|
||||
|
||||
// Need to iterate through each color space.
|
||||
// spaces[0] corresponds to the ColorSpace of the source raster, and
|
||||
// spaces[spaces.length - 1] corresponds to the ColorSpace of the
|
||||
// destination, with any number (or zero) of intermediate conversions.
|
||||
|
||||
for (int i = 0; i < spaces.length - 2; i++)
|
||||
{
|
||||
WritableRaster tmp = createCompatibleDestRaster(src, spaces[i + 1],
|
||||
false,
|
||||
src.getTransferType());
|
||||
copyraster(src, spaces[i], tmp, spaces[i + 1]);
|
||||
src = tmp;
|
||||
}
|
||||
|
||||
// The last conversion is done outside of the loop so that we can
|
||||
// use the dest raster supplied, instead of creating our own temp raster
|
||||
if (dest == null)
|
||||
dest = createCompatibleDestRaster(src, spaces[spaces.length - 1], false,
|
||||
DataBuffer.TYPE_BYTE);
|
||||
copyraster(src, spaces[spaces.length - 2], dest, spaces[spaces.length - 1]);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty BufferedImage with the size equal to the source and the
|
||||
* correct number of bands for the conversion defined in this Op. The newly
|
||||
* created image is created with the specified ColorModel, or if no ColorModel
|
||||
* is supplied, an appropriate one is chosen.
|
||||
*
|
||||
* @param src The source image.
|
||||
* @param dstCM A color model for the destination image (may be null).
|
||||
* @throws IllegalArgumentException if an appropriate colormodel cannot be
|
||||
* chosen with the information given.
|
||||
* @return The new compatible destination image.
|
||||
*/
|
||||
public BufferedImage createCompatibleDestImage(BufferedImage src,
|
||||
ColorModel dstCM)
|
||||
ColorModel dstCM)
|
||||
{
|
||||
// FIXME: set properties to those in src
|
||||
if (dstCM == null && spaces.length == 0)
|
||||
throw new IllegalArgumentException("Don't know the destination " +
|
||||
"colormodel");
|
||||
|
||||
if (dstCM == null)
|
||||
{
|
||||
dstCM = createCompatibleColorModel(src, spaces[spaces.length - 1]);
|
||||
}
|
||||
|
||||
return new BufferedImage(dstCM,
|
||||
src.getRaster().createCompatibleWritableRaster(),
|
||||
src.isPremultiplied,
|
||||
null);
|
||||
createCompatibleDestRaster(src.getRaster(),
|
||||
dstCM.getColorSpace(),
|
||||
src.getColorModel().hasAlpha,
|
||||
dstCM.getTransferType()),
|
||||
src.isPremultiplied, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new WritableRaster with the size equal to the source and the
|
||||
* correct number of bands.
|
||||
*
|
||||
* Note, the new Raster will always use a BYTE storage size, regardless of
|
||||
* the color model or defined destination; this is for compatibility with
|
||||
* the reference implementation.
|
||||
*
|
||||
* @param src The source Raster.
|
||||
* @throws IllegalArgumentException if there isn't enough colorspace
|
||||
* information to create a compatible Raster.
|
||||
* @return The new compatible destination raster.
|
||||
*/
|
||||
public WritableRaster createCompatibleDestRaster(Raster src)
|
||||
{
|
||||
if (spaces.length < 2)
|
||||
throw new IllegalArgumentException("Not enough destination colorspace " +
|
||||
"information");
|
||||
|
||||
// Create a new raster with the last ColorSpace in the conversion
|
||||
// chain, and with no alpha (implied)
|
||||
return createCompatibleDestRaster(src, spaces[spaces.length-1], false,
|
||||
DataBuffer.TYPE_BYTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array of ICC_Profiles used to create this Op, or null if the
|
||||
* Op was created using ColorSpace arguments.
|
||||
*
|
||||
* @return The array of ICC_Profiles, or null.
|
||||
*/
|
||||
public final ICC_Profile[] getICC_Profiles()
|
||||
{
|
||||
return profiles;
|
||||
}
|
||||
|
||||
/** Return the rendering hints for this op. */
|
||||
/**
|
||||
* Returns the rendering hints for this op.
|
||||
*
|
||||
* @return The rendering hints for this Op, or null.
|
||||
*/
|
||||
public final RenderingHints getRenderingHints()
|
||||
{
|
||||
return hints;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.awt.image.RasterOp#filter(java.awt.image.Raster, java.awt.image.WritableRaster)
|
||||
*/
|
||||
public final WritableRaster filter(Raster src, WritableRaster dest)
|
||||
{
|
||||
if (!rasterValid)
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
// Need to iterate through each color space - there must be at least 2
|
||||
for (int i = 1; i < spaces.length - 1; i++)
|
||||
{
|
||||
// FIXME: this is wrong. tmp needs to have the same number of bands as
|
||||
// spaces[i] has.
|
||||
WritableRaster tmp = createCompatibleDestRaster(src);
|
||||
copyraster(src, spaces[i - 1], tmp, spaces[i]);
|
||||
src = tmp;
|
||||
}
|
||||
|
||||
// FIXME: this is wrong. dst needs to have the same number of bands as
|
||||
// spaces[i] has.
|
||||
if (dest == null)
|
||||
dest = createCompatibleDestRaster(src);
|
||||
copyraster(src, spaces[spaces.length - 2],
|
||||
dest, spaces[spaces.length - 1]);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.awt.image.RasterOp#createCompatibleDestRaster(java.awt.image.Raster)
|
||||
*/
|
||||
public WritableRaster createCompatibleDestRaster(Raster src)
|
||||
{
|
||||
return src.createCompatibleWritableRaster();
|
||||
}
|
||||
|
||||
/** Return corresponding destination point for source point.
|
||||
/**
|
||||
* Returns the corresponding destination point for a source point.
|
||||
* Because this is not a geometric operation, the destination and source
|
||||
* points will be identical.
|
||||
*
|
||||
* LookupOp will return the value of src unchanged.
|
||||
* @param src The source point.
|
||||
* @param dst The destination point.
|
||||
* @see java.awt.image.RasterOp#getPoint2D(java.awt.geom.Point2D, java.awt.geom.Point2D)
|
||||
* @param dst The transformed destination point.
|
||||
* @return The transformed destination point.
|
||||
*/
|
||||
public final Point2D getPoint2D(Point2D src, Point2D dst)
|
||||
{
|
||||
if (dst == null) return (Point2D)src.clone();
|
||||
if (dst == null)
|
||||
return (Point2D)src.clone();
|
||||
|
||||
dst.setLocation(src);
|
||||
return dst;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.awt.image.BufferedImageOp#getBounds2D(java.awt.image.BufferedImage)
|
||||
/**
|
||||
* Returns the corresponding destination boundary of a source boundary.
|
||||
* Because this is not a geometric operation, the destination and source
|
||||
* boundaries will be identical.
|
||||
*
|
||||
* @param src The source boundary.
|
||||
* @return The boundaries of the destination.
|
||||
*/
|
||||
public final Rectangle2D getBounds2D(BufferedImage src)
|
||||
{
|
||||
return src.getRaster().getBounds();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.awt.image.RasterOp#getBounds2D(java.awt.image.Raster)
|
||||
/**
|
||||
* Returns the corresponding destination boundary of a source boundary.
|
||||
* Because this is not a geometric operation, the destination and source
|
||||
* boundaries will be identical.
|
||||
*
|
||||
* @param src The source boundary.
|
||||
* @return The boundaries of the destination.
|
||||
*/
|
||||
public final Rectangle2D getBounds2D(Raster src)
|
||||
{
|
||||
return src.getBounds();
|
||||
}
|
||||
|
||||
// According to Sven de Marothy, we need to copy the src into the dest
|
||||
// using Graphics2D, in order to use the rendering hints.
|
||||
|
||||
/**
|
||||
* Copy a source image to a destination image, respecting their colorspaces
|
||||
* and performing colorspace conversions if necessary.
|
||||
*
|
||||
* @param src The source image.
|
||||
* @param dst The destination image.
|
||||
*/
|
||||
private void copyimage(BufferedImage src, BufferedImage dst)
|
||||
{
|
||||
// This is done using Graphics2D in order to respect the rendering hints.
|
||||
Graphics2D gg = dst.createGraphics();
|
||||
|
||||
// If no hints are set there is no need to call
|
||||
|
@ -297,13 +444,23 @@ public class ColorConvertOp implements BufferedImageOp, RasterOp
|
|||
gg.dispose();
|
||||
}
|
||||
|
||||
private void copyraster(Raster src, ColorSpace scs, WritableRaster dst,
|
||||
ColorSpace dcs)
|
||||
/**
|
||||
* Copy a source raster to a destination raster, performing a colorspace
|
||||
* conversion between the two. The conversion will respect the
|
||||
* KEY_COLOR_RENDERING rendering hint if one is present.
|
||||
*
|
||||
* @param src The source raster.
|
||||
* @param scs The colorspace of the source raster.
|
||||
* @dst The destination raster.
|
||||
* @dcs The colorspace of the destination raster.
|
||||
*/
|
||||
private void copyraster(Raster src, ColorSpace scs, WritableRaster dst, ColorSpace dcs)
|
||||
{
|
||||
float[] sbuf = new float[src.getNumBands()];
|
||||
|
||||
if (hints.get(RenderingHints.KEY_COLOR_RENDERING) ==
|
||||
RenderingHints.VALUE_COLOR_RENDER_QUALITY)
|
||||
if (hints != null
|
||||
&& hints.get(RenderingHints.KEY_COLOR_RENDERING) ==
|
||||
RenderingHints.VALUE_COLOR_RENDER_QUALITY)
|
||||
{
|
||||
// use cie for accuracy
|
||||
for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++)
|
||||
|
@ -321,4 +478,60 @@ public class ColorConvertOp implements BufferedImageOp, RasterOp
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a color model with the same colorspace and alpha
|
||||
* settings as the source image. The created color model will always be a
|
||||
* ComponentColorModel and have a BYTE transfer type.
|
||||
*
|
||||
* @param img The source image.
|
||||
* @param cs The ColorSpace to use.
|
||||
* @return A color model compatible with the source image.
|
||||
*/
|
||||
private ColorModel createCompatibleColorModel(BufferedImage img, ColorSpace cs)
|
||||
{
|
||||
// The choice of ComponentColorModel and DataBuffer.TYPE_BYTE is based on
|
||||
// Mauve testing of the reference implementation.
|
||||
return new ComponentColorModel(cs,
|
||||
img.getColorModel().hasAlpha(),
|
||||
img.isAlphaPremultiplied(),
|
||||
img.getColorModel().getTransparency(),
|
||||
DataBuffer.TYPE_BYTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a compatible Raster, given a source raster, colorspace,
|
||||
* alpha value, and transfer type.
|
||||
*
|
||||
* @param src The source raster.
|
||||
* @param cs The ColorSpace to use.
|
||||
* @param hasAlpha Whether the raster should include a component for an alpha.
|
||||
* @param transferType The size of a single data element.
|
||||
* @return A compatible WritableRaster.
|
||||
*/
|
||||
private WritableRaster createCompatibleDestRaster(Raster src, ColorSpace cs,
|
||||
boolean hasAlpha,
|
||||
int transferType)
|
||||
{
|
||||
// The use of a PixelInterleavedSampleModel weas determined using mauve
|
||||
// tests, based on the reference implementation
|
||||
|
||||
int numComponents = cs.getNumComponents();
|
||||
if (hasAlpha)
|
||||
numComponents++;
|
||||
|
||||
int[] offsets = new int[numComponents];
|
||||
for (int i = 0; i < offsets.length; i++)
|
||||
offsets[i] = i;
|
||||
|
||||
DataBuffer db = Buffers.createBuffer(transferType,
|
||||
src.getWidth() * src.getHeight() * numComponents,
|
||||
1);
|
||||
return new WritableRaster(new PixelInterleavedSampleModel(transferType,
|
||||
src.getWidth(),
|
||||
src.getHeight(),
|
||||
numComponents,
|
||||
numComponents * src.getWidth(),
|
||||
offsets),
|
||||
db, new Point(src.getMinX(), src.getMinY()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -624,40 +624,40 @@ public abstract class ColorModel implements Transparency
|
|||
return cspace;
|
||||
}
|
||||
|
||||
// Typically overridden
|
||||
public ColorModel coerceData(WritableRaster raster,
|
||||
boolean isAlphaPremultiplied)
|
||||
boolean isAlphaPremultiplied)
|
||||
{
|
||||
if (this.isAlphaPremultiplied == isAlphaPremultiplied)
|
||||
return this;
|
||||
// This method should always be overridden, but is not abstract.
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected void coerceDataWorker(WritableRaster raster,
|
||||
boolean isAlphaPremultiplied)
|
||||
{
|
||||
int w = raster.getWidth();
|
||||
int h = raster.getHeight();
|
||||
int x = raster.getMinX();
|
||||
int y = raster.getMinY();
|
||||
int size = w*h;
|
||||
int size = w * h;
|
||||
int numColors = getNumColorComponents();
|
||||
int numComponents = getNumComponents();
|
||||
int alphaScale = (1<<getComponentSize(numColors)) - 1;
|
||||
int alphaScale = (1 << getComponentSize(numColors)) - 1;
|
||||
double[] pixels = raster.getPixels(x, y, w, h, (double[]) null);
|
||||
|
||||
for (int i=0; i<size; i++)
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
double alpha = pixels[i*numComponents+numColors]*alphaScale;
|
||||
for (int c=0; c<numColors; c++)
|
||||
{
|
||||
int offset = i*numComponents+c;
|
||||
if (isAlphaPremultiplied)
|
||||
pixels[offset] = pixels[offset]/alpha;
|
||||
else
|
||||
pixels[offset] = pixels[offset]*alpha;
|
||||
}
|
||||
double alpha = pixels[i * numComponents + numColors] / alphaScale;
|
||||
for (int c = 0; c < numColors; c++)
|
||||
{
|
||||
int offset = i * numComponents + c;
|
||||
if (isAlphaPremultiplied)
|
||||
pixels[offset] = Math.round(pixels[offset] * alpha);
|
||||
else
|
||||
pixels[offset] = Math.round(pixels[offset] / alpha);
|
||||
}
|
||||
}
|
||||
|
||||
raster.setPixels(0, 0, w, h, pixels);
|
||||
|
||||
// FIXME: what can we return?
|
||||
return null;
|
||||
raster.setPixels(0, 0, w, h, pixels);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -42,9 +42,11 @@ import gnu.java.awt.Buffers;
|
|||
|
||||
import java.awt.Point;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ComponentColorModel extends ColorModel
|
||||
{
|
||||
// Find sum of all elements of the array.
|
||||
private static int sum(int[] values)
|
||||
{
|
||||
int sum = 0;
|
||||
|
@ -52,6 +54,22 @@ public class ComponentColorModel extends ColorModel
|
|||
sum += values[i];
|
||||
return sum;
|
||||
}
|
||||
|
||||
// Create an appropriate array of bits, given a colorspace (ie, number of
|
||||
// bands), size of the storage data type, and presence of an alpha band.
|
||||
private static int[] findBits(ColorSpace colorSpace, int transferType,
|
||||
boolean hasAlpha)
|
||||
{
|
||||
int[] bits;
|
||||
if (hasAlpha)
|
||||
bits = new int[colorSpace.getNumComponents()+1];
|
||||
else
|
||||
bits = new int[colorSpace.getNumComponents()];
|
||||
|
||||
Arrays.fill(bits, DataBuffer.getDataTypeSize(transferType));
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
public ComponentColorModel(ColorSpace colorSpace, int[] bits,
|
||||
boolean hasAlpha,
|
||||
|
@ -84,8 +102,8 @@ public class ComponentColorModel extends ColorModel
|
|||
boolean isAlphaPremultiplied,
|
||||
int transparency, int transferType)
|
||||
{
|
||||
this(colorSpace, null, hasAlpha, isAlphaPremultiplied,
|
||||
transparency, transferType);
|
||||
this(colorSpace, findBits(colorSpace, transferType, hasAlpha), hasAlpha,
|
||||
isAlphaPremultiplied, transparency, transferType);
|
||||
}
|
||||
|
||||
public int getRed(int pixel)
|
||||
|
@ -288,17 +306,16 @@ public class ComponentColorModel extends ColorModel
|
|||
|
||||
public ColorModel coerceData(WritableRaster raster,
|
||||
boolean isAlphaPremultiplied) {
|
||||
if (this.isAlphaPremultiplied == isAlphaPremultiplied)
|
||||
if (this.isAlphaPremultiplied == isAlphaPremultiplied || !hasAlpha())
|
||||
return this;
|
||||
|
||||
/* TODO: provide better implementation based on the
|
||||
assumptions we can make due to the specific type of the
|
||||
color model. */
|
||||
super.coerceData(raster, isAlphaPremultiplied);
|
||||
super.coerceDataWorker(raster, isAlphaPremultiplied);
|
||||
|
||||
return new ComponentColorModel(cspace, bits, hasAlpha(),
|
||||
isAlphaPremultiplied, // argument
|
||||
transparency, transferType);
|
||||
return new ComponentColorModel(cspace, hasAlpha, isAlphaPremultiplied,
|
||||
transparency, transferType);
|
||||
}
|
||||
|
||||
public boolean isCompatibleRaster(Raster raster)
|
||||
|
|
|
@ -38,7 +38,6 @@ exception statement from your version. */
|
|||
|
||||
package java.awt.image;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
@ -51,11 +50,13 @@ import java.awt.geom.Rectangle2D;
|
|||
* with elements in the kernel to compute a new pixel.
|
||||
*
|
||||
* Each band in a Raster is convolved and copied to the destination Raster.
|
||||
* For BufferedImages, convolution is applied to all components. Color
|
||||
* conversion will be applied if needed.
|
||||
*
|
||||
* For BufferedImages, convolution is applied to all components. If the
|
||||
* source is not premultiplied, the data will be premultiplied before
|
||||
* convolving. Premultiplication will be undone if the destination is not
|
||||
* premultiplied. Color conversion will be applied if needed.
|
||||
* Note that this filter ignores whether the source or destination is alpha
|
||||
* premultiplied. The reference spec states that data will be premultiplied
|
||||
* prior to convolving and divided back out afterwards (if needed), but testing
|
||||
* has shown that this is not the case with their implementation.
|
||||
*
|
||||
* @author jlquinn@optonline.net
|
||||
*/
|
||||
|
@ -104,59 +105,83 @@ public class ConvolveOp implements BufferedImageOp, RasterOp
|
|||
hints = null;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.awt.image.BufferedImageOp#filter(java.awt.image.BufferedImage,
|
||||
* java.awt.image.BufferedImage)
|
||||
/**
|
||||
* Converts the source image using the kernel specified in the
|
||||
* constructor. The resulting image is stored in the destination image if one
|
||||
* is provided; otherwise a new BufferedImage is created and returned.
|
||||
*
|
||||
* The source and destination BufferedImage (if one is supplied) must have
|
||||
* the same dimensions.
|
||||
*
|
||||
* @param src The source image.
|
||||
* @param dst The destination image.
|
||||
* @throws IllegalArgumentException if the rasters and/or color spaces are
|
||||
* incompatible.
|
||||
* @return The convolved image.
|
||||
*/
|
||||
public final BufferedImage filter(BufferedImage src, BufferedImage dst)
|
||||
{
|
||||
if (src == dst)
|
||||
throw new IllegalArgumentException();
|
||||
throw new IllegalArgumentException("Source and destination images " +
|
||||
"cannot be the same.");
|
||||
|
||||
if (dst == null)
|
||||
dst = createCompatibleDestImage(src, src.getColorModel());
|
||||
|
||||
// Make sure source image is premultiplied
|
||||
BufferedImage src1 = src;
|
||||
if (!src.isPremultiplied)
|
||||
// The spec says we should do this, but mauve testing shows that Sun's
|
||||
// implementation does not check this.
|
||||
/*
|
||||
if (!src.isAlphaPremultiplied())
|
||||
{
|
||||
src1 = createCompatibleDestImage(src, src.getColorModel());
|
||||
src.copyData(src1.getRaster());
|
||||
src1.coerceData(true);
|
||||
}
|
||||
*/
|
||||
|
||||
BufferedImage dst1 = dst;
|
||||
if (!src.getColorModel().equals(dst.getColorModel()))
|
||||
if (src1.getColorModel().getColorSpace().getType() != dst.getColorModel().getColorSpace().getType())
|
||||
dst1 = createCompatibleDestImage(src, src.getColorModel());
|
||||
|
||||
filter(src1.getRaster(), dst1.getRaster());
|
||||
|
||||
// Since we don't coerceData above, we don't need to divide it back out.
|
||||
// This is wrong (one mauve test specifically tests converting a non-
|
||||
// premultiplied image to a premultiplied image, and it shows that Sun
|
||||
// simply ignores the premultipled flag, contrary to the spec), but we
|
||||
// mimic it for compatibility.
|
||||
/*
|
||||
if (! dst.isAlphaPremultiplied())
|
||||
dst1.coerceData(false);
|
||||
*/
|
||||
|
||||
// Convert between color models if needed
|
||||
if (dst1 != dst)
|
||||
{
|
||||
// Convert between color models.
|
||||
// TODO Check that premultiplied alpha is handled correctly here.
|
||||
Graphics2D gg = dst.createGraphics();
|
||||
gg.setRenderingHints(hints);
|
||||
gg.drawImage(dst1, 0, 0, null);
|
||||
gg.dispose();
|
||||
}
|
||||
|
||||
new ColorConvertOp(hints).filter(dst1, dst);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see
|
||||
* java.awt.image.BufferedImageOp#createCompatibleDestImage(java.awt.image.BufferedImage,
|
||||
* java.awt.image.ColorModel)
|
||||
/**
|
||||
* Creates an empty BufferedImage with the size equal to the source and the
|
||||
* correct number of bands. The new image is created with the specified
|
||||
* ColorModel, or if no ColorModel is supplied, an appropriate one is chosen.
|
||||
*
|
||||
* @param src The source image.
|
||||
* @param dstCM A color model for the destination image (may be null).
|
||||
* @return The new compatible destination image.
|
||||
*/
|
||||
public BufferedImage createCompatibleDestImage(BufferedImage src,
|
||||
ColorModel dstCM)
|
||||
ColorModel dstCM)
|
||||
{
|
||||
// FIXME: set properties to those in src
|
||||
return new BufferedImage(dstCM,
|
||||
src.getRaster().createCompatibleWritableRaster(),
|
||||
src.isPremultiplied, null);
|
||||
if (dstCM != null)
|
||||
return new BufferedImage(dstCM,
|
||||
src.getRaster().createCompatibleWritableRaster(),
|
||||
src.isAlphaPremultiplied(), null);
|
||||
|
||||
return new BufferedImage(src.getWidth(), src.getHeight(), src.getType());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
@ -168,6 +193,8 @@ public class ConvolveOp implements BufferedImageOp, RasterOp
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the edge condition for this Op.
|
||||
*
|
||||
* @return The edge condition.
|
||||
*/
|
||||
public int getEdgeCondition()
|
||||
|
@ -185,9 +212,22 @@ public class ConvolveOp implements BufferedImageOp, RasterOp
|
|||
return (Kernel) kernel.clone();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.awt.image.RasterOp#filter(java.awt.image.Raster,
|
||||
* java.awt.image.WritableRaster)
|
||||
/**
|
||||
* Converts the source raster using the kernel specified in the constructor.
|
||||
* The resulting raster is stored in the destination raster if one is
|
||||
* provided; otherwise a new WritableRaster is created and returned.
|
||||
*
|
||||
* If the convolved value for a sample is outside the range of [0-255], it
|
||||
* will be clipped.
|
||||
*
|
||||
* The source and destination raster (if one is supplied) cannot be the same,
|
||||
* and must also have the same dimensions.
|
||||
*
|
||||
* @param src The source raster.
|
||||
* @param dest The destination raster.
|
||||
* @throws IllegalArgumentException if the rasters identical.
|
||||
* @throws ImagingOpException if the convolution is not possible.
|
||||
* @return The transformed raster.
|
||||
*/
|
||||
public final WritableRaster filter(Raster src, WritableRaster dest)
|
||||
{
|
||||
|
@ -209,6 +249,11 @@ public class ConvolveOp implements BufferedImageOp, RasterOp
|
|||
int top = kernel.getYOrigin();
|
||||
int bottom = Math.max(kHeight - top - 1, 0);
|
||||
|
||||
// Calculate max sample values for clipping
|
||||
int[] maxValue = src.getSampleModel().getSampleSize();
|
||||
for (int i = 0; i < maxValue.length; i++)
|
||||
maxValue[i] = (int)Math.pow(2, maxValue[i]) - 1;
|
||||
|
||||
// process the region that is reachable...
|
||||
int regionW = src.width - left - right;
|
||||
int regionH = src.height - top - bottom;
|
||||
|
@ -228,7 +273,14 @@ public class ConvolveOp implements BufferedImageOp, RasterOp
|
|||
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.
|
||||
// out why this is necessary.
|
||||
|
||||
// This clipping is is undocumented, but determined by testing.
|
||||
if (v > maxValue[b])
|
||||
v = maxValue[b];
|
||||
else if (v < 0)
|
||||
v = 0;
|
||||
|
||||
dest.setSample(x + kernel.getXOrigin(), y + kernel.getYOrigin(),
|
||||
b, v);
|
||||
}
|
||||
|
@ -310,13 +362,14 @@ public class ConvolveOp implements BufferedImageOp, RasterOp
|
|||
return src.getBounds();
|
||||
}
|
||||
|
||||
/** Return corresponding destination point for source point.
|
||||
/**
|
||||
* Returns the corresponding destination point for a source point. Because
|
||||
* this is not a geometric operation, the destination and source points will
|
||||
* be identical.
|
||||
*
|
||||
* ConvolveOp will return the value of src unchanged.
|
||||
* @param src The source point.
|
||||
* @param dst The destination point.
|
||||
* @see java.awt.image.RasterOp#getPoint2D(java.awt.geom.Point2D,
|
||||
* java.awt.geom.Point2D)
|
||||
* @param dst The transformed destination point.
|
||||
* @return The transformed destination point.
|
||||
*/
|
||||
public final Point2D getPoint2D(Point2D src, Point2D dst)
|
||||
{
|
||||
|
|
|
@ -91,11 +91,12 @@ public class CropImageFilter extends ImageFilter
|
|||
*
|
||||
* @param props the list of properties associated with this image
|
||||
*/
|
||||
public void setProperties(Hashtable props)
|
||||
public void setProperties(Hashtable<?, ?> props)
|
||||
{
|
||||
props.put("filters", "CropImageFilter");
|
||||
if (consumer != null)
|
||||
consumer.setProperties(props);
|
||||
Hashtable<Object, Object> prop2 = (Hashtable<Object, Object>) props;
|
||||
prop2.put("filters", "CropImageFilter");
|
||||
if (consumer != null)
|
||||
consumer.setProperties(prop2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -393,20 +393,20 @@ public class DirectColorModel extends PackedColorModel
|
|||
return Buffers.getData(buffer);
|
||||
}
|
||||
|
||||
public final ColorModel coerceData (WritableRaster raster,
|
||||
boolean isAlphaPremultiplied)
|
||||
public ColorModel coerceData (WritableRaster raster,
|
||||
boolean isAlphaPremultiplied)
|
||||
{
|
||||
if (this.isAlphaPremultiplied == isAlphaPremultiplied)
|
||||
if (this.isAlphaPremultiplied == isAlphaPremultiplied || !hasAlpha())
|
||||
return this;
|
||||
|
||||
/* TODO: provide better implementation based on the
|
||||
assumptions we can make due to the specific type of the
|
||||
color model. */
|
||||
super.coerceData(raster, isAlphaPremultiplied);
|
||||
|
||||
return new ComponentColorModel(cspace, bits, hasAlpha(),
|
||||
isAlphaPremultiplied, // argument
|
||||
transparency, transferType);
|
||||
super.coerceDataWorker(raster, isAlphaPremultiplied);
|
||||
|
||||
return new DirectColorModel(cspace, pixel_bits, getRedMask(),
|
||||
getGreenMask(), getBlueMask(), getAlphaMask(),
|
||||
isAlphaPremultiplied, transferType);
|
||||
}
|
||||
|
||||
public boolean isCompatibleRaster(Raster raster)
|
||||
|
|
|
@ -136,7 +136,7 @@ public interface ImageConsumer
|
|||
*
|
||||
* @param props the list of properties associated with this image
|
||||
*/
|
||||
void setProperties(Hashtable props);
|
||||
void setProperties(Hashtable<?,?> props);
|
||||
|
||||
/**
|
||||
* This <code>ColorModel</code> should indicate the model used by
|
||||
|
|
|
@ -49,180 +49,178 @@ import java.util.Hashtable;
|
|||
*/
|
||||
public class ImageFilter implements ImageConsumer, Cloneable
|
||||
{
|
||||
/**
|
||||
* The consumer this filter is filtering an image data stream for.
|
||||
* It is initialized in the method <code>getFilterInstance</code>.
|
||||
*/
|
||||
protected ImageConsumer consumer = null;
|
||||
/**
|
||||
* The consumer this filter is filtering an image data stream for.
|
||||
* It is initialized in the method <code>getFilterInstance</code>.
|
||||
*/
|
||||
protected ImageConsumer consumer = null;
|
||||
|
||||
/**
|
||||
* The <code>ImageConsumer</code> can use this method to request
|
||||
* the pixels be delivered in top-down, left-right order.
|
||||
* <br>
|
||||
* The filter can respond in three different ways.
|
||||
* <ul>
|
||||
* <li>The default behavior is to forward the request to the
|
||||
* <code>ImageProducer</code>
|
||||
* using the method <code>requestTopDownLeftRightResend</code>
|
||||
* and using the filter as the consumer.</li>
|
||||
* <li>The filter has the pixels and can retransmit them in the
|
||||
* top-down, left-right order.</li>
|
||||
* <li>The filter can do nothing when this method is called.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public void resendTopDownLeftRight(ImageProducer ip)
|
||||
{
|
||||
ip.requestTopDownLeftRightResend(this);
|
||||
}
|
||||
/**
|
||||
* The <code>ImageConsumer</code> can use this method to request
|
||||
* the pixels be delivered in top-down, left-right order.
|
||||
* <br>
|
||||
* The filter can respond in three different ways.
|
||||
* <ul>
|
||||
* <li>The default behavior is to forward the request to the
|
||||
* <code>ImageProducer</code>
|
||||
* using the method <code>requestTopDownLeftRightResend</code>
|
||||
* and using the filter as the consumer.</li>
|
||||
* <li>The filter has the pixels and can retransmit them in the
|
||||
* top-down, left-right order.</li>
|
||||
* <li>The filter can do nothing when this method is called.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public void resendTopDownLeftRight(ImageProducer ip)
|
||||
{
|
||||
ip.requestTopDownLeftRightResend(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* By default, returns a shallow copy of the object created by
|
||||
* <code>Object.clone()</code>
|
||||
*
|
||||
* @see java.lang.Object#clone ()
|
||||
*/
|
||||
public Object clone()
|
||||
{
|
||||
try
|
||||
{
|
||||
return super.clone();
|
||||
}
|
||||
catch (CloneNotSupportedException e)
|
||||
{
|
||||
// This should never happen as this class implements the
|
||||
// Cloneable interface.
|
||||
throw new InternalError ();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* By default, returns a shallow copy of the object created by
|
||||
* <code>Object.clone()</code>
|
||||
*
|
||||
* @see java.lang.Object#clone ()
|
||||
*/
|
||||
public Object clone()
|
||||
{
|
||||
try
|
||||
{
|
||||
return super.clone();
|
||||
}
|
||||
catch (CloneNotSupportedException e)
|
||||
{
|
||||
// This should never happen as this class implements the
|
||||
// Cloneable interface.
|
||||
throw new InternalError ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the only method which can set the
|
||||
* <code>ImageConsumer</code> for this filter. By default a clone
|
||||
* of this filter with the appropriate consumer set is returned.
|
||||
*
|
||||
* @see #clone ()
|
||||
*/
|
||||
public ImageFilter getFilterInstance(ImageConsumer ic)
|
||||
{
|
||||
if ( ic == null )
|
||||
throw new IllegalArgumentException("null argument for ImageFilter.getFilterInstance(ImageConsumer)");
|
||||
/**
|
||||
* This is the only method which can set the
|
||||
* <code>ImageConsumer</code> for this filter. By default a clone
|
||||
* of this filter with the appropriate consumer set is returned.
|
||||
*
|
||||
* @see #clone ()
|
||||
*/
|
||||
public ImageFilter getFilterInstance(ImageConsumer ic)
|
||||
{
|
||||
ImageFilter f = (ImageFilter)clone();
|
||||
f.consumer = ic;
|
||||
return f;
|
||||
}
|
||||
|
||||
consumer = ic;
|
||||
ImageFilter f = (ImageFilter)clone();
|
||||
consumer = null;
|
||||
return f;
|
||||
}
|
||||
/**
|
||||
* An <code>ImageProducer</code> indicates the size of the image
|
||||
* being produced using this method. A filter can override this
|
||||
* method to intercept these calls from the producer in order to
|
||||
* change either the width or the height before in turn calling
|
||||
* the consumer's <code>setDimensions</code> method.
|
||||
*
|
||||
* @param width the width of the image
|
||||
* @param height the height of the image
|
||||
*/
|
||||
public void setDimensions(int width, int height)
|
||||
{
|
||||
consumer.setDimensions(width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* An <code>ImageProducer</code> indicates the size of the image
|
||||
* being produced using this method. A filter can override this
|
||||
* method to intercept these calls from the producer in order to
|
||||
* change either the width or the height before in turn calling
|
||||
* the consumer's <code>setDimensions</code> method.
|
||||
*
|
||||
* @param width the width of the image
|
||||
* @param height the height of the image
|
||||
*/
|
||||
public void setDimensions(int width, int height)
|
||||
{
|
||||
if (consumer != null)
|
||||
consumer.setDimensions(width, height);
|
||||
}
|
||||
/**
|
||||
* An <code>ImageProducer</code> can set a list of properties
|
||||
* associated with this image by using this method.
|
||||
*
|
||||
* @param props the list of properties associated with this image
|
||||
*/
|
||||
public void setProperties(Hashtable<?,?> props)
|
||||
{
|
||||
Hashtable copy = (Hashtable) props.clone();
|
||||
Object o = copy.get("filters");
|
||||
if (o == null)
|
||||
copy.put("filters", toString());
|
||||
else if (o instanceof String)
|
||||
copy.put("filters", ((String) o) + toString());
|
||||
|
||||
/**
|
||||
* An <code>ImageProducer</code> can set a list of properties
|
||||
* associated with this image by using this method.
|
||||
*
|
||||
* @param props the list of properties associated with this image
|
||||
*/
|
||||
public void setProperties(Hashtable props)
|
||||
{
|
||||
props.put("filters", "ImageFilter");
|
||||
if (consumer != null)
|
||||
consumer.setProperties(props);
|
||||
}
|
||||
consumer.setProperties(copy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to process calls to this method from the
|
||||
* <code>ImageProducer</code>. By default the <code>setColorModel</code>
|
||||
* method of the consumer is called with the specified <code>model</code>.
|
||||
*
|
||||
* @param model the color model to be used most often by setPixels
|
||||
* @see ColorModel */
|
||||
public void setColorModel(ColorModel model)
|
||||
{
|
||||
if (consumer != null)
|
||||
consumer.setColorModel(model);
|
||||
}
|
||||
/**
|
||||
* Override this method to process calls to this method from the
|
||||
* <code>ImageProducer</code>. By default the <code>setColorModel</code>
|
||||
* method of the consumer is called with the specified <code>model</code>.
|
||||
*
|
||||
* @param model the color model to be used most often by setPixels
|
||||
*
|
||||
* @see ColorModel
|
||||
*/
|
||||
public void setColorModel(ColorModel model)
|
||||
{
|
||||
consumer.setColorModel(model);
|
||||
}
|
||||
|
||||
/**
|
||||
* The <code>ImageProducer</code> should call this method with a
|
||||
* bit mask of hints from any of <code>RANDOMPIXELORDER</code>,
|
||||
* <code>TOPDOWNLEFTRIGHT</code>, <code>COMPLETESCANLINES</code>,
|
||||
* <code>SINGLEPASS</code>, <code>SINGLEFRAME</code> from the
|
||||
* <code>ImageConsumer</code> interface.
|
||||
*
|
||||
* @param flags a bit mask of hints
|
||||
* @see ImageConsumer
|
||||
*/
|
||||
public void setHints(int flags)
|
||||
{
|
||||
if (consumer != null)
|
||||
consumer.setHints(flags);
|
||||
}
|
||||
/**
|
||||
* The <code>ImageProducer</code> should call this method with a
|
||||
* bit mask of hints from any of <code>RANDOMPIXELORDER</code>,
|
||||
* <code>TOPDOWNLEFTRIGHT</code>, <code>COMPLETESCANLINES</code>,
|
||||
* <code>SINGLEPASS</code>, <code>SINGLEFRAME</code> from the
|
||||
* <code>ImageConsumer</code> interface.
|
||||
*
|
||||
* @param flags a bit mask of hints
|
||||
* @see ImageConsumer
|
||||
*/
|
||||
public void setHints(int flags)
|
||||
{
|
||||
consumer.setHints(flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function delivers a rectangle of pixels where any
|
||||
* pixel(m,n) is stored in the array as a <code>byte</code> at
|
||||
* index (n * scansize + m + offset).
|
||||
*
|
||||
* @param x the x coordinate of the rectangle
|
||||
* @param y the y coordinate of the rectangle
|
||||
* @param w the width of the rectangle
|
||||
* @param h the height of the rectangle
|
||||
* @param model the <code>ColorModel</code> used to translate the pixels
|
||||
* @param pixels the array of pixel values
|
||||
* @param offset the index of the first pixels in the <code>pixels</code> array
|
||||
* @param scansize the width to use in extracting pixels from the <code>pixels</code> array
|
||||
*/
|
||||
public void setPixels(int x, int y, int w, int h,
|
||||
ColorModel model, byte[] pixels, int offset, int scansize)
|
||||
{
|
||||
if (consumer != null)
|
||||
consumer.setPixels(x, y, w, h, model, pixels, offset, scansize);
|
||||
}
|
||||
/**
|
||||
* This function delivers a rectangle of pixels where any
|
||||
* pixel(m,n) is stored in the array as a <code>byte</code> at
|
||||
* index (n * scansize + m + offset).
|
||||
*
|
||||
* @param x the x coordinate of the rectangle
|
||||
* @param y the y coordinate of the rectangle
|
||||
* @param w the width of the rectangle
|
||||
* @param h the height of the rectangle
|
||||
* @param model the <code>ColorModel</code> used to translate the pixels
|
||||
* @param pixels the array of pixel values
|
||||
* @param offset the index of the first pixels in the <code>pixels</code> array
|
||||
* @param scansize the width to use in extracting pixels from the <code>pixels</code> array
|
||||
*/
|
||||
public void setPixels(int x, int y, int w, int h,
|
||||
ColorModel model, byte[] pixels, int offset,
|
||||
int scansize)
|
||||
{
|
||||
consumer.setPixels(x, y, w, h, model, pixels, offset, scansize);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function delivers a rectangle of pixels where any
|
||||
* pixel(m,n) is stored in the array as an <code>int</code> at
|
||||
* index (n * scansize + m + offset).
|
||||
*
|
||||
* @param x the x coordinate of the rectangle
|
||||
* @param y the y coordinate of the rectangle
|
||||
* @param w the width of the rectangle
|
||||
* @param h the height of the rectangle
|
||||
* @param model the <code>ColorModel</code> used to translate the pixels
|
||||
* @param pixels the array of pixel values
|
||||
* @param offset the index of the first pixels in the <code>pixels</code> array
|
||||
* @param scansize the width to use in extracting pixels from the <code>pixels</code> array
|
||||
*/
|
||||
public void setPixels(int x, int y, int w, int h,
|
||||
ColorModel model, int[] pixels, int offset, int scansize)
|
||||
{
|
||||
if (consumer != null)
|
||||
consumer.setPixels(x, y, w, h, model, pixels, offset, scansize);
|
||||
}
|
||||
/**
|
||||
* This function delivers a rectangle of pixels where any
|
||||
* pixel(m,n) is stored in the array as an <code>int</code> at
|
||||
* index (n * scansize + m + offset).
|
||||
*
|
||||
* @param x the x coordinate of the rectangle
|
||||
* @param y the y coordinate of the rectangle
|
||||
* @param w the width of the rectangle
|
||||
* @param h the height of the rectangle
|
||||
* @param model the <code>ColorModel</code> used to translate the pixels
|
||||
* @param pixels the array of pixel values
|
||||
* @param offset the index of the first pixels in the <code>pixels</code> array
|
||||
* @param scansize the width to use in extracting pixels from the <code>pixels</code> array
|
||||
*/
|
||||
public void setPixels(int x, int y, int w, int h,
|
||||
ColorModel model, int[] pixels, int offset,
|
||||
int scansize)
|
||||
{
|
||||
consumer.setPixels(x, y, w, h, model, pixels, offset, scansize);
|
||||
}
|
||||
|
||||
/**
|
||||
* The <code>ImageProducer</code> calls this method to indicate a
|
||||
* single frame or the entire image is complete. The method is
|
||||
* also used to indicate an error in loading or producing the
|
||||
* image.
|
||||
*/
|
||||
public void imageComplete(int status)
|
||||
{
|
||||
if (consumer != null)
|
||||
consumer.imageComplete(status);
|
||||
}
|
||||
/**
|
||||
* The <code>ImageProducer</code> calls this method to indicate a
|
||||
* single frame or the entire image is complete. The method is
|
||||
* also used to indicate an error in loading or producing the
|
||||
* image.
|
||||
*/
|
||||
public void imageComplete(int status)
|
||||
{
|
||||
consumer.imageComplete(status);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -134,10 +134,6 @@ public class IndexColorModel extends ColorModel
|
|||
if (size < 1)
|
||||
throw new IllegalArgumentException("size < 1");
|
||||
map_size = size;
|
||||
if (0 <= trans && trans < size) {
|
||||
this.trans = trans;
|
||||
transparency = BITMASK;
|
||||
}
|
||||
rgb = new int[size];
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
|
@ -146,6 +142,9 @@ public class IndexColorModel extends ColorModel
|
|||
| ((greens[i] & 0xff) << 8)
|
||||
| (blues[i] & 0xff));
|
||||
}
|
||||
|
||||
setTransparentPixel(trans);
|
||||
|
||||
// Generate a bigint with 1's for every pixel
|
||||
validBits = validBits.setBit(size).subtract(BigInteger.ONE);
|
||||
}
|
||||
|
@ -275,8 +274,6 @@ public class IndexColorModel extends ColorModel
|
|||
throw new IllegalArgumentException("size < 1");
|
||||
map_size = size;
|
||||
opaque = !hasAlpha;
|
||||
if (0 <= trans && trans < size)
|
||||
this.trans = trans;
|
||||
|
||||
rgb = new int[size];
|
||||
if (hasAlpha)
|
||||
|
@ -318,6 +315,8 @@ public class IndexColorModel extends ColorModel
|
|||
transparency = BITMASK;
|
||||
}
|
||||
|
||||
setTransparentPixel(trans);
|
||||
|
||||
// Generate a bigint with 1's for every pixel
|
||||
validBits = validBits.setBit(size).subtract(BigInteger.ONE);
|
||||
}
|
||||
|
@ -361,9 +360,6 @@ public class IndexColorModel extends ColorModel
|
|||
throw new IllegalArgumentException("size < 1");
|
||||
map_size = size;
|
||||
opaque = !hasAlpha;
|
||||
if (0 <= trans && trans < size)
|
||||
this.trans = trans;
|
||||
|
||||
rgb = new int[size];
|
||||
if (!hasAlpha)
|
||||
for (int i = 0; i < size; i++)
|
||||
|
@ -371,6 +367,8 @@ public class IndexColorModel extends ColorModel
|
|||
else
|
||||
System.arraycopy(cmap, start, rgb, 0, size);
|
||||
|
||||
setTransparentPixel(trans);
|
||||
|
||||
// Generate a bigint with 1's for every pixel
|
||||
validBits = validBits.setBit(size).subtract(BigInteger.ONE);
|
||||
}
|
||||
|
@ -584,12 +582,7 @@ public class IndexColorModel extends ColorModel
|
|||
*/
|
||||
public final int getAlpha(int pixel)
|
||||
{
|
||||
if (opaque && pixel != trans)
|
||||
return 255;
|
||||
if ((pixel == trans && trans != -1) || pixel >= map_size)
|
||||
return 0;
|
||||
|
||||
return (0xFF000000 & rgb[pixel]) >> 24;
|
||||
return (rgb[pixel] >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -694,4 +687,43 @@ public class IndexColorModel extends ColorModel
|
|||
|
||||
return im;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link SampleModel} that is compatible to this color model.
|
||||
* This will be a {@link MultiPixelPackedSampleModel} for bits/pixel of
|
||||
* 1, 2 or 4, or a {@link ComponentColorModel} for the other cases.
|
||||
*
|
||||
* @param w the width of the sample model to create
|
||||
* @param h the height of the sample model to create
|
||||
*
|
||||
* @return a compatible sample model
|
||||
*/
|
||||
public SampleModel createCompatibleSampleModel(int w, int h)
|
||||
{
|
||||
SampleModel sm;
|
||||
if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4)
|
||||
sm = new MultiPixelPackedSampleModel(transferType, w, h, pixel_bits);
|
||||
else
|
||||
sm = new ComponentSampleModel(transferType, w, h, 1, w, new int[]{0});
|
||||
return sm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the transparent pixel. This is called by the various constructors.
|
||||
*
|
||||
* @param t the transparent pixel
|
||||
*/
|
||||
private void setTransparentPixel(int t)
|
||||
{
|
||||
if (t >= 0 && t < map_size)
|
||||
{
|
||||
rgb[t] &= 0xffffff; // Make the value transparent.
|
||||
trans = t;
|
||||
if (transparency == OPAQUE)
|
||||
{
|
||||
transparency = BITMASK;
|
||||
hasAlpha = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@ exception statement from your version. */
|
|||
|
||||
package java.awt.image;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
@ -67,7 +66,8 @@ public class LookupOp implements BufferedImageOp, RasterOp
|
|||
private LookupTable lut;
|
||||
private RenderingHints hints;
|
||||
|
||||
/** Construct a new LookupOp.
|
||||
/**
|
||||
* Construct a new LookupOp using the given LookupTable.
|
||||
*
|
||||
* @param lookup LookupTable to use.
|
||||
* @param hints Rendering hints (can be null).
|
||||
|
@ -78,16 +78,40 @@ public class LookupOp implements BufferedImageOp, RasterOp
|
|||
this.hints = hints;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.awt.image.BufferedImageOp#filter(java.awt.image.BufferedImage, java.awt.image.BufferedImage)
|
||||
/**
|
||||
* Converts the source image using the lookup table specified in the
|
||||
* constructor. The resulting image is stored in the destination image if one
|
||||
* is provided; otherwise a new BufferedImage is created and returned.
|
||||
*
|
||||
* The source image cannot use an IndexColorModel, and the destination image
|
||||
* (if one is provided) must have the same size.
|
||||
*
|
||||
* @param src The source image.
|
||||
* @param dst The destination image.
|
||||
* @throws IllegalArgumentException if the rasters and/or color spaces are
|
||||
* incompatible.
|
||||
* @throws ArrayIndexOutOfBoundsException if a pixel in the source is not
|
||||
* contained in the LookupTable.
|
||||
* @return The convolved image.
|
||||
*/
|
||||
public final BufferedImage filter(BufferedImage src, BufferedImage dst)
|
||||
{
|
||||
if (src.getColorModel() instanceof IndexColorModel)
|
||||
throw new IllegalArgumentException("LookupOp.filter: IndexColorModel "
|
||||
+ "not allowed");
|
||||
|
||||
if (lut.getNumComponents() != 1
|
||||
&& lut.getNumComponents() != src.getColorModel().getNumComponents()
|
||||
&& lut.getNumComponents() != src.getColorModel().getNumColorComponents())
|
||||
throw new IllegalArgumentException("LookupOp.filter: Incompatible " +
|
||||
"lookup table and source image");
|
||||
|
||||
if (dst == null)
|
||||
dst = createCompatibleDestImage(src, src.getColorModel());
|
||||
dst = createCompatibleDestImage(src, null);
|
||||
|
||||
else if (src.getHeight() != dst.getHeight() || src.getWidth() != dst.getWidth())
|
||||
throw new IllegalArgumentException("Source and destination images are " +
|
||||
"different sizes.");
|
||||
|
||||
// Set up for potential colormodel mismatch
|
||||
BufferedImage tgt;
|
||||
|
@ -116,33 +140,35 @@ public class LookupOp implements BufferedImageOp, RasterOp
|
|||
sr.getPixel(x, y, dbuf);
|
||||
System.arraycopy(dbuf, 0, tmp, 0, tmpBands);
|
||||
dr.setPixel(x, y, lut.lookupPixel(tmp, dbuf));
|
||||
|
||||
/* The reference implementation does not use LookupTable.lookupPixel,
|
||||
* but rather it seems to copy the table into a native array. The
|
||||
* effect of this (a probable bug in their implementation) is that
|
||||
* an out-of-bounds lookup on a ByteLookupTable will *not* throw an
|
||||
* out of bounds exception, but will instead return random garbage.
|
||||
* A bad lookup on a ShortLookupTable, however, will throw an
|
||||
* exception.
|
||||
*
|
||||
* Instead of mimicing this behaviour, we always throw an
|
||||
* ArrayOutofBoundsException by virtue of using
|
||||
* LookupTable.lookupPixle.
|
||||
*/
|
||||
}
|
||||
}
|
||||
else if (lut.getNumComponents() != 1
|
||||
&&
|
||||
lut.getNumComponents() != src.getColorModel().getNumComponents())
|
||||
throw new IllegalArgumentException("LookupOp.filter: "
|
||||
+ "Incompatible lookup "
|
||||
+ "table and source image");
|
||||
|
||||
// No alpha to ignore
|
||||
int[] dbuf = new int[src.getColorModel().getNumComponents()];
|
||||
|
||||
// Filter the pixels
|
||||
for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++)
|
||||
for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++)
|
||||
dr.setPixel(x, y, lut.lookupPixel(sr.getPixel(x, y, dbuf), dbuf));
|
||||
|
||||
if (tgt != dst)
|
||||
else
|
||||
{
|
||||
// Convert between color models.
|
||||
// TODO Check that premultiplied alpha is handled correctly here.
|
||||
Graphics2D gg = dst.createGraphics();
|
||||
gg.setRenderingHints(hints);
|
||||
gg.drawImage(tgt, 0, 0, null);
|
||||
gg.dispose();
|
||||
// No alpha to ignore
|
||||
int[] dbuf = new int[src.getColorModel().getNumComponents()];
|
||||
|
||||
// Filter the pixels
|
||||
for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++)
|
||||
for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++)
|
||||
dr.setPixel(x, y, lut.lookupPixel(sr.getPixel(x, y, dbuf), dbuf));
|
||||
}
|
||||
|
||||
if (tgt != dst)
|
||||
new ColorConvertOp(hints).filter(tgt, dst);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
@ -160,18 +186,27 @@ public class LookupOp implements BufferedImageOp, RasterOp
|
|||
public BufferedImage createCompatibleDestImage(BufferedImage src,
|
||||
ColorModel dstCM)
|
||||
{
|
||||
// FIXME: set properties to those in src
|
||||
return new BufferedImage(dstCM,
|
||||
src.getRaster().createCompatibleWritableRaster(),
|
||||
src.isPremultiplied, null);
|
||||
if (dstCM != null)
|
||||
return new BufferedImage(dstCM,
|
||||
src.getRaster().createCompatibleWritableRaster(),
|
||||
src.isAlphaPremultiplied(), null);
|
||||
|
||||
// This is a strange exception, done for compatibility with the reference
|
||||
// (as demonstrated by a mauve testcase)
|
||||
int imgType = src.getType();
|
||||
if (imgType == BufferedImage.TYPE_USHORT_GRAY)
|
||||
imgType = BufferedImage.TYPE_BYTE_GRAY;
|
||||
|
||||
return new BufferedImage(src.getWidth(), src.getHeight(), imgType);
|
||||
}
|
||||
|
||||
/** Return corresponding destination point for source point.
|
||||
/**
|
||||
* Returns the corresponding destination point for a given source point.
|
||||
*
|
||||
* This Op will return the source point unchanged.
|
||||
*
|
||||
* LookupOp will return the value of src unchanged.
|
||||
* @param src The source point.
|
||||
* @param dst The destination point.
|
||||
* @see java.awt.image.RasterOp#getPoint2D(java.awt.geom.Point2D, java.awt.geom.Point2D)
|
||||
*/
|
||||
public final Point2D getPoint2D(Point2D src, Point2D dst)
|
||||
{
|
||||
|
@ -182,7 +217,11 @@ public class LookupOp implements BufferedImageOp, RasterOp
|
|||
return dst;
|
||||
}
|
||||
|
||||
/** Return the LookupTable for this op. */
|
||||
/**
|
||||
* Return the LookupTable for this op.
|
||||
*
|
||||
* @return The lookup table.
|
||||
*/
|
||||
public final LookupTable getTable()
|
||||
{
|
||||
return lut;
|
||||
|
@ -196,7 +235,8 @@ public class LookupOp implements BufferedImageOp, RasterOp
|
|||
return hints;
|
||||
}
|
||||
|
||||
/** Filter a raster through a lookup table.
|
||||
/**
|
||||
* Filter a raster through a lookup table.
|
||||
*
|
||||
* Applies the lookup table for this Rasterop to each pixel of src and
|
||||
* puts the results in dest. If dest is null, a new Raster is created and
|
||||
|
@ -206,8 +246,9 @@ public class LookupOp implements BufferedImageOp, RasterOp
|
|||
* @param dest The destination raster.
|
||||
* @return The WritableRaster with the filtered pixels.
|
||||
* @throws IllegalArgumentException if lookup table has more than one
|
||||
* component but not the same as src and dest.
|
||||
* @see java.awt.image.RasterOp#filter(java.awt.image.Raster, java.awt.image.WritableRaster)
|
||||
* component but not the same as src and dest.
|
||||
* @throws ArrayIndexOutOfBoundsException if a pixel in the source is not
|
||||
* contained in the LookupTable.
|
||||
*/
|
||||
public final WritableRaster filter(Raster src, WritableRaster dest)
|
||||
{
|
||||
|
@ -216,12 +257,13 @@ public class LookupOp implements BufferedImageOp, RasterOp
|
|||
dest = createCompatibleDestRaster(src);
|
||||
else
|
||||
if (src.getNumBands() != dest.getNumBands())
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
if (lut.getNumComponents() != 1
|
||||
&& lut.getNumComponents() != src.getNumBands())
|
||||
throw new IllegalArgumentException();
|
||||
throw new IllegalArgumentException("Source and destination rasters " +
|
||||
"are incompatible.");
|
||||
|
||||
if (lut.getNumComponents() != 1
|
||||
&& lut.getNumComponents() != src.getNumBands())
|
||||
throw new IllegalArgumentException("Lookup table is incompatible with " +
|
||||
"this raster.");
|
||||
|
||||
// Allocate pixel storage.
|
||||
int[] tmp = new int[src.getNumBands()];
|
||||
|
@ -230,6 +272,19 @@ public class LookupOp implements BufferedImageOp, RasterOp
|
|||
for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++)
|
||||
for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++)
|
||||
dest.setPixel(x, y, lut.lookupPixel(src.getPixel(x, y, tmp), tmp));
|
||||
|
||||
/* The reference implementation does not use LookupTable.lookupPixel,
|
||||
* but rather it seems to copy the table into a native array. The
|
||||
* effect of this (a probable bug in their implementation) is that
|
||||
* an out-of-bounds lookup on a ByteLookupTable will *not* throw an
|
||||
* out of bounds exception, but will instead return random garbage.
|
||||
* A bad lookup on a ShortLookupTable, however, will throw an
|
||||
* exception.
|
||||
*
|
||||
* Instead of mimicing this behaviour, we always throw an
|
||||
* ArrayOutofBoundsException by virtue of using
|
||||
* LookupTable.lookupPixle.
|
||||
*/
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* MemoryImageSource.java -- Java class for providing image data
|
||||
Copyright (C) 1999, 2004 Free Software Foundation, Inc.
|
||||
Copyright (C) 1999, 2004, 2006, Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -41,6 +41,9 @@ package java.awt.image;
|
|||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* An image producer that delivers image data from an array.
|
||||
*/
|
||||
public class MemoryImageSource implements ImageProducer
|
||||
{
|
||||
private boolean animated = false;
|
||||
|
@ -73,10 +76,19 @@ public class MemoryImageSource implements ImageProducer
|
|||
}
|
||||
|
||||
/**
|
||||
* Constructs an ImageProducer from memory
|
||||
* Constructs an ImageProducer from memory.
|
||||
*
|
||||
* @param w the image width.
|
||||
* @param h the image height.
|
||||
* @param cm the color model.
|
||||
* @param pix the image data.
|
||||
* @param off the offset to the first pixel in the array.
|
||||
* @param scan the number of array elements from a pixel on one row to the
|
||||
* corresponding pixel on the next row.
|
||||
* @param props image properties (<code>null</code> permitted).
|
||||
*/
|
||||
public MemoryImageSource(int w, int h, ColorModel cm, byte[] pix, int off,
|
||||
int scan, Hashtable props)
|
||||
int scan, Hashtable<?,?> props)
|
||||
{
|
||||
width = w;
|
||||
height = h;
|
||||
|
@ -106,10 +118,19 @@ public class MemoryImageSource implements ImageProducer
|
|||
}
|
||||
|
||||
/**
|
||||
Constructs an ImageProducer from memory
|
||||
*/
|
||||
* Constructs an ImageProducer from memory
|
||||
*
|
||||
* @param w the image width.
|
||||
* @param h the image height.
|
||||
* @param cm the color model.
|
||||
* @param pix the image data.
|
||||
* @param off the offset to the first pixel in the array.
|
||||
* @param scan the number of array elements from a pixel on one row to the
|
||||
* corresponding pixel on the next row.
|
||||
* @param props image properties (<code>null</code> permitted).
|
||||
*/
|
||||
public MemoryImageSource(int w, int h, ColorModel cm, int[] pix, int off,
|
||||
int scan, Hashtable props)
|
||||
int scan, Hashtable<?,?> props)
|
||||
{
|
||||
width = w;
|
||||
height = h;
|
||||
|
@ -122,16 +143,32 @@ public class MemoryImageSource implements ImageProducer
|
|||
}
|
||||
|
||||
/**
|
||||
* Constructs an ImageProducer from memory using the default RGB ColorModel
|
||||
* Constructs an ImageProducer from memory using the default RGB ColorModel.
|
||||
*
|
||||
* @param w the image width.
|
||||
* @param h the image height.
|
||||
* @param pix the image data.
|
||||
* @param off the offset to the first pixel in the array.
|
||||
* @param scan the number of array elements from a pixel on one row to the
|
||||
* corresponding pixel on the next row.
|
||||
* @param props image properties (<code>null</code> permitted).
|
||||
|
||||
*/
|
||||
public MemoryImageSource(int w, int h, int[] pix, int off, int scan,
|
||||
Hashtable props)
|
||||
Hashtable<?,?> props)
|
||||
{
|
||||
this(w, h, ColorModel.getRGBdefault(), pix, off, scan, props);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an ImageProducer from memory using the default RGB ColorModel
|
||||
* Constructs an ImageProducer from memory using the default RGB ColorModel.
|
||||
*
|
||||
* @param w the image width.
|
||||
* @param h the image height.
|
||||
* @param pix the image data.
|
||||
* @param off the offset to the first pixel in the array.
|
||||
* @param scan the number of array elements from a pixel on one row to the
|
||||
* corresponding pixel on the next row.
|
||||
*/
|
||||
public MemoryImageSource(int w, int h, int[] pix, int off, int scan)
|
||||
{
|
||||
|
@ -141,6 +178,8 @@ public class MemoryImageSource implements ImageProducer
|
|||
/**
|
||||
* Used to register an <code>ImageConsumer</code> with this
|
||||
* <code>ImageProducer</code>.
|
||||
*
|
||||
* @param ic the image consumer.
|
||||
*/
|
||||
public synchronized void addConsumer(ImageConsumer ic)
|
||||
{
|
||||
|
@ -153,6 +192,8 @@ public class MemoryImageSource implements ImageProducer
|
|||
/**
|
||||
* Used to determine if the given <code>ImageConsumer</code> is
|
||||
* already registered with this <code>ImageProducer</code>.
|
||||
*
|
||||
* @param ic the image consumer.
|
||||
*/
|
||||
public synchronized boolean isConsumer(ImageConsumer ic)
|
||||
{
|
||||
|
@ -164,6 +205,8 @@ public class MemoryImageSource implements ImageProducer
|
|||
/**
|
||||
* Used to remove an <code>ImageConsumer</code> from the list of
|
||||
* registered consumers for this <code>ImageProducer</code>.
|
||||
*
|
||||
* @param ic the image consumer.
|
||||
*/
|
||||
public synchronized void removeConsumer(ImageConsumer ic)
|
||||
{
|
||||
|
@ -197,6 +240,8 @@ public class MemoryImageSource implements ImageProducer
|
|||
* Used to register an <code>ImageConsumer</code> with this
|
||||
* <code>ImageProducer</code> and then request that this producer
|
||||
* resend the image data in the order top-down, left-right.
|
||||
*
|
||||
* @param ic the image consumer.
|
||||
*/
|
||||
public void requestTopDownLeftRightResend(ImageConsumer ic)
|
||||
{
|
||||
|
@ -219,7 +264,7 @@ public class MemoryImageSource implements ImageProducer
|
|||
* sending animation. If this flag is set then full buffers are sent
|
||||
* in the newPixels methods instead of just regions.
|
||||
*
|
||||
* @param fullbuffers - a flag indicating whether to send the full buffers
|
||||
* @param fullbuffers a flag indicating whether to send the full buffers
|
||||
*/
|
||||
public synchronized void setFullBufferUpdates(boolean fullbuffers)
|
||||
{
|
||||
|
@ -260,6 +305,11 @@ public class MemoryImageSource implements ImageProducer
|
|||
/**
|
||||
* Send an animation frame to the image consumers containing the specified
|
||||
* pixels unless setFullBufferUpdates is set.
|
||||
*
|
||||
* @param x the x-coordinate.
|
||||
* @param y the y-coordinate.
|
||||
* @param w the width.
|
||||
* @param h the height.
|
||||
*/
|
||||
public synchronized void newPixels(int x, int y, int w, int h)
|
||||
{
|
||||
|
@ -306,6 +356,12 @@ public class MemoryImageSource implements ImageProducer
|
|||
*
|
||||
* If framenotify is set then a notification is sent when the frame
|
||||
* is sent otherwise no status is sent.
|
||||
*
|
||||
* @param x the x-coordinate.
|
||||
* @param y the y-coordinate.
|
||||
* @param w the width.
|
||||
* @param h the height.
|
||||
* @param framenotify send notification?
|
||||
*/
|
||||
public synchronized void newPixels(int x, int y, int w, int h,
|
||||
boolean framenotify)
|
||||
|
|
|
@ -55,7 +55,7 @@ public class PixelGrabber implements ImageConsumer
|
|||
|
||||
ColorModel model = ColorModel.getRGBdefault();
|
||||
int hints;
|
||||
Hashtable props;
|
||||
Hashtable<?,?> props;
|
||||
|
||||
int int_pixel_buffer[];
|
||||
boolean ints_delivered = false;
|
||||
|
@ -442,7 +442,7 @@ public class PixelGrabber implements ImageConsumer
|
|||
* @param props a list of properties associated with the image being
|
||||
* produced
|
||||
*/
|
||||
public synchronized void setProperties(Hashtable props)
|
||||
public synchronized void setProperties(Hashtable<?,?> props)
|
||||
{
|
||||
this.props = props;
|
||||
}
|
||||
|
|
|
@ -46,228 +46,220 @@ package java.awt.image;
|
|||
*/
|
||||
public abstract class RGBImageFilter extends ImageFilter
|
||||
{
|
||||
protected ColorModel origmodel;
|
||||
protected ColorModel origmodel;
|
||||
|
||||
protected ColorModel newmodel;
|
||||
protected ColorModel newmodel;
|
||||
|
||||
/**
|
||||
Specifies whether to apply the filter to the index entries of the
|
||||
IndexColorModel. Subclasses should set this to true if the filter
|
||||
does not depend on the pixel's coordinate.
|
||||
*/
|
||||
protected boolean canFilterIndexColorModel = false;
|
||||
/**
|
||||
* Specifies whether to apply the filter to the index entries of the
|
||||
* IndexColorModel. Subclasses should set this to true if the filter
|
||||
* does not depend on the pixel's coordinate.
|
||||
*/
|
||||
protected boolean canFilterIndexColorModel = false;
|
||||
|
||||
/**
|
||||
Construct new RGBImageFilter.
|
||||
*/
|
||||
public RGBImageFilter()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* Construct new RGBImageFilter.
|
||||
*/
|
||||
public RGBImageFilter()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ColorModel used to filter with. If the specified ColorModel is IndexColorModel
|
||||
* and canFilterIndexColorModel is true, we subsitute the ColorModel for a filtered one
|
||||
* here and in setPixels whenever the original one appears. Otherwise overrides the default
|
||||
* ColorModel of ImageProducer and specifies the default RGBColorModel
|
||||
*
|
||||
* @param model the color model to be used most often by setPixels
|
||||
* @see ColorModel */
|
||||
public void setColorModel(ColorModel model)
|
||||
{
|
||||
origmodel = model;
|
||||
newmodel = model;
|
||||
/**
|
||||
* Sets the ColorModel used to filter with. If the specified ColorModel is
|
||||
* IndexColorModel and canFilterIndexColorModel is true, we subsitute the
|
||||
* ColorModel for a filtered one here and in setPixels whenever the original
|
||||
* one appears. Otherwise overrides the default ColorModel of ImageProducer
|
||||
* and specifies the default RGBColorModel
|
||||
*
|
||||
* @param model the color model to be used most often by setPixels
|
||||
*
|
||||
* @see ColorModel
|
||||
*/
|
||||
public void setColorModel(ColorModel model)
|
||||
{
|
||||
if ((model instanceof IndexColorModel) && canFilterIndexColorModel)
|
||||
{
|
||||
ColorModel newCM = filterIndexColorModel((IndexColorModel) model);
|
||||
substituteColorModel(model, newCM);
|
||||
consumer.setColorModel(newmodel);
|
||||
}
|
||||
else
|
||||
{
|
||||
consumer.setColorModel(ColorModel.getRGBdefault());
|
||||
}
|
||||
}
|
||||
|
||||
if( ( model instanceof IndexColorModel) && canFilterIndexColorModel ) {
|
||||
newmodel = filterIndexColorModel( (IndexColorModel) model );
|
||||
if (consumer != null)
|
||||
consumer.setColorModel(newmodel);
|
||||
}
|
||||
else {
|
||||
if (consumer != null)
|
||||
consumer.setColorModel(ColorModel.getRGBdefault());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Registers a new ColorModel to subsitute for the old ColorModel when
|
||||
setPixels encounters the a pixel with the old ColorModel. The pixel
|
||||
remains unchanged except for a new ColorModel.
|
||||
|
||||
@param oldcm the old ColorModel
|
||||
@param newcm the new ColorModel
|
||||
*/
|
||||
public void substituteColorModel(ColorModel oldcm,
|
||||
ColorModel newcm)
|
||||
{
|
||||
origmodel = oldcm;
|
||||
newmodel = newcm;
|
||||
}
|
||||
/**
|
||||
* Registers a new ColorModel to subsitute for the old ColorModel when
|
||||
* setPixels encounters the a pixel with the old ColorModel. The pixel
|
||||
* remains unchanged except for a new ColorModel.
|
||||
*
|
||||
* @param oldcm the old ColorModel
|
||||
* @param newcm the new ColorModel
|
||||
*/
|
||||
public void substituteColorModel(ColorModel oldcm, ColorModel newcm)
|
||||
{
|
||||
origmodel = oldcm;
|
||||
newmodel = newcm;
|
||||
}
|
||||
|
||||
/**
|
||||
Filters an IndexColorModel through the filterRGB function. Uses
|
||||
coordinates of -1 to indicate its filtering an index and not a pixel.
|
||||
/**
|
||||
* Filters an IndexColorModel through the filterRGB function. Uses
|
||||
* coordinates of -1 to indicate its filtering an index and not a pixel.
|
||||
*
|
||||
* @param icm an IndexColorModel to filter
|
||||
*/
|
||||
public IndexColorModel filterIndexColorModel(IndexColorModel icm)
|
||||
{
|
||||
int len = icm.getMapSize();
|
||||
byte[] reds = new byte[len];
|
||||
byte[] greens = new byte[len];
|
||||
byte[] blues = new byte[len];
|
||||
byte[] alphas = new byte[len];
|
||||
|
||||
@param icm an IndexColorModel to filter
|
||||
*/
|
||||
public IndexColorModel filterIndexColorModel(IndexColorModel icm)
|
||||
{
|
||||
int len = icm.getMapSize(), rgb;
|
||||
byte reds[] = new byte[len], greens[] = new byte[len], blues[] = new byte[len], alphas[] = new byte[len];
|
||||
|
||||
icm.getAlphas( alphas );
|
||||
icm.getReds( reds );
|
||||
icm.getGreens( greens );
|
||||
icm.getBlues( blues );
|
||||
icm.getAlphas( alphas );
|
||||
icm.getReds( reds );
|
||||
icm.getGreens( greens );
|
||||
icm.getBlues( blues );
|
||||
|
||||
for( int i = 0; i < len; i++ )
|
||||
{
|
||||
rgb = filterRGB( -1, -1, makeColor ( alphas[i], reds[i], greens[i], blues[i] ) );
|
||||
alphas[i] = (byte)(( 0xff000000 & rgb ) >> 24);
|
||||
reds[i] = (byte)(( 0xff0000 & rgb ) >> 16);
|
||||
greens[i] = (byte)(( 0xff00 & rgb ) >> 8);
|
||||
blues[i] = (byte)(0xff & rgb);
|
||||
}
|
||||
return new IndexColorModel( icm.getPixelSize(), len, reds, greens, blues, alphas );
|
||||
}
|
||||
int transparent = icm.getTransparentPixel();
|
||||
boolean needAlpha = false;
|
||||
for( int i = 0; i < len; i++ )
|
||||
{
|
||||
int rgb = filterRGB(-1, -1, icm.getRGB(i));
|
||||
alphas[i] = (byte) (rgb >> 24);
|
||||
if (alphas[i] != ((byte) 0xff) && i != transparent)
|
||||
needAlpha = true;
|
||||
reds[i] = (byte) (rgb >> 16);
|
||||
greens[i] = (byte) (rgb >> 8);
|
||||
blues[i] = (byte) (rgb);
|
||||
}
|
||||
IndexColorModel newIcm;
|
||||
if (needAlpha)
|
||||
newIcm = new IndexColorModel(icm.getPixelSize(), len, reds, greens,
|
||||
blues, alphas);
|
||||
else
|
||||
newIcm = new IndexColorModel(icm.getPixelSize(), len, reds, greens,
|
||||
blues, transparent);
|
||||
return newIcm;
|
||||
}
|
||||
|
||||
private int makeColor( byte a, byte r, byte g, byte b )
|
||||
{
|
||||
return ( 0xff000000 & (a << 24) | 0xff0000 & (r << 16) | 0xff00 & (g << 8) | 0xff & b );
|
||||
}
|
||||
/**
|
||||
* This functions filters a set of RGB pixels through filterRGB.
|
||||
*
|
||||
* @param x the x coordinate of the rectangle
|
||||
* @param y the y coordinate of the rectangle
|
||||
* @param w the width of the rectangle
|
||||
* @param h the height of the rectangle
|
||||
* @param pixels the array of pixel values
|
||||
* @param offset the index of the first pixels in the
|
||||
* <code>pixels</code> array
|
||||
* @param scansize the width to use in extracting pixels from the
|
||||
* <code>pixels</code> array
|
||||
*/
|
||||
public void filterRGBPixels(int x, int y, int w, int h, int[] pixels,
|
||||
int offset, int scansize)
|
||||
{
|
||||
int index = offset;
|
||||
for (int yp = 0; yp < h; yp++)
|
||||
{
|
||||
for (int xp = 0; xp < w; xp++)
|
||||
{
|
||||
pixels[index] = filterRGB(xp + x, yp + y, pixels[index]);
|
||||
index++;
|
||||
}
|
||||
index += scansize - w;
|
||||
}
|
||||
consumer.setPixels(x, y, w, h, ColorModel.getRGBdefault(), pixels, offset,
|
||||
scansize);
|
||||
}
|
||||
|
||||
/**
|
||||
This functions filters a set of RGB pixels through filterRGB.
|
||||
/**
|
||||
* If the ColorModel is the same ColorModel which as already converted
|
||||
* then it converts it the converted ColorModel. Otherwise it passes the
|
||||
* array of pixels through filterRGBpixels.
|
||||
*
|
||||
* @param x the x coordinate of the rectangle
|
||||
* @param y the y coordinate of the rectangle
|
||||
* @param w the width of the rectangle
|
||||
* @param h the height of the rectangle
|
||||
* @param model the <code>ColorModel</code> used to translate the pixels
|
||||
* @param pixels the array of pixel values
|
||||
* @param offset the index of the first pixels in the <code>pixels</code>
|
||||
* array
|
||||
* @param scansize the width to use in extracting pixels from the
|
||||
* <code>pixels</code> array
|
||||
*/
|
||||
public void setPixels(int x, int y, int w, int h, ColorModel model,
|
||||
byte[] pixels, int offset, int scansize)
|
||||
{
|
||||
if (model == origmodel)
|
||||
{
|
||||
consumer.setPixels(x, y, w, h, newmodel, pixels, offset, scansize);
|
||||
}
|
||||
else
|
||||
{
|
||||
int[] filtered = new int[w];
|
||||
int index = offset;
|
||||
for (int yp = 0; yp < h; yp++)
|
||||
{
|
||||
for (int xp = 0; xp < w; xp++)
|
||||
{
|
||||
filtered[xp] = model.getRGB((pixels[index] & 0xff));
|
||||
index++;
|
||||
}
|
||||
index += scansize - w;
|
||||
filterRGBPixels(x, y + yp, w, 1, filtered, 0, w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@param x the x coordinate of the rectangle
|
||||
@param y the y coordinate of the rectangle
|
||||
@param w the width of the rectangle
|
||||
@param h the height of the rectangle
|
||||
@param pixels the array of pixel values
|
||||
@param offset the index of the first pixels in the <code>pixels</code> array
|
||||
@param scansize the width to use in extracting pixels from the <code>pixels</code> array
|
||||
*/
|
||||
public void filterRGBPixels(int x, int y, int w, int h, int[] pixels,
|
||||
int offset, int scansize)
|
||||
{
|
||||
for (int yp = 0; yp < h; yp++)
|
||||
{
|
||||
for (int xp = 0; xp < w; xp++)
|
||||
{
|
||||
pixels[offset + xp] = filterRGB(xp + x, yp + y, pixels[offset + xp]);
|
||||
}
|
||||
offset += scansize;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* This function delivers a rectangle of pixels where any
|
||||
* pixel(m,n) is stored in the array as an <code>int</code> at
|
||||
* index (n * scansize + m + offset).
|
||||
*
|
||||
* @param x the x coordinate of the rectangle
|
||||
* @param y the y coordinate of the rectangle
|
||||
* @param w the width of the rectangle
|
||||
* @param h the height of the rectangle
|
||||
* @param model the <code>ColorModel</code> used to translate the pixels
|
||||
* @param pixels the array of pixel values
|
||||
* @param offset the index of the first pixels in the <code>pixels</code>
|
||||
* array
|
||||
* @param scansize the width to use in extracting pixels from the
|
||||
* <code>pixels</code> array
|
||||
*/
|
||||
public void setPixels(int x, int y, int w, int h, ColorModel model,
|
||||
int[] pixels, int offset, int scansize)
|
||||
{
|
||||
if (model == origmodel)
|
||||
{
|
||||
consumer.setPixels(x, y, w, h, newmodel, pixels, offset, scansize);
|
||||
}
|
||||
else
|
||||
{
|
||||
int[] filtered = new int[w];
|
||||
int index = offset;
|
||||
for (int yp = 0; yp < h; yp++)
|
||||
{
|
||||
for (int xp = 0; xp < w; xp++)
|
||||
{
|
||||
filtered[xp] = model.getRGB((pixels[index] & 0xff));
|
||||
index++;
|
||||
}
|
||||
index += scansize - w;
|
||||
filterRGBPixels(x, y + yp, w, 1, filtered, 0, w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If the ColorModel is the same ColorModel which as already converted
|
||||
* then it converts it the converted ColorModel. Otherwise it passes the
|
||||
* array of pixels through filterRGBpixels.
|
||||
*
|
||||
* @param x the x coordinate of the rectangle
|
||||
* @param y the y coordinate of the rectangle
|
||||
* @param w the width of the rectangle
|
||||
* @param h the height of the rectangle
|
||||
* @param model the <code>ColorModel</code> used to translate the pixels
|
||||
* @param pixels the array of pixel values
|
||||
* @param offset the index of the first pixels in the <code>pixels</code> array
|
||||
* @param scansize the width to use in extracting pixels from the <code>pixels</code> array
|
||||
*/
|
||||
public void setPixels(int x, int y, int w, int h,
|
||||
ColorModel model, byte[] pixels,
|
||||
int offset, int scansize)
|
||||
{
|
||||
if(model == origmodel && (model instanceof IndexColorModel) && canFilterIndexColorModel)
|
||||
{
|
||||
if (consumer != null)
|
||||
consumer.setPixels(x, y, w, h, newmodel, pixels, offset, scansize);
|
||||
}
|
||||
else
|
||||
{
|
||||
int intPixels[] =
|
||||
convertColorModelToDefault( x, y, w, h, model, pixels, offset, scansize );
|
||||
filterRGBPixels( x, y, w, h, intPixels, offset, scansize );
|
||||
if (consumer != null)
|
||||
consumer.setPixels(x, y, w, h, ColorModel.getRGBdefault(), intPixels, offset, scansize);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function delivers a rectangle of pixels where any
|
||||
* pixel(m,n) is stored in the array as an <code>int</code> at
|
||||
* index (n * scansize + m + offset).
|
||||
*
|
||||
* @param x the x coordinate of the rectangle
|
||||
* @param y the y coordinate of the rectangle
|
||||
* @param w the width of the rectangle
|
||||
* @param h the height of the rectangle
|
||||
* @param model the <code>ColorModel</code> used to translate the pixels
|
||||
* @param pixels the array of pixel values
|
||||
* @param offset the index of the first pixels in the <code>pixels</code> array
|
||||
* @param scansize the width to use in extracting pixels from the <code>pixels</code> array
|
||||
*/
|
||||
public void setPixels(int x, int y, int w, int h,
|
||||
ColorModel model, int[] pixels,
|
||||
int offset, int scansize)
|
||||
{
|
||||
if(model == origmodel && (model instanceof IndexColorModel) && canFilterIndexColorModel)
|
||||
{
|
||||
if (consumer != null)
|
||||
consumer.setPixels(x, y, w, h, newmodel, pixels, offset, scansize);
|
||||
}
|
||||
else
|
||||
{
|
||||
//FIXME: Store the filtered pixels in a separate temporary buffer?
|
||||
convertColorModelToDefault( x, y, w, h, model, pixels, offset, scansize );
|
||||
filterRGBPixels( x, y, w, h, pixels, offset, scansize );
|
||||
if (consumer != null)
|
||||
consumer.setPixels(x, y, w, h, ColorModel.getRGBdefault(), pixels, offset, scansize);
|
||||
}
|
||||
}
|
||||
|
||||
private int[] convertColorModelToDefault(int x, int y, int w, int h,
|
||||
ColorModel model, byte pixels[],
|
||||
int offset, int scansize)
|
||||
{
|
||||
int intPixels[] = new int[pixels.length];
|
||||
for (int i = 0; i < pixels.length; i++)
|
||||
intPixels[i] = makeColorbyDefaultCM(model, pixels[i]);
|
||||
return intPixels;
|
||||
}
|
||||
|
||||
private void convertColorModelToDefault(int x, int y, int w, int h,
|
||||
ColorModel model, int pixels[],
|
||||
int offset, int scansize)
|
||||
{
|
||||
for (int i = 0; i < pixels.length; i++)
|
||||
pixels[i] = makeColorbyDefaultCM(model, pixels[i]);
|
||||
}
|
||||
|
||||
private int makeColorbyDefaultCM(ColorModel model, byte rgb)
|
||||
{
|
||||
return makeColor( model.getAlpha( rgb ) * 4, model.getRed( rgb ) * 4, model.getGreen( rgb ) * 4, model.getBlue( rgb ) * 4 );
|
||||
}
|
||||
|
||||
private int makeColorbyDefaultCM(ColorModel model, int rgb)
|
||||
{
|
||||
return makeColor( model.getAlpha( rgb ), model.getRed( rgb ), model.getGreen( rgb ), model.getBlue( rgb ) );
|
||||
}
|
||||
|
||||
private int makeColor( int a, int r, int g, int b )
|
||||
{
|
||||
return (int)( 0xff000000 & (a << 24) | 0xff0000 & (r << 16) | 0xff00 & (g << 8) | 0xff & b );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Filters a single pixel from the default ColorModel.
|
||||
|
||||
@param x x-coordinate
|
||||
@param y y-coordinate
|
||||
@param rgb color
|
||||
*/
|
||||
public abstract int filterRGB(int x,
|
||||
int y,
|
||||
int rgb);
|
||||
/**
|
||||
* Filters a single pixel from the default ColorModel.
|
||||
*
|
||||
* @param x x-coordinate
|
||||
* @param y y-coordinate
|
||||
* @param rgb color
|
||||
*/
|
||||
public abstract int filterRGB(int x, int y, int rgb);
|
||||
}
|
||||
|
|
|
@ -511,9 +511,10 @@ public class Raster
|
|||
int height, int childMinX, int childMinY,
|
||||
int[] bandList)
|
||||
{
|
||||
/* FIXME: Throw RasterFormatException if child bounds extends
|
||||
beyond the bounds of this raster. */
|
||||
|
||||
if (parentX < minX || parentX + width > minX + this.width
|
||||
|| parentY < minY || parentY + height > minY + this.height)
|
||||
throw new RasterFormatException("Child raster extends beyond parent");
|
||||
|
||||
SampleModel sm = (bandList == null) ?
|
||||
sampleModel :
|
||||
sampleModel.createSubsetSampleModel(bandList);
|
||||
|
|
|
@ -46,7 +46,7 @@ import java.util.Vector;
|
|||
*/
|
||||
public interface RenderedImage
|
||||
{
|
||||
Vector getSources();
|
||||
Vector<RenderedImage> getSources();
|
||||
Object getProperty(String name);
|
||||
String[] getPropertyNames();
|
||||
ColorModel getColorModel();
|
||||
|
|
|
@ -46,6 +46,7 @@ import java.util.Hashtable;
|
|||
* exact method is not defined by Sun but some sort of fast Box filter should
|
||||
* probably be correct.
|
||||
* <br>
|
||||
* Currently this filter does nothing and needs to be implemented.
|
||||
*
|
||||
* @author C. Brian Jones (cbj@gnu.org)
|
||||
*/
|
||||
|
@ -116,11 +117,11 @@ public class ReplicateScaleFilter extends ImageFilter
|
|||
}
|
||||
else if (destWidth < 0)
|
||||
{
|
||||
destWidth = (int) (width * ((double) destHeight / srcHeight));
|
||||
destWidth = width * destHeight / srcHeight;
|
||||
}
|
||||
else if (destHeight < 0)
|
||||
{
|
||||
destHeight = (int) (height * ((double) destWidth / srcWidth));
|
||||
destHeight = height * destWidth / srcWidth;
|
||||
}
|
||||
|
||||
if (consumer != null)
|
||||
|
@ -133,11 +134,12 @@ public class ReplicateScaleFilter extends ImageFilter
|
|||
*
|
||||
* @param props the list of properties associated with this image
|
||||
*/
|
||||
public void setProperties(Hashtable props)
|
||||
public void setProperties(Hashtable<?, ?> props)
|
||||
{
|
||||
props.put("filters", "ReplicateScaleFilter");
|
||||
if (consumer != null)
|
||||
consumer.setProperties(props);
|
||||
Hashtable<Object, Object> prop2 = (Hashtable<Object, Object>) props;
|
||||
prop2.put("filters", "ReplicateScaleFilter");
|
||||
if (consumer != null)
|
||||
consumer.setProperties(prop2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -157,19 +159,35 @@ public class ReplicateScaleFilter extends ImageFilter
|
|||
public void setPixels(int x, int y, int w, int h,
|
||||
ColorModel model, byte[] pixels, int offset, int scansize)
|
||||
{
|
||||
double rx = ((double) srcWidth) / destWidth;
|
||||
double ry = ((double) srcHeight) / destHeight;
|
||||
|
||||
int destScansize = (int) Math.round(scansize / rx);
|
||||
|
||||
byte[] destPixels = replicatePixels(x, y, w, h,
|
||||
model, pixels, offset, scansize,
|
||||
rx, ry, destScansize);
|
||||
|
||||
if (consumer != null)
|
||||
consumer.setPixels((int) Math.floor(x/rx), (int) Math.floor(y/ry),
|
||||
(int) Math.ceil(w/rx), (int) Math.ceil(h/ry),
|
||||
model, destPixels, 0, destScansize);
|
||||
if (srcrows == null || srccols == null)
|
||||
setupSources();
|
||||
int dx1 = (2 * x * destWidth + srcWidth - 1) / (2 * destWidth);
|
||||
int dy1 = (2 * y * destHeight + srcHeight - 1) / (2 * destHeight);
|
||||
byte[] pix;
|
||||
if (outpixbuf != null && outpixbuf instanceof byte[])
|
||||
{
|
||||
pix = (byte[]) outpixbuf;
|
||||
}
|
||||
else
|
||||
{
|
||||
pix = new byte[destWidth];
|
||||
outpixbuf = pix;
|
||||
}
|
||||
int sy, sx;
|
||||
for (int yy = dy1; (sy = srcrows[yy]) < y + h; yy++)
|
||||
{
|
||||
int offs = offset + scansize * (sy - y);
|
||||
int xx;
|
||||
for (xx = dx1; (sx = srccols[xx]) < x + w; xx++)
|
||||
{
|
||||
pix[xx] = pixels[offs + sx - x];
|
||||
}
|
||||
if (xx > dx1)
|
||||
{
|
||||
consumer.setPixels(dx1, yy, xx - dx1, 1, model, pix, dx1,
|
||||
destWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -189,59 +207,52 @@ public class ReplicateScaleFilter extends ImageFilter
|
|||
public void setPixels(int x, int y, int w, int h,
|
||||
ColorModel model, int[] pixels, int offset, int scansize)
|
||||
{
|
||||
double rx = ((double) srcWidth) / destWidth;
|
||||
double ry = ((double) srcHeight) / destHeight;
|
||||
|
||||
int destScansize = (int) Math.round(scansize / rx);
|
||||
|
||||
int[] destPixels = replicatePixels(x, y, w, h,
|
||||
model, pixels, offset, scansize,
|
||||
rx, ry, destScansize);
|
||||
|
||||
if (consumer != null)
|
||||
consumer.setPixels((int) Math.floor(x/rx), (int) Math.floor(y/ry),
|
||||
(int) Math.ceil(w/rx), (int) Math.ceil(h/ry),
|
||||
model, destPixels, 0, destScansize);
|
||||
if (srcrows == null || srccols == null)
|
||||
setupSources();
|
||||
int dx1 = (2 * x * destWidth + srcWidth - 1) / (2 * destWidth);
|
||||
int dy1 = (2 * y * destHeight + srcHeight - 1) / (2 * destHeight);
|
||||
int[] pix;
|
||||
if (outpixbuf != null && outpixbuf instanceof int[])
|
||||
{
|
||||
pix = (int[]) outpixbuf;
|
||||
}
|
||||
else
|
||||
{
|
||||
pix = new int[destWidth];
|
||||
outpixbuf = pix;
|
||||
}
|
||||
int sy, sx;
|
||||
for (int yy = dy1; (sy = srcrows[yy]) < y + h; yy++)
|
||||
{
|
||||
int offs = offset + scansize * (sy - y);
|
||||
int xx;
|
||||
for (xx = dx1; (sx = srccols[xx]) < x + w; xx++)
|
||||
{
|
||||
pix[xx] = pixels[offs + sx - x];
|
||||
}
|
||||
if (xx > dx1)
|
||||
{
|
||||
consumer.setPixels(dx1, yy, xx - dx1, 1, model, pix, dx1,
|
||||
destWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] replicatePixels(int srcx, int srcy, int srcw, int srch,
|
||||
ColorModel model, byte[] srcPixels,
|
||||
int srcOffset, int srcScansize,
|
||||
double rx, double ry, int destScansize)
|
||||
{
|
||||
byte[] destPixels =
|
||||
new byte[(int) Math.ceil(srcw/rx) * (int) Math.ceil(srch/ry)];
|
||||
|
||||
int a, b;
|
||||
for (int i = 0; i < destPixels.length; i++)
|
||||
{
|
||||
a = (int) ((int) ( ((double) i) / destScansize) * ry) * srcScansize;
|
||||
b = (int) ((i % destScansize) * rx);
|
||||
if ((a + b + srcOffset) < srcPixels.length)
|
||||
destPixels[i] = srcPixels[a + b + srcOffset];
|
||||
}
|
||||
|
||||
return destPixels;
|
||||
}
|
||||
|
||||
private int[] replicatePixels(int srcx, int srcy, int srcw, int srch,
|
||||
ColorModel model, int[] srcPixels,
|
||||
int srcOffset, int srcScansize,
|
||||
double rx, double ry, int destScansize)
|
||||
{
|
||||
int[] destPixels =
|
||||
new int[(int) Math.ceil(srcw/rx) * (int) Math.ceil(srch/ry)];
|
||||
|
||||
int a, b;
|
||||
for (int i = 0; i < destPixels.length; i++)
|
||||
{
|
||||
a = (int) ((int) ( ((double) i) / destScansize) * ry) * srcScansize;
|
||||
b = (int) ((i % destScansize) * rx);
|
||||
if ((a + b + srcOffset) < srcPixels.length)
|
||||
destPixels[i] = srcPixels[a + b + srcOffset];
|
||||
}
|
||||
|
||||
return destPixels;
|
||||
}
|
||||
/**
|
||||
* Sets up the srcrows and srccols arrays.
|
||||
*/
|
||||
private void setupSources()
|
||||
{
|
||||
srcrows = new int[destHeight + 1];
|
||||
for (int y = 0; y <= destHeight; y++)
|
||||
{
|
||||
srcrows[y] = (2 * y * srcHeight + srcHeight) / (2 * destHeight);
|
||||
}
|
||||
srccols = new int[destWidth + 1];
|
||||
for (int x = 0; x <= destWidth; x++)
|
||||
{
|
||||
srccols[x] = (2 * x * srcWidth + srcWidth) / (2 * destWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2004 Free Software Foundation
|
||||
/* Copyright (C) 2004, 2006 Free Software Foundation
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -43,7 +43,23 @@ import java.awt.geom.Rectangle2D;
|
|||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* RescaleOp is a filter that changes each pixel by a scaling factor and offset.
|
||||
*
|
||||
* For filtering Rasters, either one scaling factor and offset can be specified,
|
||||
* which will be applied to all bands; or a scaling factor and offset can be
|
||||
* specified for each band.
|
||||
*
|
||||
* For BufferedImages, the scaling may apply to both color and alpha components.
|
||||
* If only one scaling factor is provided, or if the number of factors provided
|
||||
* equals the number of color components, the scaling is performed on all color
|
||||
* components. Otherwise, the scaling is performed on all components including
|
||||
* alpha. Alpha premultiplication is ignored.
|
||||
*
|
||||
* After filtering, if color conversion is necessary, the conversion happens,
|
||||
* taking alpha premultiplication into account.
|
||||
*
|
||||
* @author Jerry Quinn (jlquinn@optonline.net)
|
||||
* @author Francis Kung (fkung@redhat.com)
|
||||
*/
|
||||
public class RescaleOp implements BufferedImageOp, RasterOp
|
||||
{
|
||||
|
@ -51,15 +67,43 @@ public class RescaleOp implements BufferedImageOp, RasterOp
|
|||
private float[] offsets;
|
||||
private RenderingHints hints = null;
|
||||
|
||||
/**
|
||||
* Create a new RescaleOp object using the given scale factors and offsets.
|
||||
*
|
||||
* The length of the arrays must be equal to the number of bands (or number of
|
||||
* data or color components) of the raster/image that this Op will be used on,
|
||||
* otherwise an IllegalArgumentException will be thrown when calling the
|
||||
* filter method.
|
||||
*
|
||||
* @param scaleFactors an array of scale factors.
|
||||
* @param offsets an array of offsets.
|
||||
* @param hints any rendering hints to use (can be null).
|
||||
* @throws NullPointerException if the scaleFactors or offsets array is null.
|
||||
*/
|
||||
public RescaleOp(float[] scaleFactors,
|
||||
float[] offsets,
|
||||
RenderingHints hints)
|
||||
{
|
||||
this.scale = scaleFactors;
|
||||
this.offsets = offsets;
|
||||
int length = Math.min(scaleFactors.length, offsets.length);
|
||||
|
||||
scale = new float[length];
|
||||
System.arraycopy(scaleFactors, 0, this.scale, 0, length);
|
||||
|
||||
this.offsets = new float[length];
|
||||
System.arraycopy(offsets, 0, this.offsets, 0, length);
|
||||
|
||||
this.hints = hints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new RescaleOp object using the given scale factor and offset.
|
||||
*
|
||||
* The same scale factor and offset will be used on all bands/components.
|
||||
*
|
||||
* @param scaleFactor the scale factor to use.
|
||||
* @param offset the offset to use.
|
||||
* @param hints any rendering hints to use (can be null).
|
||||
*/
|
||||
public RescaleOp(float scaleFactor,
|
||||
float offset,
|
||||
RenderingHints hints)
|
||||
|
@ -69,22 +113,47 @@ public class RescaleOp implements BufferedImageOp, RasterOp
|
|||
this.hints = hints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scaling factors. This method accepts an optional array, which
|
||||
* will be used to store the factors if not null (this avoids allocating a
|
||||
* new array). If this array is too small to hold all the scaling factors,
|
||||
* the array will be filled and the remaining factors discarded.
|
||||
*
|
||||
* @param scaleFactors array to store the scaling factors in (can be null).
|
||||
* @return an array of scaling factors.
|
||||
*/
|
||||
public final float[] getScaleFactors(float[] scaleFactors)
|
||||
{
|
||||
if (scaleFactors == null)
|
||||
scaleFactors = new float[scale.length];
|
||||
System.arraycopy(scale, 0, scaleFactors, 0, scale.length);
|
||||
System.arraycopy(scale, 0, scaleFactors, 0, Math.min(scale.length,
|
||||
scaleFactors.length));
|
||||
return scaleFactors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offsets. This method accepts an optional array, which
|
||||
* will be used to store the offsets if not null (this avoids allocating a
|
||||
* new array). If this array is too small to hold all the offsets, the array
|
||||
* will be filled and the remaining factors discarded.
|
||||
*
|
||||
* @param offsets array to store the offsets in (can be null).
|
||||
* @return an array of offsets.
|
||||
*/
|
||||
public final float[] getOffsets(float[] offsets)
|
||||
{
|
||||
if (offsets == null)
|
||||
offsets = new float[this.offsets.length];
|
||||
System.arraycopy(this.offsets, 0, offsets, 0, this.offsets.length);
|
||||
System.arraycopy(this.offsets, 0, offsets, 0, Math.min(this.offsets.length,
|
||||
offsets.length));
|
||||
return offsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of scaling factors / offsets.
|
||||
*
|
||||
* @return the number of scaling factors / offsets.
|
||||
*/
|
||||
public final int getNumFactors()
|
||||
{
|
||||
return scale.length;
|
||||
|
@ -98,36 +167,74 @@ public class RescaleOp implements BufferedImageOp, RasterOp
|
|||
return hints;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.awt.image.BufferedImageOp#filter(java.awt.image.BufferedImage, java.awt.image.BufferedImage)
|
||||
/**
|
||||
* Converts the source image using the scale factors and offsets specified in
|
||||
* the constructor. The resulting image is stored in the destination image if
|
||||
* one is provided; otherwise a new BufferedImage is created and returned.
|
||||
*
|
||||
* The source image cannot use an IndexColorModel, and the destination image
|
||||
* (if one is provided) must have the same size.
|
||||
*
|
||||
* If the final value of a sample is beyond the range of the color model, it
|
||||
* will be clipped to the appropriate maximum / minimum.
|
||||
*
|
||||
* @param src The source image.
|
||||
* @param dst The destination image.
|
||||
* @throws IllegalArgumentException if the rasters and/or color spaces are
|
||||
* incompatible.
|
||||
* @return The rescaled image.
|
||||
*/
|
||||
public final BufferedImage filter(BufferedImage src, BufferedImage dst)
|
||||
{
|
||||
// TODO Make sure premultiplied alpha is handled correctly.
|
||||
// TODO See that color conversion is handled.
|
||||
// TODO figure out how to use rendering hints.
|
||||
if (scale.length != offsets.length)
|
||||
throw new IllegalArgumentException();
|
||||
// Initial checks
|
||||
if (scale.length != 1
|
||||
&& scale.length != src.getColorModel().getNumComponents()
|
||||
&& (scale.length != src.getColorModel().getNumColorComponents()))
|
||||
throw new IllegalArgumentException("Source image has wrong number of "
|
||||
+ "bands for these scaling factors.");
|
||||
|
||||
ColorModel scm = src.getColorModel();
|
||||
if (dst == null) dst = createCompatibleDestImage(src, null);
|
||||
if (dst == null)
|
||||
dst = createCompatibleDestImage(src, null);
|
||||
else if (src.getHeight() != dst.getHeight()
|
||||
|| src.getWidth() != dst.getWidth())
|
||||
throw new IllegalArgumentException("Source and destination images are "
|
||||
+ "different sizes.");
|
||||
|
||||
WritableRaster wsrc = src.getRaster();
|
||||
WritableRaster wdst = dst.getRaster();
|
||||
|
||||
// Share constant across colors except alpha
|
||||
if (scale.length == 1 || scale.length == scm.getNumColorComponents())
|
||||
// Prepare for possible colorspace conversion
|
||||
BufferedImage dst2 = dst;
|
||||
if (dst.getColorModel().getColorSpace().getType() != src.getColorModel().getColorSpace().getType())
|
||||
dst2 = createCompatibleDestImage(src, src.getColorModel());
|
||||
|
||||
// Figure out how many bands to scale
|
||||
int numBands = scale.length;
|
||||
if (scale.length == 1)
|
||||
numBands = src.getColorModel().getNumColorComponents();
|
||||
boolean[] bands = new boolean[numBands];
|
||||
// this assumes the alpha, if present, is the last band
|
||||
Arrays.fill(bands, true);
|
||||
|
||||
// Perform rescaling
|
||||
filter(src.getRaster(), dst2.getRaster(), bands);
|
||||
|
||||
// Copy alpha band if needed (ie if it exists and wasn't scaled)
|
||||
// NOTE: This assumes the alpha component is the last band!
|
||||
if (src.getColorModel().hasAlpha()
|
||||
&& numBands == src.getColorModel().getNumColorComponents())
|
||||
{
|
||||
// Construct a raster that doesn't include an alpha band.
|
||||
int[] subbands = new int[scm.getNumColorComponents()];
|
||||
for (int i=0; i < subbands.length; i++) subbands[i] = i;
|
||||
wsrc =
|
||||
wsrc.createWritableChild(wsrc.minX, wsrc.minY, wsrc.width, wsrc.height,
|
||||
wsrc.minX, wsrc.minY, subbands);
|
||||
}
|
||||
// else all color bands
|
||||
|
||||
filter(wsrc, wdst);
|
||||
dst2.getRaster().setSamples(0, 0, src.getWidth(), src.getHeight(),
|
||||
numBands,
|
||||
src.getRaster().getSamples(0, 0,
|
||||
src.getWidth(),
|
||||
src.getHeight(),
|
||||
numBands,
|
||||
(int[]) null));
|
||||
}
|
||||
|
||||
// Perform colorspace conversion if needed
|
||||
if (dst != dst2)
|
||||
new ColorConvertOp(hints).filter(dst2, dst);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
@ -136,50 +243,106 @@ public class RescaleOp implements BufferedImageOp, RasterOp
|
|||
*/
|
||||
public final WritableRaster filter(Raster src, WritableRaster dest)
|
||||
{
|
||||
if (dest == null) dest = src.createCompatibleWritableRaster();
|
||||
|
||||
// Required sanity checks
|
||||
if (src.numBands != dest.numBands || scale.length != offsets.length)
|
||||
throw new IllegalArgumentException();
|
||||
if (scale.length != 1 && scale.length != src.numBands)
|
||||
throw new IllegalArgumentException();
|
||||
throw new IllegalArgumentException("Number of rasters is incompatible "
|
||||
+ "with the number of scaling "
|
||||
+ "factors provided.");
|
||||
|
||||
// Create scaling arrays if needed
|
||||
float[] lscale = scale;
|
||||
float[] loff = offsets;
|
||||
if (scale.length == 1)
|
||||
{
|
||||
lscale = new float[src.numBands];
|
||||
Arrays.fill(lscale, scale[0]);
|
||||
loff = new float[src.numBands];
|
||||
Arrays.fill(loff, offsets[0]);
|
||||
}
|
||||
if (dest == null)
|
||||
dest = src.createCompatibleWritableRaster();
|
||||
else if (src.getHeight() != dest.getHeight()
|
||||
|| src.getWidth() != dest.getWidth())
|
||||
throw new IllegalArgumentException("Source and destination rasters are "
|
||||
+ "different sizes.");
|
||||
else if (src.numBands != dest.numBands)
|
||||
throw new IllegalArgumentException("Source and destination rasters "
|
||||
+ "are incompatible.");
|
||||
|
||||
// TODO The efficiency here can be improved for various data storage
|
||||
// patterns, aka SampleModels.
|
||||
float[] pixel = new float[src.numBands];
|
||||
for (int y = src.minY; y < src.height + src.minY; y++)
|
||||
for (int x = src.minX; x < src.width + src.minX; x++)
|
||||
{
|
||||
src.getPixel(x, y, pixel);
|
||||
for (int b = 0; b < src.numBands; b++)
|
||||
pixel[b] = pixel[b] * lscale[b] + loff[b];
|
||||
dest.setPixel(x, y, pixel);
|
||||
}
|
||||
// Filter all bands
|
||||
boolean[] bands = new boolean[src.getNumBands()];
|
||||
Arrays.fill(bands, true);
|
||||
return filter(src, dest, bands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform raster-based filtering on a selected number of bands.
|
||||
*
|
||||
* The length of the bands array should equal the number of bands; a true
|
||||
* element indicates filtering should happen on the corresponding band, while
|
||||
* a false element will skip the band.
|
||||
*
|
||||
* The rasters are assumed to be compatible and non-null.
|
||||
*
|
||||
* @param src the source raster.
|
||||
* @param dest the destination raster.
|
||||
* @param bands an array indicating which bands to filter.
|
||||
* @throws NullPointerException if any parameter is null.
|
||||
* @throws ArrayIndexOutOfBoundsException if the bands array is too small.
|
||||
* @return the destination raster.
|
||||
*/
|
||||
private WritableRaster filter(Raster src, WritableRaster dest, boolean[] bands)
|
||||
{
|
||||
int[] values = new int[src.getHeight() * src.getWidth()];
|
||||
float scaleFactor, offset;
|
||||
|
||||
// Find max sample value, to be used for clipping later
|
||||
int[] maxValue = src.getSampleModel().getSampleSize();
|
||||
for (int i = 0; i < maxValue.length; i++)
|
||||
maxValue[i] = (int)Math.pow(2, maxValue[i]) - 1;
|
||||
|
||||
// TODO: can this be optimized further?
|
||||
// Filter all samples of all requested bands
|
||||
for (int band = 0; band < bands.length; band++)
|
||||
if (bands[band])
|
||||
{
|
||||
values = src.getSamples(src.getMinX(), src.getMinY(), src.getWidth(),
|
||||
src.getHeight(), band, values);
|
||||
|
||||
if (scale.length == 1)
|
||||
{
|
||||
scaleFactor = scale[0];
|
||||
offset = offsets[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
scaleFactor = scale[band];
|
||||
offset = offsets[band];
|
||||
}
|
||||
|
||||
for (int i = 0; i < values.length; i++)
|
||||
{
|
||||
values[i] = (int) (values[i] * scaleFactor + offset);
|
||||
|
||||
// Clip if needed
|
||||
if (values[i] < 0)
|
||||
values[i] = 0;
|
||||
if (values[i] > maxValue[band])
|
||||
values[i] = maxValue[band];
|
||||
}
|
||||
|
||||
dest.setSamples(dest.getMinX(), dest.getMinY(), dest.getWidth(),
|
||||
dest.getHeight(), band, values);
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.awt.image.BufferedImageOp#createCompatibleDestImage(java.awt.image.BufferedImage, java.awt.image.ColorModel)
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.awt.image.BufferedImageOp#createCompatibleDestImage(java.awt.image.BufferedImage,
|
||||
* java.awt.image.ColorModel)
|
||||
*/
|
||||
public BufferedImage createCompatibleDestImage(BufferedImage src,
|
||||
ColorModel dstCM)
|
||||
{
|
||||
if (dstCM == null) dstCM = src.getColorModel();
|
||||
WritableRaster wr = src.getRaster().createCompatibleWritableRaster();
|
||||
BufferedImage image
|
||||
= new BufferedImage(dstCM, wr, src.isPremultiplied, null);
|
||||
return image;
|
||||
if (dstCM == null)
|
||||
return new BufferedImage(src.getWidth(), src.getHeight(), src.getType());
|
||||
|
||||
return new BufferedImage(dstCM,
|
||||
src.getRaster().createCompatibleWritableRaster(),
|
||||
src.isAlphaPremultiplied(), null);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
@ -209,9 +372,13 @@ public class RescaleOp implements BufferedImageOp, RasterOp
|
|||
/* (non-Javadoc)
|
||||
* @see java.awt.image.BufferedImageOp#getPoint2D(java.awt.geom.Point2D, java.awt.geom.Point2D)
|
||||
*/
|
||||
public final Point2D getPoint2D(Point2D src, Point2D dst) {
|
||||
if (dst == null) dst = (Point2D) src.clone();
|
||||
else dst.setLocation(src);
|
||||
public final Point2D getPoint2D(Point2D src, Point2D dst)
|
||||
{
|
||||
if (dst == null)
|
||||
dst = (Point2D) src.clone();
|
||||
else
|
||||
dst.setLocation(src);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
|
|
@ -246,9 +246,7 @@ public abstract class SampleModel
|
|||
public void setDataElements(int x, int y, int w, int h,
|
||||
Object obj, DataBuffer data)
|
||||
{
|
||||
int size = w * h;
|
||||
int numDataElements = getNumDataElements();
|
||||
int dataSize = numDataElements * size;
|
||||
|
||||
Object pixelData;
|
||||
switch (getTransferType())
|
||||
|
@ -257,25 +255,34 @@ public abstract class SampleModel
|
|||
pixelData = new byte[numDataElements];
|
||||
break;
|
||||
case DataBuffer.TYPE_USHORT:
|
||||
case DataBuffer.TYPE_SHORT:
|
||||
pixelData = new short[numDataElements];
|
||||
break;
|
||||
case DataBuffer.TYPE_INT:
|
||||
pixelData = new int[numDataElements];
|
||||
break;
|
||||
case DataBuffer.TYPE_FLOAT:
|
||||
pixelData = new float[numDataElements];
|
||||
break;
|
||||
case DataBuffer.TYPE_DOUBLE:
|
||||
pixelData = new double[numDataElements];
|
||||
break;
|
||||
default:
|
||||
// Seems like the only sensible thing to do.
|
||||
throw new ClassCastException();
|
||||
// The RI silently igores invalid types.
|
||||
pixelData = null;
|
||||
}
|
||||
int inOffset = 0;
|
||||
|
||||
for (int yy = y; yy < (y + h); yy++)
|
||||
int inOffset = 0;
|
||||
if (pixelData != null)
|
||||
{
|
||||
for (int xx = x; xx < (x + w); xx++)
|
||||
for (int yy=y; yy<(y+h); yy++)
|
||||
{
|
||||
System.arraycopy(obj, inOffset, pixelData, 0,
|
||||
numDataElements);
|
||||
setDataElements(xx, yy, pixelData, data);
|
||||
inOffset += numDataElements;
|
||||
for (int xx=x; xx<(x+w); xx++)
|
||||
{
|
||||
System.arraycopy(obj, inOffset, pixelData, 0, numDataElements);
|
||||
setDataElements(xx, yy, pixelData, data);
|
||||
inOffset += numDataElements;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -412,110 +412,31 @@ public class SinglePixelPackedSampleModel extends SampleModel
|
|||
return (samples & bitMasks[b]) >>> bitOffsets[b];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
public void setDataElements(int x, int y, int w, int h,
|
||||
Object obj, DataBuffer data)
|
||||
{
|
||||
|
||||
Object pixelData;
|
||||
switch (getTransferType())
|
||||
{
|
||||
case DataBuffer.TYPE_BYTE:
|
||||
pixelData = ((DataBufferByte) data).getData();
|
||||
break;
|
||||
case DataBuffer.TYPE_USHORT:
|
||||
pixelData = ((DataBufferUShort) data).getData();
|
||||
break;
|
||||
case DataBuffer.TYPE_INT:
|
||||
pixelData = ((DataBufferInt) data).getData();
|
||||
break;
|
||||
default:
|
||||
// Seems like the only sensible thing to do.
|
||||
throw new ClassCastException();
|
||||
}
|
||||
|
||||
int inOffset = 0;
|
||||
int dataOffset = scanlineStride*y + x + data.getOffset();
|
||||
for (int yy=y; yy<(y+h); yy++)
|
||||
{
|
||||
System.arraycopy(obj,inOffset,pixelData,dataOffset,w);
|
||||
dataOffset += scanlineStride;
|
||||
inOffset += w;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setDataElements(int x, int y, Object obj, DataBuffer data)
|
||||
{
|
||||
int offset = scanlineStride*y + x + data.getOffset();
|
||||
|
||||
int transferType = getTransferType();
|
||||
if (getTransferType() != data.getDataType())
|
||||
{
|
||||
throw new IllegalArgumentException("transfer type ("+
|
||||
getTransferType()+"), "+
|
||||
"does not match data "+
|
||||
"buffer type (" +
|
||||
data.getDataType() +
|
||||
").");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
// FIXME: Fill in the other possible types.
|
||||
default:
|
||||
throw new InternalError();
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
switch (transferType)
|
||||
{
|
||||
case DataBuffer.TYPE_BYTE:
|
||||
{
|
||||
byte[] in = (byte[]) obj;
|
||||
data.setElem(y * scanlineStride + x, ((int) in[0]) & 0xff);
|
||||
break;
|
||||
}
|
||||
case DataBuffer.TYPE_USHORT:
|
||||
{
|
||||
short[] in = (short[]) obj;
|
||||
data.setElem(y * scanlineStride + x, ((int) in[0]) & 0xffff);
|
||||
break;
|
||||
}
|
||||
case DataBuffer.TYPE_INT:
|
||||
{
|
||||
int[] in = (int[]) obj;
|
||||
data.setElem(y * scanlineStride + x, in[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -136,8 +136,9 @@ public class WritableRaster extends Raster
|
|||
{
|
||||
// This mirrors the code from the super class
|
||||
|
||||
// FIXME: Throw RasterFormatException if child bounds extends
|
||||
// beyond the bounds of this raster.
|
||||
if (parentX < minX || parentX + w > minX + width
|
||||
|| parentY < minY || parentY + h > minY + height)
|
||||
throw new RasterFormatException("Child raster extends beyond parent");
|
||||
|
||||
SampleModel sm = (bandList == null) ?
|
||||
sampleModel :
|
||||
|
@ -149,6 +150,25 @@ public class WritableRaster extends Raster
|
|||
sampleModelTranslateY + childMinY - parentY),
|
||||
this);
|
||||
}
|
||||
|
||||
public Raster createChild(int parentX, int parentY, int width,
|
||||
int height, int childMinX, int childMinY,
|
||||
int[] bandList)
|
||||
{
|
||||
if (parentX < minX || parentX + width > minX + this.width
|
||||
|| parentY < minY || parentY + height > minY + this.height)
|
||||
throw new RasterFormatException("Child raster extends beyond parent");
|
||||
|
||||
SampleModel sm = (bandList == null) ?
|
||||
sampleModel :
|
||||
sampleModel.createSubsetSampleModel(bandList);
|
||||
|
||||
return new WritableRaster(sm, dataBuffer,
|
||||
new Rectangle(childMinX, childMinY, width, height),
|
||||
new Point(sampleModelTranslateX + childMinX - parentX,
|
||||
sampleModelTranslateY + childMinY - parentY),
|
||||
this);
|
||||
}
|
||||
|
||||
public void setDataElements(int x, int y, Object inData)
|
||||
{
|
||||
|
|
|
@ -45,20 +45,20 @@ import java.util.Vector;
|
|||
public class ParameterBlock implements Cloneable, Serializable
|
||||
{
|
||||
private static final long serialVersionUID = -7577115551785240750L;
|
||||
protected Vector sources;
|
||||
protected Vector parameters;
|
||||
protected Vector<Object> sources;
|
||||
protected Vector<Object> parameters;
|
||||
|
||||
public ParameterBlock()
|
||||
{
|
||||
this(new Vector(), new Vector());
|
||||
this(new Vector<Object>(), new Vector<Object>());
|
||||
}
|
||||
|
||||
public ParameterBlock(Vector sources)
|
||||
public ParameterBlock(Vector<Object> sources)
|
||||
{
|
||||
this(sources, new Vector());
|
||||
this(sources, new Vector<Object>());
|
||||
}
|
||||
|
||||
public ParameterBlock(Vector sources, Vector parameters)
|
||||
public ParameterBlock(Vector<Object> sources, Vector<Object> parameters)
|
||||
{
|
||||
this.sources = sources;
|
||||
this.parameters = parameters;
|
||||
|
@ -80,9 +80,9 @@ public class ParameterBlock implements Cloneable, Serializable
|
|||
{
|
||||
ParameterBlock pb = (ParameterBlock) shallowClone();
|
||||
if (sources != null)
|
||||
pb.sources = (Vector) sources.clone();
|
||||
pb.sources = (Vector<Object>) sources.clone();
|
||||
if (parameters != null)
|
||||
pb.parameters = (Vector) parameters.clone();
|
||||
pb.parameters = (Vector<Object>) parameters.clone();
|
||||
return pb;
|
||||
}
|
||||
|
||||
|
@ -119,12 +119,12 @@ public class ParameterBlock implements Cloneable, Serializable
|
|||
return sources.size();
|
||||
}
|
||||
|
||||
public Vector getSources()
|
||||
public Vector<Object> getSources()
|
||||
{
|
||||
return sources;
|
||||
}
|
||||
|
||||
public void setSources(Vector sources)
|
||||
public void setSources(Vector<Object> sources)
|
||||
{
|
||||
this.sources = sources;
|
||||
}
|
||||
|
@ -140,12 +140,12 @@ public class ParameterBlock implements Cloneable, Serializable
|
|||
return parameters.size();
|
||||
}
|
||||
|
||||
public Vector getParameters()
|
||||
public Vector<Object> getParameters()
|
||||
{
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public void setParameters(Vector parameters)
|
||||
public void setParameters(Vector<Object> parameters)
|
||||
{
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ public interface RenderableImage
|
|||
{
|
||||
String HINTS_OBSERVED = "HINTS_OBSERVED";
|
||||
|
||||
Vector getSources();
|
||||
Vector<RenderableImage> getSources();
|
||||
Object getProperty(String name);
|
||||
String[] getPropertyNames();
|
||||
boolean isDynamic();
|
||||
|
|
|
@ -55,7 +55,7 @@ public class RenderableImageOp implements RenderableImage
|
|||
this.block = (ParameterBlock) block.clone();
|
||||
}
|
||||
|
||||
public Vector getSources()
|
||||
public Vector<RenderableImage> getSources()
|
||||
{
|
||||
if (block.sources == null)
|
||||
return null;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue