diff options
Diffstat (limited to 'libjava/classpath/javax/swing/JComponent.java')
-rw-r--r-- | libjava/classpath/javax/swing/JComponent.java | 753 |
1 files changed, 392 insertions, 361 deletions
diff --git a/libjava/classpath/javax/swing/JComponent.java b/libjava/classpath/javax/swing/JComponent.java index 66c562d110b..fa83502946d 100644 --- a/libjava/classpath/javax/swing/JComponent.java +++ b/libjava/classpath/javax/swing/JComponent.java @@ -48,12 +48,10 @@ import java.awt.EventQueue; import java.awt.FocusTraversalPolicy; import java.awt.Font; import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Image; import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; -import java.awt.Shape; import java.awt.Window; import java.awt.dnd.DropTarget; import java.awt.event.ActionEvent; @@ -69,8 +67,8 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyVetoException; import java.beans.VetoableChangeListener; +import java.beans.VetoableChangeSupport; import java.io.Serializable; -import java.util.ArrayList; import java.util.EventListener; import java.util.Hashtable; import java.util.Locale; @@ -571,6 +569,21 @@ public abstract class JComponent extends Container implements Serializable */ String toolTipText; + /** + * The popup menu for the component. + * + * @see #getComponentPopupMenu() + * @see #setComponentPopupMenu(JPopupMenu) + */ + JPopupMenu componentPopupMenu; + + /** + * A flag that controls whether the {@link #getComponentPopupMenu()} method + * looks to the component's parent when the <code>componentPopupMenu</code> + * field is <code>null</code>. + */ + boolean inheritsPopupMenu; + /** * <p>Whether to double buffer this component when painting. This flag * should generally be <code>true</code>, to ensure good painting @@ -668,7 +681,13 @@ public abstract class JComponent extends Container implements Serializable * Indicates whether the current paint call is already double buffered or * not. */ - static boolean isPaintingDoubleBuffered = false; + static boolean paintingDoubleBuffered = false; + + /** + * Indicates whether we are calling paintDoubleBuffered() from + * paintImmadiately (RepaintManager) or from paint() (AWT refresh). + */ + static private boolean isRepainting = false; /** * Listeners for events other than {@link PropertyChangeEvent} are @@ -677,6 +696,11 @@ public abstract class JComponent extends Container implements Serializable */ protected EventListenerList listenerList = new EventListenerList(); + /** + * Handles VetoableChangeEvents. + */ + private VetoableChangeSupport vetoableChangeSupport; + /** * Storage for "client properties", which are key/value pairs associated * with this component by a "client", such as a user application or a @@ -690,7 +714,7 @@ public abstract class JComponent extends Container implements Serializable private ComponentInputMap inputMap_whenInFocusedWindow; private ActionMap actionMap; /** @since 1.3 */ - private boolean verifyInputWhenFocusTarget; + private boolean verifyInputWhenFocusTarget = true; private InputVerifier inputVerifier; private TransferHandler transferHandler; @@ -784,7 +808,7 @@ public abstract class JComponent extends Container implements Serializable { super(); setDropTarget(new DropTarget()); - defaultLocale = Locale.getDefault(); + setLocale(getDefaultLocale()); debugGraphicsOptions = DebugGraphics.NONE_OPTION; setRequestFocusEnabled(true); } @@ -868,7 +892,8 @@ public abstract class JComponent extends Container implements Serializable */ public void removeVetoableChangeListener(VetoableChangeListener listener) { - listenerList.remove(VetoableChangeListener.class, listener); + if (vetoableChangeSupport != null) + vetoableChangeSupport.removeVetoableChangeListener(listener); } /** @@ -884,23 +909,6 @@ public abstract class JComponent extends Container implements Serializable } /** - * Register a <code>PropertyChangeListener</code> for a specific, named - * property. To listen to all property changes, regardless of name, use - * {@link #addPropertyChangeListener(PropertyChangeListener)} instead. - * - * @param propertyName The property name to listen to - * @param listener The listener to register - * - * @see #removePropertyChangeListener(String, PropertyChangeListener) - * @see #changeSupport - */ - public void addPropertyChangeListener(String propertyName, - PropertyChangeListener listener) - { - listenerList.add(PropertyChangeListener.class, listener); - } - - /** * Register a <code>VetoableChangeListener</code>. * * @param listener The listener to register @@ -910,7 +918,10 @@ public abstract class JComponent extends Container implements Serializable */ public void addVetoableChangeListener(VetoableChangeListener listener) { - listenerList.add(VetoableChangeListener.class, listener); + // Lazily instantiate this, it's rarely needed. + if (vetoableChangeSupport == null) + vetoableChangeSupport = new VetoableChangeSupport(this); + vetoableChangeSupport.addVetoableChangeListener(listener); } /** @@ -936,6 +947,8 @@ public abstract class JComponent extends Container implements Serializable { if (listenerType == PropertyChangeListener.class) return getPropertyChangeListeners(); + else if (listenerType == VetoableChangeListener.class) + return getVetoableChangeListeners(); else return listenerList.getListeners(listenerType); } @@ -954,84 +967,89 @@ public abstract class JComponent extends Container implements Serializable /** * Return all registered <code>VetoableChangeListener</code> objects. * - * @return The set of <code>VetoableChangeListener</code> objects in {@link - * #listenerList} + * @return An array of the <code>VetoableChangeListener</code> objects + * registered with this component (possibly empty but never + * <code>null</code>). + * + * @since 1.4 */ public VetoableChangeListener[] getVetoableChangeListeners() - { - return (VetoableChangeListener[]) getListeners(VetoableChangeListener.class); + { + return vetoableChangeSupport == null ? new VetoableChangeListener[0] + : vetoableChangeSupport.getVetoableChangeListeners(); } /** - * A variant of {@link #firePropertyChange(String,Object,Object)} - * for properties with <code>boolean</code> values. + * Call {@link VetoableChangeListener#vetoableChange} on all listeners + * registered to listen to a given property. Any method which changes + * the specified property of this component should call this method. + * + * @param propertyName The property which changed + * @param oldValue The old value of the property + * @param newValue The new value of the property + * + * @throws PropertyVetoException if the change was vetoed by a listener * - * @specnote It seems that in JDK1.5 all property related methods have been - * moved to java.awt.Component, except this and 2 others. We call - * super here. I guess this will also be removed in one of the next - * releases. + * @see #addVetoableChangeListener + * @see #removeVetoableChangeListener */ - public void firePropertyChange(String propertyName, boolean oldValue, - boolean newValue) + protected void fireVetoableChange(String propertyName, Object oldValue, + Object newValue) + throws PropertyVetoException { - super.firePropertyChange(propertyName, oldValue, newValue); + if (vetoableChangeSupport != null) + vetoableChangeSupport.fireVetoableChange(propertyName, oldValue, newValue); } + /** - * A variant of {@link #firePropertyChange(String,Object,Object)} - * for properties with <code>char</code> values. + * Fires a property change for a primitive integer property. + * + * @param property the name of the property + * @param oldValue the old value of the property + * @param newValue the new value of the property * - * @specnote It seems that in JDK1.5 all property related methods have been - * moved to java.awt.Component, except this and 2 others. We call - * super here. I guess this will also be removed in one of the next - * releases. + * @specnote This method is implemented in + * {@link Component#firePropertyChange(String, int, int)}. It is + * only here because it is specified to be public, whereas the + * Component method is protected. */ - public void firePropertyChange(String propertyName, char oldValue, - char newValue) + public void firePropertyChange(String property, int oldValue, int newValue) { - super.firePropertyChange(propertyName, oldValue, newValue); + super.firePropertyChange(property, oldValue, newValue); } - + /** - * A variant of {@link #firePropertyChange(String,Object,Object)} - * for properties with <code>int</code> values. + * Fires a property change for a primitive boolean property. + * + * @param property the name of the property + * @param oldValue the old value of the property + * @param newValue the new value of the property * - * @specnote It seems that in JDK1.5 all property related methods have been - * moved to java.awt.Component, except this and 2 others. We call - * super here. I guess this will also be removed in one of the next - * releases. + * @specnote This method is implemented in + * {@link Component#firePropertyChange(String, boolean, boolean)}. + * It is only here because it is specified to be public, whereas + * the Component method is protected. */ - public void firePropertyChange(String propertyName, int oldValue, - int newValue) + public void firePropertyChange(String property, boolean oldValue, + boolean newValue) { - super.firePropertyChange(propertyName, oldValue, newValue); + super.firePropertyChange(property, oldValue, newValue); } /** - * Call {@link VetoableChangeListener#vetoableChange} on all listeners - * registered to listen to a given property. Any method which changes - * the specified property of this component should call this method. - * - * @param propertyName The property which changed - * @param oldValue The old value of the property - * @param newValue The new value of the property - * - * @throws PropertyVetoException if the change was vetoed by a listener + * Fires a property change for a primitive character property. * - * @see #addVetoableChangeListener - * @see #removeVetoableChangeListener + * @param property the name of the property + * @param oldValue the old value of the property + * @param newValue the new value of the property */ - protected void fireVetoableChange(String propertyName, Object oldValue, - Object newValue) - throws PropertyVetoException + public void firePropertyChange(String property, char oldValue, + char newValue) { - VetoableChangeListener[] listeners = getVetoableChangeListeners(); - - PropertyChangeEvent evt = - new PropertyChangeEvent(this, propertyName, oldValue, newValue); - - for (int i = 0; i < listeners.length; i++) - listeners[i].vetoableChange(evt); + // FIXME - This method is already public in awt Component, but + // is included here to work around a compilation bug in gcj 4.1. + super.firePropertyChange(property, oldValue, newValue); } /** @@ -1402,11 +1420,32 @@ public abstract class JComponent extends Container implements Serializable * Return the set of {@link KeyStroke} objects which are registered * to initiate actions on this component. * - * @return An array of the registered keystrokes + * @return An array of the registered keystrokes (possibly empty but never + * <code>null</code>). */ public KeyStroke[] getRegisteredKeyStrokes() { - return null; + KeyStroke[] ks0; + KeyStroke[] ks1; + KeyStroke[] ks2; + if (inputMap_whenFocused != null) + ks0 = inputMap_whenFocused.keys(); + else + ks0 = new KeyStroke[0]; + if (inputMap_whenAncestorOfFocused != null) + ks1 = inputMap_whenAncestorOfFocused.keys(); + else + ks1 = new KeyStroke[0]; + if (inputMap_whenInFocusedWindow != null) + ks2 = inputMap_whenInFocusedWindow.keys(); + else + ks2 = new KeyStroke[0]; + int count = ks0.length + ks1.length + ks2.length; + KeyStroke[] result = new KeyStroke[count]; + System.arraycopy(ks0, 0, result, 0, ks0.length); + System.arraycopy(ks1, 0, result, ks0.length, ks1.length); + System.arraycopy(ks2, 0, result, ks0.length + ks1.length, ks2.length); + return result; } /** @@ -1524,8 +1563,90 @@ public abstract class JComponent extends Container implements Serializable { return getToolTipText(); } + + /** + * Returns the flag that controls whether or not the component inherits its + * parent's popup menu when no popup menu is specified for this component. + * + * @return A boolean. + * + * @since 1.5 + * + * @see #setInheritsPopupMenu(boolean) + */ + public boolean getInheritsPopupMenu() + { + return inheritsPopupMenu; + } + + /** + * Sets the flag that controls whether or not the component inherits its + * parent's popup menu when no popup menu is specified for this component. + * This is a bound property with the property name 'inheritsPopupMenu'. + * + * @param inherit the new flag value. + * + * @since 1.5 + * + * @see #getInheritsPopupMenu() + */ + public void setInheritsPopupMenu(boolean inherit) + { + if (inheritsPopupMenu != inherit) + { + inheritsPopupMenu = inherit; + this.firePropertyChange("inheritsPopupMenu", ! inherit, inherit); + } + } + + /** + * Returns the popup menu for this component. If the popup menu is + * <code>null</code> AND the {@link #getInheritsPopupMenu()} method returns + * <code>true</code>, this method will return the parent's popup menu (if it + * has one). + * + * @return The popup menu (possibly <code>null</code>. + * + * @since 1.5 + * + * @see #setComponentPopupMenu(JPopupMenu) + * @see #getInheritsPopupMenu() + */ + public JPopupMenu getComponentPopupMenu() + { + if (componentPopupMenu == null && getInheritsPopupMenu()) + { + Container parent = getParent(); + if (parent instanceof JComponent) + return ((JComponent) parent).getComponentPopupMenu(); + else + return null; + } + else + return componentPopupMenu; + } /** + * Sets the popup menu for this component (this is a bound property with + * the property name 'componentPopupMenu'). + * + * @param popup the popup menu (<code>null</code> permitted). + * + * @since 1.5 + * + * @see #getComponentPopupMenu() + */ + public void setComponentPopupMenu(JPopupMenu popup) + { + if (componentPopupMenu != popup) + { + JPopupMenu old = componentPopupMenu; + componentPopupMenu = popup; + firePropertyChange("componentPopupMenu", old, popup); + } + } + + /** * Return the top level ancestral container (usually a {@link * java.awt.Window} or {@link java.applet.Applet}) which this component is * contained within, or <code>null</code> if no ancestors exist. @@ -1725,7 +1846,7 @@ public abstract class JComponent extends Container implements Serializable // buffer. When this method completes, the call stack unwinds back to // paintDoubleBuffered, where the buffer contents is finally drawn to the // screen. - if (!isPaintingDoubleBuffered && isDoubleBuffered() + if (!paintingDoubleBuffered && isDoubleBuffered() && rm.isDoubleBufferingEnabled()) { Rectangle clip = g.getClipBounds(); @@ -1816,235 +1937,77 @@ public abstract class JComponent extends Container implements Serializable { if (getComponentCount() > 0) { - if (isOptimizedDrawingEnabled()) - paintChildrenOptimized(g); - else - paintChildrenWithOverlap(g); - } - } - - /** - * Paints the children of this JComponent in the case when the component - * is not marked as optimizedDrawingEnabled, that means the container cannot - * guarantee that it's children are tiled. For this case we must - * perform a more complex optimization to determine the minimal rectangle - * to be painted for each child component. - * - * @param g the graphics context to use - */ - private void paintChildrenWithOverlap(Graphics g) - { - Shape originalClip = g.getClip(); - Rectangle inner = SwingUtilities.calculateInnerArea(this, rectCache); - g.clipRect(inner.x, inner.y, inner.width, inner.height); - Component[] children = getComponents(); - - // Find the rectangles that need to be painted for each child component. - // We push on this list arrays that have the Rectangles to be painted as - // the first elements and the component to be painted as the last one. - // Later we go through that list in reverse order and paint the rectangles. - ArrayList paintRegions = new ArrayList(children.length); - ArrayList paintRectangles = new ArrayList(); - ArrayList newPaintRects = new ArrayList(); - paintRectangles.add(g.getClipBounds()); - ArrayList componentRectangles = new ArrayList(); - - // Go through children from top to bottom and find out their paint - // rectangles. - for (int index = 0; paintRectangles.size() > 0 && - index < children.length; index++) - { - Component comp = children[index]; - if (! comp.isVisible()) - continue; - - Rectangle compBounds = comp.getBounds(); - boolean isOpaque = comp instanceof JComponent - && ((JComponent) comp).isOpaque(); - - // Add all the current paint rectangles that intersect with the - // component to the component's paint rectangle array. - for (int i = paintRectangles.size() - 1; i >= 0; i--) + // Need to lock the tree to avoid problems with AWT and concurrency. + synchronized (getTreeLock()) { - Rectangle r = (Rectangle) paintRectangles.get(i); - if (r.intersects(compBounds)) + for (int i = getComponentCount() - 1; i >= 0; i--) { - Rectangle compRect = r.intersection(compBounds); - componentRectangles.add(compRect); - // If the component is opaque, split up each paint rect and - // add paintRect - compBounds to the newPaintRects array. - if (isOpaque) + Component child = getComponent(i); + if (child != null && child.isLightweight() + && child.isVisible()) { - int x, y, w, h; - Rectangle rect = new Rectangle(); - - // The north retangle. - x = Math.max(compBounds.x, r.x); - y = r.y; - w = Math.min(compBounds.width, r.width + r.x - x); - h = compBounds.y - r.y; - rect.setBounds(x, y, w, h); - if (! rect.isEmpty()) - { - newPaintRects.add(rect); - rect = new Rectangle(); - } - - // The south rectangle. - x = Math.max(compBounds.x, r.x); - y = compBounds.y + compBounds.height; - w = Math.min(compBounds.width, r.width + r.x - x); - h = r.height - (compBounds.y - r.y) - compBounds.height; - rect.setBounds(x, y, w, h); - if (! rect.isEmpty()) - { - newPaintRects.add(rect); - rect = new Rectangle(); - } - - // The west rectangle. - x = r.x; - y = r.y; - w = compBounds.x - r.x; - h = r.height; - rect.setBounds(x, y, w, h); - if (! rect.isEmpty()) + int cx = child.getX(); + int cy = child.getY(); + int cw = child.getWidth(); + int ch = child.getHeight(); + if (g.hitClip(cx, cy, cw, ch)) { - newPaintRects.add(rect); - rect = new Rectangle(); - } - - // The east rectangle. - x = compBounds.x + compBounds.width; - y = r.y; - w = r.width - (compBounds.x - r.x) - compBounds.width; - h = r.height; - rect.setBounds(x, y, w, h); - if (! rect.isEmpty()) - { - newPaintRects.add(rect); + if ((! isOptimizedDrawingEnabled()) && i > 0) + { + // Check if the child is completely obscured. + Rectangle clip = g.getClipBounds(); // A copy. + SwingUtilities.computeIntersection(cx, cy, cw, ch, + clip); + if (isCompletelyObscured(i, clip)) + continue; // Continues the for-loop. + } + Graphics cg = g.create(cx, cy, cw, ch); + cg.setColor(child.getForeground()); + cg.setFont(child.getFont()); + try + { + child.paint(cg); + } + finally + { + cg.dispose(); + } } } - else - { - // Not opaque, need to reuse the current paint rectangles - // for the next component. - newPaintRects.add(r); - } - - } - else - { - newPaintRects.add(r); } } - - // Replace the paintRectangles with the new split up - // paintRectangles. - paintRectangles.clear(); - paintRectangles.addAll(newPaintRects); - newPaintRects.clear(); - - // Store paint rectangles if there are any for the current component. - int compRectsSize = componentRectangles.size(); - if (compRectsSize > 0) - { - componentRectangles.add(comp); - paintRegions.add(componentRectangles); - componentRectangles = new ArrayList(); - } } - - // paintingTile becomes true just before we start painting the component's - // children. - paintingTile = true; - - // We must go through the painting regions backwards, because the - // topmost components have been added first, followed by the components - // below. - int prEndIndex = paintRegions.size() - 1; - for (int i = prEndIndex; i >= 0; i--) - { - // paintingTile must be set to false before we begin to start painting - // the last tile. - if (i == 0) - paintingTile = false; - - ArrayList paintingRects = (ArrayList) paintRegions.get(i); - // The last element is always the component. - Component c = (Component) paintingRects.get(paintingRects.size() - 1); - int endIndex = paintingRects.size() - 2; - for (int j = 0; j <= endIndex; j++) - { - Rectangle cBounds = c.getBounds(); - Rectangle bounds = (Rectangle) paintingRects.get(j); - Rectangle oldClip = g.getClipBounds(); - if (oldClip == null) - oldClip = bounds; - - boolean translated = false; - try - { - g.setClip(bounds); - g.translate(cBounds.x, cBounds.y); - translated = true; - c.paint(g); - } - finally - { - if (translated) - g.translate(-cBounds.x, -cBounds.y); - g.setClip(oldClip); - } - } - } - g.setClip(originalClip); } /** - * Paints the children of this container when it is marked as - * optimizedDrawingEnabled. In this case the container can guarantee that - * it's children are tiled, which allows for a much more efficient - * algorithm to determine the minimum rectangles to be painted for - * each child. + * Determines if a region of a child component is completely obscured by one + * of its siblings. + * + * @param index the index of the child component + * @param rect the region to check * - * @param g the graphics context to use + * @return <code>true</code> if the region is completely obscured by a + * sibling, <code>false</code> otherwise */ - private void paintChildrenOptimized(Graphics g) + private boolean isCompletelyObscured(int index, Rectangle rect) { - Shape originalClip = g.getClip(); - Rectangle inner = SwingUtilities.calculateInnerArea(this, rectCache); - g.clipRect(inner.x, inner.y, inner.width, inner.height); - Component[] children = getComponents(); - - // paintingTile becomes true just before we start painting the component's - // children. - paintingTile = true; - for (int i = children.length - 1; i >= 0; i--) //children.length; i++) + boolean obscured = false; + for (int i = index - 1; i >= 0 && obscured == false; i--) { - // paintingTile must be set to false before we begin to start painting - // the last tile. - if (i == children.length - 1) - paintingTile = false; - - if (!children[i].isVisible()) - continue; - - Rectangle bounds = children[i].getBounds(rectCache); - Rectangle oldClip = g.getClipBounds(); - if (oldClip == null) - oldClip = bounds; - - if (!g.hitClip(bounds.x, bounds.y, bounds.width, bounds.height)) - continue; - - boolean translated = false; - Graphics g2 = g.create(bounds.x, bounds.y, bounds.width, - bounds.height); - children[i].paint(g2); - g2.dispose(); + Component sib = getComponent(i); + if (sib.isVisible()) + { + Rectangle sibRect = sib.getBounds(rectCache); + if (sib.isOpaque() && rect.x >= sibRect.x + && (rect.x + rect.width) <= (sibRect.x + sibRect.width) + && rect.y >= sibRect.y + && (rect.y + rect.height) <= (sibRect.y + sibRect.height)) + { + obscured = true; + } + } } - g.setClip(originalClip); + return obscured; } /** @@ -2064,12 +2027,15 @@ public abstract class JComponent extends Container implements Serializable { if (ui != null) { - Graphics g2 = g; - if (!(g instanceof Graphics2D)) - g2 = g.create(); - ui.update(g2, this); - if (!(g instanceof Graphics2D)) - g2.dispose(); + Graphics g2 = g.create(); + try + { + ui.update(g2, this); + } + finally + { + g2.dispose(); + } } } @@ -2112,16 +2078,13 @@ public abstract class JComponent extends Container implements Serializable Component root = findPaintRoot(r); // If no paint root is found, then this component is completely overlapped // by another component and we don't need repainting. - if (root == null) + if (root == null|| !root.isShowing()) return; - if (root == null || !root.isShowing()) - return; - - Rectangle rootClip = SwingUtilities.convertRectangle(this, r, root); + SwingUtilities.convertRectangleToAncestor(this, r, root); if (root instanceof JComponent) - ((JComponent) root).paintImmediately2(rootClip); + ((JComponent) root).paintImmediately2(r); else - root.repaint(rootClip.x, rootClip.y, rootClip.width, rootClip.height); + root.repaint(r.x, r.y, r.width, r.height); } /** @@ -2131,40 +2094,35 @@ public abstract class JComponent extends Container implements Serializable */ void paintImmediately2(Rectangle r) { + isRepainting = true; RepaintManager rm = RepaintManager.currentManager(this); - if (rm.isDoubleBufferingEnabled() && isDoubleBuffered()) + if (rm.isDoubleBufferingEnabled() && isPaintingDoubleBuffered()) paintDoubleBuffered(r); else paintSimple(r); + isRepainting = false; } /** - * Gets the root of the component given. If a parent of the - * component is an instance of Applet, then the applet is - * returned. The applet is considered the root for painting - * and adding/removing components. Otherwise, the root Window - * is returned if it exists. - * - * @param comp - The component to get the root for. - * @return the parent root. An applet if it is a parent, - * or the root window. If neither exist, null is returned. + * Returns true if we must paint double buffered, that is, when this + * component or any of it's ancestors are double buffered. + * + * @return true if we must paint double buffered, that is, when this + * component or any of it's ancestors are double buffered */ - private Component getRoot(Component comp) + private boolean isPaintingDoubleBuffered() { - Applet app = null; - - while (comp != null) - { - if (app == null && comp instanceof Window) - return comp; - else if (comp instanceof Applet) - app = (Applet) comp; - comp = comp.getParent(); - } - - return app; + boolean doubleBuffered = isDoubleBuffered(); + Component parent = getParent(); + while (! doubleBuffered && parent != null) + { + doubleBuffered = parent instanceof JComponent + && ((JComponent) parent).isDoubleBuffered(); + parent = parent.getParent(); + } + return doubleBuffered; } - + /** * Performs double buffered repainting. */ @@ -2173,7 +2131,7 @@ public abstract class JComponent extends Container implements Serializable RepaintManager rm = RepaintManager.currentManager(this); // Paint on the offscreen buffer. - Component root = getRoot(this); + Component root = SwingUtilities.getRoot(this); Image buffer = rm.getVolatileOffscreenBuffer(this, root.getWidth(), root.getHeight()); @@ -2183,26 +2141,30 @@ public abstract class JComponent extends Container implements Serializable buffer = rm.getOffscreenBuffer(this, root.getWidth(), root.getHeight()); //Rectangle targetClip = SwingUtilities.convertRectangle(this, r, root); - Point translation = SwingUtilities.convertPoint(this, 0, 0, root); Graphics g2 = buffer.getGraphics(); clipAndTranslateGraphics(root, this, g2); g2.clipRect(r.x, r.y, r.width, r.height); g2 = getComponentGraphics(g2); - isPaintingDoubleBuffered = true; + paintingDoubleBuffered = true; try { - paint(g2); + if (isRepainting) // Called from paintImmediately, go through paint(). + paint(g2); + else // Called from paint() (AWT refresh), don't call it again. + { + paintComponent(g2); + paintBorder(g2); + paintChildren(g2); + } } finally { - isPaintingDoubleBuffered = false; + paintingDoubleBuffered = false; g2.dispose(); } // Paint the buffer contents on screen. - rm.commitBuffer(root, new Rectangle(translation.x + r.x, - translation.y + r.y, r.width, - r.height)); + rm.commitBuffer(this, r); } /** @@ -2217,11 +2179,16 @@ public abstract class JComponent extends Container implements Serializable private void clipAndTranslateGraphics(Component root, Component target, Graphics g) { - Component parent = target.getParent(); - if (parent != root) - clipAndTranslateGraphics(root, parent, g); - - g.translate(target.getX(), target.getY()); + Component parent = target; + int deltaX = 0; + int deltaY = 0; + while (parent != root) + { + deltaX += parent.getX(); + deltaY += parent.getY(); + parent = parent.getParent(); + } + g.translate(deltaX, deltaY); g.clipRect(0, 0, target.getWidth(), target.getHeight()); } @@ -2271,7 +2238,13 @@ public abstract class JComponent extends Container implements Serializable /** * A variant of {@link * #registerKeyboardAction(ActionListener,String,KeyStroke,int)} which - * provides <code>null</code> for the command name. + * provides <code>null</code> for the command name. + * + * @param act the action listener to notify when the keystroke occurs. + * @param stroke the key stroke. + * @param cond the condition (one of {@link #WHEN_FOCUSED}, + * {@link #WHEN_IN_FOCUSED_WINDOW} and + * {@link #WHEN_ANCESTOR_OF_FOCUSED_COMPONENT}). */ public void registerKeyboardAction(ActionListener act, KeyStroke stroke, @@ -2348,9 +2321,22 @@ public abstract class JComponent extends Container implements Serializable KeyStroke stroke, int cond) { - getInputMap(cond).put(stroke, new ActionListenerProxy(act, cmd)); + ActionListenerProxy proxy = new ActionListenerProxy(act, cmd); + getInputMap(cond).put(stroke, proxy); + getActionMap().put(proxy, proxy); } + /** + * Sets the input map for the given condition. + * + * @param condition the condition (one of {@link #WHEN_FOCUSED}, + * {@link #WHEN_IN_FOCUSED_WINDOW} and + * {@link #WHEN_ANCESTOR_OF_FOCUSED_COMPONENT}). + * @param map the map. + * + * @throws IllegalArgumentException if <code>condition</code> is not one of + * the specified values. + */ public final void setInputMap(int condition, InputMap map) { enableEvents(AWTEvent.KEY_EVENT_MASK); @@ -2486,13 +2472,17 @@ public abstract class JComponent extends Container implements Serializable */ public ActionListener getActionForKeyStroke(KeyStroke ks) { - Object cmd = getInputMap().get(ks); - if (cmd != null) + Object key = getInputMap(JComponent.WHEN_FOCUSED).get(ks); + if (key == null) + key = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).get(ks); + if (key == null) + key = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).get(ks); + if (key != null) { - if (cmd instanceof ActionListenerProxy) - return (ActionListenerProxy) cmd; - else if (cmd instanceof String) - return getActionMap().get(cmd); + if (key instanceof ActionListenerProxy) + return ((ActionListenerProxy) key).target; + else + return getActionMap().get(key); } return null; } @@ -2591,10 +2581,11 @@ public abstract class JComponent extends Container implements Serializable if (isEnabled()) { Action act = null; + Object cmd = null; InputMap map = getInputMap(condition); if (map != null) { - Object cmd = map.get(ks); + cmd = map.get(ks); if (cmd != null) { if (cmd instanceof ActionListenerProxy) @@ -2604,7 +2595,23 @@ public abstract class JComponent extends Container implements Serializable } } if (act != null && act.isEnabled()) - return SwingUtilities.notifyAction(act, ks, e, this, e.getModifiers()); + { + // Need to synchronize here so we don't get in trouble with + // our __command__ hack. + synchronized (act) + { + // We add the command as value to the action, so that + // the action can later determine the command with which it + // was called. This is undocumented, but shouldn't affect + // compatibility. It allows us to use only one Action instance + // to do the work for all components of one type, instead of + // having loads of small Actions. This effectivly saves startup + // time of Swing. + act.putValue("__command__", cmd); + return SwingUtilities.notifyAction(act, ks, e, this, + e.getModifiers()); + } + } } return false; } @@ -2706,6 +2713,11 @@ public abstract class JComponent extends Container implements Serializable */ public void revalidate() { + // As long as we don't have a parent we don't need to do any layout, since + // this is done anyway as soon as we get connected to a parent. + if (getParent() == null) + return; + if (! EventQueue.isDispatchThread()) SwingUtilities.invokeLater(new Runnable() { @@ -3089,11 +3101,29 @@ public abstract class JComponent extends Container implements Serializable // Nothing to do here. } + /** + * Returns the locale used as the default for all new components. The + * default value is {@link Locale#getDefault()} (that is, the platform + * default locale). + * + * @return The locale (never <code>null</code>). + * + * @see #setDefaultLocale(Locale) + */ public static Locale getDefaultLocale() { + if (defaultLocale == null) + defaultLocale = Locale.getDefault(); return defaultLocale; } + /** + * Sets the locale to be used as the default for all new components. If this + * is set to <code>null</code>, the {@link #getDefaultLocale()} method will + * return the platform default locale. + * + * @param l the locale (<code>null</code> permitted). + */ public static void setDefaultLocale(Locale l) { defaultLocale = l; @@ -3531,12 +3561,13 @@ public abstract class JComponent extends Container implements Serializable } } // Dispatch event to all children. - Component[] children = getComponents(); - for (int i = 0; i < children.length; i++) + int numChildren = getComponentCount(); + for (int i = 0; i < numChildren; i++) { - if (!(children[i] instanceof JComponent)) + Component child = getComponent(i); + if (! (child instanceof JComponent)) continue; - JComponent jc = (JComponent) children[i]; + JComponent jc = (JComponent) child; jc.fireAncestorEvent(ancestor, id); } } @@ -3619,10 +3650,10 @@ public abstract class JComponent extends Container implements Serializable ! SwingUtilities.isRectangleContainingRectangle(parentRect, target); if (! haveOverlap) { - Component[] children = newParent.getComponents(); - for (int i = 0; children[i] != parent && !haveOverlap; i++) + Component child; + for (int i = 0; (child = newParent.getComponent(i)) != parent && !haveOverlap; i++) { - Rectangle childRect = children[i].getBounds(); + Rectangle childRect = child.getBounds(); haveOverlap = target.intersects(childRect); } } @@ -3654,7 +3685,7 @@ public abstract class JComponent extends Container implements Serializable { if ((found instanceof JComponent) && ((JComponent) found).isOpaque()) break; - else if (!(found instanceof JComponent)) + else if (!(found instanceof JComponent) && !found.isLightweight()) break; Container p = found.getParent(); if (p == null) |