OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libjava/] [classpath/] [javax/] [swing/] [plaf/] [basic/] [BasicPopupMenuUI.java] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* BasicPopupMenuUI.java
2
   Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
package javax.swing.plaf.basic;
39
 
40
import java.awt.AWTEvent;
41
import java.awt.Component;
42
import java.awt.Container;
43
import java.awt.Cursor;
44
import java.awt.Dimension;
45
import java.awt.Point;
46
import java.awt.event.ComponentEvent;
47
import java.awt.event.ComponentListener;
48
import java.awt.event.MouseEvent;
49
 
50
import javax.swing.BoxLayout;
51
import javax.swing.JComponent;
52
import javax.swing.JLayeredPane;
53
import javax.swing.JMenu;
54
import javax.swing.JMenuItem;
55
import javax.swing.JPopupMenu;
56
import javax.swing.LookAndFeel;
57
import javax.swing.MenuElement;
58
import javax.swing.MenuSelectionManager;
59
import javax.swing.RootPaneContainer;
60
import javax.swing.SwingUtilities;
61
import javax.swing.event.MouseInputListener;
62
import javax.swing.event.PopupMenuEvent;
63
import javax.swing.event.PopupMenuListener;
64
import javax.swing.plaf.ComponentUI;
65
import javax.swing.plaf.PopupMenuUI;
66
 
67
 
68
/**
69
 * UI Delegate for JPopupMenu
70
 */
