import java.awt.event.ContainerListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
+import java.awt.peer.ComponentPeer;
import java.awt.peer.ContainerPeer;
import java.awt.peer.LightweightPeer;
import java.beans.PropertyChangeListener;
import java.util.Set;
import javax.accessibility.Accessible;
-import javax.swing.SwingUtilities;
+
+import gnu.java.awt.AWTUtilities;
/**
* A generic window toolkit object that acts as a container for other objects.
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);
}
}
- invalidate();
+ // Invalidate the layout of the added component and its ancestors.
+ comp.invalidate();
if (component == null)
component = new Component[4]; // FIXME, better initial size?
ContainerEvent.COMPONENT_ADDED,
comp);
getToolkit().getSystemEventQueue().postEvent(ce);
+
+ // Repaint this container.
+ repaint();
}
}
}
ContainerEvent.COMPONENT_REMOVED,
r);
getToolkit().getSystemEventQueue().postEvent(ce);
+
+ // Repaint this container.
+ repaint();
}
}
}
public void invalidate()
{
super.invalidate();
+ if (layoutMgr != null && layoutMgr instanceof LayoutManager2)
+ {
+ LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
+ lm2.invalidateLayout(this);
+ }
}
/**
*/
void invalidateTree()
{
+ super.invalidate(); // Clean cached layout state.
for (int i = 0; i < ncomponents; i++)
{
Component comp = component[i];
if (comp instanceof Container)
((Container) comp).invalidateTree();
}
+
+ if (layoutMgr != null && layoutMgr instanceof LayoutManager2)
+ {
+ LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
+ lm2.invalidateLayout(this);
+ }
}
/**
public void setFont(Font f)
{
- 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();
+ if( (f != null && (font == null || !font.equals(f)))
+ || f == null)
+ {
+ 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();
+ }
}
/**
*/
public Dimension preferredSize()
{
- if (layoutMgr != null)
- return layoutMgr.preferredLayoutSize (this);
- else
- return super.preferredSize ();
+ synchronized(treeLock)
+ {
+ if(valid && prefSize != null)
+ return new Dimension(prefSize);
+ LayoutManager layout = getLayout();
+ if (layout != null)
+ {
+ Dimension layoutSize = layout.preferredLayoutSize(this);
+ if(valid)
+ prefSize = layoutSize;
+ return new Dimension(layoutSize);
+ }
+ else
+ return super.preferredSize ();
+ }
}
/**
*/
public Dimension minimumSize()
{
- if (layoutMgr != null)
- return layoutMgr.minimumLayoutSize (this);
+ if(valid && minSize != null)
+ return new Dimension(minSize);
+
+ LayoutManager layout = getLayout();
+ if (layout != null)
+ {
+ minSize = layout.minimumLayoutSize (this);
+ return minSize;
+ }
else
return super.minimumSize ();
}
*/
public Dimension getMaximumSize()
{
- if (layoutMgr != null && layoutMgr instanceof LayoutManager2)
+ if (valid && maxSize != null)
+ return new Dimension(maxSize);
+
+ LayoutManager layout = getLayout();
+ if (layout != null && layout instanceof LayoutManager2)
{
- LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
- return lm2.maximumLayoutSize(this);
+ LayoutManager2 lm2 = (LayoutManager2) layout;
+ maxSize = lm2.maximumLayoutSize(this);
+ return maxSize;
}
else
return super.getMaximumSize();
*/
public float getAlignmentX()
{
- if (layoutMgr instanceof LayoutManager2)
- {
- LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
- return lm2.getLayoutAlignmentX(this);
- }
- else
- return super.getAlignmentX();
+ return super.getAlignmentX();
}
/**
*/
public float getAlignmentY()
{
- if (layoutMgr instanceof LayoutManager2)
- {
- LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
- return lm2.getLayoutAlignmentY(this);
- }
- else
- return super.getAlignmentY();
+ return super.getAlignmentY();
}
/**
{
if (!isShowing())
return;
- // Paint self first.
- super.paint(g);
+
// Visit heavyweights as well, in case they were
// erased when we cleared the background for this container.
visitChildren(g, GfxPaintVisitor.INSTANCE, false);
* drawn.
*
* @param g The graphics context for this update.
+ *
+ * @specnote The specification suggests that this method forwards the
+ * update() call to all its lightweight children. Tests show
+ * that this is not done either in the JDK. The exact behaviour
+ * seems to be that the background is cleared in heavyweight
+ * Containers, and all other containers
+ * directly call paint(), causing the (lightweight) children to
+ * be painted.
*/
public void update(Graphics g)
{
- super.update(g);
+ // It seems that the JDK clears the background of containers like Panel
+ // and Window (within this method) but not of 'plain' Containers or
+ // JComponents. This could
+ // lead to the assumption that it only clears heavyweight containers.
+ // However that is not quite true. In a test with a custom Container
+ // that overrides isLightweight() to return false, the background is
+ // also not cleared. So we do a check on !(peer instanceof LightweightPeer)
+ // instead.
+ ComponentPeer p = peer;
+ if (p != null && !(p instanceof LightweightPeer))
+ g.clearRect(0, 0, getWidth(), getHeight());
+
+ paint(g);
}
/**
}
if (focusTraversalKeys == null)
- focusTraversalKeys = new Set[3];
+ focusTraversalKeys = new Set[4];
keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes));
firePropertyChange (name, focusTraversalKeys[id], keystrokes);
for (int i = ncomponents - 1; i >= 0; --i)
{
Component comp = component[i];
- // If we're visiting heavyweights as well,
- // don't recurse into Containers here. This avoids
- // painting the same nested child multiple times.
boolean applicable = comp.isVisible()
- && (comp.isLightweight()
- || !lightweightOnly && ! (comp instanceof Container));
+ && (comp.isLightweight() || !lightweightOnly);
if (applicable)
visitChild(gfx, visitor, comp);
void dispatchEventImpl(AWTEvent e)
{
// Give lightweight dispatcher a chance to handle it.
- if (eventTypeEnabled (e.id)
- && dispatcher != null
- && dispatcher.handleEvent (e))
+ if (dispatcher != null && dispatcher.handleEvent (e))
return;
-
+
if ((e.id <= ContainerEvent.CONTAINER_LAST
&& e.id >= ContainerEvent.CONTAINER_FIRST)
&& (containerListener != null
super.dispatchEventImpl(e);
}
+ /**
+ * Tests if this container has an interest in the given event id.
+ *
+ * @param eventId The event id to check.
+ *
+ * @return <code>true</code> if a listener for the event id exists or
+ * if the eventMask is set for the event id.
+ *
+ * @see java.awt.Component#eventTypeEnabled(int)
+ */
+ boolean eventTypeEnabled(int eventId)
+ {
+ if(eventId <= ContainerEvent.CONTAINER_LAST
+ && eventId >= ContainerEvent.CONTAINER_FIRST)
+ return containerListener != null
+ || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0;
+ else
+ return super.eventTypeEnabled(eventId);
+ }
+
// This is used to implement Component.transferFocus.
Component findNextFocusComponent(Component child)
{
// If we're not lightweight, and we just got a lightweight
// child, we need a lightweight dispatcher to feed it events.
- if (! this.isLightweight())
- {
- if (dispatcher == null)
- dispatcher = new LightweightDispatcher (this);
- }
-
+ if (!this.isLightweight() && dispatcher == null)
+ dispatcher = new LightweightDispatcher (this);
+
+ if (dispatcher != null)
+ dispatcher.enableEvents(component[i].eventMask);
enableEvents(component[i].eventMask);
if (peer != null && !isLightweight ())
* rather than mimic it exactly we write something which does "roughly
* the same thing".
*/
-
class LightweightDispatcher implements Serializable
{
private static final long serialVersionUID = 5184291520170872969L;
private Cursor nativeCursor;
private long eventMask;
- private transient Component mouseEventTarget;
private transient Component pressedComponent;
private transient Component lastComponentEntered;
- private transient Component tempComponent;
private transient int pressCount;
LightweightDispatcher(Container c)
nativeContainer = c;
}
- void acquireComponentForMouseEvent(MouseEvent me)
+ void enableEvents(long l)
+ {
+ eventMask |= l;
+ }
+
+ Component acquireComponentForMouseEvent(MouseEvent me)
{
int x = me.getX ();
int y = me.getY ();
+ Component mouseEventTarget = null;
// Find the candidate which should receive this event.
Component parent = nativeContainer;
Component candidate = null;
while (candidate == null && parent != null)
{
candidate =
- SwingUtilities.getDeepestComponentAt(parent, p.x, p.y);
+ AWTUtilities.getDeepestComponentAt(parent, p.x, p.y);
if (candidate == null || (candidate.eventMask & me.getID()) == 0)
- {
- candidate = null;
- p = SwingUtilities.convertPoint(parent, p.x, p.y, parent.parent);
- parent = parent.parent;
- }
+ {
+ candidate = null;
+ p = AWTUtilities.convertPoint(parent, p.x, p.y, parent.parent);
+ parent = parent.parent;
+ }
}
// If the only candidate we found was the native container itself,
{
// Old candidate could have been removed from
// the nativeContainer so we check first.
- if (SwingUtilities.isDescendingFrom(lastComponentEntered, nativeContainer))
- {
- Point tp =
- SwingUtilities.convertPoint(nativeContainer,
- x, y, lastComponentEntered);
- MouseEvent exited = new MouseEvent (lastComponentEntered,
- MouseEvent.MOUSE_EXITED,
- me.getWhen (),
- me.getModifiersEx (),
- tp.x, tp.y,
- me.getClickCount (),
- me.isPopupTrigger (),
- me.getButton ());
- tempComponent = lastComponentEntered;
- lastComponentEntered = null;
- tempComponent.dispatchEvent(exited);
- }
+ if (AWTUtilities.isDescendingFrom(lastComponentEntered,
+ nativeContainer))
+ {
+ Point tp = AWTUtilities.convertPoint(nativeContainer,
+ x, y, lastComponentEntered);
+ MouseEvent exited = new MouseEvent (lastComponentEntered,
+ MouseEvent.MOUSE_EXITED,
+ me.getWhen (),
+ me.getModifiersEx (),
+ tp.x, tp.y,
+ me.getClickCount (),
+ me.isPopupTrigger (),
+ me.getButton ());
+ lastComponentEntered.dispatchEvent (exited);
+ }
lastComponentEntered = null;
}
+
// If we have a candidate, maybe enter it.
if (candidate != null)
{
&& candidate.isShowing()
&& candidate != nativeContainer
&& candidate != lastComponentEntered)
- {
+ {
lastComponentEntered = mouseEventTarget;
- Point cp = SwingUtilities.convertPoint(nativeContainer,
- x, y, lastComponentEntered);
+ Point cp = AWTUtilities.convertPoint(nativeContainer,
+ x, y, lastComponentEntered);
MouseEvent entered = new MouseEvent (lastComponentEntered,
MouseEvent.MOUSE_ENTERED,
me.getWhen (),
}
}
+ // Check which buttons where pressed except the last button that
+ // changed state.
+ int modifiers = me.getModifiersEx() & (MouseEvent.BUTTON1_DOWN_MASK
+ | MouseEvent.BUTTON2_DOWN_MASK
+ | MouseEvent.BUTTON3_DOWN_MASK);
+ switch(me.getButton())
+ {
+ case MouseEvent.BUTTON1:
+ modifiers &= ~MouseEvent.BUTTON1_DOWN_MASK;
+ break;
+ case MouseEvent.BUTTON2:
+ modifiers &= ~MouseEvent.BUTTON2_DOWN_MASK;
+ break;
+ case MouseEvent.BUTTON3:
+ modifiers &= ~MouseEvent.BUTTON3_DOWN_MASK;
+ break;
+ }
+
if (me.getID() == MouseEvent.MOUSE_RELEASED
- || me.getID() == MouseEvent.MOUSE_PRESSED && pressCount > 0
+ || me.getID() == MouseEvent.MOUSE_PRESSED && modifiers > 0
|| me.getID() == MouseEvent.MOUSE_DRAGGED)
- // If any of the following events occur while a button is held down,
- // they should be dispatched to the same component to which the
- // original MOUSE_PRESSED event was dispatched:
- // - MOUSE_RELEASED
- // - MOUSE_PRESSED: another button pressed while the first is held down
- // - MOUSE_DRAGGED
- if (SwingUtilities.isDescendingFrom(pressedComponent, nativeContainer))
- mouseEventTarget = pressedComponent;
+ {
+ // If any of the following events occur while a button is held down,
+ // they should be dispatched to the same component to which the
+ // original MOUSE_PRESSED event was dispatched:
+ // - MOUSE_RELEASED
+ // - MOUSE_PRESSED: another button pressed while the first is held
+ // down
+ // - MOUSE_DRAGGED
+ if (AWTUtilities.isDescendingFrom(pressedComponent, nativeContainer))
+ mouseEventTarget = pressedComponent;
+ }
else if (me.getID() == MouseEvent.MOUSE_CLICKED)
{
// Don't dispatch CLICKED events whose target is not the same as the
else if (pressCount == 0)
pressedComponent = null;
}
+ return mouseEventTarget;
}
boolean handleEvent(AWTEvent e)
{
MouseEvent me = (MouseEvent) e;
- acquireComponentForMouseEvent(me);
-
+ // Make the LightWeightDispatcher reentrant. This is necessary when
+ // a lightweight component does its own modal event queue.
+ Component mouseEventTarget = acquireComponentForMouseEvent(me);
+
// Avoid dispatching ENTERED and EXITED events twice.
if (mouseEventTarget != null
&& mouseEventTarget.isShowing()
&& e.getID() != MouseEvent.MOUSE_ENTERED
&& e.getID() != MouseEvent.MOUSE_EXITED)
{
- MouseEvent newEvt =
- SwingUtilities.convertMouseEvent(nativeContainer, me,
- mouseEventTarget);
- mouseEventTarget.dispatchEvent(newEvt);
-
switch (e.getID())
{
- case MouseEvent.MOUSE_PRESSED:
- if (pressCount++ == 0)
- pressedComponent = mouseEventTarget;
- break;
-
- case MouseEvent.MOUSE_RELEASED:
- // Clear our memory of the original PRESSED event, only if
- // we're not expecting a CLICKED event after this. If
- // there is a CLICKED event after this, it will do clean up.
- if (--pressCount == 0
- && mouseEventTarget != pressedComponent)
- pressedComponent = null;
- break;
+ case MouseEvent.MOUSE_PRESSED:
+ if (pressCount++ == 0)
+ pressedComponent = mouseEventTarget;
+ break;
+ case MouseEvent.MOUSE_RELEASED:
+ // Clear our memory of the original PRESSED event, only if
+ // we're not expecting a CLICKED event after this. If
+ // there is a CLICKED event after this, it will do clean up.
+ if (--pressCount == 0
+ && mouseEventTarget != pressedComponent)
+ pressedComponent = null;
+ break;
}
- if (newEvt.isConsumed())
- e.consume();
+
+ MouseEvent newEvt =
+ AWTUtilities.convertMouseEvent(nativeContainer, me,
+ mouseEventTarget);
+ mouseEventTarget.dispatchEvent(newEvt);
+
+ if (newEvt.isConsumed())
+ e.consume();
}
}
-
+
return e.isConsumed();
}
-
-} // class LightweightDispatcher
+}