6982661: Complete JLayer component
authoralexp
Fri, 17 Sep 2010 22:50:44 +0400
changeset 6647 9d119d6c36b9
parent 6513 83264865df37
child 6648 6b796dace707
6982661: Complete JLayer component Reviewed-by: malenkov
jdk/src/share/classes/javax/swing/JComponent.java
jdk/src/share/classes/javax/swing/JLayer.java
jdk/src/share/classes/javax/swing/plaf/LayerUI.java
--- a/jdk/src/share/classes/javax/swing/JComponent.java	Thu Sep 16 09:07:03 2010 +0400
+++ b/jdk/src/share/classes/javax/swing/JComponent.java	Fri Sep 17 22:50:44 2010 +0400
@@ -4787,6 +4787,17 @@
      * @see RepaintManager#addDirtyRegion
      */
     public void repaint(long tm, int x, int y, int width, int height) {
+        Container p = this;
+        while ((p = p.getParent()) instanceof JComponent) {
+            JComponent jp = (JComponent) p;
+            if (jp.isPaintingOrigin()) {
+                Rectangle rectangle = SwingUtilities.convertRectangle(
+                        this, new Rectangle(x, y, width, height), jp);
+                jp.repaint(tm,
+                        rectangle.x, rectangle.y, rectangle.width, rectangle.height);
+                return;
+            }
+        }
         RepaintManager.currentManager(this).addDirtyRegion(this, x, y, width, height);
     }
 
--- a/jdk/src/share/classes/javax/swing/JLayer.java	Thu Sep 16 09:07:03 2010 +0400
+++ b/jdk/src/share/classes/javax/swing/JLayer.java	Fri Sep 17 22:50:44 2010 +0400
@@ -25,17 +25,17 @@
 
 package javax.swing;
 
+import sun.awt.AWTAccessor;
+
 import javax.swing.plaf.LayerUI;
+import javax.swing.border.Border;
 import java.awt.*;
 import java.awt.event.*;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.io.IOException;
 import java.io.ObjectInputStream;
-import java.io.Serializable;
-import java.lang.ref.WeakReference;
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 
@@ -156,8 +156,6 @@
     private LayerUI<? super V> layerUI;
     private JPanel glassPane;
     private boolean isPainting;
-    private static final DefaultLayerLayout sharedLayoutInstance =
-            new DefaultLayerLayout();
     private long eventMask;
 
     private static final LayerEventController eventController =
