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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [javax/] [swing/] [plaf/] [basic/] [BasicMenuItemUI.java] - Blame information for rev 772

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 772 jeremybenn
/* BasicMenuItemUI.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
 
39
package javax.swing.plaf.basic;
40
 
41
import gnu.classpath.SystemProperties;
42
 
43
import java.awt.Color;
44
import java.awt.Component;
45
import java.awt.Container;
46
import java.awt.Dimension;
47
import java.awt.Font;
48
import java.awt.FontMetrics;
49
import java.awt.Graphics;
50
import java.awt.Insets;
51
import java.awt.Rectangle;
52
import java.awt.event.ActionEvent;
53
import java.awt.event.ItemEvent;
54
import java.awt.event.ItemListener;
55
import java.awt.event.KeyEvent;
56
import java.awt.event.MouseEvent;
57
import java.awt.font.FontRenderContext;
58
import java.awt.font.TextLayout;
59
import java.awt.geom.AffineTransform;
60
import java.beans.PropertyChangeEvent;
61
import java.beans.PropertyChangeListener;
62
import java.util.ArrayList;
63
 
64
import javax.swing.AbstractAction;
65
import javax.swing.AbstractButton;
66
import javax.swing.ActionMap;
67
import javax.swing.ButtonModel;
68
import javax.swing.Icon;
69
import javax.swing.InputMap;
70
import javax.swing.JCheckBoxMenuItem;
71
import javax.swing.JComponent;
72
import javax.swing.JMenu;
73
import javax.swing.JMenuItem;
74
import javax.swing.JPopupMenu;
75
import javax.swing.KeyStroke;
76
import javax.swing.LookAndFeel;
77
import javax.swing.MenuElement;
78
import javax.swing.MenuSelectionManager;
79
import javax.swing.SwingConstants;
80
import javax.swing.SwingUtilities;
81
import javax.swing.UIDefaults;
82
import javax.swing.UIManager;
83
import javax.swing.event.MenuDragMouseEvent;
84
import javax.swing.event.MenuDragMouseListener;
85
import javax.swing.event.MenuKeyEvent;
86
import javax.swing.event.MenuKeyListener;
87
import javax.swing.event.MouseInputListener;
88
import javax.swing.plaf.ActionMapUIResource;
89
import javax.swing.plaf.ComponentInputMapUIResource;
90
import javax.swing.plaf.ComponentUI;
91
import javax.swing.plaf.MenuItemUI;
92
import javax.swing.text.View;
93
 
94
/**
95
 * UI Delegate for JMenuItem.
96
 */
