[cp-patches] FYI: JLayeredPane fixes
A couple of fixes for the JLayeredPane. This fixes the behaviour of toFront(), toBack(), setPosition() and setLayer() which was slightly broken before. 2006-06-23 Roman Kennke <[EMAIL PROTECTED]> * javax/swing/JLayeredPane.java (getPosition): Moved code around to avoid unnecessary method calls. (setPosition): Delegate to setLayer(). (insertIndexForLayer(int,int)): Delegate to new private helper method. (insertIndexForLayer(Component,int,int)): New helper method to support the use of setComponentZOrder() which doesn't remove the component and thus the insertIndexForLayer must ignore the component to be moved to get the index right. (setLayer): Added check to prevent unnecessary execution of method body. Changed to update the component order here. Added repaint() to make sure that the update becomes visible. (addImpl): Call setLayer() only when a constraint has been specified. Validate and repaint the JLayeredPane. /Roman -- “Improvement makes straight roads, but the crooked roads, without Improvement, are roads of Genius.” - William Blake Index: javax/swing/JLayeredPane.java === RCS file: /cvsroot/classpath/classpath/javax/swing/JLayeredPane.java,v retrieving revision 1.46 diff -u -2 -0 -r1.46 JLayeredPane.java --- javax/swing/JLayeredPane.java 1 Jun 2006 04:38:49 - 1.46 +++ javax/swing/JLayeredPane.java 23 Jun 2006 11:07:55 - @@ -26,40 +26,41 @@ 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 javax.swing; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Graphics; import java.awt.Rectangle; +import java.util.ArrayList; import java.util.Hashtable; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; /** * A container that adds depth to the usual Container semantics. * Each child component of a Layered Pane is placed within one * of several layers. JLayeredPane defines a set of standard * layers. The pre-defined sets are (in the order from button to top): * * *[EMAIL PROTECTED] #DEFAULT_LAYER} *The layer where most of the normal components are placed. This * is the bottommost layer. * *[EMAIL PROTECTED] #PALETTE_LAYER} *Palette windows are placed in this layer. * @@ -309,70 +310,68 @@ { setPosition (c, -1); } /** * Return the position of a component within its layer. Positions are assigned * from the "front" (position 0) to the "back" (position N-1), and drawn from * the back towards the front. * * @param c the component to get the position of * * @return the position of c within its layer or -1 if * c is not a child of this layered pane * * @see #setPosition */ public int getPosition(Component c) { int pos = -1; int index = getIndexOf(c); -Component[] components = getComponents(); -int layer = getLayer(c); if (index >= 0) { -for (int i = index; i >= 0; --i) +pos = 0; +int layer = getLayer(c); +for (int i = index - 1; i >= 0; --i) { -if (layer == getLayer(components[i])) +if (layer == getLayer(getComponent(i))) pos++; else break; } } return pos; } /** * Change the position of a component within its layer. Positions are assigned * from the "front" (position 0) to the "back" (position N-1), and drawn from * the back towards the front. * * @param c the component to change the position of * @param position the position to assign the component to * * @see #getPosition */ public void setPosition(Component c, int position) { -int layer = getLayer(c); -int index = insertIndexForLayer(layer, position); -setComponentZOrder(c, index); +setLayer(c, getLayer(c), position); } /** * Return an array of all components within a layer of this * container. Components are ordered front-to-back, with the "front" * element (which draws last) at position 0 of the returned
[cp-patches] FYI: JLayeredPane fixes
I have essentially rewritten most of JLayeredPane. I noticed some troubles with this class and read a little in the OReilly Swing book 1st edition. I learned that we did a couple of things wrong in this class: - we stored all components and their layers in the Hashtable. This is wrong. JComponents should have their layer stored as client property with LAYER_PROPERTY as key. - a lot of the methods used to throw IllegalArgumentExceptions for unusual arguments like components that are not children of the layered pane. These methods should ignore this instead and return -1 or 0. (This error actually caused several problems in some applications) Also, our implementation used a second datastructure called 'layers' to manage the layers. This is really not needed and makes maintainence of the code less straightforward. I removed this and rewrote most stuff in a more straightforward manner. 2006-01-27 Roman Kennke <[EMAIL PROTECTED]> * javax/swing/JLayeredPane.java (FRAME_CONTENT_LAYER): Made field final. (componentToLayer): Made field private. (rectCache): Removed field. (layers): Removed field. (JLayeredPane()): Removed initialization of removed fields. (getLayer): Rewritten to make use of client properties in JComponents and to be more straighforward. (static getLayer): Rewritten to make use of client properties in JComponents. (layerToRange): Removed method. (incrLayer): Removed method. (decrLayer): Removed method. (highestLayer): Rewritten to be more straightforward. (lowestLayer): Rewritten to be more straightforward. (getPosition): Rewritten to be more straightforward. (getComponentsInLayer): Rewritten to be more straightforward. (getComponentCountInLayer): Rewritten to be more straightforward. (getIndexOf): Rewritten to be more straightforward. (inserIndexForLayer): Rewritten to be more straightforward. (remove): Rewritten to be more straightforward. (setLayer): Rewritten to be more straightforward. (addImpl): Rewritten to be more straightforward. (putLayer): Rewritten to be more straightforward. /Roman Index: javax/swing/JLayeredPane.java === RCS file: /cvsroot/classpath/classpath/javax/swing/JLayeredPane.java,v retrieving revision 1.37 diff -u -r1.37 JLayeredPane.java --- javax/swing/JLayeredPane.java 27 Jan 2006 15:51:21 - 1.37 +++ javax/swing/JLayeredPane.java 27 Jan 2006 19:56:19 - @@ -43,11 +43,7 @@ import java.awt.Container; import java.awt.Graphics; import java.awt.Rectangle; -import java.awt.Shape; import java.util.Hashtable; -import java.util.Iterator; -import java.util.Map; -import java.util.TreeMap; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; @@ -119,6 +115,7 @@ * component indexing and position order * * @author Graydon Hoare ([EMAIL PROTECTED]) + * @author Roman Kennke ([EMAIL PROTECTED]) */ public class JLayeredPane extends JComponent implements Accessible { @@ -150,7 +147,7 @@ public static final String LAYER_PROPERTY = "layeredContainerLayer"; - public static Integer FRAME_CONTENT_LAYER = new Integer (-3); + public static final Integer FRAME_CONTENT_LAYER = new Integer (-3); public static final Integer DEFAULT_LAYER = new Integer (0); public static final Integer PALETTE_LAYER = new Integer (100); @@ -158,14 +155,10 @@ public static final Integer POPUP_LAYER = new Integer (300); public static final Integer DRAG_LAYER= new Integer (400); - TreeMap layers; // Layer Number (Integer) -> Layer Size (Integer) - Hashtable componentToLayer; // Component -> Layer Number (Integer) + private Hashtable componentToLayer; // Component -> Layer Number (Integer) - private transient Rectangle rectCache; - public JLayeredPane() { -layers = new TreeMap (); componentToLayer = new Hashtable (); setLayout(null); } @@ -173,47 +166,50 @@ /** * Looks up the layer a child component is currently assigned to. * + * If c is an instance of [EMAIL PROTECTED] JComponent}, then the layer + * is fetched from the client property with the key [EMAIL PROTECTED] #LAYER_PROPERTY}. + * Otherwise it is looked up in an internal hashtable that maps + * non-JComponent components to layers. If the components cannot be found + * in either way, the [EMAIL PROTECTED] #DEFAULT_LAYER} is returned. + * * @param c the component to look up. - * @return the layer the component is currently assigned to, in this container. - * @throws IllegalArgumentException if the component is not a child of this container. + * + * @return the layer the component is currently assigned to; if the component + * is not in this layered pane, then 0 (DEFAULT_LAYER) is returned */ public int getLayer(Co
[cp-patches] FYI: JLayeredPane fixes
The attached patch fixes two issues with JLayeredPane. It avoids a potential memory leak that comes from not overriding removeAll in JLayeredPane. Calling removeAll() would cause components to be removed but their layer information to be kept forever in JLayeredPane's Hashtable. Also, I improved the isOptimizedDrawingEnabled method so that it accurately calculates if child components overlap or not. Before, I had a heuristic there that returns false for #components>2. Now I go through all the components and compare their rectangles. This is surprisingly efficient, I had a JLayeredPane here with 9 children and this method still took 1ms or less. As a reward the painting is done more efficient, which is well worth the effort. 2006-02-13 Roman Kennke <[EMAIL PROTECTED]> * javax/swing/JLayeredPane.java (removeAll): New method. Avoid potential memory leak. (isOptimizedDrawingEnabled): Replaced heuristic with accurate calculation. /Roman Index: javax/swing/JLayeredPane.java === RCS file: /cvsroot/classpath/classpath/javax/swing/JLayeredPane.java,v retrieving revision 1.43 diff -u -r1.43 JLayeredPane.java --- javax/swing/JLayeredPane.java 4 Feb 2006 11:08:43 - 1.43 +++ javax/swing/JLayeredPane.java 14 Feb 2006 11:12:57 - @@ -523,6 +523,17 @@ } /** + * Removes all components from this container. + * + * @since 1.5 + */ + public void removeAll() + { + componentToLayer.clear(); + super.removeAll(); + } + + /** * Set the layer property for a component, within this container. The * component will be implicitly mapped to the bottom-most position in the * layer, but only if added after calling this method. @@ -646,30 +657,33 @@ public boolean isOptimizedDrawingEnabled() { int numChildren = getComponentCount(); -boolean result = false; -// We implement a heuristic here in order to return a quick result: -// - For 0 or 1 children it is clear that they do not overlap, return true. -// - For 2 children we check their bounding rectangles and if they don't -// interect, return true. -// - For more than 2 children we return false. Comparing all the bounding -// rectangles costs too much time and in most cases this will return -// false anyway, since JLayeredPane are mostly used in JRootPane and then -// have at least one child (the contentPane) that takes up the whole -// area of the JLayeredPane. -switch (numChildren) -{ - case 0: - case 1: -result = true; -break; - case 2: -Rectangle r1 = getComponent(0).getBounds(); -Rectangle r2 = getComponent(1).getBounds(); -result = !r1.intersects(r2); -break; - default: -result = false; -} +boolean result = true; +for (int i = 0; i < numChildren; ++i) + { + Component c1 = getComponent(i); + if (! c1.isVisible()) + continue; + Rectangle r1 = c1.getBounds(); + if (r1.isEmpty()) + continue; + + for (int j = i + 1; j < numChildren; ++j) + { +Component c2 = getComponent(j); +if (! c2.isVisible()) + continue; +Rectangle r2 = c2.getBounds(); +if (r2.isEmpty()) + continue; +if (r1.intersects(r2)) + { +result = false; +break; + } +if (result == false) + break; + } + } return result; } }
[cp-patches] FYI: JLayeredPane fixes / new Container methods
This fixes a mauve test for JLayeredPane. In order to fix this, I implemented the set/getComponentZOrder() methods in Container and made JLayeredPane use these methods. This is not only much more efficient than adding/removing components when changing the order, it also fixes a nasty problem when there is a layout manager installed on the JLayeredPane (which is discouraged but not forbidden). 2006-02-04 Roman Kennke <[EMAIL PROTECTED]> * java/awt/Container.java (getComponentZOrder): New method. (setComponentZOrder): New method. * javax/swing/JLayeredPane.java (setPosition): Reimplemented to use setComponentZOrder(). (getIndexOf): Reimplemented to use getComponentZOrder(). (addImpl): Pass layerContraint to super call. Important for possibly installed layout managers. (swapComponents): Remove unneeded method. /Roman Index: java/awt/Container.java === RCS file: /cvsroot/classpath/classpath/java/awt/Container.java,v retrieving revision 1.77 diff -u -r1.77 Container.java --- java/awt/Container.java 27 Jan 2006 15:51:21 - 1.77 +++ java/awt/Container.java 4 Feb 2006 11:04:18 - @@ -1565,6 +1565,93 @@ changeSupport.addPropertyChangeListener (name, listener); } + + /** + * Sets the Z ordering for the component comp to + * index. Components with lower Z order paint above components + * with higher Z order. + * + * @param comp the component for which to change the Z ordering + * @param index the index to set + * + * @throws NullPointerException if comp == null + * @throws IllegalArgumentException if comp is an ancestor of this container + * @throws IllegalArgumentException if index is not in + * [0, getComponentCount()] for moving between + * containers or [0, getComponentCount() - 1] for moving + * inside this container + * @throws IllegalArgumentException if comp == this + * @throws IllegalArgumentException if comp is a + * Window + * + * @see #getComponentZOrder(Component) + * + * @since 1.5 + */ + public final void setComponentZOrder(Component comp, int index) + { +if (comp == null) + throw new NullPointerException("comp must not be null"); +if (comp instanceof Container && ((Container) comp).isAncestorOf(this)) + throw new IllegalArgumentException("comp must not be an ancestor of " + + "this"); +if (comp instanceof Window) + throw new IllegalArgumentException("comp must not be a Window"); + +if (comp == this) + throw new IllegalArgumentException("cannot add component to itself"); + +// FIXME: Implement reparenting. +if ( comp.getParent() != this) + throw new AssertionError("Reparenting is not implemented yet"); +else + { +// Find current component index. +int currentIndex = getComponentZOrder(comp); +if (currentIndex < index) + { +System.arraycopy(component, currentIndex + 1, component, + currentIndex, index - currentIndex); + } +else + { +System.arraycopy(component, index, component, index + 1, + currentIndex - index); + } +component[index] = comp; + } + } + + /** + * Returns the Z ordering index of comp. If comp + * is not a child component of this Container, this returns -1. + * + * @param comp the component for which to query the Z ordering + * + * @return the Z ordering index of comp or -1 if + * comp is not a child of this Container + * + * @see #setComponentZOrder(Component, int) + * + * @since 1.5 + */ + public final int getComponentZOrder(Component comp) + { +int index = -1; +if (component != null) + { +for (int i = 0; i < component.length; i++) + { +if (component[i] == comp) + { +index = i; +break; + } + } + } +return index; + } + // Hidden helper methods. /** Index: javax/swing/JLayeredPane.java === RCS file: /cvsroot/classpath/classpath/javax/swing/JLayeredPane.java,v retrieving revision 1.42 diff -u -r1.42 JLayeredPane.java --- javax/swing/JLayeredPane.java 1 Feb 2006 12:17:13 - 1.42 +++ javax/swing/JLayeredPane.java 4 Feb 2006 11:04:18 - @@ -353,16 +353,9 @@ */ public void setPosition(Component c, int position) { -int currentPos = getPosition(c); -if (currentPos == position) - return; - int layer = getLayer(c); -int i1 = position; -int i2 = getPosition(c); -int incr = (i1 - i2) / Math.abs(i1 - i2); -for (int p = i2; p != i1; p += incr) - swapComponents(p, p + incr, layer); +int index = insertIndexForLayer(layer, position); +set