865 lines · 30.2 KB · Java
RawDownload
/* * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.swing; import sun.awt.AWTAccessor; import javax.swing.plaf.LayerUI;import javax.swing.border.Border;import javax.accessibility.*;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.util.ArrayList;import java.security.AccessController;import java.security.PrivilegedAction; /** * {@code JLayer} is a universal decorator for Swing components * which enables you to implement various advanced painting effects as well as * receive notifications of all {@code AWTEvent}s generated within its borders. * <p/> * {@code JLayer} delegates the handling of painting and input events to a * {@link javax.swing.plaf.LayerUI} object, which performs the actual decoration. * <p/> * The custom painting implemented in the {@code LayerUI} and events notification * work for the JLayer itself and all its subcomponents. * This combination enables you to enrich existing components * by adding new advanced functionality such as temporary locking of a hierarchy, * data tips for compound components, enhanced mouse scrolling etc and so on. * <p/> * {@code JLayer} is a good solution if you only need to do custom painting * over compound component or catch input events from its subcomponents. * <pre> * import javax.swing.*; * import javax.swing.plaf.LayerUI; * import java.awt.*; * * public class JLayerSample { * *     private static JLayer&lt;JComponent&gt; createLayer() { *         // This custom layerUI will fill the layer with translucent green *         // and print out all mouseMotion events generated within its borders *         LayerUI&lt;JComponent&gt; layerUI = new LayerUI&lt;JComponent&gt;() { * *             public void paint(Graphics g, JComponent c) { *                 // paint the layer as is *                 super.paint(g, c); *                 // fill it with the translucent green *                 g.setColor(new Color(0, 128, 0, 128)); *                 g.fillRect(0, 0, c.getWidth(), c.getHeight()); *             } * *             public void installUI(JComponent c) { *                 super.installUI(c); *                 // enable mouse motion events for the layer's subcomponents *                 ((JLayer) c).setLayerEventMask(AWTEvent.MOUSE_MOTION_EVENT_MASK); *             } * *             public void uninstallUI(JComponent c) { *                 super.uninstallUI(c); *                 // reset the layer event mask *                 ((JLayer) c).setLayerEventMask(0); *             } * *             // overridden method which catches MouseMotion events *             public void eventDispatched(AWTEvent e, JLayer&lt;? extends JComponent&gt; l) { *                 System.out.println("AWTEvent detected: " + e); *             } *         }; *         // create a component to be decorated with the layer *         JPanel panel = new JPanel(); *         panel.add(new JButton("JButton")); * *         // create the layer for the panel using our custom layerUI *         return new JLayer&lt;JComponent&gt;(panel, layerUI); *     } * *     private static void createAndShowGUI() { *         final JFrame frame = new JFrame(); *         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); * *         // work with the layer as with any other Swing component *         frame.add(createLayer()); * *         frame.setSize(200, 200); *         frame.setLocationRelativeTo(null); *         frame.setVisible(true); *     } * *     public static void main(String[] args) throws Exception { *         SwingUtilities.invokeAndWait(new Runnable() { *             public void run() { *                 createAndShowGUI(); *             } *         }); *     } * } * </pre> * * <b>Note:</b> {@code JLayer} doesn't support the following methods: * <ul> * <li>{@link Container#add(java.awt.Component)}</li> * <li>{@link Container#add(String, java.awt.Component)}</li> * <li>{@link Container#add(java.awt.Component, int)}</li> * <li>{@link Container#add(java.awt.Component, Object)}</li> * <li>{@link Container#add(java.awt.Component, Object, int)}</li> * </ul> * using any of of them will cause {@code UnsupportedOperationException} to be thrown, * to add a component to {@code JLayer} * use {@link #setView(Component)} or {@link #setGlassPane(JPanel)}. * * @param <V> the type of {@code JLayer}'s view component * * @see #JLayer(Component) * @see #setView(Component) * @see #getView() * @see javax.swing.plaf.LayerUI * @see #JLayer(Component, LayerUI) * @see #setUI(javax.swing.plaf.LayerUI) * @see #getUI() * @since 1.7 * * @author Alexander Potochkin */public final class JLayer<V extends Component>        extends JComponent        implements Scrollable, PropertyChangeListener, Accessible {    private V view;    // this field is necessary because JComponent.ui is transient    // when layerUI is serializable    private LayerUI<? super V> layerUI;    private JPanel glassPane;    private long eventMask;    private transient boolean isPainting;    private transient boolean isPaintingImmediately;     private static final LayerEventController eventController =            new LayerEventController();     /**     * Creates a new {@code JLayer} object with a {@code null} view component     * and default {@link javax.swing.plaf.LayerUI}.     *     * @see #setView     * @see #setUI     */    public JLayer() {        this(null);    }     /**     * Creates a new {@code JLayer} object     * 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, new LayerUI<V>());    }     /**     * Creates a new {@code JLayer} object with the specified view component     * and {@link javax.swing.plaf.LayerUI} object.     *     * @param view the component to be decorated     * @param ui the {@link javax.swing.plaf.LayerUI} delegate     * to be used by this {@code JLayer}     */    public JLayer(V view, LayerUI<V> ui) {        setGlassPane(createGlassPane());        setView(view);        setUI(ui);    }     /**     * Returns the {@code JLayer}'s view component or {@code null}.     * <br/>This is a bound property.     *     * @return the {@code JLayer}'s view component     *         or {@code null} if none exists     *     * @see #setView(Component)     */    public V getView() {        return view;    }     /**     * Sets the {@code JLayer}'s view component, which can be {@code null}.     * <br/>This is a bound property.     *     * @param view the view component for this {@code JLayer}     *     * @see #getView()     */    public void setView(V view) {        Component oldView = getView();        if (oldView != null) {            super.remove(oldView);        }        if (view != null) {            super.addImpl(view, null, getComponentCount());        }        this.view = view;        firePropertyChange("view", oldView, view);        revalidate();        repaint();    }     /**     * Sets the {@link javax.swing.plaf.LayerUI} which will perform painting     * and receive input events for this {@code JLayer}.     *     * @param ui the {@link javax.swing.plaf.LayerUI} for this {@code JLayer}     */    public void setUI(LayerUI<? super V> ui) {        this.layerUI = ui;        super.setUI(ui);    }     /**     * Returns the {@link javax.swing.plaf.LayerUI} for this {@code JLayer}.     *     * @return the {@code LayerUI} for this {@code JLayer}     */    public LayerUI<? super V> getUI() {        return layerUI;    }     /**     * Returns the {@code JLayer}'s glassPane component or {@code null}.     * <br/>This is a bound property.     *     * @return the {@code JLayer}'s glassPane component     *         or {@code null} if none exists     *     * @see #setGlassPane(JPanel)     */    public JPanel getGlassPane() {        return glassPane;    }     /**     * Sets the {@code JLayer}'s glassPane component, which can be {@code null}.     * <br/>This is a bound property.     *     * @param glassPane the glassPane component of this {@code JLayer}     *     * @see #getGlassPane()     */    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;        firePropertyChange("glassPane", oldGlassPane, glassPane);        revalidate();        repaint();    }     /**     * Called by the constructor methods to create a default {@code glassPane}.     * By default this method creates a new JPanel with visibility set to true     * and opacity set to false.     *     * @return the default {@code glassPane}     */    public JPanel createGlassPane() {        return new DefaultLayerGlassPane();    }     /**     * 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}     *     * @throws UnsupportedOperationException this method is not supported     *     * @see #setView(Component)     * @see #setGlassPane(JPanel)     */    protected void addImpl(Component comp, Object constraints, int index) {        throw new UnsupportedOperationException(                "Adding components to JLayer is not supported, " +                        "use setView() or setGlassPane() instead");    }     /**     * {@inheritDoc}     */    public void remove(Component comp) {        if (comp == null) {            super.remove(comp);        } else if (comp == getView()) {            setView(null);        } else if (comp == getGlassPane()) {            setGlassPane(null);        } else {            super.remove(comp);        }    }     /**     * {@inheritDoc}     */    public void removeAll() {        if (view != null) {            setView(null);        }        if (glassPane != null) {            setGlassPane(null);        }    }     /**     * Always returns {@code true} to cause painting to originate from {@code JLayer},     * or one of its ancestors.     *     * @return true     * @see JComponent#isPaintingOrigin()     */    protected boolean isPaintingOrigin() {        return true;    }     /**     * Delegates its functionality to the     * {@link javax.swing.plaf.LayerUI#paintImmediately(int, int, int, int, JLayer)} method,     * if {@code LayerUI} is set.     *     * @param x  the x value of the region to be painted     * @param y  the y value of the region to be painted     * @param w  the width of the region to be painted     * @param h  the height of the region to be painted     */    public void paintImmediately(int x, int y, int w, int h) {        if (!isPaintingImmediately && getUI() != null) {            isPaintingImmediately = true;            try {                getUI().paintImmediately(x, y, w, h, this);            } finally {                isPaintingImmediately = false;            }        } else {            super.paintImmediately(x, y, w, h);        }    }     /**     * Delegates all painting to the {@link javax.swing.plaf.LayerUI} object.     *     * @param g the {@code Graphics} to render to     */    public void paint(Graphics g) {        if (!isPainting) {            isPainting = true;            try {                super.paintComponent(g);            } finally {                isPainting = false;            }        } else {            super.paint(g);        }    }     /**     * This method is empty, because all painting is done by     * {@link #paint(Graphics)} and     * {@link javax.swing.plaf.LayerUI#update(Graphics, JComponent)} methods     */    protected void paintComponent(Graphics g) {    }     /**     * 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     */    public boolean isOptimizedDrawingEnabled() {        return false;    }     /**     * {@inheritDoc}     */    public void propertyChange(PropertyChangeEvent evt) {        if (getUI() != null) {            getUI().applyPropertyChange(evt, this);        }    }     /**     * Enables the events from JLayer and <b>all its descendants</b>     * defined by the specified event mask parameter     * to be delivered to the     * {@link LayerUI#eventDispatched(AWTEvent, JLayer)} method.     * <p/>     * Events are delivered provided that {@code LayerUI} is set     * for this {@code JLayer} and the {@code JLayer}     * is displayable.     * <p/>     * The following example shows how to correctly use this method     * in the {@code LayerUI} implementations:     * <pre>     *    public void installUI(JComponent c) {     *       super.installUI(c);     *       JLayer l = (JLayer) c;     *       // this LayerUI will receive only key and focus events     *       l.setLayerEventMask(AWTEvent.KEY_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK);     *    }     *     *    public void uninstallUI(JComponent c) {     *       super.uninstallUI(c);     *       JLayer l = (JLayer) c;     *       // JLayer must be returned to its initial state     *       l.setLayerEventMask(0);     *    }     * </pre>     *     * By default {@code JLayer} receives no events and its event mask is {@code 0}.     *     * @param layerEventMask the bitmask of event types to receive     *

Lines 1–500 of 865.