@@ -165,7 +163,7 @@
 
     /**
      * Creates a new {@code JLayer} object with a {@code null} view component
-     * and {@code null} {@link javax.swing.plaf.LayerUI}.
+     * and default {@link javax.swing.plaf.LayerUI}.
      *
      * @see #setView
      * @see #setUI
@@ -176,14 +174,14 @@
 
     /**
      * Creates a new {@code JLayer} object
-     * with {@code null} {@link javax.swing.plaf.LayerUI}.
+     * with default {@link javax.swing.plaf.LayerUI}.
      *
      * @param view the component to be decorated by this {@code JLayer}
      *
      * @see #setUI
      */
     public JLayer(V view) {
-        this(view, null);
+        this(view, new LayerUI<V>());
     }
 
     /**
@@ -195,7 +193,6 @@
      * to be used by this {@code JLayer}
      */
     public JLayer(V view, LayerUI<V> ui) {
-        setLayout(sharedLayoutInstance);
         setGlassPane(createGlassPane());
         setView(view);
         setUI(ui);
@@ -279,10 +276,15 @@
      */
     public void setGlassPane(JPanel glassPane) {
         Component oldGlassPane = getGlassPane();
+        boolean isGlassPaneVisible = false;
         if (oldGlassPane != null) {
+            isGlassPaneVisible = oldGlassPane.isVisible();
             super.remove(oldGlassPane);
         }
         if (glassPane != null) {
+            AWTAccessor.getComponentAccessor().setMixingCutoutShape(glassPane,
+                    new Rectangle());
+            glassPane.setVisible(isGlassPaneVisible);
             super.addImpl(glassPane, null, 0);
         }
         this.glassPane = glassPane;
@@ -303,6 +305,40 @@
     }
 
     /**
+     * Sets the layout manager for this container.  This method is
+     * overridden to prevent the layout manager from being set.
+     * <p/>Note:  If {@code mgr} is non-{@code null}, this
+     * method will throw an exception as layout managers are not supported on
+     * a {@code JLayer}.
+     *
+     * @param mgr the specified layout manager
+     * @exception IllegalArgumentException this method is not supported
+     */
+    public void setLayout(LayoutManager mgr) {
+        if (mgr != null) {
+            throw new IllegalArgumentException("JLayer.setLayout() not supported");
+        }
+    }
+
+    /**
+     * A non-{@code null] border, or non-zero insets, isn't supported, to prevent the geometry
+     * of this component from becoming complex enough to inhibit
+     * subclassing of {@code LayerUI} class.  To create a {@code JLayer} with a border,
+     * add it to a {@code JPanel} that has a border.
+     * <p/>Note:  If {@code border} is non-{@code null}, this
+     * method will throw an exception as borders are not supported on
+     * a {@code JLayer}.
+     *
+     * @param border the {@code Border} to set
+     * @exception IllegalArgumentException this method is not supported
+     */
+    public void setBorder(Border border) {
+        if (border != null) {
+            throw new IllegalArgumentException("JLayer.setBorder() not supported");
+        }
+    }
+
+    /**
      * This method is not supported by {@code JLayer}
      * and always throws {@code UnsupportedOperationException}
      *
@@ -341,6 +377,32 @@
     }
 
     /**
+     * Always returns {@code true} to cause painting to originate from {@code JLayer},
+     * or one of its ancestors.
+     *
+     * @return true
+     * @see JComponent#isPaintingOrigin()
+     */
+    boolean isPaintingOrigin() {
+        return true;
+    }
+
+    /**
+     * Delegates repainting to {@link javax.swing.plaf.LayerUI#repaint} method.
+     *
+     * @param tm  this parameter is not used
+     * @param x  the x value of the dirty region
+     * @param y  the y value of the dirty region
+     * @param width  the width of the dirty region
+     * @param height  the height of the dirty region
+     */
+    public void repaint(long tm, int x, int y, int width, int height) {
+        if (getUI() != null) {
+            getUI().repaint(tm, x, y, width, height, this);
+        }
+    }
+
+    /**
      * Delegates all painting to the {@link javax.swing.plaf.LayerUI} object.
      *
      * @param g the {@code Graphics} to render to
@@ -364,14 +426,18 @@
     }
 
     /**
-     * To enable the correct painting of the {@code glassPane} and view component,
-     * the {@code JLayer} overrides the default implementation of
-     * this method to return {@code false} when the {@code glassPane} is visible.
+     * The {@code JLayer} overrides the default implementation of
+     * this method (in {@code JComponent}) to return {@code false}.
+     * This ensures
+     * that the drawing machinery will call the {@code JLayer}'s
+     * {@code paint}
+     * implementation rather than messaging the {@code JLayer}'s
+     * children directly.
      *
-     * @return false if {@code JLayer}'s {@code glassPane} is visible
+     * @return false
      */
     public boolean isOptimizedDrawingEnabled() {
-        return glassPane == null || !glassPane.isVisible();
+        return false;
     }
 
     /**
@@ -461,17 +527,16 @@
     /**
      * Returns the preferred size of the viewport for a view component.
      * <p/>
-     * If the ui delegate of this layer is not {@code null}, this method delegates its
-     * implementation to the {@code LayerUI.getPreferredScrollableViewportSize(JLayer)}
+     * If the view component of this layer implements {@link Scrollable}, this method delegates its
+     * implementation to the view component.
      *
      * @return the preferred size of the viewport for a view component
      *
      * @see Scrollable
-     * @see LayerUI#getPreferredScrollableViewportSize(JLayer)
      */
     public Dimension getPreferredScrollableViewportSize() {
-        if (getUI() != null) {
-            return getUI().getPreferredScrollableViewportSize(this);
+        if (getView() instanceof Scrollable) {
+            return ((Scrollable)getView()).getPreferredScrollableViewportSize();
         }
         return getPreferredSize();
     }
@@ -481,18 +546,17 @@
      * that display logical rows or columns in order to completely expose
      * one block of rows or columns, depending on the value of orientation.
      * <p/>
-     * If the ui delegate of this layer is not {@code null}, this method delegates its
-     * implementation to the {@code LayerUI.getScrollableBlockIncrement(JLayer,Rectangle,int,int)}
+     * If the view component of this layer implements {@link Scrollable}, this method delegates its
+     * implementation to the view component.
      *
      * @return the "block" increment for scrolling in the specified direction
      *
      * @see Scrollable
-     * @see LayerUI#getScrollableBlockIncrement(JLayer, Rectangle, int, int)
      */
     public int getScrollableBlockIncrement(Rectangle visibleRect,
                                            int orientation, int direction) {
-        if (getUI() != null) {
-            return getUI().getScrollableBlockIncrement(this, visibleRect,
+        if (getView() instanceof Scrollable) {
+            return ((Scrollable)getView()).getScrollableBlockIncrement(visibleRect,
                     orientation, direction);
         }
         return (orientation == SwingConstants.VERTICAL) ? visibleRect.height :
@@ -504,17 +568,16 @@
      * determine the height of the layer, unless the preferred height
      * of the layer is smaller than the height of the viewport.
      * <p/>
-     * If the ui delegate of this layer is not null, this method delegates its
-     * implementation to the {@code LayerUI.getScrollableTracksViewportHeight(JLayer)}
+     * If the view component of this layer implements {@link Scrollable}, this method delegates its
+     * implementation to the view component.
      *
      * @return whether the layer should track the height of the viewport
      *
      * @see Scrollable
-     * @see LayerUI#getScrollableTracksViewportHeight(JLayer)
      */
     public boolean getScrollableTracksViewportHeight() {
-        if (getUI() != null) {
-            return getUI().getScrollableTracksViewportHeight(this);
+        if (getView() instanceof Scrollable) {
+            return ((Scrollable)getView()).getScrollableTracksViewportHeight();
         }
         return false;
     }
@@ -524,17 +587,16 @@
      * determine the width of the layer, unless the preferred width
      * of the layer is smaller than the width of the viewport.
      * <p/>
-     * If the ui delegate of this layer is not null, this method delegates its
-     * implementation to the {@code LayerUI.getScrollableTracksViewportWidth(JLayer)}
+     * If the view component of this layer implements {@link Scrollable}, this method delegates its
+     * implementation to the view component.
      *
      * @return whether the layer should track the width of the viewport
      *
      * @see Scrollable
-     * @see LayerUI#getScrollableTracksViewportWidth(JLayer)
      */
     public boolean getScrollableTracksViewportWidth() {
-        if (getUI() != null) {
-            return getUI().getScrollableTracksViewportWidth(this);
+        if (getView() instanceof Scrollable) {
+            return ((Scrollable)getView()).getScrollableTracksViewportWidth();
         }
         return false;
     }
@@ -549,20 +611,19 @@
      * Scrolling containers, like {@code JScrollPane}, will use this method
      * each time the user requests a unit scroll.
      * <p/>
-     * If the ui delegate of this layer is not {@code null}, this method delegates its
-     * implementation to the {@code LayerUI.getScrollableUnitIncrement(JLayer,Rectangle,int,int)}
+     * If the view component of this layer implements {@link Scrollable}, this method delegates its
+     * implementation to the view component.
      *
      * @return The "unit" increment for scrolling in the specified direction.
      *         This value should always be positive.
      *
      * @see Scrollable
-     * @see LayerUI#getScrollableUnitIncrement(JLayer, Rectangle, int, int)
      */
     public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation,
                                           int direction) {
-        if (getUI() != null) {
-            return getUI().getScrollableUnitIncrement(
-                    this, visibleRect, orientation, direction);
+        if (getView() instanceof Scrollable) {
+            return ((Scrollable) getView()).getScrollableUnitIncrement(
+                    visibleRect, orientation, direction);
         }
         return 1;
     }
@@ -595,6 +656,16 @@
     }
 
     /**
+     * Delegates its functionality to the {@link javax.swing.plaf.LayerUI#doLayout(JLayer)} method,
+     * if {@code LayerUI} is set.
+     */
+    public void doLayout() {
+        if (getUI() != null) {
+            getUI().doLayout(this);
+        }
+    }
+
+    /**
      * static AWTEventListener to be shared with all AbstractLayerUIs
      */
     private static class LayerEventController implements AWTEventListener {
@@ -625,8 +696,8 @@
                         JLayer l = (JLayer) component;
                         LayerUI ui = l.getUI();
                         if (ui != null &&
-                                isEventEnabled(l.getLayerEventMask(),
-                                        event.getID())) {
+                                isEventEnabled(l.getLayerEventMask(), event.getID()) &&
+                                (!(event instanceof InputEvent) || !((InputEvent)event).isConsumed())) {
                             ui.eventDispatched(event, l);
                         }
                     }
@@ -758,82 +829,4 @@
             return super.contains(x, y);
         }
     }
-
-    /**
-     * The default layout manager for the {@link javax.swing.JLayer}.<br/>
-     * It places the glassPane on top of the view component
-     * and makes it the same size as {@code JLayer},
-     * it also makes the view component the same size but minus layer's insets<br/>
-     */
-    private static class DefaultLayerLayout implements LayoutManager, Serializable {
-        /**
-         * {@inheritDoc}
-         */
-        public void layoutContainer(Container parent) {
-            JLayer layer = (JLayer) parent;
-            Component view = layer.getView();
-            Component glassPane = layer.getGlassPane();
-            if (view != null) {
-                Insets insets = layer.getInsets();
-                view.setLocation(insets.left, insets.top);
-                view.setSize(layer.getWidth() - insets.left - insets.right,
-                        layer.getHeight() - insets.top - insets.bottom);
-            }
-            if (glassPane != null) {
-                glassPane.setLocation(0, 0);
-                glassPane.setSize(layer.getWidth(), layer.getHeight());
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public Dimension minimumLayoutSize(Container parent) {
-            JLayer layer = (JLayer) parent;
-            Insets insets = layer.getInsets();
-            Dimension ret = new Dimension(insets.left + insets.right,
-                    insets.top + insets.bottom);
-            Component view = layer.getView();
-            if (view != null) {
-                Dimension size = view.getMinimumSize();
-                ret.width += size.width;
-                ret.height += size.height;
-            }
-            if (ret.width == 0 || ret.height == 0) {
-                ret.width = ret.height = 4;
-            }
-            return ret;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public Dimension preferredLayoutSize(Container parent) {
-            JLayer layer = (JLayer) parent;
-            Insets insets = layer.getInsets();
-            Dimension ret = new Dimension(insets.left + insets.right,
-                    insets.top + insets.bottom);
-            Component view = layer.getView();
-            if (view != null) {
-                Dimension size = view.getPreferredSize();
-                if (size.width > 0 && size.height > 0) {
-                    ret.width += size.width;
-                    ret.height += size.height;
-                }
-            }
-            return ret;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public void addLayoutComponent(String name, Component comp) {
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public void removeLayoutComponent(Component comp) {
-        }
-    }
 }
--- a/jdk/src/share/classes/javax/swing/plaf/LayerUI.java	Thu Sep 16 09:07:03 2010 +0400
+++ b/jdk/src/share/classes/javax/swing/plaf/LayerUI.java	Fri Sep 17 22:50:44 2010 +0400
@@ -600,104 +600,6 @@
     }
 
     /**
-     * Returns the preferred size of the viewport for a view component.
-     *
-     * @param l the {@code JLayer} component where this UI delegate is being installed
-     * @return the preferred size of the viewport for a view component
-     * @see Scrollable#getPreferredScrollableViewportSize()
-     */
-    public Dimension getPreferredScrollableViewportSize(JLayer<? extends V> l) {
-        if (l.getView() instanceof Scrollable) {
-            return ((Scrollable)l.getView()).getPreferredScrollableViewportSize();
-        }
-        return l.getPreferredSize();
-    }
-
-    /**
-     * Returns a scroll increment, which is required for components
-     * that display logical rows or columns in order to completely expose
-     * one block of rows or columns, depending on the value of orientation.
-     *
-     * @param l the {@code JLayer} component where this UI delegate is being installed
-     * @param visibleRect The view area visible within the viewport
-     * @param orientation Either SwingConstants.VERTICAL or SwingConstants.HORIZONTAL.
-     * @param direction Less than zero to scroll up/left, greater than zero for down/right.
-     * @return the "block" increment for scrolling in the specified direction
-     * @see Scrollable#getScrollableBlockIncrement(Rectangle, int, int)
-     */
-     public int getScrollableBlockIncrement(JLayer<? extends V> l,
-                                           Rectangle visibleRect,
-                                           int orientation, int direction) {
-        if (l.getView() instanceof Scrollable) {
-            return ((Scrollable)l.getView()).getScrollableBlockIncrement(
-                    visibleRect,orientation, direction);
-        }
-        return (orientation == SwingConstants.VERTICAL) ? visibleRect.height :
-            visibleRect.width;
-    }
-
-    /**
-     * Returns {@code false} to indicate that the height of the viewport does not
-     * determine the height of the layer, unless the preferred height
-     * of the layer is smaller than the height of the viewport.
-     *
-     * @param l the {@code JLayer} component where this UI delegate is being installed
-     * @return whether the layer should track the height of the viewport
-     * @see Scrollable#getScrollableTracksViewportHeight()
-     */
-    public boolean getScrollableTracksViewportHeight(JLayer<? extends V> l) {
-        if (l.getView() instanceof Scrollable) {
-            return ((Scrollable)l.getView()).getScrollableTracksViewportHeight();
-        }
-        return false;
-    }
-
-    /**
-     * Returns {@code false} to indicate that the width of the viewport does not
-     * determine the width of the layer, unless the preferred width
-     * of the layer is smaller than the width of the viewport.
-     *
-     * @param l the {@code JLayer} component where this UI delegate is being installed
-     * @return whether the layer should track the width of the viewport
-     * @see Scrollable
-     * @see LayerUI#getScrollableTracksViewportWidth(JLayer)
-     */
-    public boolean getScrollableTracksViewportWidth(JLayer<? extends V> l) {
-        if (l.getView() instanceof Scrollable) {
-            return ((Scrollable)l.getView()).getScrollableTracksViewportWidth();
-        }
-        return false;
-    }
-
-    /**
-     * Returns a scroll increment, which is required for components
-     * that display logical rows or columns in order to completely expose
-     * one new row or column, depending on the value of orientation.
-     * Ideally, components should handle a partially exposed row or column
-     * by returning the distance required to completely expose the item.
-     * <p>
-     * Scrolling containers, like JScrollPane, will use this method
-     * each time the user requests a unit scroll.
-     *
-     * @param l the {@code JLayer} component where this UI delegate is being installed
-     * @param visibleRect The view area visible within the viewport
-     * @param orientation Either SwingConstants.VERTICAL or SwingConstants.HORIZONTAL.
-     * @param direction Less than zero to scroll up/left, greater than zero for down/right.
-     * @return The "unit" increment for scrolling in the specified direction.
-     *         This value should always be positive.
-     * @see Scrollable#getScrollableUnitIncrement(Rectangle, int, int)
-     */
-    public int getScrollableUnitIncrement(JLayer<? extends V> l,
-                                          Rectangle visibleRect,
-                                          int orientation, int direction) {
-        if (l.getView() instanceof Scrollable) {
-            return ((Scrollable)l.getView()).getScrollableUnitIncrement(
-                    visibleRect, orientation, direction);
-        }
-        return 1;
-    }
-
-    /**
      * If the {@code JLayer}'s view component is not {@code null},
      * this calls the view's {@code getBaseline()} method.
      * Otherwise, the default implementation is called.
@@ -718,7 +620,7 @@
 
     /**
      * If the {@code JLayer}'s view component is not {@code null},
-     * this calls the view's {@code getBaselineResizeBehavior()} method.
+     * this returns the result of the view's {@code getBaselineResizeBehavior()} method.
      * Otherwise, the default implementation is called.
      *
      * @param c {@code JLayer} to return baseline resize behavior for
@@ -732,4 +634,90 @@
         }
         return super.getBaselineResizeBehavior(c);
     }
+
+    /**
+     * Causes the passed instance of {@code JLayer} to lay out its components.
+     *
+     * @param l the {@code JLayer} component where this UI delegate is being installed
+     */
+    public void doLayout(JLayer<? extends V> l) {
+        Component view = l.getView();
+        if (view != null) {
+            view.setBounds(0, 0, l.getWidth(), l.getHeight());
+        }
+        Component glassPane = l.getGlassPane();
+        if (glassPane != null) {
+            glassPane.setBounds(0, 0, l.getWidth(), l.getHeight());
+        }
+    }
+
+    /**
+     * If the {@code JLayer}'s view component is not {@code null},
+     * this returns the result of  the view's {@code getPreferredSize()} method.
+     * Otherwise, the default implementation is used.
+     *
+     * @param c {@code JLayer} to return preferred size for
+     * @return preferred size for the passed {@code JLayer}
+     */
+    public Dimension getPreferredSize(JComponent c) {
+        JLayer l = (JLayer) c;
+        Component view = l.getView();
+        if (view != null) {
+            return view.getPreferredSize();
+        }
+        return super.getPreferredSize(c);
+    }
+
+    /**
+     * If the {@code JLayer}'s view component is not {@code null},
+     * this returns the result of  the view's {@code getMinimalSize()} method.
+     * Otherwise, the default implementation is used.
+     *
+     * @param c {@code JLayer} to return preferred size for
+     * @return minimal size for the passed {@code JLayer}
+     */
+    public Dimension getMinimumSize(JComponent c) {
+        JLayer l = (JLayer) c;
+        Component view = l.getView();
+        if (view != null) {
+            return view.getMinimumSize();
+        }
+        return super.getMinimumSize(c);
+    }
+
+    /**
+     * If the {@code JLayer}'s view component is not {@code null},
+     * this returns the result of  the view's {@code getMaximumSize()} method.
+     * Otherwise, the default implementation is used.
+     *
+     * @param c {@code JLayer} to return preferred size for
+     * @return maximun size for the passed {@code JLayer}
+     */
+    public Dimension getMaximumSize(JComponent c) {
+        JLayer l = (JLayer) c;
+        Component view = l.getView();
+        if (view != null) {
+            return view.getMaximumSize();
+        }
+        return super.getMaximumSize(c);
+    }
+
+    /**
+     * Adds the specified region to the dirty region list if the component
+     * is showing.  The component will be repainted after all of the
+     * currently pending events have been dispatched.
+     * <p/>
+     * This method is to be overridden when the dirty region needs to be changed.
+     *
+     * @param tm  this parameter is not used
+     * @param x  the x value of the dirty region
+     * @param y  the y value of the dirty region
+     * @param width  the width of the dirty region
+     * @param height  the height of the dirty region
+     * @see java.awt.Component#isShowing
+     * @see RepaintManager#addDirtyRegion
+     */
+    public void repaint(long tm, int x, int y, int width, int height, JLayer<? extends V> l) {
+        RepaintManager.currentManager(l).addDirtyRegion(l, x, y, width, height);
+    }
 }