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 @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 }