97
public class BasicMenuItemUI extends MenuItemUI
98
{
99
  /**
100
   * Font to be used when displaying menu item's accelerator.
101
   */
102
  protected Font acceleratorFont;
103
 
104
  /**
105
   * Color to be used when displaying menu item's accelerator.
106
   */
107
  protected Color acceleratorForeground;
108
 
109
  /**
110
   * Color to be used when displaying menu item's accelerator when menu item is
111
   * selected.
112
   */
113
  protected Color acceleratorSelectionForeground;
114
 
115
  /**
116
   * Icon that is displayed after the text to indicated that this menu contains
117
   * submenu.
118
   */
119
  protected Icon arrowIcon;
120
 
121
  /**
122
   * Icon that is displayed before the text. This icon is only used in
123
   * JCheckBoxMenuItem or JRadioBoxMenuItem.
124
   */
125
  protected Icon checkIcon;
126
 
127
  /**
128
   * Number of spaces between icon and text.
129
   */
130
  protected int defaultTextIconGap = 4;
131
 
132
  /**
133
   * Color of the text when menu item is disabled
134
   */
135
  protected Color disabledForeground;
136
 
137
  /**
138
   * The menu Drag mouse listener listening to the menu item.
139
   */
140
  protected MenuDragMouseListener menuDragMouseListener;
141
 
142
  /**
143
   * The menu item itself
144
   */
145
  protected JMenuItem menuItem;
146
 
147
  /**
148
   * Menu Key listener listening to the menu item.
149
   */
150
  protected MenuKeyListener menuKeyListener;
151
 
152
  /**
153
   * mouse input listener listening to menu item.
154
   */
155
  protected MouseInputListener mouseInputListener;
156
 
157
  /**
158
   * Indicates if border should be painted
159
   */
160
  protected boolean oldBorderPainted;
161
 
162
  /**
163
   * Color of text that is used when menu item is selected
164
   */
165
  protected Color selectionBackground;
166
 
167
  /**
168
   * Color of the text that is used when menu item is selected.
169
   */
170
  protected Color selectionForeground;
171
 
172
  /**
173
   * String that separates description of the modifiers and the key
174
   */
175
  private String acceleratorDelimiter;
176
 
177
  /**
178
   * ItemListener to listen for item changes in the menu item
179
   */
180
  private ItemListener itemListener;
181
 
182
  /**
183
   * A PropertyChangeListener to make UI updates after property changes.
184
   */
185
  private PropertyChangeHandler propertyChangeListener;
186
 
187
  /**
188
   * The view rectangle used for layout of the menu item.
189
   */
190
  private Rectangle viewRect;
191
 
192
  /**
193
   * The rectangle that holds the area of the label.
194
   */
195
  private Rectangle textRect;
196
 
197
  /**
198
   * The rectangle that holds the area of the accelerator.
199
   */
200
  private Rectangle accelRect;
201
 
202
  /**
203
   * The rectangle that holds the area of the icon.
204
   */
205
  private Rectangle iconRect;
206
 
207
  /**
208
   * The rectangle that holds the area of the icon.
209
   */
210
  private Rectangle arrowIconRect;
211
 
212
  /**
213
   * The rectangle that holds the area of the check icon.
214
   */
215
  private Rectangle checkIconRect;
216
 
217
  /**
218
   * A rectangle used for temporary storage to avoid creation of new
219
   * rectangles.
220
   */
221
  private Rectangle cachedRect;
222
 
223
  /**
224
   * A class to handle PropertChangeEvents for the JMenuItem
225
   * @author Anthony Balkissoon abalkiss at redhat dot com.
226
   */
227
  class PropertyChangeHandler implements PropertyChangeListener
228
  {
229
    /**
230
     * This method is called when a property of the menuItem is changed.
231
     * Currently it is only used to update the accelerator key bindings.
232
     *
233
     * @param e
234
     *          the PropertyChangeEvent
235
     */
236
    public void propertyChange(PropertyChangeEvent e)
237
    {
238
      String property = e.getPropertyName();
239
      if (property.equals("accelerator"))
240
        {
241
          InputMap map = SwingUtilities.getUIInputMap(menuItem,
242
              JComponent.WHEN_IN_FOCUSED_WINDOW);
243
          if (map != null)
244
            map.remove((KeyStroke) e.getOldValue());
245
          else
246
            map = new ComponentInputMapUIResource(menuItem);
247
 
248
          KeyStroke accelerator = (KeyStroke) e.getNewValue();
249
          if (accelerator != null)
250
            map.put(accelerator, "doClick");
251
        }
252
      // TextLayout caching for speed-up drawing of text.
253
      else if ((property.equals(AbstractButton.TEXT_CHANGED_PROPERTY)
254
                || property.equals("font"))
255
               && SystemProperties.getProperty("gnu.javax.swing.noGraphics2D")
256
               == null)
257
        {
258
          AbstractButton b = (AbstractButton) e.getSource();
259
          String text = b.getText();
260
          if (text == null)
261
            text = "";
262
          FontRenderContext frc = new FontRenderContext(new AffineTransform(),
263
                                                        false, false);
264
          TextLayout layout = new TextLayout(text, b.getFont(), frc);
265
          b.putClientProperty(BasicGraphicsUtils.CACHED_TEXT_LAYOUT, layout);
266
        }
267
    }
268
  }
269
 
270
  /**
271
   * A class to handle accelerator keys.  This is the Action we will
272
   * perform when the accelerator key for this JMenuItem is pressed.
273
   * @author Anthony Balkissoon abalkiss at redhat dot com
274
   *
275
   */
276
  class ClickAction extends AbstractAction
277
  {
278
    /**
279
     * This is what is done when the accelerator key for the JMenuItem is
280
     * pressed.
281
     */
282
    public void actionPerformed(ActionEvent event)
283
    {
284
      doClick(MenuSelectionManager.defaultManager());
285
    }
286
  }
287
 
288
  /**
289
   * Creates a new BasicMenuItemUI object.
290
   */
291
  public BasicMenuItemUI()
292
  {
293
    mouseInputListener = createMouseInputListener(menuItem);
294
    menuDragMouseListener = createMenuDragMouseListener(menuItem);
295
    menuKeyListener = createMenuKeyListener(menuItem);
296
    itemListener = new ItemHandler();
297
    propertyChangeListener = new PropertyChangeHandler();
298
 
299
    // Initialize rectangles for layout.
300
    viewRect = new Rectangle();
301
    textRect = new Rectangle();
302
    iconRect = new Rectangle();
303
    arrowIconRect = new Rectangle();
304
    checkIconRect = new Rectangle();
305
    accelRect = new Rectangle();
306
    cachedRect = new Rectangle();
307
  }
308
 
309
  /**
310
   * Create MenuDragMouseListener to listen for mouse dragged events.
311
   *
312
   * @param c
313
   *          menu item to listen to
314
   * @return The MenuDragMouseListener
315
   */
316
  protected MenuDragMouseListener createMenuDragMouseListener(JComponent c)
317
  {
318
    return new MenuDragMouseHandler();
319
  }
320
 
321
  /**
322
   * Creates MenuKeyListener to listen to key events occuring when menu item is
323
   * visible on the screen.
324
   *
325
   * @param c
326
   *          menu item to listen to
327
   * @return The MenuKeyListener
328
   */
329
  protected MenuKeyListener createMenuKeyListener(JComponent c)
330
  {
331
    return new MenuKeyHandler();
332
  }
333
 
334
  /**
335
   * Handles mouse input events occuring for this menu item
336
   *
337
   * @param c
338
   *          menu item to listen to
339
   * @return The MouseInputListener
340
   */
341
  protected MouseInputListener createMouseInputListener(JComponent c)
342
  {
343
    return new MouseInputHandler();
344
  }
345
 
346
  /**
347
   * Factory method to create a BasicMenuItemUI for the given {@link
348
   * JComponent}, which should be a {@link JMenuItem}.
349
   *
350
   * @param c
351
   *          The {@link JComponent} a UI is being created for.
352
   * @return A BasicMenuItemUI for the {@link JComponent}.
353
   */
354
  public static ComponentUI createUI(JComponent c)
355
  {
356
    return new BasicMenuItemUI();
357
  }
358
 
359
  /**
360
   * Programatically clicks menu item.
361
   *
362
   * @param msm
363
   *          MenuSelectionManager for the menu hierarchy
364
   */
365
  protected void doClick(MenuSelectionManager msm)
366
  {
367
    menuItem.doClick(0);
368
    msm.clearSelectedPath();
369
  }
370
 
371
  /**
372
   * Returns maximum size for the specified menu item
373
   *
374
   * @param c
375
   *          component for which to get maximum size
376
   * @return Maximum size for the specified menu item.
377
   */
378
  public Dimension getMaximumSize(JComponent c)
379
  {
380
    return null;
381
  }
382
 
383
  /**
384
   * Returns minimum size for the specified menu item
385
   *
386
   * @param c
387
   *          component for which to get minimum size
388
   * @return Minimum size for the specified menu item.
389
   */
390
  public Dimension getMinimumSize(JComponent c)
391
  {
392
    return null;
393
  }
394
 
395
  /**
396
   * Returns path to this menu item.
397
   *
398
   * @return $MenuElement[]$ Returns array of menu elements that constitute a
399
   *         path to this menu item.
400
   */
401
  public MenuElement[] getPath()
402
  {
403
    ArrayList path = new ArrayList();
404
 
405
    Component c = menuItem;
406
    while (c instanceof MenuElement)
407
      {
408
        path.add(0, c);
409
 
410
        if (c instanceof JPopupMenu)
411
          c = ((JPopupMenu) c).getInvoker();
412
        else
413
          c = c.getParent();
414
      }
415
 
416
    MenuElement[] pathArray = new MenuElement[path.size()];
417
    path.toArray(pathArray);
418
    return pathArray;
419
  }
420
 
421
  /**
422
   * Returns preferred size for the given menu item.
423
   *
424
   * @param c
425
   *          menu item for which to get preferred size
426
   * @param checkIcon
427
   *          check icon displayed in the given menu item
428
   * @param arrowIcon
429
   *          arrow icon displayed in the given menu item
430
   * @param defaultTextIconGap
431
   *          space between icon and text in the given menuItem
432
   * @return $Dimension$ preferred size for the given menu item
433
   */
434
  protected Dimension getPreferredMenuItemSize(JComponent c, Icon checkIcon,
435
                                               Icon arrowIcon,
436
                                               int defaultTextIconGap)
437
  {
438
    JMenuItem m = (JMenuItem) c;
439
    String accelText = getAcceleratorString(m);
440
 
441
    // Layout the menu item. The result gets stored in the rectangle
442
    // fields of this class.
443
    resetRectangles(null);
444
    layoutMenuItem(m, accelText);
445
 
446
    // The union of the text and icon areas is the label area.
447
    cachedRect.setBounds(textRect);
448
    Rectangle pref = SwingUtilities.computeUnion(iconRect.x, iconRect.y,
449
                                                 iconRect.width,
450
                                                 iconRect.height,
451
                                                 cachedRect);
452
 
453
    // Find the widest menu item text and accelerator and store it in
454
    // client properties of the parent, so that we can align the accelerators
455
    // properly. Of course, we only need can do this, if the parent is
456
    // a JComponent and this menu item is not a toplevel menu.
457
    Container parent = m.getParent();
458
    if (parent != null && parent instanceof JComponent
459
        && !(m instanceof JMenu && ((JMenu) m).isTopLevelMenu()))
460
      {
461
        JComponent p = (JComponent) parent;
462
 
463
        // The widest text so far.
464
        Integer maxTextWidth = (Integer) p.getClientProperty("maxTextWidth");
465
        int maxTextValue = maxTextWidth == null ? 0 : maxTextWidth.intValue();
466
        if (pref.width < maxTextValue)
467
          pref.width = maxTextValue;
468
        else
469
          p.putClientProperty("maxTextWidth", new Integer(pref.width));
470
 
471
        // The widest accelerator so far.
472
        Integer maxAccelWidth = (Integer) p.getClientProperty("maxAccelWidth");
473
        int maxAccelValue = maxAccelWidth == null ? 0
474
                                                  : maxAccelWidth.intValue();
475
        if (accelRect.width > maxAccelValue)
476
          {
477
            maxAccelValue = accelRect.width;
478
            p.putClientProperty("maxAccelWidth", new Integer(accelRect.width));
479
          }
480
        pref.width += maxAccelValue;
481
        pref.width += defaultTextIconGap;
482
      }
483
 
484
    // Add arrow and check size if appropriate.
485
    if (! (m instanceof JMenu && ((JMenu) m).isTopLevelMenu()))
486
      {
487
        pref.width += checkIconRect.width;
488
        pref.width += defaultTextIconGap;
489
        pref.width += arrowIconRect.width;
490
        pref.width += defaultTextIconGap;
491
      }
492
 
493
    // Add a gap ~2 times as wide as the defaultTextIconGap.
494
    pref.width += 2 * defaultTextIconGap;
495
 
496
    // Respect the insets of the menu item.
497
    Insets i = m.getInsets();
498
    pref.width += i.left + i.right;
499
    pref.height += i.top + i.bottom;
500
 
501
    // Return a copy, so that nobody messes with our textRect.
502
    return pref.getSize();
503
  }
504
 
505
  /**
506
   * Returns preferred size of the given component
507
   *
508
   * @param c
509
   *          component for which to return preferred size
510
   * @return $Dimension$ preferred size for the given component
511
   */
512
  public Dimension getPreferredSize(JComponent c)
513
  {
514
    return getPreferredMenuItemSize(c, checkIcon, arrowIcon,
515
                                    defaultTextIconGap);
516
  }
517
 
518
  /**
519
   * Returns the prefix for entries in the {@link UIDefaults} table.
520
   *
521
   * @return "MenuItem"
522
   */
523
  protected String getPropertyPrefix()
524
  {
525
    return "MenuItem";
526
  }
527
 
528
  /**
529
   * This method installs the components for this {@link JMenuItem}.
530
   *
531
   * @param menuItem
532
   *          The {@link JMenuItem} to install components for.
533
   */
534
  protected void installComponents(JMenuItem menuItem)
535
  {
536
    // FIXME: Need to implement
537
  }
538
 
539
  /**
540
   * This method installs the defaults that are defined in the Basic look and
541
   * feel for this {@link JMenuItem}.
542
   */
543
  protected void installDefaults()
544
  {
545
    String prefix = getPropertyPrefix();
546
    LookAndFeel.installBorder(menuItem, prefix + ".border");
547
    LookAndFeel.installColorsAndFont(menuItem, prefix + ".background",
548
                                     prefix + ".foreground", prefix + ".font");
549
    menuItem.setMargin(UIManager.getInsets(prefix + ".margin"));
550
    acceleratorFont = UIManager.getFont(prefix + ".acceleratorFont");
551
    acceleratorForeground = UIManager.getColor(prefix
552
        + ".acceleratorForeground");
553
    acceleratorSelectionForeground = UIManager.getColor(prefix
554
        + ".acceleratorSelectionForeground");
555
    selectionBackground = UIManager.getColor(prefix + ".selectionBackground");
556
    selectionForeground = UIManager.getColor(prefix + ".selectionForeground");
557
    acceleratorDelimiter = UIManager.getString(prefix + ".acceleratorDelimiter");
558
    checkIcon = UIManager.getIcon(prefix + ".checkIcon");
559
 
560
    menuItem.setHorizontalTextPosition(SwingConstants.TRAILING);
561
    menuItem.setHorizontalAlignment(SwingConstants.LEADING);
562
  }
563
 
564
  /**
565
   * This method installs the keyboard actions for this {@link JMenuItem}.
566
   */
567
  protected void installKeyboardActions()
568
  {
569
    InputMap focusedWindowMap = SwingUtilities.getUIInputMap(menuItem,
570
        JComponent.WHEN_IN_FOCUSED_WINDOW);
571
    if (focusedWindowMap == null)
572
      focusedWindowMap = new ComponentInputMapUIResource(menuItem);
573
    KeyStroke accelerator = menuItem.getAccelerator();
574
    if (accelerator != null)
575
      focusedWindowMap.put(accelerator, "doClick");
576
    SwingUtilities.replaceUIInputMap(menuItem,
577
        JComponent.WHEN_IN_FOCUSED_WINDOW, focusedWindowMap);
578
 
579
    ActionMap UIActionMap = SwingUtilities.getUIActionMap(menuItem);
580
    if (UIActionMap == null)
581
      UIActionMap = new ActionMapUIResource();
582
    UIActionMap.put("doClick", new ClickAction());
583
    SwingUtilities.replaceUIActionMap(menuItem, UIActionMap);
584
  }
585
 
586
  /**
587
   * This method installs the listeners for the {@link JMenuItem}.
588
   */
589
  protected void installListeners()
590
  {
591
    menuItem.addMouseListener(mouseInputListener);
592
    menuItem.addMouseMotionListener(mouseInputListener);
593
    menuItem.addMenuDragMouseListener(menuDragMouseListener);
594
    menuItem.addMenuKeyListener(menuKeyListener);
595
    menuItem.addItemListener(itemListener);
596
    menuItem.addPropertyChangeListener(propertyChangeListener);
597
    // Fire synthetic property change event to let the listener update
598
    // the TextLayout cache.
599
    propertyChangeListener.propertyChange(new PropertyChangeEvent(menuItem,
600
                                                                  "font", null,
601
                                                          menuItem.getFont()));
602
  }
603
 
604
  /**
605
   * Installs and initializes all fields for this UI delegate. Any properties of
606
   * the UI that need to be initialized and/or set to defaults will be done now.
607
   * It will also install any listeners necessary.
608
   *
609
   * @param c
610
   *          The {@link JComponent} that is having this UI installed.
611
   */
612
  public void installUI(JComponent c)
613
  {
614
    super.installUI(c);
615
    menuItem = (JMenuItem) c;
616
    installDefaults();
617
    installComponents(menuItem);
618
    installListeners();
619
    installKeyboardActions();
620
  }
621
 
622
  /**
623
   * Paints given menu item using specified graphics context
624
   *
625
   * @param g
626
   *          The graphics context used to paint this menu item
627
   * @param c
628
   *          Menu Item to paint
629
   */
630
  public void paint(Graphics g, JComponent c)
631
  {
632
    paintMenuItem(g, c, checkIcon, arrowIcon, selectionBackground,
633
                  c.getForeground(), defaultTextIconGap);
634
  }
635
 
636
  /**
637
   * Paints background of the menu item
638
   *
639
   * @param g
640
   *          The graphics context used to paint this menu item
641
   * @param menuItem
642
   *          menu item to paint
643
   * @param bgColor
644
   *          Background color to use when painting menu item
645
   */
646
  protected void paintBackground(Graphics g, JMenuItem menuItem, Color bgColor)
647
  {
648
    // Menu item is considered to be highlighted when it is selected.
649
    // But we don't want to paint the background of JCheckBoxMenuItems
650
    ButtonModel mod = menuItem.getModel();
651
    Color saved = g.getColor();
652
    if (mod.isArmed() || ((menuItem instanceof JMenu) && mod.isSelected()))
653
      {
654
        g.setColor(bgColor);
655
        g.fillRect(0, 0, menuItem.getWidth(), menuItem.getHeight());
656
      }
657
    else if (menuItem.isOpaque())
658
      {
659
        g.setColor(menuItem.getBackground());
660
        g.fillRect(0, 0, menuItem.getWidth(), menuItem.getHeight());
661
      }
662
    g.setColor(saved);
663
  }
664
 
665
  /**
666
   * Paints specified menu item
667
   *
668
   * @param g
669
   *          The graphics context used to paint this menu item
670
   * @param c
671
   *          menu item to paint
672
   * @param checkIcon
673
   *          check icon to use when painting menu item
674
   * @param arrowIcon
675
   *          arrow icon to use when painting menu item
676
   * @param background
677
   *          Background color of the menu item
678
   * @param foreground
679
   *          Foreground color of the menu item
680
   * @param defaultTextIconGap
681
   *          space to use between icon and text when painting menu item
682
   */
683
  protected void paintMenuItem(Graphics g, JComponent c, Icon checkIcon,
684
                               Icon arrowIcon, Color background,
685
                               Color foreground, int defaultTextIconGap)
686
  {
687
    JMenuItem m = (JMenuItem) c;
688
 
689
    // Fetch fonts.
690
    Font oldFont = g.getFont();
691
    Font font = c.getFont();
692
    g.setFont(font);
693
    FontMetrics accelFm = m.getFontMetrics(acceleratorFont);
694
 
695
    // Create accelerator string.
696
    String accelText = getAcceleratorString(m);
697
 
698
    // Layout menu item. The result gets stored in the rectangle fields
699
    // of this class.
700
    resetRectangles(m);
701
 
702
    layoutMenuItem(m, accelText);
703
 
704
    // Paint the background.
705
    paintBackground(g, m, background);
706
 
707
    Color oldColor = g.getColor();
708
 
709
    // Paint the check icon.
710
    if (checkIcon != null)
711
      {
712
        checkIcon.paintIcon(m, g, checkIconRect.x, checkIconRect.y);
713
      }
714
 
715
    // Paint the icon.
716
    ButtonModel model = m.getModel();
717
    if (m.getIcon() != null)
718
      {
719
        // Determine icon depending on the menu item
720
        // state (normal/disabled/pressed).
721
        Icon icon;
722
        if (! m.isEnabled())
723
          {
724
            icon = m.getDisabledIcon();
725
          }
726
        else if (model.isPressed() && model.isArmed())
727
          {
728
            icon = m.getPressedIcon();
729
            if (icon == null)
730
              {
731
                icon = m.getIcon();
732
              }
733
          }
734
        else
735
          {
736
            icon = m.getIcon();
737
          }
738
 
739
        if (icon != null)
740
          {
741
            icon.paintIcon(m, g, iconRect.x, iconRect.y);
742
          }
743
      }
744
 
745
    // Paint the text.
746
    String text = m.getText();
747
    if (text != null)
748
      {
749
        // Handle HTML.
750
        View html = (View) m.getClientProperty(BasicHTML.propertyKey);
751
        if (html != null)
752
          {
753
            html.paint(g, textRect);
754
          }
755
        else
756
          {
757
            paintText(g, m, textRect, text);
758
          }
759
      }
760
 
761
    // Paint accelerator text.
762
    if (! accelText.equals(""))
763
      {
764
        // Align the accelerator text. In getPreferredMenuItemSize() we
765
        // store a client property 'maxAccelWidth' in the parent which holds
766
        // the maximum accelerator width for the children of this parent.
767
        // We use this here to align the accelerators properly.
768
        int accelOffset = 0;
769
        Container parent = m.getParent();
770
        if (parent != null && parent instanceof JComponent)
771
          {
772
            JComponent p = (JComponent) parent;
773
            Integer maxAccelWidth =
774
              (Integer) p.getClientProperty("maxAccelWidth");
775
            int maxAccelValue = maxAccelWidth == null ? 0
776
                                                    : maxAccelWidth.intValue();
777
            accelOffset = maxAccelValue - accelRect.width;
778
          }
779
 
780
        g.setFont(acceleratorFont);
781
        if (! m.isEnabled())
782
          {
783
            // Paint accelerator disabled.
784
            g.setColor(disabledForeground);
785
          }
786
        else
787
          {
788
            if (m.isArmed() || (m instanceof JMenu && m.isSelected()))
789
              g.setColor(acceleratorSelectionForeground);
790
            else
791
              g.setColor(acceleratorForeground);
792
          }
793
        g.drawString(accelText, accelRect.x - accelOffset,
794
                     accelRect.y + accelFm.getAscent());
795
      }
796
 
797
    // Paint arrow.
798
    if (arrowIcon != null
799
        && ! (m instanceof JMenu && ((JMenu) m).isTopLevelMenu()))
800
      {
801
        arrowIcon.paintIcon(m, g, arrowIconRect.x, arrowIconRect.y);
802
      }
803
 
804
    g.setFont(oldFont);
805
    g.setColor(oldColor);
806
 
807
  }
808
 
809
  /**
810
   * Paints label for the given menu item
811
   *
812
   * @param g
813
   *          The graphics context used to paint this menu item
814
   * @param menuItem
815
   *          menu item for which to draw its label
816
   * @param textRect
817
   *          rectangle specifiying position of the text relative to the given
818
   *          menu item
819
   * @param text
820
   *          label of the menu item
821
   */
822
  protected void paintText(Graphics g, JMenuItem menuItem, Rectangle textRect,
823
                           String text)
824
  {
825
    Font f = menuItem.getFont();
826
    g.setFont(f);
827
    FontMetrics fm = g.getFontMetrics(f);
828
 
829
    if (text != null && !text.equals(""))
830
      {
831
        if (menuItem.isEnabled())
832
          {
833
            // Menu item is considered to be highlighted when it is selected.
834
            // But not if it's a JCheckBoxMenuItem
835
            ButtonModel mod = menuItem.getModel();
836
            if ((menuItem.isSelected() && checkIcon == null)
837
                || (mod != null && mod.isArmed())
838
                && (menuItem.getParent() instanceof MenuElement))
839
              g.setColor(selectionForeground);
840
            else
841
              g.setColor(menuItem.getForeground());
842
          }
843
        else
844
          // FIXME: should fix this to use 'disabledForeground', but its
845
          // default value in BasicLookAndFeel is null.
846
 
847
          // FIXME: should there be different foreground colours for selected
848
          // or deselected, when disabled?
849
          g.setColor(Color.gray);
850
 
851
        int mnemonicIndex = menuItem.getDisplayedMnemonicIndex();
852
 
853
        if (mnemonicIndex != -1)
854
          BasicGraphicsUtils.drawStringUnderlineCharAt(menuItem, g, text,
855
                                                       mnemonicIndex,
856
                                                       textRect.x,
857
                                                       textRect.y
858
                                                           + fm.getAscent());
859
        else
860
          BasicGraphicsUtils.drawString(menuItem, g, text, 0, textRect.x,
861
                                        textRect.y + fm.getAscent());
862
      }
863
  }
864
 
865
  /**
866
   * This method uninstalls the components for this {@link JMenuItem}.
867
   *
868
   * @param menuItem
869
   *          The {@link JMenuItem} to uninstall components for.
870
   */
871
  protected void uninstallComponents(JMenuItem menuItem)
872
  {
873
    // FIXME: need to implement
874
  }
875
 
876
  /**
877
   * This method uninstalls the defaults and sets any objects created during
878
   * install to null
879
   */
880
  protected void uninstallDefaults()
881
  {
882
    menuItem.setForeground(null);
883
    menuItem.setBackground(null);
884
    menuItem.setBorder(null);
885
    menuItem.setMargin(null);
886
    menuItem.setBackground(null);
887
    menuItem.setBorder(null);
888
    menuItem.setFont(null);
889
    menuItem.setForeground(null);
890
    menuItem.setMargin(null);
891
    acceleratorFont = null;
892
    acceleratorForeground = null;
893
    acceleratorSelectionForeground = null;
894
    arrowIcon = null;
895
    selectionBackground = null;
896
    selectionForeground = null;
897
    acceleratorDelimiter = null;
898
  }
899
 
900
  /**
901
   * Uninstalls any keyboard actions.
902
   */
903
  protected void uninstallKeyboardActions()
904
  {
905
    SwingUtilities.replaceUIInputMap(menuItem,
906
                                     JComponent.WHEN_IN_FOCUSED_WINDOW, null);
907
  }
908
 
909
  /**
910
   * Unregisters all the listeners that this UI delegate was using.
911
   */
912
  protected void uninstallListeners()
913
  {
914
    menuItem.removeMouseListener(mouseInputListener);
915
    menuItem.removeMenuDragMouseListener(menuDragMouseListener);
916
    menuItem.removeMenuKeyListener(menuKeyListener);
917
    menuItem.removeItemListener(itemListener);
918
    menuItem.removePropertyChangeListener(propertyChangeListener);
919
  }
920
 
921
  /**
922
   * Performs the opposite of installUI. Any properties or resources that need
923
   * to be cleaned up will be done now. It will also uninstall any listeners it
924
   * has. In addition, any properties of this UI will be nulled.
925
   *
926
   * @param c
927
   *          The {@link JComponent} that is having this UI uninstalled.
928
   */
929
  public void uninstallUI(JComponent c)
930
  {
931
    uninstallListeners();
932
    uninstallDefaults();
933
    uninstallComponents(menuItem);
934
    c.putClientProperty(BasicGraphicsUtils.CACHED_TEXT_LAYOUT, null);
935
    menuItem = null;
936
  }
937
 
938
  /**
939
   * This method calls paint.
940
   *
941
   * @param g
942
   *          The graphics context used to paint this menu item
943
   * @param c
944
   *          The menu item to paint
945
   */
946
  public void update(Graphics g, JComponent c)
947
  {
948
    paint(g, c);
949
  }
950
 
951
  /**
952
   * This class handles mouse events occuring inside the menu item. Most of the
953
   * events are forwarded for processing to MenuSelectionManager of the current
954
   * menu hierarchy.
955
   */
956
  protected class MouseInputHandler implements MouseInputListener
957
  {
958
    /**
959
     * Creates a new MouseInputHandler object.
960
     */
961
    protected MouseInputHandler()
962
    {
963
      // Nothing to do here.
964
    }
965
 
966
    /**
967
     * This method is called when mouse is clicked on the menu item. It forwards
968
     * this event to MenuSelectionManager.
969
     *
970
     * @param e
971
     *          A {@link MouseEvent}.
972
     */
973
    public void mouseClicked(MouseEvent e)
974
    {
975
      MenuSelectionManager manager = MenuSelectionManager.defaultManager();
976
      manager.processMouseEvent(e);
977
    }
978
 
979
    /**
980
     * This method is called when mouse is dragged inside the menu item. It
981
     * forwards this event to MenuSelectionManager.
982
     *
983
     * @param e
984
     *          A {@link MouseEvent}.
985
     */
986
    public void mouseDragged(MouseEvent e)
987
    {
988
      MenuSelectionManager manager = MenuSelectionManager.defaultManager();
989
      manager.processMouseEvent(e);
990
    }
991
 
992
    /**
993
     * This method is called when mouse enters menu item. When this happens menu
994
     * item is considered to be selected and selection path in
995
     * MenuSelectionManager is set. This event is also forwarded to
996
     * MenuSelection Manager for further processing.
997
     *
998
     * @param e
999
     *          A {@link MouseEvent}.
1000
     */
1001
    public void mouseEntered(MouseEvent e)
1002
    {
1003
      Component source = (Component) e.getSource();
1004
      if (source.getParent() instanceof MenuElement)
1005
        {
1006
          MenuSelectionManager manager = MenuSelectionManager.defaultManager();
1007
          manager.setSelectedPath(getPath());
1008
          manager.processMouseEvent(e);
1009
        }
1010
    }
1011
 
1012
    /**
1013
     * This method is called when mouse exits menu item. The event is forwarded
1014
     * to MenuSelectionManager for processing.
1015
     *
1016
     * @param e
1017
     *          A {@link MouseEvent}.
1018
     */
1019
    public void mouseExited(MouseEvent e)
1020
    {
1021
      MenuSelectionManager manager = MenuSelectionManager.defaultManager();
1022
      manager.processMouseEvent(e);
1023
    }
1024
 
1025
    /**
1026
     * This method is called when mouse is inside the menu item. This event is
1027
     * forwarder to MenuSelectionManager for further processing.
1028
     *
1029
     * @param e
1030
     *          A {@link MouseEvent}.
1031
     */
1032
    public void mouseMoved(MouseEvent e)
1033
    {
1034
      MenuSelectionManager manager = MenuSelectionManager.defaultManager();
1035
      manager.processMouseEvent(e);
1036
    }
1037
 
1038
    /**
1039
     * This method is called when mouse is pressed. This event is forwarded to
1040
     * MenuSelectionManager for further processing.
1041
     *
1042
     * @param e
1043
     *          A {@link MouseEvent}.
1044
     */
1045
    public void mousePressed(MouseEvent e)
1046
    {
1047
      MenuSelectionManager manager = MenuSelectionManager.defaultManager();
1048
      manager.processMouseEvent(e);
1049
    }
1050
 
1051
    /**
1052
     * This method is called when mouse is released. If the mouse is released
1053
     * inside this menuItem, then this menu item is considered to be chosen and
1054
     * the menu hierarchy should be closed.
1055
     *
1056
     * @param e
1057
     *          A {@link MouseEvent}.
1058
     */
1059
    public void mouseReleased(MouseEvent e)
1060
    {
1061
      MenuSelectionManager manager = MenuSelectionManager.defaultManager();
1062
      int x = e.getX();
1063
      int y = e.getY();
1064
      if (x > 0 && x < menuItem.getWidth() && y > 0
1065
          && y < menuItem.getHeight())
1066
        {
1067
          doClick(manager);
1068
        }
1069
      else
1070
        manager.processMouseEvent(e);
1071
    }
1072
  }
1073
 
1074
  /**
1075
   * This class handles mouse dragged events.
1076
   */
1077
  private class MenuDragMouseHandler implements MenuDragMouseListener
1078
  {
1079
    /**
1080
     * Tbis method is invoked when mouse is dragged over the menu item.
1081
     *
1082
     * @param e
1083
     *          The MenuDragMouseEvent
1084
     */
1085
    public void menuDragMouseDragged(MenuDragMouseEvent e)
1086
    {
1087
      MenuSelectionManager manager = e.getMenuSelectionManager();
1088
      manager.setSelectedPath(e.getPath());
1089
    }
1090
 
1091
    /**
1092
     * Tbis method is invoked when mouse enters the menu item while it is being
1093
     * dragged.
1094
     *
1095
     * @param e
1096
     *          The MenuDragMouseEvent
1097
     */
1098
    public void menuDragMouseEntered(MenuDragMouseEvent e)
1099
    {
1100
      MenuSelectionManager manager = e.getMenuSelectionManager();
1101
      manager.setSelectedPath(e.getPath());
1102
    }
1103
 
1104
    /**
1105
     * Tbis method is invoked when mouse exits the menu item while it is being
1106
     * dragged
1107
     *
1108
     * @param e the MenuDragMouseEvent
1109
     */
1110
    public void menuDragMouseExited(MenuDragMouseEvent e)
1111
    {
1112
      // Nothing to do here yet.
1113
    }
1114
 
1115
    /**
1116
     * Tbis method is invoked when mouse was dragged and released inside the
1117
     * menu item.
1118
     *
1119
     * @param e
1120
     *          The MenuDragMouseEvent
1121
     */
1122
    public void menuDragMouseReleased(MenuDragMouseEvent e)
1123
    {
1124
      MenuSelectionManager manager = e.getMenuSelectionManager();
1125
      int x = e.getX();
1126
      int y = e.getY();
1127
      if (x >= 0 && x < menuItem.getWidth() && y >= 0
1128
          && y < menuItem.getHeight())
1129
        doClick(manager);
1130
      else
1131
        manager.clearSelectedPath();
1132
    }
1133
  }
1134
 
1135
  /**
1136
   * This class handles key events occuring when menu item is visible on the
1137
   * screen.
1138
   */
1139
  private class MenuKeyHandler implements MenuKeyListener
1140
  {
1141
    /**
1142
     * This method is invoked when key has been pressed
1143
     *
1144
     * @param e
1145
     *          A {@link MenuKeyEvent}.
1146
     */
1147
    public void menuKeyPressed(MenuKeyEvent e)
1148
    {
1149
      // TODO: What should be done here, if anything?
1150
    }
1151
 
1152
    /**
1153
     * This method is invoked when key has been pressed
1154
     *
1155
     * @param e
1156
     *          A {@link MenuKeyEvent}.
1157
     */
1158
    public void menuKeyReleased(MenuKeyEvent e)
1159
    {
1160
      // TODO: What should be done here, if anything?
1161
    }
1162
 
1163
    /**
1164
     * This method is invoked when key has been typed It handles the mnemonic
1165
     * key for the menu item.
1166
     *
1167
     * @param e
1168
     *          A {@link MenuKeyEvent}.
1169
     */
1170
    public void menuKeyTyped(MenuKeyEvent e)
1171
    {
1172
      // TODO: What should be done here, if anything?
1173
    }
1174
  }
1175
 
1176
  /**
1177
   * Helper class that listens for item changes to the properties of the {@link
1178
   * JMenuItem}.
1179
   */
1180
  private class ItemHandler implements ItemListener
1181
  {
1182
    /**
1183
     * This method is called when one of the menu item changes.
1184
     *
1185
     * @param evt A {@link ItemEvent}.
1186
     */
1187
    public void itemStateChanged(ItemEvent evt)
1188
    {
1189
      boolean state = false;
1190
      if (menuItem instanceof JCheckBoxMenuItem)
1191
        {
1192
          if (evt.getStateChange() == ItemEvent.SELECTED)
1193
            state = true;
1194
          ((JCheckBoxMenuItem) menuItem).setState(state);
1195
        }
1196
      menuItem.revalidate();
1197
      menuItem.repaint();
1198
    }
1199
  }
1200
 
1201
  /**
1202
   * A helper method to create the accelerator string from the menu item's
1203
   * accelerator property. The returned string is empty if there is
1204
   * no accelerator defined.
1205
   *
1206
   * @param m the menu item
1207
   *
1208
   * @return the accelerator string, not null
1209
   */
1210
  private String getAcceleratorString(JMenuItem m)
1211
  {
1212
    // Create accelerator string.
1213
    KeyStroke accel = m.getAccelerator();
1214
    String accelText = "";
1215
    if (accel != null)
1216
      {
1217
        int mods = accel.getModifiers();
1218
        if (mods > 0)
1219
          {
1220
            accelText = KeyEvent.getKeyModifiersText(mods);
1221
            accelText += acceleratorDelimiter;
1222
          }
1223
        int keycode = accel.getKeyCode();
1224
        if (keycode != 0)
1225
          accelText += KeyEvent.getKeyText(keycode);
1226
        else
1227
          accelText += accel.getKeyChar();
1228
      }
1229
    return accelText;
1230
  }
1231
 
1232
  /**
1233
   * Resets the cached layout rectangles. If <code>i</code> is not null, then
1234
   * the view rectangle is set to the inner area of the component, otherwise
1235
   * it is set to (0, 0, Short.MAX_VALUE, Short.MAX_VALUE), this is needed
1236
   * for layouting.
1237
   *
1238
   * @param i the component for which to initialize the rectangles
1239
   */
1240
  private void resetRectangles(JMenuItem i)
1241
  {
1242
    // Reset rectangles.
1243
    iconRect.setBounds(0, 0, 0, 0);
1244
    textRect.setBounds(0, 0, 0, 0);
1245
    accelRect.setBounds(0, 0, 0, 0);
1246
    checkIconRect.setBounds(0, 0, 0, 0);
1247
    arrowIconRect.setBounds(0, 0, 0, 0);
1248
    if (i == null)
1249
      viewRect.setBounds(0, 0, Short.MAX_VALUE, Short.MAX_VALUE);
1250
    else
1251
      {
1252
        Insets insets = i.getInsets();
1253
        viewRect.setBounds(insets.left, insets.top,
1254
                           i.getWidth() - insets.left - insets.right,
1255
                           i.getHeight() - insets.top - insets.bottom);
1256
      }
1257
  }
1258
 
1259
  /**
1260
   * A helper method that lays out the menu item. The layout is stored
1261
   * in the fields of this class.
1262
   *
1263
   * @param m the menu item to layout
1264
   * @param accelText the accelerator text
1265
   */
1266
  private void layoutMenuItem(JMenuItem m, String accelText)
1267
  {
1268
    // Fetch the fonts.
1269
    Font font = m.getFont();
1270
    FontMetrics fm = m.getFontMetrics(font);
1271
    FontMetrics accelFm = m.getFontMetrics(acceleratorFont);
1272
 
1273
    String text = m.getText();
1274
    SwingUtilities.layoutCompoundLabel(m, fm, text, m.getIcon(),
1275
                                       m.getVerticalAlignment(),
1276
                                       m.getHorizontalAlignment(),
1277
                                       m.getVerticalTextPosition(),
1278
                                       m.getHorizontalTextPosition(),
1279
                                       viewRect, iconRect, textRect,
1280
                                       defaultTextIconGap);
1281
 
1282
    // Initialize accelerator width and height.
1283
    if (! accelText.equals(""))
1284
      {
1285
        accelRect.width = accelFm.stringWidth(accelText);
1286
        accelRect.height = accelFm.getHeight();
1287
      }
1288
 
1289
    // Initialize check and arrow icon width and height.
1290
    if (! (m instanceof JMenu && ((JMenu) m).isTopLevelMenu()))
1291
      {
1292
        if (checkIcon != null)
1293
          {
1294
            checkIconRect.width = checkIcon.getIconWidth();
1295
            checkIconRect.height = checkIcon.getIconHeight();
1296
          }
1297
        if (arrowIcon != null)
1298
          {
1299
            arrowIconRect.width = arrowIcon.getIconWidth();
1300
            arrowIconRect.height = arrowIcon.getIconHeight();
1301
          }
1302
      }
1303
 
1304
    // The union of the icon and text of the menu item is the 'label area'.
1305
    cachedRect.setBounds(textRect);
1306
    Rectangle labelRect = SwingUtilities.computeUnion(iconRect.x,
1307
                                                      iconRect.y,
1308
                                                      iconRect.width,
1309
                                                      iconRect.height,
1310
                                                      cachedRect);
1311
    textRect.x += defaultTextIconGap;
1312
    iconRect.x += defaultTextIconGap;
1313
 
1314
    // Layout accelerator rect.
1315
    accelRect.x = viewRect.x + viewRect.width - arrowIconRect.width
1316
      - defaultTextIconGap - accelRect.width;
1317
    // Layout check and arrow icons only when not in toplevel menu.
1318
    if (! (m instanceof JMenu && ((JMenu) m).isTopLevelMenu()))
1319
      {
1320
        checkIconRect.x = viewRect.x + defaultTextIconGap;
1321
        textRect.x += defaultTextIconGap + checkIconRect.width;
1322
        iconRect.x += defaultTextIconGap + checkIconRect.width;
1323
        arrowIconRect.x = viewRect.x + viewRect.width - defaultTextIconGap
1324
          - arrowIconRect.width;
1325
      }
1326
 
1327
    // Align the accelerator text and all the icons vertically centered to
1328
    // the menu text.
1329
    accelRect.y = labelRect.y + (labelRect.height / 2)
1330
      - (accelRect.height / 2);
1331
    if (! (m instanceof JMenu && ((JMenu) m).isTopLevelMenu()))
1332
      {
1333
        arrowIconRect.y = labelRect.y + (labelRect.height / 2)
1334
          - (arrowIconRect.height / 2);
1335
        checkIconRect.y = labelRect.y + (labelRect.height / 2)
1336
          - (checkIconRect.height / 2);
1337
      }
1338
  }
1339
}

powered by: WebSVN 2.1.0

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