/[classpath]/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java
ViewVC logotype

Diff of /classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.8 by rabbit78, Wed May 11 15:13:02 2005 UTC revision 1.9 by fitzsim, Wed May 18 16:02:19 2005 UTC
# Line 37  exception statement from your version. * Line 37  exception statement from your version. *
37    
38  package javax.swing.plaf.basic;  package javax.swing.plaf.basic;
39    
40    import java.awt.AWTEvent;
41  import java.awt.Component;  import java.awt.Component;
42  import java.awt.Container;  import java.awt.Container;
43    import java.awt.Cursor;
44  import java.awt.Dimension;  import java.awt.Dimension;
45    import java.awt.Point;
46  import java.awt.event.ComponentEvent;  import java.awt.event.ComponentEvent;
47  import java.awt.event.ComponentListener;  import java.awt.event.ComponentListener;
48  import java.awt.event.MouseEvent;  import java.awt.event.MouseEvent;
49    
50  import javax.swing.BoxLayout;  import javax.swing.BoxLayout;
51  import javax.swing.JComponent;  import javax.swing.JComponent;
52    import javax.swing.JLayeredPane;
53    import javax.swing.JMenu;
54  import javax.swing.JPopupMenu;  import javax.swing.JPopupMenu;
55  import javax.swing.MenuElement;  import javax.swing.MenuElement;
56  import javax.swing.MenuSelectionManager;  import javax.swing.MenuSelectionManager;
57    import javax.swing.RootPaneContainer;
58  import javax.swing.SwingUtilities;  import javax.swing.SwingUtilities;
59  import javax.swing.UIDefaults;  import javax.swing.UIDefaults;
60  import javax.swing.UIManager;  import javax.swing.UIManager;
# Line 83  public class BasicPopupMenuUI extends Po Line 89  public class BasicPopupMenuUI extends Po
89    public BasicPopupMenuUI()    public BasicPopupMenuUI()
90    {    {
91      popupMenuListener = new PopupMenuHandler();      popupMenuListener = new PopupMenuHandler();
     mouseInputListener = new MouseInputHandler();  
92      topWindowListener = new TopWindowListener();      topWindowListener = new TopWindowListener();
93    }    }
94    
# Line 120  public class BasicPopupMenuUI extends Po Line 125  public class BasicPopupMenuUI extends Po
125    }    }
126    
127    /**    /**
128     * This method installs the defaults that are defined in  the Basic look and     * This method installs the defaults that are defined in  the Basic look
129     * feel for this {@link JPopupMenu}.     * and feel for this {@link JPopupMenu}.
130     */     */
131    public void installDefaults()    public void installDefaults()
132    {    {
# Line 139  public class BasicPopupMenuUI extends Po Line 144  public class BasicPopupMenuUI extends Po
144     */     */
145    protected void installListeners()    protected void installListeners()
146    {    {
     popupMenu.addMouseListener(mouseInputListener);  
     popupMenu.addMouseMotionListener(mouseInputListener);  
147      popupMenu.addPopupMenuListener(popupMenuListener);      popupMenu.addPopupMenuListener(popupMenuListener);
148    }    }
149    
# Line 183  public class BasicPopupMenuUI extends Po Line 186  public class BasicPopupMenuUI extends Po
186     */     */
187    protected void uninstallListeners()    protected void uninstallListeners()
188    {    {
     popupMenu.removeMouseListener(mouseInputListener);  
     popupMenu.removeMouseMotionListener(mouseInputListener);  
189      popupMenu.removePopupMenuListener(popupMenuListener);      popupMenu.removePopupMenuListener(popupMenuListener);
190    }    }
191    
# Line 273  public class BasicPopupMenuUI extends Po Line 274  public class BasicPopupMenuUI extends Po
274        // by the top - level window that this popup belongs to.        // by the top - level window that this popup belongs to.
275        Component invoker = popupMenu.getInvoker();        Component invoker = popupMenu.getInvoker();
276    
277        Container rootContainer = (Container) SwingUtilities.getRoot(invoker);        RootPaneContainer rootContainer = (RootPaneContainer) SwingUtilities
278        rootContainer.removeComponentListener(topWindowListener);                                          .getRoot(invoker);
279          ((Container) rootContainer).removeComponentListener(topWindowListener);
280    
281          // If this popup menu is the last popup menu visible on the screen, then
282          // stop interrupting mouse events in the glass pane before hiding this
283          // last popup menu.
284          boolean topLevelMenu = (popupMenu.getInvoker() instanceof JMenu)
285                                 && ((JMenu) popupMenu.getInvoker())
286                                    .isTopLevelMenu();
287    
288          if (topLevelMenu || ! (popupMenu.getInvoker() instanceof MenuElement))
289            {
290              // set glass pane not to interrupt mouse events and remove
291              // mouseInputListener
292              Container glassPane = (Container) rootContainer.getGlassPane();
293              glassPane.setVisible(false);
294              glassPane.removeMouseListener(mouseInputListener);
295              mouseInputListener = null;
296            }
297      }      }
298    
299      /**      /**
# Line 288  public class BasicPopupMenuUI extends Po Line 307  public class BasicPopupMenuUI extends Po
307        // ComponentEvents fired by it. We need to cancel this popup menu        // ComponentEvents fired by it. We need to cancel this popup menu
308        // if topWindow to which this popup belongs was resized or moved.        // if topWindow to which this popup belongs was resized or moved.
309        Component invoker = popupMenu.getInvoker();        Component invoker = popupMenu.getInvoker();
310        Container rootContainer = (Container) SwingUtilities.getRoot(invoker);        RootPaneContainer rootContainer = (RootPaneContainer) SwingUtilities
311        rootContainer.addComponentListener(topWindowListener);                                          .getRoot(invoker);
312          ((Container) rootContainer).addComponentListener(topWindowListener);
313    
314          // Set the glass pane to interrupt all mouse events originating in root
315          // container
316          if (mouseInputListener == null)
317            {
318              Container glassPane = (Container) rootContainer.getGlassPane();
319              glassPane.setVisible(true);
320              mouseInputListener = new MouseInputHandler(rootContainer);
321              glassPane.addMouseListener(mouseInputListener);
322              glassPane.addMouseMotionListener(mouseInputListener);
323            }
324    
325        // if this popup menu is a free floating popup menu,        // if this popup menu is a free floating popup menu,
326        // then by default its first element should be always selected when        // then by default its first element should be always selected when
# Line 344  public class BasicPopupMenuUI extends Po Line 375  public class BasicPopupMenuUI extends Po
375      }      }
376    
377      /**      /**
378       * This method is invoked when top-level window is shown This method does       * This method is invoked when top-level window is shown This method
379       * nothing by default.       * does nothing by default.
380       *       *
381       * @param e The ComponentEvent       * @param e The ComponentEvent
382       */       */
# Line 368  public class BasicPopupMenuUI extends Po Line 399  public class BasicPopupMenuUI extends Po
399      }      }
400    }    }
401    
402      /**
403       * MouseInputHandler listens to all mouse events originated in the root
404       * container. This class is responsible for closing menu hierarchy when the
405       * user presses mouse over any component that do not belong to the current
406       * menu hierarchy. This is acomplished by interrupting all mouse event in
407       * the glass pane and checking if other component was pressed while menu
408       * was open, before redestributing events further to intended components
409       */
410    private class MouseInputHandler implements MouseInputListener    private class MouseInputHandler implements MouseInputListener
411    {    {
412        private JLayeredPane layeredPane;
413        private Container glassPane;
414        private Cursor nativeCursor;
415        private transient Component mouseEventTarget;
416        private transient Component pressedComponent;
417        private transient Component lastComponentEntered;
418        private transient int pressCount;
419    
420        /**
421         * Creates a new MouseInputHandler object.
422         *
423         * @param c the top most root container
424         */
425        public MouseInputHandler(RootPaneContainer c)
426        {
427          layeredPane = c.getLayeredPane();
428          glassPane = (Container) c.getGlassPane();
429        }
430    
431        /**
432         * Handles mouse clicked event
433         *
434         * @param e Mouse event
435         */
436      public void mouseClicked(MouseEvent e)      public void mouseClicked(MouseEvent e)
437      {      {
438          handleEvent(e);
439      }      }
440    
441        /**
442         * Handles mouseDragged event
443         *
444         * @param e MouseEvent
445         */
446      public void mouseDragged(MouseEvent e)      public void mouseDragged(MouseEvent e)
447      {      {
448          handleEvent(e);
449      }      }
450    
451        /**
452         * Handles mouseEntered event
453         *
454         * @param e MouseEvent
455         */
456      public void mouseEntered(MouseEvent e)      public void mouseEntered(MouseEvent e)
457      {      {
458          handleEvent(e);
459      }      }
460    
461        /**
462         * Handles mouseExited event
463         *
464         * @param e MouseEvent
465         */
466      public void mouseExited(MouseEvent e)      public void mouseExited(MouseEvent e)
467      {      {
468          handleEvent(e);
469      }      }
470    
471        /**
472         * Handles mouse moved event
473         *
474         * @param e MouseEvent
475         */
476      public void mouseMoved(MouseEvent e)      public void mouseMoved(MouseEvent e)
477      {      {
478          handleEvent(e);
479      }      }
480    
481        /**
482         * Handles mouse pressed event
483         *
484         * @param e MouseEvent
485         */
486      public void mousePressed(MouseEvent e)      public void mousePressed(MouseEvent e)
487      {      {
488          handleEvent(e);
489      }      }
490    
491        /**
492         * Handles mouse released event
493         *
494         * @param e MouseEvent
495         */
496      public void mouseReleased(MouseEvent e)      public void mouseReleased(MouseEvent e)
497      {      {
498          handleEvent(e);
499        }
500    
501        /*
502         * This method determines component that was intended to received mouse
503         * event, before it was interrupted within the glass pane. This method
504         * also redispatches mouse entered and mouse exited events to the
505         * appropriate components. This code is slightly modified code from
506         * Container.LightweightDispatcher class, which is private inside
507         * Container class and cannot be used here.
508         */
509        public void acquireComponentForMouseEvent(MouseEvent me)
510        {
511          int x = me.getX();
512          int y = me.getY();
513    
514          // Find the candidate which should receive this event.
515          Component parent = layeredPane;
516          Component candidate = null;
517          Point p = me.getPoint();
518          while ((candidate == null) && (parent != null))
519            {
520              p = SwingUtilities.convertPoint(glassPane, p.x, p.y, parent);
521              candidate = SwingUtilities.getDeepestComponentAt(parent, p.x, p.y);
522    
523              if (candidate == null)
524                {
525                  p = SwingUtilities.convertPoint(parent, p.x, p.y,
526                                                  parent.getParent());
527                  parent = parent.getParent();
528                }
529            }
530    
531          // If the only candidate we found was the native container itself,
532          // don't dispatch any event at all.  We only care about the lightweight
533          // children here.
534          if (candidate == layeredPane)
535            candidate = null;
536    
537          // If our candidate is new, inform the old target we're leaving.
538          if ((lastComponentEntered != null) && lastComponentEntered.isShowing()
539              && (lastComponentEntered != candidate))
540            {
541              // Old candidate could have been removed from
542              // the layeredPane so we check first.
543              if (SwingUtilities.isDescendingFrom(lastComponentEntered, layeredPane))
544                {
545                  Point tp = SwingUtilities.convertPoint(layeredPane, x, y,
546                                                         lastComponentEntered);
547                  MouseEvent exited = new MouseEvent(lastComponentEntered,
548                                                     MouseEvent.MOUSE_EXITED,
549                                                     me.getWhen(),
550                                                     me.getModifiersEx(), tp.x,
551                                                     tp.y, me.getClickCount(),
552                                                     me.isPopupTrigger(),
553                                                     me.getButton());
554    
555                  lastComponentEntered.dispatchEvent(exited);
556                }
557    
558              lastComponentEntered = null;
559            }
560    
561          // If we have a candidate, maybe enter it.
562          if (candidate != null)
563            {
564              mouseEventTarget = candidate;
565    
566              if (candidate.isLightweight() && candidate.isShowing()
567                  && (candidate != layeredPane)
568                  && (candidate != lastComponentEntered))
569                {
570                  lastComponentEntered = mouseEventTarget;
571    
572                  Point cp = SwingUtilities.convertPoint(layeredPane, x, y,
573                                                         lastComponentEntered);
574                  MouseEvent entered = new MouseEvent(lastComponentEntered,
575                                                      MouseEvent.MOUSE_ENTERED,
576                                                      me.getWhen(),
577                                                      me.getModifiersEx(), cp.x,
578                                                      cp.y, me.getClickCount(),
579                                                      me.isPopupTrigger(),
580                                                      me.getButton());
581                  lastComponentEntered.dispatchEvent(entered);
582                }
583            }
584    
585          if ((me.getID() == MouseEvent.MOUSE_RELEASED)
586              || ((me.getID() == MouseEvent.MOUSE_PRESSED) && (pressCount > 0))
587              || (me.getID() == MouseEvent.MOUSE_DRAGGED))
588            {
589              // If any of the following events occur while a button is held down,
590              // they should be dispatched to the same component to which the
591              // original MOUSE_PRESSED event was dispatched:
592              //   - MOUSE_RELEASED
593              //   - MOUSE_PRESSED: another button pressed while the first is held down
594              //   - MOUSE_DRAGGED
595              if (SwingUtilities.isDescendingFrom(pressedComponent, layeredPane))
596                mouseEventTarget = pressedComponent;
597              else if (me.getID() == MouseEvent.MOUSE_CLICKED)
598                {
599                  // Don't dispatch CLICKED events whose target is not the same as the
600                  // target for the original PRESSED event.
601                  if (candidate != pressedComponent)
602                    mouseEventTarget = null;
603                  else if (pressCount == 0)
604                    pressedComponent = null;
605                }
606            }
607        }
608    
609        /*
610         * This method handles mouse events interrupted by glassPane. It
611         * redispatches the mouse events appropriately to the intended components.
612         * The code in this method is also taken from
613         * Container.LightweightDispatcher class. The code is slightly modified
614         * to handle the case when mouse is released over non-menu component. In
615         * this case this method closes current menu hierarchy before
616         * redispatching the event further.
617         */
618        public void handleEvent(AWTEvent e)
619        {
620          if (e instanceof MouseEvent)
621            {
622              MouseEvent me = (MouseEvent) e;
623    
624              acquireComponentForMouseEvent(me);
625    
626              // Avoid dispatching ENTERED and EXITED events twice.
627              if (mouseEventTarget != null && mouseEventTarget.isShowing()
628                  && (e.getID() != MouseEvent.MOUSE_ENTERED)
629                  && (e.getID() != MouseEvent.MOUSE_EXITED))
630                {
631                  MouseEvent newEvt = SwingUtilities.convertMouseEvent(glassPane,
632                                                                       me,
633                                                                       mouseEventTarget);
634    
635                  mouseEventTarget.dispatchEvent(newEvt);
636    
637                  // If mouse was clicked over the component that is not part
638                  // of menu hierarchy,then must close the menu hierarchy */
639                  if (e.getID() == MouseEvent.MOUSE_RELEASED)
640                    {
641                      boolean partOfMenuHierarchy = false;
642                      MenuSelectionManager manager = MenuSelectionManager
643                                                     .defaultManager();
644    
645                      partOfMenuHierarchy = manager.isComponentPartOfCurrentMenu(mouseEventTarget);
646    
647                      if (! partOfMenuHierarchy)
648                        manager.clearSelectedPath();
649                    }
650    
651                  switch (e.getID())
652                    {
653                    case MouseEvent.MOUSE_PRESSED:
654                      if (pressCount++ == 0)
655                        pressedComponent = mouseEventTarget;
656                      break;
657                    case MouseEvent.MOUSE_RELEASED:
658                      // Clear our memory of the original PRESSED event, only if
659                      // we're not expecting a CLICKED event after this. If
660                      // there is a CLICKED event after this, it will do clean up.
661                      if ((--pressCount == 0)
662                          && (mouseEventTarget != pressedComponent))
663                        pressedComponent = null;
664                      break;
665                    }
666                }
667            }
668      }      }
669    }    }
670  }  }

Legend:
Removed from v.1.8  
changed lines
  Added in v.1.9

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26