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<JComponent> 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<JComponent> layerUI = new LayerUI<JComponent>() { 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<? extends JComponent> 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<JComponent>(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 public final class JLayer<V extends Component> 152 extends JComponent 153 implements Scrollable, PropertyChangeListener, Accessible { 154 private V view; 155 // this field is necessary because JComponent.ui is transient 156 // when layerUI is serializable 157 private LayerUI<? super V> layerUI; 158 private JPanel glassPane; 159 private long eventMask; 160 private transient boolean isPainting; 161 private transient boolean isPaintingImmediately; 162 163 private static final LayerEventController eventController = 164 new LayerEventController(); 165 166 /** 167 * Creates a new {@code JLayer} object with a {@code null} view component 168 * and default {@link javax.swing.plaf.LayerUI}. 169 * 170 * @see #setView 171 * @see #setUI 172 */ JLayer()173 public JLayer() { 174 this(null); 175 } 176 177 /** 178 * Creates a new {@code JLayer} object 179 * with default {@link javax.swing.plaf.LayerUI}. 180 * 181 * @param view the component to be decorated by this {@code JLayer} 182 * 183 * @see #setUI 184 */ JLayer(V view)185 public JLayer(V view) { 186 this(view, new LayerUI<V>()); 187 } 188 189 /** 190 * Creates a new {@code JLayer} object with the specified view component 191 * and {@link javax.swing.plaf.LayerUI} object. 192 * 193 * @param view the component to be decorated 194 * @param ui the {@link javax.swing.plaf.LayerUI} delegate 195 * to be used by this {@code JLayer} 196 */ JLayer(V view, LayerUI<V> ui)197 public JLayer(V view, LayerUI<V> ui) { 198 setGlassPane(createGlassPane()); 199 setView(view); 200 setUI(ui); 201 } 202 203 /** 204 * Returns the {@code JLayer}'s view component or {@code null}. 205 * <br>This is a bound property. 206 * 207 * @return the {@code JLayer}'s view component 208 * or {@code null} if none exists 209 * 210 * @see #setView(Component) 211 */ getView()212 public V getView() { 213 return view; 214 } 215 216 /** 217 * Sets the {@code JLayer}'s view component, which can be {@code null}. 218 * <br>This is a bound property. 219 * 220 * @param view the view component for this {@code JLayer} 221 * 222 * @see #getView() 223 */ setView(V view)224 public void setView(V view) { 225 Component oldView = getView(); 226 if (oldView != null) { 227 super.remove(oldView); 228 } 229 if (view != null) { 230 super.addImpl(view, null, getComponentCount()); 231 } 232 this.view = view; 233 firePropertyChange("view", oldView, view); 234 revalidate(); 235 repaint(); 236 } 237 238 /** 239 * Sets the {@link javax.swing.plaf.LayerUI} which will perform painting 240 * and receive input events for this {@code JLayer}. 241 * 242 * @param ui the {@link javax.swing.plaf.LayerUI} for this {@code JLayer} 243 */ setUI(LayerUI<? super V> ui)244 public void setUI(LayerUI<? super V> ui) { 245 this.layerUI = ui; 246 super.setUI(ui); 247 } 248 249 /** 250 * Returns the {@link javax.swing.plaf.LayerUI} for this {@code JLayer}. 251 * 252 * @return the {@code LayerUI} for this {@code JLayer} 253 */ getUI()254 public LayerUI<? super V> getUI() { 255 return layerUI; 256 } 257 258 /** 259 * Returns the {@code JLayer}'s glassPane component or {@code null}. 260 * <br>This is a bound property. 261 * 262 * @return the {@code JLayer}'s glassPane component 263 * or {@code null} if none exists 264 * 265 * @see #setGlassPane(JPanel) 266 */ getGlassPane()267 public JPanel getGlassPane() { 268 return glassPane; 269 } 270 271 /** 272 * Sets the {@code JLayer}'s glassPane component, which can be {@code null}. 273 * <br>This is a bound property. 274 * 275 * @param glassPane the glassPane component of this {@code JLayer} 276 * 277 * @see #getGlassPane() 278 */ setGlassPane(JPanel glassPane)279 public void setGlassPane(JPanel glassPane) { 280 Component oldGlassPane = getGlassPane(); 281 boolean isGlassPaneVisible = false; 282 if (oldGlassPane != null) { 283 isGlassPaneVisible = oldGlassPane.isVisible(); 284 super.remove(oldGlassPane); 285 } 286 if (glassPane != null) { 287 AWTAccessor.getComponentAccessor().setMixingCutoutShape(glassPane, 288 new Rectangle()); 289 glassPane.setVisible(isGlassPaneVisible); 290 super.addImpl(glassPane, null, 0); 291 } 292 this.glassPane = glassPane; 293 firePropertyChange("glassPane", oldGlassPane, glassPane); 294 revalidate(); 295 repaint(); 296 } 297 298 /** 299 * Called by the constructor methods to create a default {@code glassPane}. 300 * By default this method creates a new JPanel with visibility set to true 301 * and opacity set to false. 302 * 303 * @return the default {@code glassPane} 304 */ createGlassPane()305 public JPanel createGlassPane() { 306 return new DefaultLayerGlassPane(); 307 } 308 309 /** 310 * Sets the layout manager for this container. This method is 311 * overridden to prevent the layout manager from being set. 312 * <p>Note: If {@code mgr} is non-{@code null}, this 313 * method will throw an exception as layout managers are not supported on 314 * a {@code JLayer}. 315 * 316 * @param mgr the specified layout manager 317 * @exception IllegalArgumentException this method is not supported 318 */ setLayout(LayoutManager mgr)319 public void setLayout(LayoutManager mgr) { 320 if (mgr != null) { 321 throw new IllegalArgumentException("JLayer.setLayout() not supported"); 322 } 323 } 324 325 /** 326 * A non-{@code null} border, or non-zero insets, isn't supported, to prevent the geometry 327 * of this component from becoming complex enough to inhibit 328 * subclassing of {@code LayerUI} class. To create a {@code JLayer} with a border, 329 * add it to a {@code JPanel} that has a border. 330 * <p>Note: If {@code border} is non-{@code null}, this 331 * method will throw an exception as borders are not supported on 332 * a {@code JLayer}. 333 * 334 * @param border the {@code Border} to set 335 * @exception IllegalArgumentException this method is not supported 336 */ setBorder(Border border)337 public void setBorder(Border border) { 338 if (border != null) { 339 throw new IllegalArgumentException("JLayer.setBorder() not supported"); 340 } 341 } 342 343 /** 344 * This method is not supported by {@code JLayer} 345 * and always throws {@code UnsupportedOperationException} 346 * 347 * @throws UnsupportedOperationException this method is not supported 348 * 349 * @see #setView(Component) 350 * @see #setGlassPane(JPanel) 351 */ addImpl(Component comp, Object constraints, int index)352 protected void addImpl(Component comp, Object constraints, int index) { 353 throw new UnsupportedOperationException( 354 "Adding components to JLayer is not supported, " + 355 "use setView() or setGlassPane() instead"); 356 } 357 358 /** 359 * {@inheritDoc} 360 */ remove(Component comp)361 public void remove(Component comp) { 362 if (comp == null) { 363 super.remove(comp); 364 } else if (comp == getView()) { 365 setView(null); 366 } else if (comp == getGlassPane()) { 367 setGlassPane(null); 368 } else { 369 super.remove(comp); 370 } 371 } 372 373 /** 374 * {@inheritDoc} 375 */ removeAll()376 public void removeAll() { 377 if (view != null) { 378 setView(null); 379 } 380 if (glassPane != null) { 381 setGlassPane(null); 382 } 383 } 384 385 /** 386 * Always returns {@code true} to cause painting to originate from {@code JLayer}, 387 * or one of its ancestors. 388 * 389 * @return true 390 * @see JComponent#isPaintingOrigin() 391 */ isPaintingOrigin()392 protected boolean isPaintingOrigin() { 393 return true; 394 } 395 396 /** 397 * Delegates its functionality to the 398 * {@link javax.swing.plaf.LayerUI#paintImmediately(int, int, int, int, JLayer)} method, 399 * if {@code LayerUI} is set. 400 * 401 * @param x the x value of the region to be painted 402 * @param y the y value of the region to be painted 403 * @param w the width of the region to be painted 404 * @param h the height of the region to be painted 405 */ paintImmediately(int x, int y, int w, int h)406 public void paintImmediately(int x, int y, int w, int h) { 407 if (!isPaintingImmediately && getUI() != null) { 408 isPaintingImmediately = true; 409 try { 410 getUI().paintImmediately(x, y, w, h, this); 411 } finally { 412 isPaintingImmediately = false; 413 } 414 } else { 415 super.paintImmediately(x, y, w, h); 416 } 417 } 418 419 /** 420 * Delegates all painting to the {@link javax.swing.plaf.LayerUI} object. 421 * 422 * @param g the {@code Graphics} to render to 423 */ paint(Graphics g)424 public void paint(Graphics g) { 425 if (!isPainting) { 426 isPainting = true; 427 try { 428 super.paintComponent(g); 429 } finally { 430 isPainting = false; 431 } 432 } else { 433 super.paint(g); 434 } 435 } 436 437 /** 438 * This method is empty, because all painting is done by 439 * {@link #paint(Graphics)} and 440 * {@link javax.swing.plaf.LayerUI#update(Graphics, JComponent)} methods 441 */ paintComponent(Graphics g)442 protected void paintComponent(Graphics g) { 443 } 444 445 /** 446 * The {@code JLayer} overrides the default implementation of 447 * this method (in {@code JComponent}) to return {@code false}. 448 * This ensures 449 * that the drawing machinery will call the {@code JLayer}'s 450 * {@code paint} 451 * implementation rather than messaging the {@code JLayer}'s 452 * children directly. 453 * 454 * @return false 455 */ isOptimizedDrawingEnabled()456 public boolean isOptimizedDrawingEnabled() { 457 return false; 458 } 459 460 /** 461 * {@inheritDoc} 462 */ propertyChange(PropertyChangeEvent evt)463 public void propertyChange(PropertyChangeEvent evt) { 464 if (getUI() != null) { 465 getUI().applyPropertyChange(evt, this); 466 } 467 } 468 469 /** 470 * Enables the events from JLayer and <b>all its descendants</b> 471 * defined by the specified event mask parameter 472 * to be delivered to the 473 * {@link LayerUI#eventDispatched(AWTEvent, JLayer)} method. 474 * <p> 475 * Events are delivered provided that {@code LayerUI} is set 476 * for this {@code JLayer} and the {@code JLayer} 477 * is displayable. 478 * <p> 479 * The following example shows how to correctly use this method 480 * in the {@code LayerUI} implementations: 481 * <pre> 482 * public void installUI(JComponent c) { 483 * super.installUI(c); 484 * JLayer l = (JLayer) c; 485 * // this LayerUI will receive only key and focus events 486 * l.setLayerEventMask(AWTEvent.KEY_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK); 487 * } 488 * 489 * public void uninstallUI(JComponent c) { 490 * super.uninstallUI(c); 491 * JLayer l = (JLayer) c; 492 * // JLayer must be returned to its initial state 493 * l.setLayerEventMask(0); 494 * } 495 * </pre> 496 * 497 * By default {@code JLayer} receives no events and its event mask is {@code 0}. 498 * 499 * @param layerEventMask the bitmask of event types to receive 500 * 501 * @see #getLayerEventMask() 502 * @see LayerUI#eventDispatched(AWTEvent, JLayer) 503 * @see Component#isDisplayable() 504 */ setLayerEventMask(long layerEventMask)505 public void setLayerEventMask(long layerEventMask) { 506 long oldEventMask = getLayerEventMask(); 507 this.eventMask = layerEventMask; 508 firePropertyChange("layerEventMask", oldEventMask, layerEventMask); 509 if (layerEventMask != oldEventMask) { 510 disableEvents(oldEventMask); 511 enableEvents(eventMask); 512 if (isDisplayable()) { 513 eventController.updateAWTEventListener( 514 oldEventMask, layerEventMask); 515 } 516 } 517 } 518 519 /** 520 * Returns the bitmap of event mask to receive by this {@code JLayer} 521 * and its {@code LayerUI}. 522 * <p> 523 * It means that {@link javax.swing.plaf.LayerUI#eventDispatched(AWTEvent, JLayer)} method 524 * will only receive events that match the event mask. 525 * <p> 526 * By default {@code JLayer} receives no events. 527 * 528 * @return the bitmask of event types to receive for this {@code JLayer} 529 */ getLayerEventMask()530 public long getLayerEventMask() { 531 return eventMask; 532 } 533 534 /** 535 * Delegates its functionality to the {@link javax.swing.plaf.LayerUI#updateUI(JLayer)} method, 536 * if {@code LayerUI} is set. 537 */ updateUI()538 public void updateUI() { 539 if (getUI() != null) { 540 getUI().updateUI(this); 541 } 542 } 543 544 /** 545 * Returns the preferred size of the viewport for a view component. 546 * <p> 547 * If the view component of this layer implements {@link Scrollable}, this method delegates its 548 * implementation to the view component. 549 * 550 * @return the preferred size of the viewport for a view component 551 * 552 * @see Scrollable 553 */ getPreferredScrollableViewportSize()554 public Dimension getPreferredScrollableViewportSize() { 555 if (getView() instanceof Scrollable) { 556 return ((Scrollable)getView()).getPreferredScrollableViewportSize(); 557 } 558 return getPreferredSize(); 559 } 560 561 /** 562 * Returns a scroll increment, which is required for components 563 * that display logical rows or columns in order to completely expose 564 * one block of rows or columns, depending on the value of orientation. 565 * <p> 566 * If the view component of this layer implements {@link Scrollable}, this method delegates its 567 * implementation to the view component. 568 * 569 * @return the "block" increment for scrolling in the specified direction 570 * 571 * @see Scrollable 572 */ getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction)573 public int getScrollableBlockIncrement(Rectangle visibleRect, 574 int orientation, int direction) { 575 if (getView() instanceof Scrollable) { 576 return ((Scrollable)getView()).getScrollableBlockIncrement(visibleRect, 577 orientation, direction); 578 } 579 return (orientation == SwingConstants.VERTICAL) ? visibleRect.height : 580 visibleRect.width; 581 } 582 583 /** 584 * Returns {@code false} to indicate that the height of the viewport does not 585 * determine the height of the layer, unless the preferred height 586 * of the layer is smaller than the height of the viewport. 587 * <p> 588 * If the view component of this layer implements {@link Scrollable}, this method delegates its 589 * implementation to the view component. 590 * 591 * @return whether the layer should track the height of the viewport 592 * 593 * @see Scrollable 594 */ getScrollableTracksViewportHeight()595 public boolean getScrollableTracksViewportHeight() { 596 if (getView() instanceof Scrollable) { 597 return ((Scrollable)getView()).getScrollableTracksViewportHeight(); 598 } 599 return false; 600 } 601 602 /** 603 * Returns {@code false} to indicate that the width of the viewport does not 604 * determine the width of the layer, unless the preferred width 605 * of the layer is smaller than the width of the viewport. 606 * <p> 607 * If the view component of this layer implements {@link Scrollable}, this method delegates its 608 * implementation to the view component. 609 * 610 * @return whether the layer should track the width of the viewport 611 * 612 * @see Scrollable 613 */ getScrollableTracksViewportWidth()614 public boolean getScrollableTracksViewportWidth() { 615 if (getView() instanceof Scrollable) { 616 return ((Scrollable)getView()).getScrollableTracksViewportWidth(); 617 } 618 return false; 619 } 620 621 /** 622 * Returns a scroll increment, which is required for components 623 * that display logical rows or columns in order to completely expose 624 * one new row or column, depending on the value of orientation. 625 * Ideally, components should handle a partially exposed row or column 626 * by returning the distance required to completely expose the item. 627 * <p> 628 * Scrolling containers, like {@code JScrollPane}, will use this method 629 * each time the user requests a unit scroll. 630 * <p> 631 * If the view component of this layer implements {@link Scrollable}, this method delegates its 632 * implementation to the view component. 633 * 634 * @return The "unit" increment for scrolling in the specified direction. 635 * This value should always be positive. 636 * 637 * @see Scrollable 638 */ getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction)639 public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, 640 int direction) { 641 if (getView() instanceof Scrollable) { 642 return ((Scrollable) getView()).getScrollableUnitIncrement( 643 visibleRect, orientation, direction); 644 } 645 return 1; 646 } 647 readObject(ObjectInputStream s)648 private void readObject(ObjectInputStream s) 649 throws IOException, ClassNotFoundException { 650 s.defaultReadObject(); 651 if (layerUI != null) { 652 setUI(layerUI); 653 } 654 if (eventMask != 0) { 655 eventController.updateAWTEventListener(0, eventMask); 656 } 657 } 658 659 /** 660 * {@inheritDoc} 661 */ addNotify()662 public void addNotify() { 663 super.addNotify(); 664 eventController.updateAWTEventListener(0, eventMask); 665 } 666 667 /** 668 * {@inheritDoc} 669 */ removeNotify()670 public void removeNotify() { 671 super.removeNotify(); 672 eventController.updateAWTEventListener(eventMask, 0); 673 } 674 675 /** 676 * Delegates its functionality to the {@link javax.swing.plaf.LayerUI#doLayout(JLayer)} method, 677 * if {@code LayerUI} is set. 678 */ doLayout()679 public void doLayout() { 680 if (getUI() != null) { 681 getUI().doLayout(this); 682 } 683 } 684 685 /** 686 * Gets the AccessibleContext associated with this {@code JLayer}. 687 * 688 * @return the AccessibleContext associated with this {@code JLayer}. 689 */ getAccessibleContext()690 public AccessibleContext getAccessibleContext() { 691 if (accessibleContext == null) { 692 accessibleContext = new AccessibleJComponent() { 693 public AccessibleRole getAccessibleRole() { 694 return AccessibleRole.PANEL; 695 } 696 }; 697 } 698 return accessibleContext; 699 } 700 701 /** 702 * static AWTEventListener to be shared with all AbstractLayerUIs 703 */ 704 private static class LayerEventController implements AWTEventListener { 705 private ArrayList<Long> layerMaskList = 706 new ArrayList<Long>(); 707 708 private long currentEventMask; 709 710 private static final long ACCEPTED_EVENTS = 711 AWTEvent.COMPONENT_EVENT_MASK | 712 AWTEvent.CONTAINER_EVENT_MASK | 713 AWTEvent.FOCUS_EVENT_MASK | 714 AWTEvent.KEY_EVENT_MASK | 715 AWTEvent.MOUSE_WHEEL_EVENT_MASK | 716 AWTEvent.MOUSE_MOTION_EVENT_MASK | 717 AWTEvent.MOUSE_EVENT_MASK | 718 AWTEvent.INPUT_METHOD_EVENT_MASK | 719 AWTEvent.HIERARCHY_EVENT_MASK | 720 AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK; 721 722 @SuppressWarnings("unchecked") eventDispatched(AWTEvent event)723 public void eventDispatched(AWTEvent event) { 724 Object source = event.getSource(); 725 if (source instanceof Component) { 726 Component component = (Component) source; 727 while (component != null) { 728 if (component instanceof JLayer) { 729 JLayer l = (JLayer) component; 730 LayerUI ui = l.getUI(); 731 if (ui != null && 732 isEventEnabled(l.getLayerEventMask(), event.getID()) && 733 (!(event instanceof InputEvent) || !((InputEvent)event).isConsumed())) { 734 ui.eventDispatched(event, l); 735 } 736 } 737 component = component.getParent(); 738 } 739 } 740 } 741 updateAWTEventListener(long oldEventMask, long newEventMask)742 private void updateAWTEventListener(long oldEventMask, long newEventMask) { 743 if (oldEventMask != 0) { 744 layerMaskList.remove(oldEventMask); 745 } 746 if (newEventMask != 0) { 747 layerMaskList.add(newEventMask); 748 } 749 long combinedMask = 0; 750 for (Long mask : layerMaskList) { 751 combinedMask |= mask; 752 } 753 // filter out all unaccepted events 754 combinedMask &= ACCEPTED_EVENTS; 755 if (combinedMask == 0) { 756 removeAWTEventListener(); 757 } else if (getCurrentEventMask() != combinedMask) { 758 removeAWTEventListener(); 759 addAWTEventListener(combinedMask); 760 } 761 currentEventMask = combinedMask; 762 } 763 getCurrentEventMask()764 private long getCurrentEventMask() { 765 return currentEventMask; 766 } 767 addAWTEventListener(final long eventMask)768 private void addAWTEventListener(final long eventMask) { 769 AccessController.doPrivileged(new PrivilegedAction<Void>() { 770 public Void run() { 771 Toolkit.getDefaultToolkit(). 772 addAWTEventListener(LayerEventController.this, eventMask); 773 return null; 774 } 775 }); 776 777 } 778 removeAWTEventListener()779 private void removeAWTEventListener() { 780 AccessController.doPrivileged(new PrivilegedAction<Void>() { 781 public Void run() { 782 Toolkit.getDefaultToolkit(). 783 removeAWTEventListener(LayerEventController.this); 784 return null; 785 } 786 }); 787 } 788 isEventEnabled(long eventMask, int id)789 private boolean isEventEnabled(long eventMask, int id) { 790 return (((eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0 && 791 id >= ComponentEvent.COMPONENT_FIRST && 792 id <= ComponentEvent.COMPONENT_LAST) 793 || ((eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 && 794 id >= ContainerEvent.CONTAINER_FIRST && 795 id <= ContainerEvent.CONTAINER_LAST) 796 || ((eventMask & AWTEvent.FOCUS_EVENT_MASK) != 0 && 797 id >= FocusEvent.FOCUS_FIRST && 798 id <= FocusEvent.FOCUS_LAST) 799 || ((eventMask & AWTEvent.KEY_EVENT_MASK) != 0 && 800 id >= KeyEvent.KEY_FIRST && 801 id <= KeyEvent.KEY_LAST) 802 || ((eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0 && 803 id == MouseEvent.MOUSE_WHEEL) 804 || ((eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0 && 805 (id == MouseEvent.MOUSE_MOVED || 806 id == MouseEvent.MOUSE_DRAGGED)) 807 || ((eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0 && 808 id != MouseEvent.MOUSE_MOVED && 809 id != MouseEvent.MOUSE_DRAGGED && 810 id != MouseEvent.MOUSE_WHEEL && 811 id >= MouseEvent.MOUSE_FIRST && 812 id <= MouseEvent.MOUSE_LAST) 813 || ((eventMask & AWTEvent.INPUT_METHOD_EVENT_MASK) != 0 && 814 id >= InputMethodEvent.INPUT_METHOD_FIRST && 815 id <= InputMethodEvent.INPUT_METHOD_LAST) 816 || ((eventMask & AWTEvent.HIERARCHY_EVENT_MASK) != 0 && 817 id == HierarchyEvent.HIERARCHY_CHANGED) 818 || ((eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0 && 819 (id == HierarchyEvent.ANCESTOR_MOVED || 820 id == HierarchyEvent.ANCESTOR_RESIZED))); 821 } 822 } 823 824 /** 825 * The default glassPane for the {@link javax.swing.JLayer}. 826 * It is a subclass of {@code JPanel} which is non opaque by default. 827 */ 828 private static class DefaultLayerGlassPane extends JPanel { 829 /** 830 * Creates a new {@link DefaultLayerGlassPane} 831 */ DefaultLayerGlassPane()832 public DefaultLayerGlassPane() { 833 setOpaque(false); 834 } 835 836 /** 837 * First, implementation of this method iterates through 838 * glassPane's child components and returns {@code true} 839 * if any of them is visible and contains passed x,y point. 840 * After that it checks if no mouseListeners is attached to this component 841 * and no mouse cursor is set, then it returns {@code false}, 842 * otherwise calls the super implementation of this method. 843 * 844 * @param x the <i>x</i> coordinate of the point 845 * @param y the <i>y</i> coordinate of the point 846 * @return true if this component logically contains x,y 847 */ contains(int x, int y)848 public boolean contains(int x, int y) { 849 for (int i = 0; i < getComponentCount(); i++) { 850 Component c = getComponent(i); 851 Point point = SwingUtilities.convertPoint(this, new Point(x, y), c); 852 if(c.isVisible() && c.contains(point)){ 853 return true; 854 } 855 } 856 if (getMouseListeners().length == 0 857 && getMouseMotionListeners().length == 0 858 && getMouseWheelListeners().length == 0 859 && !isCursorSet()) { 860 return false; 861 } 862 return super.contains(x, y); 863 } 864 } 865 } 866