71
public class BasicPopupMenuUI extends PopupMenuUI
72
{
73
  /* popupMenu for which this UI delegate is for*/
74
  protected JPopupMenu popupMenu;
75
 
76
  /* MouseInputListener listens to mouse events. Package private for inner classes. */
77
  static transient MouseInputListener mouseInputListener;
78
 
79
  /* PopupMenuListener listens to popup menu events fired by JPopupMenu*/
80
  private transient PopupMenuListener popupMenuListener;
81
 
82
  /* ComponentListener listening to popupMenu's invoker.
83
   * This is package-private to avoid an accessor method.  */
84
  TopWindowListener topWindowListener;
85
 
86
  /**
87
   * Creates a new BasicPopupMenuUI object.
88
   */
89
  public BasicPopupMenuUI()
90
  {
91
    popupMenuListener = new PopupMenuHandler();
92
    topWindowListener = new TopWindowListener();
93
  }
94
 
95
  /**
96
   * Factory method to create a BasicPopupMenuUI for the given {@link
97
   * JComponent}, which should be a {@link JMenuItem}.
98
   *
99
   * @param x The {@link JComponent} a UI is being created for.
100
   *
101
   * @return A BasicPopupMenuUI for the {@link JComponent}.
102
   */
103
  public static ComponentUI createUI(JComponent x)
104
  {
105
    return new BasicPopupMenuUI();
106
  }
107
 
108
  /**
109
   * Installs and initializes all fields for this UI delegate. Any properties
110
   * of the UI that need to be initialized and/or set to defaults will be
111
   * done now. It will also install any listeners necessary.
112
   *
113
   * @param c The {@link JComponent} that is having this UI installed.
114
   */
115
  public void installUI(JComponent c)
116
  {
117
    super.installUI(c);
118
    popupMenu = (JPopupMenu) c;
119
    popupMenu.setLayout(new DefaultMenuLayout(popupMenu, BoxLayout.Y_AXIS));
120
    popupMenu.setBorderPainted(true);
121
    JPopupMenu.setDefaultLightWeightPopupEnabled(true);
122
 
123
    installDefaults();
124
    installListeners();
125
  }
126
 
127
  /**
128
   * This method installs the defaults that are defined in  the Basic look
129
   * and feel for this {@link JPopupMenu}.
130
   */
131
  public void installDefaults()
132
  {
133
    LookAndFeel.installColorsAndFont(popupMenu, "PopupMenu.background",
134
                                     "PopupMenu.foreground", "PopupMenu.font");
135
    LookAndFeel.installBorder(popupMenu, "PopupMenu.border");
136
    popupMenu.setOpaque(true);
137
  }
138
 
139
  /**
140
   * This method installs the listeners for the {@link JMenuItem}.
141
   */
142
  protected void installListeners()
143
  {
144
    popupMenu.addPopupMenuListener(popupMenuListener);
145
  }
146
 
147
  /**
148
   * This method installs the keyboard actions for this {@link JPopupMenu}.
149
   */
150
  protected void installKeyboardActions()
151
  {
152
    // FIXME: Need to implement
153
  }
154
 
155
  /**
156
   * Performs the opposite of installUI. Any properties or resources that need
157
   * to be cleaned up will be done now. It will also uninstall any listeners
158
   * it has. In addition, any properties of this UI will be nulled.
159
   *
160
   * @param c The {@link JComponent} that is having this UI uninstalled.
161
   */
162
  public void uninstallUI(JComponent c)
163
  {
164
    uninstallListeners();
165
    uninstallDefaults();
166
    popupMenu = null;
167
  }
168
 
169
  /**
170
   * This method uninstalls the defaults and sets any objects created during
171
   * install to null
172
   */
173
  protected void uninstallDefaults()
174
  {
175
    popupMenu.setBackground(null);
176
    popupMenu.setBorder(null);
177
    popupMenu.setFont(null);
178
    popupMenu.setForeground(null);
179
  }
180
 
181
  /**
182
   * Unregisters all the listeners that this UI delegate was using.
183
   */
184
  protected void uninstallListeners()
185
  {
186
    popupMenu.removePopupMenuListener(popupMenuListener);
187
  }
188
 
189
  /**
190
   * Uninstalls any keyboard actions.
191
   */
192
  protected void uninstallKeyboardActions()
193
  {
194
    // FIXME: Need to implement
195
  }
196
 
197
  /**
198
   * This method returns the minimum size of the JPopupMenu.
199
   *
200
   * @param c The JComponent to find a size for.
201
   *
202
   * @return The minimum size.
203
   */
204
  public Dimension getMinimumSize(JComponent c)
205
  {
206
    return null;
207
  }
208
 
209
  /**
210
   * This method returns the preferred size of the JPopupMenu.
211
   *
212
   * @param c The JComponent to find a size for.
213
   *
214
   * @return The preferred size.
215
   */
216
  public Dimension getPreferredSize(JComponent c)
217
  {
218
    return null;
219
  }
220
 
221
  /**
222
   * This method returns the minimum size of the JPopupMenu.
223
   *
224
   * @param c The JComponent to find a size for.
225
   *
226
   * @return The minimum size.
227
   */
228
  public Dimension getMaximumSize(JComponent c)
229
  {
230
    return null;
231
  }
232
 
233
  /**
234
   * Return true if given mouse event is a platform popup trigger, and false
235
   * otherwise
236
   *
237
   * @param e MouseEvent that is to be checked for popup trigger event
238
   *
239
   * @return true if given mouse event is a platform popup trigger, and false
240
   *         otherwise
241
   */
242
  public boolean isPopupTrigger(MouseEvent e)
243
  {
244
    return false;
245
  }
246
 
247
  /**
248
   * This listener handles PopupMenuEvents fired by JPopupMenu
249
   */
250
  private class PopupMenuHandler implements PopupMenuListener
251
  {
252
    /**
253
     * This method is invoked when JPopupMenu is cancelled.
254
     *
255
     * @param event the PopupMenuEvent
256
     */
257
    public void popupMenuCanceled(PopupMenuEvent event)
258
    {
259
      MenuSelectionManager manager = MenuSelectionManager.defaultManager();
260
      manager.clearSelectedPath();
261
    }
262
 
263
    /**
264
     * This method is invoked when JPopupMenu becomes invisible
265
     *
266
     * @param event the PopupMenuEvent
267
     */
268
    public void popupMenuWillBecomeInvisible(PopupMenuEvent event)
269
    {
270
      // remove listener that listens to component events fired 
271
      // by the top - level window that this popup belongs to.
272
      Component invoker = popupMenu.getInvoker();
273
 
274
      RootPaneContainer rootContainer = (RootPaneContainer) SwingUtilities
275
                                        .getRoot(invoker);
276
      if (rootContainer != null)
277
        {
278
          ((Container) rootContainer).removeComponentListener(topWindowListener);
279
 
280
          // If this popup menu is the last popup menu visible on the screen,
281
          // 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()).isTopLevelMenu();
286
 
287
          if (topLevelMenu || !(popupMenu.getInvoker() instanceof MenuElement))
288
            {
289
              // set glass pane not to interrupt mouse events and remove
290
              // mouseInputListener
291
              Container glassPane = (Container) rootContainer.getGlassPane();
292
              glassPane.setVisible(false);
293
              glassPane.removeMouseListener(mouseInputListener);
294
              mouseInputListener = null;
295
            }
296
        }
297
    }
298
 
299
    /**
300
     * This method is invoked when JPopupMenu becomes visible
301
     *
302
     * @param event the PopupMenuEvent
303
     */
304
    public void popupMenuWillBecomeVisible(PopupMenuEvent event)
305
    {
306
      // Adds topWindowListener to top-level window to listener to 
307
      // ComponentEvents fired by it. We need to cancel this popup menu
308
      // if topWindow to which this popup belongs was resized or moved.
309
      Component invoker = popupMenu.getInvoker();
310
      RootPaneContainer rootContainer = (RootPaneContainer) SwingUtilities
311
                                        .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,
326
      // then by default its first element should be always selected when
327
      // this popup menu becomes visible. 
328
      MenuSelectionManager manager = MenuSelectionManager.defaultManager();
329
 
330
      if (manager.getSelectedPath().length == 0)
331
        {
332
          // Set selected path to point to the first item in the popup menu
333
          MenuElement[] path = new MenuElement[2];
334
          path[0] = popupMenu;
335
          Component[] comps = popupMenu.getComponents();
336
          if (comps.length != 0 && comps[0] instanceof MenuElement)
337
            {
338
              path[1] = (MenuElement) comps[0];
339
              manager.setSelectedPath(path);
340
            }
341
        }
342
    }
343
  }
344
 
345
  /**
346
   * ComponentListener that listens to Component Events fired by the top -
347
   * level window to which popup menu belongs. If top-level window was
348
   * resized, moved or hidded then popup menu will be hidded and selected
349
   * path of current menu hierarchy will be set to null.
350
   */
351
  private class TopWindowListener implements ComponentListener
352
  {
353
    /**
354
     * This method is invoked when top-level window is resized. This method
355
     * closes current menu hierarchy.
356
     *
357
     * @param e The ComponentEvent
358
     */
359
    public void componentResized(ComponentEvent e)
360
    {
361
      MenuSelectionManager manager = MenuSelectionManager.defaultManager();
362
      manager.clearSelectedPath();
363
    }
364
 
365
    /**
366
     * This method is invoked when top-level window is moved. This method
367
     * closes current menu hierarchy.
368
     *
369
     * @param e The ComponentEvent
370
     */
371
    public void componentMoved(ComponentEvent e)
372
    {
373
      MenuSelectionManager manager = MenuSelectionManager.defaultManager();
374
      manager.clearSelectedPath();
375
    }
376
 
377
    /**
378
     * This method is invoked when top-level window is shown This method
379
     * does nothing by default.
380
     *
381
     * @param e The ComponentEvent
382
     */
383
    public void componentShown(ComponentEvent e)
384
    {
385
      MenuSelectionManager manager = MenuSelectionManager.defaultManager();
386
      manager.clearSelectedPath();
387
    }
388
 
389
    /**
390
     * This method is invoked when top-level window is hidden This method
391
     * closes current menu hierarchy.
392
     *
393
     * @param e The ComponentEvent
394
     */
395
    public void componentHidden(ComponentEvent e)
396
    {
397
      MenuSelectionManager manager = MenuSelectionManager.defaultManager();
398
      manager.clearSelectedPath();
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
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 Component tempComponent;
419
    private transient int pressCount;
420
 
421
    /**
422
     * Creates a new MouseInputHandler object.
423
     *
424
     * @param c the top most root container
425
     */
426
    public MouseInputHandler(RootPaneContainer c)
427
    {
428
      layeredPane = c.getLayeredPane();
429
      glassPane = (Container) c.getGlassPane();
430
    }
431
 
432
    /**
433
     * Handles mouse clicked event
434
     *
435
     * @param e Mouse event
436
     */
437
    public void mouseClicked(MouseEvent e)
438
    {
439
      handleEvent(e);
440
    }
441
 
442
    /**
443
     * Handles mouseDragged event
444
     *
445
     * @param e MouseEvent
446
     */
447
    public void mouseDragged(MouseEvent e)
448
    {
449
      handleEvent(e);
450
    }
451
 
452
    /**
453
     * Handles mouseEntered event
454
     *
455
     * @param e MouseEvent
456
     */
457
    public void mouseEntered(MouseEvent e)
458
    {
459
      handleEvent(e);
460
    }
461
 
462
    /**
463
     * Handles mouseExited event
464
     *
465
     * @param e MouseEvent
466
     */
467
    public void mouseExited(MouseEvent e)
468
    {
469
      handleEvent(e);
470
    }
471
 
472
    /**
473
     * Handles mouse moved event
474
     *
475
     * @param e MouseEvent
476
     */
477
    public void mouseMoved(MouseEvent e)
478
    {
479
      handleEvent(e);
480
    }
481
 
482
    /**
483
     * Handles mouse pressed event
484
     *
485
     * @param e MouseEvent
486
     */
487
    public void mousePressed(MouseEvent e)
488
    {
489
      handleEvent(e);
490
    }
491
 
492
    /**
493
     * Handles mouse released event
494
     *
495
     * @param e MouseEvent
496
     */
497
    public void mouseReleased(MouseEvent e)
498
    {
499
      handleEvent(e);
500
    }
501
 
502
    /*
503
     * This method determines component that was intended to received mouse
504
     * event, before it was interrupted within the glass pane. This method
505
     * also redispatches mouse entered and mouse exited events to the
506
     * appropriate components. This code is slightly modified code from
507
     * Container.LightweightDispatcher class, which is private inside
508
     * Container class and cannot be used here.
509
     */
510
    public void acquireComponentForMouseEvent(MouseEvent me)
511
    {
512
      int x = me.getX();
513
      int y = me.getY();
514
 
515
      // Find the candidate which should receive this event.
516
      Component parent = layeredPane;
517
      Component candidate = null;
518
      Point p = me.getPoint();
519
      while ((candidate == null) && (parent != null))
520
        {
521
          p = SwingUtilities.convertPoint(glassPane, p.x, p.y, parent);
522
          candidate = SwingUtilities.getDeepestComponentAt(parent, p.x, p.y);
523
 
524
          if (candidate == null)
525
            {
526
              p = SwingUtilities.convertPoint(parent, p.x, p.y,
527
                                              parent.getParent());
528
              parent = parent.getParent();
529
            }
530
        }
531
 
532
      // If the only candidate we found was the native container itself,
533
      // don't dispatch any event at all.  We only care about the lightweight
534
      // children here.
535
      if (candidate == layeredPane)
536
        candidate = null;
537
 
538
      // If our candidate is new, inform the old target we're leaving.
539
      if ((lastComponentEntered != null) && lastComponentEntered.isShowing()
540
          && (lastComponentEntered != candidate))
541
        {
542
          // Old candidate could have been removed from 
543
          // the layeredPane so we check first.
544
          if (SwingUtilities.isDescendingFrom(lastComponentEntered, layeredPane))
545
            {
546
              Point tp = SwingUtilities.convertPoint(layeredPane, x, y,
547
                                                     lastComponentEntered);
548
              MouseEvent exited = new MouseEvent(lastComponentEntered,
549
                                                 MouseEvent.MOUSE_EXITED,
550
                                                 me.getWhen(),
551
                                                 me.getModifiersEx(), tp.x,
552
                                                 tp.y, me.getClickCount(),
553
                                                 me.isPopupTrigger(),
554
                                                 me.getButton());
555
 
556
              tempComponent = lastComponentEntered;
557
              lastComponentEntered = null;
558
              tempComponent.dispatchEvent(exited);
559
            }
560
 
561
          lastComponentEntered = null;
562
        }
563
 
564
      // If we have a candidate, maybe enter it.
565
      if (candidate != null)
566
        {
567
          mouseEventTarget = candidate;
568
 
569
          if (candidate.isLightweight() && candidate.isShowing()
570
              && (candidate != layeredPane)
571
              && (candidate != lastComponentEntered))
572
            {
573
              lastComponentEntered = mouseEventTarget;
574
 
575
              Point cp = SwingUtilities.convertPoint(layeredPane, x, y,
576
                                                     lastComponentEntered);
577
              MouseEvent entered = new MouseEvent(lastComponentEntered,
578
                                                  MouseEvent.MOUSE_ENTERED,
579
                                                  me.getWhen(),
580
                                                  me.getModifiersEx(), cp.x,
581
                                                  cp.y, me.getClickCount(),
582
                                                  me.isPopupTrigger(),
583
                                                  me.getButton());
584
              lastComponentEntered.dispatchEvent(entered);
585
            }
586
        }
587
 
588
      if ((me.getID() == MouseEvent.MOUSE_RELEASED)
589
          || ((me.getID() == MouseEvent.MOUSE_PRESSED) && (pressCount > 0))
590
          || (me.getID() == MouseEvent.MOUSE_DRAGGED))
591
        {
592
          // If any of the following events occur while a button is held down,
593
          // they should be dispatched to the same component to which the
594
          // original MOUSE_PRESSED event was dispatched:
595
          //   - MOUSE_RELEASED
596
          //   - MOUSE_PRESSED: another button pressed while the first is held down
597
          //   - MOUSE_DRAGGED
598
          if (SwingUtilities.isDescendingFrom(pressedComponent, layeredPane))
599
            mouseEventTarget = pressedComponent;
600
          else if (me.getID() == MouseEvent.MOUSE_CLICKED)
601
            {
602
              // Don't dispatch CLICKED events whose target is not the same as the
603
              // target for the original PRESSED event.
604
              if (candidate != pressedComponent)
605
                mouseEventTarget = null;
606
              else if (pressCount == 0)
607
                pressedComponent = null;
608
            }
609
        }
610
    }
611
 
612
    /*
613
     * This method handles mouse events interrupted by glassPane. It
614
     * redispatches the mouse events appropriately to the intended components.
615
     * The code in this method is also taken from
616
     * Container.LightweightDispatcher class. The code is slightly modified
617
     * to handle the case when mouse is released over non-menu component. In
618
     * this case this method closes current menu hierarchy before
619
     * redispatching the event further.
620
     */
621
    public void handleEvent(AWTEvent e)
622
    {
623
      if (e instanceof MouseEvent)
624
        {
625
          MouseEvent me = (MouseEvent) e;
626
 
627
          acquireComponentForMouseEvent(me);
628
 
629
          // Avoid dispatching ENTERED and EXITED events twice.
630
          if (mouseEventTarget != null && mouseEventTarget.isShowing()
631
              && (e.getID() != MouseEvent.MOUSE_ENTERED)
632
              && (e.getID() != MouseEvent.MOUSE_EXITED))
633
            {
634
              MouseEvent newEvt = SwingUtilities.convertMouseEvent(glassPane,
635
                                                                   me,
636
                                                                   mouseEventTarget);
637
 
638
              mouseEventTarget.dispatchEvent(newEvt);
639
 
640
              // If mouse was clicked over the component that is not part 
641
              // of menu hierarchy,then must close the menu hierarchy */
642
              if (e.getID() == MouseEvent.MOUSE_RELEASED)
643
                {
644
                  boolean partOfMenuHierarchy = false;
645
                  MenuSelectionManager manager = MenuSelectionManager
646
                                                 .defaultManager();
647
 
648
                  partOfMenuHierarchy = manager.isComponentPartOfCurrentMenu(mouseEventTarget);
649
 
650
                  if (! partOfMenuHierarchy)
651
                    manager.clearSelectedPath();
652
                }
653
 
654
              switch (e.getID())
655
                {
656
                case MouseEvent.MOUSE_PRESSED:
657
                  if (pressCount++ == 0)
658
                    pressedComponent = mouseEventTarget;
659
                  break;
660
                case MouseEvent.MOUSE_RELEASED:
661
                  // Clear our memory of the original PRESSED event, only if
662
                  // we're not expecting a CLICKED event after this. If
663
                  // there is a CLICKED event after this, it will do clean up.
664
                  if ((--pressCount == 0)
665
                      && (mouseEventTarget != pressedComponent))
666
                    pressedComponent = null;
667
                  break;
668
                }
669
            }
670
        }
671
    }
672
  }
673
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.