Merged gcj-eclipse branch to trunk.

From-SVN: r120621
This commit is contained in:
Tom Tromey
2007-01-09 19:58:05 +00:00
parent c648dedbde
commit 97b8365caf
17478 changed files with 606493 additions and 100744 deletions
@@ -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;
}
}