1 /*
   2  * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.swing;
  27 
  28 import sun.awt.AWTAccessor;
  29 
  30 import javax.swing.plaf.LayerUI;
  31 import javax.swing.border.Border;
  32 import javax.accessibility.*;
  33 import java.awt.*;
  34 import java.awt.event.*;
  35 import java.beans.PropertyChangeEvent;
  36 import java.beans.PropertyChangeListener;
  37 import java.io.IOException;
  38 import java.io.ObjectInputStream;
  39 import java.util.ArrayList;
  40 import java.security.AccessController;
  41 import java.security.PrivilegedAction;
  42 
  43 /**
  44  * {@code JLayer} is a universal decorator for Swing components
  45  * which enables you to implement various advanced painting effects as well as
  46  * receive notifications of all {@code AWTEvent}s generated within its borders.
  47  * <p>
  48  * {@code JLayer} delegates the handling of painting and input events to a
  49  * {@link javax.swing.plaf.LayerUI} object, which performs the actual decoration.
  50  * <p>
  51  * The custom painting implemented in the {@code LayerUI} and events notification
  52  * work for the JLayer itself and all its subcomponents.
  53  * This combination enables you to enrich existing components
  54  * by adding new advanced functionality such as temporary locking of a hierarchy,
  55  * data tips for compound components, enhanced mouse scrolling etc and so on.
  56  * <p>
  57  * {@code JLayer} is a good solution if you only need to do custom painting
  58  * over compound component or catch input events from its subcomponents.
  59  * <pre>
  60  * import javax.swing.*;
  61  * import javax.swing.plaf.LayerUI;
  62  * import java.awt.*;
  63  *
  64  * public class JLayerSample {
  65  *
  66  *     private static JLayer&lt;JComponent&gt; createLayer() {
  67  *         // This custom layerUI will fill the layer with translucent green
  68  *         // and print out all mouseMotion events generated within its borders
  69  *         LayerUI&lt;JComponent&gt; layerUI = new LayerUI&lt;JComponent&gt;() {
  70  *
  71  *             public void paint(Graphics g, JComponent c) {
  72  *                 // paint the layer as is
  73  *                 super.paint(g, c);
  74  *                 // fill it with the translucent green
  75  *                 g.setColor(new Color(0, 128, 0, 128));
  76  *                 g.fillRect(0, 0, c.getWidth(), c.getHeight());
  77  *             }
  78  *
  79  *             public void installUI(JComponent c) {
  80  *                 super.installUI(c);
  81  *                 // enable mouse motion events for the layer's subcomponents
  82  *                 ((JLayer) c).setLayerEventMask(AWTEvent.MOUSE_MOTION_EVENT_MASK);
  83  *             }
  84  *
  85  *             public void uninstallUI(JComponent c) {
  86  *                 super.uninstallUI(c);
  87  *                 // reset the layer event mask
  88  *                 ((JLayer) c).setLayerEventMask(0);
  89  *             }
  90  *
  91  *             // overridden method which catches MouseMotion events
  92  *             public void eventDispatched(AWTEvent e, JLayer&lt;? extends JComponent&gt; l) {
  93  *                 System.out.println("AWTEvent detected: " + e);
  94  *             }
  95  *         };
  96  *         // create a component to be decorated with the layer
  97  *         JPanel panel = new JPanel();
  98  *         panel.add(new JButton("JButton"));
  99  *
 100  *         // create the layer for the panel using our custom layerUI
 101  *         return new JLayer&lt;JComponent&gt;(panel, layerUI);
 102  *     }
 103  *
 104  *     private static void createAndShowGUI() {
 105  *         final JFrame frame = new JFrame();
 106  *         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 107  *
 108  *         // work with the layer as with any other Swing component
 109  *         frame.add(createLayer());
 110  *
 111  *         frame.setSize(200, 200);
 112  *         frame.setLocationRelativeTo(null);
 113  *         frame.setVisible(true);
 114  *     }
 115  *
 116  *     public static void main(String[] args) throws Exception {
 117  *         SwingUtilities.invokeAndWait(new Runnable() {
 118  *             public void run() {
 119  *                 createAndShowGUI();
 120  *             }
 121  *         });
 122  *     }
 123  * }
 124  * </pre>
 125  *
 126  * <b>Note:</b> {@code JLayer} doesn't support the following methods:
 127  * <ul>
 128  * <li>{@link Container#add(java.awt.Component)}</li>
 129  * <li>{@link Container#add(String, java.awt.Component)}</li>
 130  * <li>{@link Container#add(java.awt.Component, int)}</li>
 131  * <li>{@link Container#add(java.awt.Component, Object)}</li>
 132  * <li>{@link Container#add(java.awt.Component, Object, int)}</li>
 133  * </ul>
 134  * using any of of them will cause {@code UnsupportedOperationException} to be thrown,
 135  * to add a component to {@code JLayer}
 136  * use {@link #setView(Component)} or {@link #setGlassPane(JPanel)}.
 137  *
 138  * @param <V> the type of {@code JLayer}'s view component
 139  *
 140  * @see #JLayer(Component)
 141  * @see #setView(Component)
 142  * @see #getView()
 143  * @see javax.swing.plaf.LayerUI
 144  * @see #JLayer(Component, LayerUI)
 145  * @see #setUI(javax.swing.plaf.LayerUI)
 146  * @see #getUI()
 147  * @since 1.7
 148  *
 149  * @author Alexander Potochkin
 150  */
 151 @SuppressWarnings("serial") // Superclass is not serializable across versions
 152 public final class JLayer<V extends Component>
 153         extends JComponent
 154         implements Scrollable, PropertyChangeListener, Accessible {
 155     private V view;
 156     // this field is necessary because JComponent.ui is transient
 157     // when layerUI is serializable
 158     private LayerUI<? super V> layerUI;
 159     private JPanel glassPane;
 160     private long eventMask;
 161     private transient boolean isPainting;
 162     private transient boolean isPaintingImmediately;
 163 
 164     private static final LayerEventController eventController =
 165             new LayerEventController();
 166 
 167     /**
 168      * Creates a new {@code JLayer} object with a {@code null} view component
 169      * and default {@link javax.swing.plaf.LayerUI}.
 170      *
 171      * @see #setView
 172      * @see #setUI
 173      */
 174     public JLayer() {
 175         this(null);
 176     }
 177 
 178     /**
 179      * Creates a new {@code JLayer} object
 180      * with default {@link javax.swing.plaf.LayerUI}.
 181      *
 182      * @param view the component to be decorated by this {@code JLayer}
 183      *
 184      * @see #setUI
 185      */
 186     public JLayer(V view) {
 187         this(view, new LayerUI<V>());
 188     }
 189 
 190     /**
 191      * Creates a new {@code JLayer} object with the specified view component
 192      * and {@link javax.swing.plaf.LayerUI} object.
 193      *
 194      * @param view the component to be decorated
 195      * @param ui the {@link javax.swing.plaf.LayerUI} delegate
 196      * to be used by this {@code JLayer}
 197      */
 198     public JLayer(V view, LayerUI<V> ui) {
 199         setGlassPane(createGlassPane());
 200         setView(view);
 201         setUI(ui);
 202     }
 203 
 204     /**
 205      * Returns the {@code JLayer}'s view component or {@code null}.
 206      * <br>This is a bound property.
 207      *
 208      * @return the {@code JLayer}'s view component
 209      *         or {@code null} if none exists
 210      *
 211      * @see #setView(Component)
 212      */
 213     public V getView() {
 214         return view;
 215     }
 216 
 217     /**
 218      * Sets the {@code JLayer}'s view component, which can be {@code null}.
 219      * <br>This is a bound property.
 220      *
 221      * @param view the view component for this {@code JLayer}
 222      *
 223      * @see #getView()
 224      */
 225     public void setView(V view) {
 226         Component oldView = getView();
 227         if (oldView != null) {
 228             super.remove(oldView);
 229         }
 230         if (view != null) {
 231             super.addImpl(view, null, getComponentCount());
 232         }
 233         this.view = view;
 234         firePropertyChange("view", oldView, view);
 235         revalidate();
 236         repaint();
 237     }
 238 
 239     /**
 240      * Sets the {@link javax.swing.plaf.LayerUI} which will perform painting
 241      * and receive input events for this {@code JLayer}.
 242      *
 243      * @param ui the {@link javax.swing.plaf.LayerUI} for this {@code JLayer}
 244      */
 245     public void setUI(LayerUI<? super V> ui) {
 246         this.layerUI = ui;
 247         super.setUI(ui);
 248     }
 249 
 250     /**
 251      * Returns the {@link javax.swing.plaf.LayerUI} for this {@code JLayer}.
 252      *
 253      * @return the {@code LayerUI} for this {@code JLayer}
 254      */
 255     public LayerUI<? super V> getUI() {
 256         return layerUI;
 257     }
 258 
 259     /**
 260      * Returns the {@code JLayer}'s glassPane component or {@code null}.
 261      * <br>This is a bound property.
 262      *
 263      * @return the {@code JLayer}'s glassPane component
 264      *         or {@code null} if none exists
 265      *
 266      * @see #setGlassPane(JPanel)
 267      */
 268     public JPanel getGlassPane() {
 269         return glassPane;
 270     }
 271 
 272     /**
 273      * Sets the {@code JLayer}'s glassPane component, which can be {@code null}.
 274      * <br>This is a bound property.
 275      *
 276      * @param glassPane the glassPane component of this {@code JLayer}
 277      *
 278      * @see #getGlassPane()
 279      */
 280     public void setGlassPane(JPanel glassPane) {
 281         Component oldGlassPane = getGlassPane();
 282         boolean isGlassPaneVisible = false;
 283         if (oldGlassPane != null) {
 284             isGlassPaneVisible = oldGlassPane.isVisible();
 285             super.remove(oldGlassPane);
 286         }
 287         if (glassPane != null) {
 288             AWTAccessor.getComponentAccessor().setMixingCutoutShape(glassPane,
 289                     new Rectangle());
 290             glassPane.setVisible(isGlassPaneVisible);
 291             super.addImpl(glassPane, null, 0);
 292         }
 293         this.glassPane = glassPane;
 294         firePropertyChange("glassPane", oldGlassPane, glassPane);
 295         revalidate();
 296         repaint();
 297     }
 298 
 299     /**
 300      * Called by the constructor methods to create a default {@code glassPane}.
 301      * By default this method creates a new JPanel with visibility set to true
 302      * and opacity set to false.
 303      *
 304      * @return the default {@code glassPane}
 305      */
 306     public JPanel createGlassPane() {
 307         return new DefaultLayerGlassPane();
 308     }
 309 
 310     /**
 311      * Sets the layout manager for this container.  This method is
 312      * overridden to prevent the layout manager from being set.
 313      * <p>Note:  If {@code mgr} is non-{@code null}, this
 314      * method will throw an exception as layout managers are not supported on
 315      * a {@code JLayer}.
 316      *
 317      * @param mgr the specified layout manager
 318      * @exception IllegalArgumentException this method is not supported
 319      */
 320     public void setLayout(LayoutManager mgr) {
 321         if (mgr != null) {
 322             throw new IllegalArgumentException("JLayer.setLayout() not supported");
 323         }
 324     }
 325 
 326     /**
 327      * A non-{@code null} border, or non-zero insets, isn't supported, to prevent the geometry
 328      * of this component from becoming complex enough to inhibit
 329      * subclassing of {@code LayerUI} class.  To create a {@code JLayer} with a border,
 330      * add it to a {@code JPanel} that has a border.
 331      * <p>Note:  If {@code border} is non-{@code null}, this
 332      * method will throw an exception as borders are not supported on
 333      * a {@code JLayer}.
 334      *
 335      * @param border the {@code Border} to set
 336      * @exception IllegalArgumentException this method is not supported
 337      */
 338     public void setBorder(Border border) {
 339         if (border != null) {
 340             throw new IllegalArgumentException("JLayer.setBorder() not supported");
 341         }
 342     }
 343 
 344     /**
 345      * This method is not supported by {@code JLayer}
 346      * and always throws {@code UnsupportedOperationException}
 347      *
 348      * @throws UnsupportedOperationException this method is not supported
 349      *
 350      * @see #setView(Component)
 351      * @see #setGlassPane(JPanel)
 352      */
 353     protected void addImpl(Component comp, Object constraints, int index) {
 354         throw new UnsupportedOperationException(
 355                 "Adding components to JLayer is not supported, " +
 356                         "use setView() or setGlassPane() instead");
 357     }
 358 
 359     /**
 360      * {@inheritDoc}
 361      */
 362     public void remove(Component comp) {
 363         if (comp == null) {
 364             super.remove(comp);
 365         } else if (comp == getView()) {
 366             setView(null);
 367         } else if (comp == getGlassPane()) {
 368             setGlassPane(null);
 369         } else {
 370             super.remove(comp);
 371         }
 372     }
 373 
 374     /**
 375      * {@inheritDoc}
 376      */
 377     public void removeAll() {
 378         if (view != null) {
 379             setView(null);
 380         }
 381         if (glassPane != null) {
 382             setGlassPane(null);
 383         }
 384     }
 385 
 386     /**
 387      * Always returns {@code true} to cause painting to originate from {@code JLayer},
 388      * or one of its ancestors.
 389      *
 390      * @return true
 391      * @see JComponent#isPaintingOrigin()
 392      */
 393     protected boolean isPaintingOrigin() {
 394         return true;
 395     }
 396 
 397     /**
 398      * Delegates its functionality to the
 399      * {@link javax.swing.plaf.LayerUI#paintImmediately(int, int, int, int, JLayer)} method,
 400      * if {@code LayerUI} is set.
 401      *
 402      * @param x  the x value of the region to be painted
 403      * @param y  the y value of the region to be painted
 404      * @param w  the width of the region to be painted
 405      * @param h  the height of the region to be painted
 406      */
 407     public void paintImmediately(int x, int y, int w, int h) {
 408         if (!isPaintingImmediately && getUI() != null) {
 409             isPaintingImmediately = true;
 410             try {
 411                 getUI().paintImmediately(x, y, w, h, this);
 412             } finally {
 413                 isPaintingImmediately = false;
 414             }
 415         } else {
 416             super.paintImmediately(x, y, w, h);
 417         }
 418     }
 419 
 420     /**
 421      * Delegates all painting to the {@link javax.swing.plaf.LayerUI} object.
 422      *
 423      * @param g the {@code Graphics} to render to
 424      */
 425     public void paint(Graphics g) {
 426         if (!isPainting) {
 427             isPainting = true;
 428             try {
 429                 super.paintComponent(g);
 430             } finally {
 431                 isPainting = false;
 432             }
 433         } else {
 434             super.paint(g);
 435         }
 436     }
 437 
 438     /**
 439      * This method is empty, because all painting is done by
 440      * {@link #paint(Graphics)} and
 441      * {@link javax.swing.plaf.LayerUI#update(Graphics, JComponent)} methods
 442      */
 443     protected void paintComponent(Graphics g) {
 444     }
 445 
 446     /**
 447      * The {@code JLayer} overrides the default implementation of
 448      * this method (in {@code JComponent}) to return {@code false}.
 449      * This ensures
 450      * that the drawing machinery will call the {@code JLayer}'s
 451      * {@code paint}
 452      * implementation rather than messaging the {@code JLayer}'s
 453      * children directly.
 454      *
 455      * @return false
 456      */
 457     public boolean isOptimizedDrawingEnabled() {
 458         return false;
 459     }
 460 
 461     /**
 462      * {@inheritDoc}
 463      */
 464     public void propertyChange(PropertyChangeEvent evt) {
 465         if (getUI() != null) {
 466             getUI().applyPropertyChange(evt, this);
 467         }
 468     }
 469 
 470     /**
 471      * Enables the events from JLayer and <b>all its descendants</b>
 472      * defined by the specified event mask parameter
 473      * to be delivered to the
 474      * {@link LayerUI#eventDispatched(AWTEvent, JLayer)} method.
 475      * <p>
 476      * Events are delivered provided that {@code LayerUI} is set
 477      * for this {@code JLayer} and the {@code JLayer}
 478      * is displayable.
 479      * <p>
 480      * The following example shows how to correctly use this method
 481      * in the {@code LayerUI} implementations:
 482      * <pre>
 483      *    public void installUI(JComponent c) {
 484      *       super.installUI(c);
 485      *       JLayer l = (JLayer) c;
 486      *       // this LayerUI will receive only key and focus events
 487      *       l.setLayerEventMask(AWTEvent.KEY_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK);
 488      *    }
 489      *
 490      *    public void uninstallUI(JComponent c) {
 491      *       super.uninstallUI(c);
 492      *       JLayer l = (JLayer) c;
 493      *       // JLayer must be returned to its initial state
 494      *       l.setLayerEventMask(0);
 495      *    }
 496      * </pre>
 497      *
 498      * By default {@code JLayer} receives no events and its event mask is {@code 0}.
 499      *
 500      * @param layerEventMask the bitmask of event types to receive
 501      *
 502      * @see #getLayerEventMask()
 503      * @see LayerUI#eventDispatched(AWTEvent, JLayer)
 504      * @see Component#isDisplayable()
 505      */
 506     public void setLayerEventMask(long layerEventMask) {
 507         long oldEventMask = getLayerEventMask();
 508         this.eventMask = layerEventMask;
 509         firePropertyChange("layerEventMask", oldEventMask, layerEventMask);
 510         if (layerEventMask != oldEventMask) {
 511             disableEvents(oldEventMask);
 512             enableEvents(eventMask);
 513             if (isDisplayable()) {
 514                 eventController.updateAWTEventListener(
 515                         oldEventMask, layerEventMask);
 516             }
 517         }
 518     }
 519 
 520     /**
 521      * Returns the bitmap of event mask to receive by this {@code JLayer}
 522      * and its {@code LayerUI}.
 523      * <p>
 524      * It means that {@link javax.swing.plaf.LayerUI#eventDispatched(AWTEvent, JLayer)} method
 525      * will only receive events that match the event mask.
 526      * <p>
 527      * By default {@code JLayer} receives no events.
 528      *
 529      * @return the bitmask of event types to receive for this {@code JLayer}
 530      */
 531     public long getLayerEventMask() {
 532         return eventMask;
 533     }
 534 
 535     /**
 536      * Delegates its functionality to the {@link javax.swing.plaf.LayerUI#updateUI(JLayer)} method,
 537      * if {@code LayerUI} is set.
 538      */
 539     public void updateUI() {
 540         if (getUI() != null) {
 541             getUI().updateUI(this);
 542         }
 543     }
 544 
 545     /**
 546      * Returns the preferred size of the viewport for a view component.
 547      * <p>
 548      * If the view component of this layer implements {@link Scrollable}, this method delegates its
 549      * implementation to the view component.
 550      *
 551      * @return the preferred size of the viewport for a view component
 552      *
 553      * @see Scrollable
 554      */
 555     public Dimension getPreferredScrollableViewportSize() {
 556         if (getView() instanceof Scrollable) {
 557             return ((Scrollable)getView()).getPreferredScrollableViewportSize();
 558         }
 559         return getPreferredSize();
 560     }
 561 
 562     /**
 563      * Returns a scroll increment, which is required for components
 564      * that display logical rows or columns in order to completely expose
 565      * one block of rows or columns, depending on the value of orientation.
 566      * <p>
 567      * If the view component of this layer implements {@link Scrollable}, this method delegates its
 568      * implementation to the view component.
 569      *
 570      * @return the "block" increment for scrolling in the specified direction
 571      *
 572      * @see Scrollable
 573      */
 574     public int getScrollableBlockIncrement(Rectangle visibleRect,
 575                                            int orientation, int direction) {
 576         if (getView() instanceof Scrollable) {
 577             return ((Scrollable)getView()).getScrollableBlockIncrement(visibleRect,
 578                     orientation, direction);
 579         }
 580         return (orientation == SwingConstants.VERTICAL) ? visibleRect.height :
 581                 visibleRect.width;
 582     }
 583 
 584     /**
 585      * Returns {@code false} to indicate that the height of the viewport does not
 586      * determine the height of the layer, unless the preferred height
 587      * of the layer is smaller than the height of the viewport.
 588      * <p>
 589      * If the view component of this layer implements {@link Scrollable}, this method delegates its
 590      * implementation to the view component.
 591      *
 592      * @return whether the layer should track the height of the viewport
 593      *
 594      * @see Scrollable
 595      */
 596     public boolean getScrollableTracksViewportHeight() {
 597         if (getView() instanceof Scrollable) {
 598             return ((Scrollable)getView()).getScrollableTracksViewportHeight();
 599         }
 600         return false;
 601     }
 602 
 603     /**
 604      * Returns {@code false} to indicate that the width of the viewport does not
 605      * determine the width of the layer, unless the preferred width
 606      * of the layer is smaller than the width of the viewport.
 607      * <p>
 608      * If the view component of this layer implements {@link Scrollable}, this method delegates its
 609      * implementation to the view component.
 610      *
 611      * @return whether the layer should track the width of the viewport
 612      *
 613      * @see Scrollable
 614      */
 615     public boolean getScrollableTracksViewportWidth() {
 616         if (getView() instanceof Scrollable) {
 617             return ((Scrollable)getView()).getScrollableTracksViewportWidth();
 618         }
 619         return false;
 620     }
 621 
 622     /**
 623      * Returns a scroll increment, which is required for components
 624      * that display logical rows or columns in order to completely expose
 625      * one new row or column, depending on the value of orientation.
 626      * Ideally, components should handle a partially exposed row or column
 627      * by returning the distance required to completely expose the item.
 628      * <p>
 629      * Scrolling containers, like {@code JScrollPane}, will use this method
 630      * each time the user requests a unit scroll.
 631      * <p>
 632      * If the view component of this layer implements {@link Scrollable}, this method delegates its
 633      * implementation to the view component.
 634      *
 635      * @return The "unit" increment for scrolling in the specified direction.
 636      *         This value should always be positive.
 637      *
 638      * @see Scrollable
 639      */
 640     public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation,
 641                                           int direction) {
 642         if (getView() instanceof Scrollable) {
 643             return ((Scrollable) getView()).getScrollableUnitIncrement(
 644                     visibleRect, orientation, direction);
 645         }
 646         return 1;
 647     }
 648 
 649     private void readObject(ObjectInputStream s)
 650             throws IOException, ClassNotFoundException {
 651         s.defaultReadObject();
 652         if (layerUI != null) {
 653             setUI(layerUI);
 654         }
 655         if (eventMask != 0) {
 656             eventController.updateAWTEventListener(0, eventMask);
 657         }
 658     }
 659 
 660     /**
 661      * {@inheritDoc}
 662      */
 663     public void addNotify() {
 664         super.addNotify();
 665         eventController.updateAWTEventListener(0, eventMask);
 666     }
 667 
 668     /**
 669      * {@inheritDoc}
 670      */
 671     public void removeNotify() {
 672         super.removeNotify();
 673         eventController.updateAWTEventListener(eventMask, 0);
 674     }
 675 
 676     /**
 677      * Delegates its functionality to the {@link javax.swing.plaf.LayerUI#doLayout(JLayer)} method,
 678      * if {@code LayerUI} is set.
 679      */
 680     public void doLayout() {
 681         if (getUI() != null) {
 682             getUI().doLayout(this);
 683         }
 684     }
 685 
 686     /**
 687      * Gets the AccessibleContext associated with this {@code JLayer}.
 688      *
 689      * @return the AccessibleContext associated with this {@code JLayer}.
 690      */
 691     @SuppressWarnings("serial") // anonymous class
 692     public AccessibleContext getAccessibleContext() {
 693         if (accessibleContext == null) {
 694             accessibleContext = new AccessibleJComponent() {
 695                 public AccessibleRole getAccessibleRole() {
 696                     return AccessibleRole.PANEL;
 697                 }
 698             };
 699         }
 700         return accessibleContext;
 701     }
 702 
 703     /**
 704      * static AWTEventListener to be shared with all AbstractLayerUIs
 705      */
 706     private static class LayerEventController implements AWTEventListener {
 707         private ArrayList<Long> layerMaskList =
 708                 new ArrayList<Long>();
 709 
 710         private long currentEventMask;
 711 
 712         private static final long ACCEPTED_EVENTS =
 713                 AWTEvent.COMPONENT_EVENT_MASK |
 714                         AWTEvent.CONTAINER_EVENT_MASK |
 715                         AWTEvent.FOCUS_EVENT_MASK |
 716                         AWTEvent.KEY_EVENT_MASK |
 717                         AWTEvent.MOUSE_WHEEL_EVENT_MASK |
 718                         AWTEvent.MOUSE_MOTION_EVENT_MASK |
 719                         AWTEvent.MOUSE_EVENT_MASK |
 720                         AWTEvent.INPUT_METHOD_EVENT_MASK |
 721                         AWTEvent.HIERARCHY_EVENT_MASK |
 722                         AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK;
 723 
 724         @SuppressWarnings({"unchecked", "rawtypes"})
 725         public void eventDispatched(AWTEvent event) {
 726             Object source = event.getSource();
 727             if (source instanceof Component) {
 728                 Component component = (Component) source;
 729                 while (component != null) {
 730                     if (component instanceof JLayer) {
 731                         JLayer l = (JLayer) component;
 732                         LayerUI<?> ui = l.getUI();
 733                         if (ui != null &&
 734                                 isEventEnabled(l.getLayerEventMask(), event.getID()) &&
 735                                 (!(event instanceof InputEvent) || !((InputEvent)event).isConsumed())) {
 736                             ui.eventDispatched(event, l);
 737                         }
 738                     }
 739                     component = component.getParent();
 740                 }
 741             }
 742         }
 743 
 744         private void updateAWTEventListener(long oldEventMask, long newEventMask) {
 745             if (oldEventMask != 0) {
 746                 layerMaskList.remove(oldEventMask);
 747             }
 748             if (newEventMask != 0) {
 749                 layerMaskList.add(newEventMask);
 750             }
 751             long combinedMask = 0;
 752             for (Long mask : layerMaskList) {
 753                 combinedMask |= mask;
 754             }
 755             // filter out all unaccepted events
 756             combinedMask &= ACCEPTED_EVENTS;
 757             if (combinedMask == 0) {
 758                 removeAWTEventListener();
 759             } else if (getCurrentEventMask() != combinedMask) {
 760                 removeAWTEventListener();
 761                 addAWTEventListener(combinedMask);
 762             }
 763             currentEventMask = combinedMask;
 764         }
 765 
 766         private long getCurrentEventMask() {
 767             return currentEventMask;
 768         }
 769 
 770         private void addAWTEventListener(final long eventMask) {
 771             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 772                 public Void run() {
 773                     Toolkit.getDefaultToolkit().
 774                             addAWTEventListener(LayerEventController.this, eventMask);
 775                     return null;
 776                 }
 777             });
 778 
 779         }
 780 
 781         private void removeAWTEventListener() {
 782             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 783                 public Void run() {
 784                     Toolkit.getDefaultToolkit().
 785                             removeAWTEventListener(LayerEventController.this);
 786                     return null;
 787                 }
 788             });
 789         }
 790 
 791         private boolean isEventEnabled(long eventMask, int id) {
 792             return (((eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0 &&
 793                     id >= ComponentEvent.COMPONENT_FIRST &&
 794                     id <= ComponentEvent.COMPONENT_LAST)
 795                     || ((eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 &&
 796                     id >= ContainerEvent.CONTAINER_FIRST &&
 797                     id <= ContainerEvent.CONTAINER_LAST)
 798                     || ((eventMask & AWTEvent.FOCUS_EVENT_MASK) != 0 &&
 799                     id >= FocusEvent.FOCUS_FIRST &&
 800                     id <= FocusEvent.FOCUS_LAST)
 801                     || ((eventMask & AWTEvent.KEY_EVENT_MASK) != 0 &&
 802                     id >= KeyEvent.KEY_FIRST &&
 803                     id <= KeyEvent.KEY_LAST)
 804                     || ((eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0 &&
 805                     id == MouseEvent.MOUSE_WHEEL)
 806                     || ((eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0 &&
 807                     (id == MouseEvent.MOUSE_MOVED ||
 808                             id == MouseEvent.MOUSE_DRAGGED))
 809                     || ((eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0 &&
 810                     id != MouseEvent.MOUSE_MOVED &&
 811                     id != MouseEvent.MOUSE_DRAGGED &&
 812                     id != MouseEvent.MOUSE_WHEEL &&
 813                     id >= MouseEvent.MOUSE_FIRST &&
 814                     id <= MouseEvent.MOUSE_LAST)
 815                     || ((eventMask & AWTEvent.INPUT_METHOD_EVENT_MASK) != 0 &&
 816                     id >= InputMethodEvent.INPUT_METHOD_FIRST &&
 817                     id <= InputMethodEvent.INPUT_METHOD_LAST)
 818                     || ((eventMask & AWTEvent.HIERARCHY_EVENT_MASK) != 0 &&
 819                     id == HierarchyEvent.HIERARCHY_CHANGED)
 820                     || ((eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0 &&
 821                     (id == HierarchyEvent.ANCESTOR_MOVED ||
 822                             id == HierarchyEvent.ANCESTOR_RESIZED)));
 823         }
 824     }
 825 
 826     /**
 827      * The default glassPane for the {@link javax.swing.JLayer}.
 828      * It is a subclass of {@code JPanel} which is non opaque by default.
 829      */
 830     @SuppressWarnings("serial") // Superclass is not serializable across versions
 831     private static class DefaultLayerGlassPane extends JPanel {
 832         /**
 833          * Creates a new {@link DefaultLayerGlassPane}
 834          */
 835         public DefaultLayerGlassPane() {
 836             setOpaque(false);
 837         }
 838 
 839         /**
 840          * First, implementation of this method iterates through
 841          * glassPane's child components and returns {@code true}
 842          * if any of them is visible and contains passed x,y point.
 843          * After that it checks if no mouseListeners is attached to this component
 844          * and no mouse cursor is set, then it returns {@code false},
 845          * otherwise calls the super implementation of this method.
 846          *
 847          * @param x the <i>x</i> coordinate of the point
 848          * @param y the <i>y</i> coordinate of the point
 849          * @return true if this component logically contains x,y
 850          */
 851         public boolean contains(int x, int y) {
 852             for (int i = 0; i < getComponentCount(); i++) {
 853                 Component c = getComponent(i);
 854                 Point point = SwingUtilities.convertPoint(this, new Point(x, y), c);
 855                 if(c.isVisible() && c.contains(point)){
 856                     return true;
 857                 }
 858             }
 859             if (getMouseListeners().length == 0
 860                     && getMouseMotionListeners().length == 0
 861                     && getMouseWheelListeners().length == 0
 862                     && !isCursorSet()) {
 863                 return false;
 864             }
 865             return super.contains(x, y);
 866         }
 867     }
 868 }