jdk/src/solaris/classes/sun/awt/X11/XMenuItemPeer.java
changeset 2 90ce3da70b43
child 116 9c43d9eb1029
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 2002-2007 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 package sun.awt.X11;
       
    26 
       
    27 import java.awt.*;
       
    28 import java.awt.peer.*;
       
    29 import java.awt.event.*;
       
    30 
       
    31 import java.util.logging.*;
       
    32 
       
    33 import java.lang.reflect.Field;
       
    34 import java.lang.reflect.Method;
       
    35 import java.lang.reflect.InvocationTargetException;
       
    36 import sun.awt.SunToolkit;
       
    37 
       
    38 public class XMenuItemPeer implements MenuItemPeer {
       
    39 
       
    40     /************************************************
       
    41      *
       
    42      * Data members
       
    43      *
       
    44      ************************************************/
       
    45 
       
    46     private static Logger log = Logger.getLogger("sun.awt.X11.XMenuItemPeer");
       
    47 
       
    48     /*
       
    49      * Primary members
       
    50      */
       
    51 
       
    52     /**
       
    53      * Window that this item belongs to.
       
    54      */
       
    55     private XBaseMenuWindow container;
       
    56 
       
    57     /**
       
    58      * Target MenuItem. Note that 'target' member
       
    59      * in XWindow is required for dispatching events.
       
    60      * This member is only used for accessing its fields
       
    61      * and firing ActionEvent & ItemEvent
       
    62      */
       
    63     private MenuItem target;
       
    64 
       
    65     /*
       
    66      * Mapping to window
       
    67      */
       
    68 
       
    69     /**
       
    70      * Rectange occupied by menu item in container's
       
    71      * coordinates. Filled by map(...) function from
       
    72      * XBaseMenuWindow.map()
       
    73      */
       
    74     private Rectangle bounds;
       
    75 
       
    76     /**
       
    77      * Point in container's coordinate system used as
       
    78      * origin by drawText.
       
    79      */
       
    80     private Point textOrigin;
       
    81 
       
    82     /*
       
    83      * Size constants
       
    84      */
       
    85     private final static int SEPARATOR_WIDTH = 20;
       
    86     private final static int SEPARATOR_HEIGHT = 5;
       
    87 
       
    88     /*
       
    89      * MenuItem's fields & methods
       
    90      */
       
    91     private final static Field f_enabled;
       
    92     private final static Field f_label;
       
    93     private final static Field f_shortcut;
       
    94     private final static Method m_getFont;
       
    95     private final static Method m_isItemEnabled;
       
    96     private final static Method m_getActionCommand;
       
    97     static {
       
    98         f_enabled = SunToolkit.getField(MenuItem.class, "enabled");
       
    99         f_label = SunToolkit.getField(MenuItem.class, "label");
       
   100         f_shortcut = SunToolkit.getField(MenuItem.class, "shortcut");
       
   101 
       
   102         m_getFont = SunToolkit.getMethod(MenuComponent.class, "getFont_NoClientCode", null);
       
   103         m_getActionCommand = SunToolkit.getMethod(MenuItem.class, "getActionCommandImpl", null);
       
   104         m_isItemEnabled = SunToolkit.getMethod(MenuItem.class, "isItemEnabled", null);
       
   105     }
       
   106     /************************************************
       
   107      *
       
   108      * Text Metrics
       
   109      *
       
   110      ************************************************/
       
   111 
       
   112     /**
       
   113      * Text metrics are filled in calcTextMetrics function
       
   114      * and reset in resetTextMetrics function. Text metrics
       
   115      * contain calculated dimensions of various components of
       
   116      * menu item.
       
   117      */
       
   118     private TextMetrics textMetrics;
       
   119 
       
   120     static class TextMetrics implements Cloneable {
       
   121         /*
       
   122          * Calculated text size members
       
   123          */
       
   124         private Dimension textDimension;
       
   125         private int shortcutWidth;
       
   126         private int textBaseline;
       
   127 
       
   128         TextMetrics(Dimension textDimension, int shortcutWidth, int textBaseline) {
       
   129             this.textDimension = textDimension;
       
   130             this.shortcutWidth = shortcutWidth;
       
   131             this.textBaseline = textBaseline;
       
   132         }
       
   133 
       
   134         public Object clone() {
       
   135             try {
       
   136                 return super.clone();
       
   137             } catch (CloneNotSupportedException ex) {
       
   138                 throw new InternalError();
       
   139             }
       
   140         }
       
   141 
       
   142         Dimension getTextDimension() {
       
   143             return this.textDimension;
       
   144         }
       
   145 
       
   146         int getShortcutWidth() {
       
   147             return this.shortcutWidth;
       
   148         }
       
   149 
       
   150         int getTextBaseline() {
       
   151             return this.textBaseline;
       
   152         }
       
   153     }
       
   154 
       
   155     /************************************************
       
   156      *
       
   157      * Construction
       
   158      *
       
   159      ************************************************/
       
   160     XMenuItemPeer(MenuItem target) {
       
   161         this.target = target;
       
   162     }
       
   163 
       
   164     /************************************************
       
   165      *
       
   166      * Implementaion of interface methods
       
   167      *
       
   168      ************************************************/
       
   169 
       
   170     /*
       
   171      * From MenuComponentPeer
       
   172      */
       
   173     public void dispose() {
       
   174         //Empty function
       
   175     }
       
   176 
       
   177     public void setFont(Font font) {
       
   178         resetTextMetrics();
       
   179         repaintIfShowing();
       
   180     }
       
   181     /*
       
   182      * From MenuItemPeer
       
   183      */
       
   184     public void setLabel(String label) {
       
   185         resetTextMetrics();
       
   186         repaintIfShowing();
       
   187     }
       
   188 
       
   189     public void setEnabled(boolean enabled) {
       
   190         repaintIfShowing();
       
   191     }
       
   192 
       
   193     /**
       
   194      * DEPRECATED:  Replaced by setEnabled(boolean).
       
   195      * @see java.awt.peer.MenuItemPeer
       
   196      */
       
   197     public void enable() {
       
   198         setEnabled( true );
       
   199     }
       
   200 
       
   201     /**
       
   202      * DEPRECATED:  Replaced by setEnabled(boolean).
       
   203      * @see java.awt.peer.MenuItemPeer
       
   204      */
       
   205     public void disable() {
       
   206         setEnabled( false );
       
   207     }
       
   208 
       
   209     /************************************************
       
   210      *
       
   211      * Access to target's fields
       
   212      *
       
   213      ************************************************/
       
   214 
       
   215     MenuItem getTarget() {
       
   216         return this.target;
       
   217     }
       
   218 
       
   219     Font getTargetFont() {
       
   220         if (target == null) {
       
   221             return XWindow.defaultFont;
       
   222         }
       
   223         try {
       
   224             return (Font)m_getFont.invoke(target, new Object[0]);
       
   225         } catch (IllegalAccessException e) {
       
   226             e.printStackTrace();
       
   227         } catch (InvocationTargetException e) {
       
   228             e.printStackTrace();
       
   229         }
       
   230         return XWindow.defaultFont;
       
   231     }
       
   232 
       
   233     String getTargetLabel() {
       
   234         if (target == null) {
       
   235             return "";
       
   236         }
       
   237         try {
       
   238             String label = (String)f_label.get(target);
       
   239             return (label == null) ? "" : label;
       
   240         } catch (IllegalAccessException e) {
       
   241             e.printStackTrace();
       
   242         }
       
   243         return "";
       
   244     }
       
   245 
       
   246     boolean isTargetEnabled() {
       
   247         if (target == null) {
       
   248             return false;
       
   249         }
       
   250         try {
       
   251             return f_enabled.getBoolean(target);
       
   252         } catch (IllegalAccessException e) {
       
   253             e.printStackTrace();
       
   254         }
       
   255         return false;
       
   256     }
       
   257 
       
   258     /**
       
   259      * Returns true if item and all its parents are enabled
       
   260      * This function is used to fix
       
   261      * 6184485: Popup menu is not disabled on XToolkit even when calling setEnabled (false)
       
   262      */
       
   263     boolean isTargetItemEnabled() {
       
   264         if (target == null) {
       
   265             return false;
       
   266         }
       
   267         try {
       
   268             return ((Boolean)m_isItemEnabled.invoke(target, new Object[0])).booleanValue();
       
   269         } catch (IllegalAccessException e) {
       
   270             e.printStackTrace();
       
   271         } catch (InvocationTargetException e) {
       
   272             e.printStackTrace();
       
   273         }
       
   274         return false;
       
   275     }
       
   276 
       
   277     String getTargetActionCommand() {
       
   278         if (target == null) {
       
   279             return "";
       
   280         }
       
   281         try {
       
   282             return (String) m_getActionCommand.invoke(target,(Object[]) null);
       
   283         } catch (IllegalAccessException e) {
       
   284             e.printStackTrace();
       
   285         } catch (InvocationTargetException e) {
       
   286             e.printStackTrace();
       
   287         }
       
   288         return "";
       
   289     }
       
   290 
       
   291     MenuShortcut getTargetShortcut() {
       
   292         if (target == null) {
       
   293             return null;
       
   294         }
       
   295         try {
       
   296             return (MenuShortcut)f_shortcut.get(target);
       
   297         } catch (IllegalAccessException e) {
       
   298             e.printStackTrace();
       
   299         }
       
   300         return null;
       
   301     }
       
   302 
       
   303     String getShortcutText() {
       
   304         //Fix for 6180413: shortcuts should not be displayed for any of the menuitems in a popup menu
       
   305         if (container == null) {
       
   306             return null;
       
   307         }
       
   308         if (container.getRootMenuWindow() instanceof XPopupMenuPeer) {
       
   309             return null;
       
   310         }
       
   311         MenuShortcut sc = getTargetShortcut();
       
   312         //TODO:This can potentially call user code
       
   313         return (sc == null) ? null : sc.toString();
       
   314     }
       
   315 
       
   316 
       
   317     /************************************************
       
   318      *
       
   319      * Basic manipulations
       
   320      *
       
   321      ************************************************/
       
   322 
       
   323     /**
       
   324      * This function is called when filling item vectors
       
   325      * in XMenuWindow & XMenuBar. We need it because peers
       
   326      * are created earlier than windows.
       
   327      * @param container the window that this item belongs to.
       
   328      */
       
   329     void setContainer(XBaseMenuWindow container) {
       
   330         synchronized(XBaseMenuWindow.getMenuTreeLock()) {
       
   331             this.container = container;
       
   332         }
       
   333     }
       
   334 
       
   335     /**
       
   336      * returns the window that this item belongs to
       
   337      */
       
   338     XBaseMenuWindow getContainer() {
       
   339         return this.container;
       
   340     }
       
   341 
       
   342     /************************************************
       
   343      *
       
   344      * Overridable behaviour
       
   345      *
       
   346      ************************************************/
       
   347 
       
   348     /**
       
   349      * This function should be overriden simply to
       
   350      * return false in inherited classes.
       
   351      */
       
   352     boolean isSeparator() {
       
   353         boolean r = (getTargetLabel().equals("-"));
       
   354         return r;
       
   355     }
       
   356 
       
   357     /************************************************
       
   358      *
       
   359      * Utility functions
       
   360      *
       
   361      ************************************************/
       
   362 
       
   363     /**
       
   364      * Returns true if container exists and is showing
       
   365      */
       
   366     boolean isContainerShowing() {
       
   367         if (container == null) {
       
   368             return false;
       
   369         }
       
   370         return container.isShowing();
       
   371     }
       
   372 
       
   373     /**
       
   374      * Repaints item if it is showing
       
   375      */
       
   376     void repaintIfShowing() {
       
   377         if (isContainerShowing()) {
       
   378             container.postPaintEvent();
       
   379         }
       
   380     }
       
   381 
       
   382     /**
       
   383      * This function is invoked when the user clicks
       
   384      * on menu item.
       
   385      * @param when the timestamp of action event
       
   386      */
       
   387     void action(long when) {
       
   388         if (!isSeparator() && isTargetItemEnabled()) {
       
   389             XWindow.postEventStatic(new ActionEvent(target, ActionEvent.ACTION_PERFORMED,
       
   390                                                     getTargetActionCommand(), when,
       
   391                                                     0));
       
   392         }
       
   393     }
       
   394     /************************************************
       
   395      *
       
   396      * Text metrics
       
   397      *
       
   398      ************************************************/
       
   399 
       
   400     /**
       
   401      * Returns text metrics of menu item.
       
   402      * This function does not use any locks
       
   403      * and is guaranteed to return some value
       
   404      * (possibly actual, possibly expired)
       
   405      */
       
   406     TextMetrics getTextMetrics() {
       
   407         TextMetrics textMetrics = this.textMetrics;
       
   408         if (textMetrics == null) {
       
   409             textMetrics = calcTextMetrics();
       
   410             this.textMetrics = textMetrics;
       
   411         }
       
   412         return textMetrics;
       
   413     }
       
   414 
       
   415     /**
       
   416      * Returns dimensions of item's label.
       
   417      * This function does not use any locks
       
   418      * Returns actual or expired  value
       
   419      * or null if error occurs
       
   420      */
       
   421     /*Dimension getTextDimension() {
       
   422         TextMetrics textMetrics = this.textMetrics;
       
   423         if (textMetrics == null) {
       
   424             textMetrics = calcTextMetrics();
       
   425             this.textMetrics = textMetrics;
       
   426         }
       
   427         return (textMetrics != null) ? textMetrics.textDimension : null;
       
   428         }*/
       
   429 
       
   430     /**
       
   431      * Returns width of item's shortcut label,
       
   432      * 0 if item has no shortcut.
       
   433      * The height of shortcut can be deternimed
       
   434      * from text dimensions.
       
   435      * This function does not use any locks
       
   436      * and is guaranteed to return some value
       
   437      * (possibly actual, possibly expired)
       
   438      */
       
   439     /*int getShortcutWidth() {
       
   440         TextMetrics textMetrics = this.textMetrics;
       
   441         if (textMetrics == null) {
       
   442             textMetrics = calcTextMetrics();
       
   443             this.textMetrics = textMetrics;
       
   444         }
       
   445         return (textMetrics != null) ? textMetrics.shortcutWidth : 0;
       
   446     }
       
   447 
       
   448     int getTextBaseline() {
       
   449         TextMetrics textMetrics = this.textMetrics;
       
   450         if (textMetrics == null) {
       
   451             textMetrics = calcTextMetrics();
       
   452             this.textMetrics = textMetrics;
       
   453         }
       
   454         return (textMetrics != null) ? textMetrics.textBaseline : 0;
       
   455         }*/
       
   456 
       
   457     TextMetrics calcTextMetrics() {
       
   458         if (container == null) {
       
   459             return null;
       
   460         }
       
   461         if (isSeparator()) {
       
   462             return new TextMetrics(new Dimension(SEPARATOR_WIDTH, SEPARATOR_HEIGHT), 0, 0);
       
   463         }
       
   464         Graphics g = container.getGraphics();
       
   465         if (g == null) {
       
   466             return null;
       
   467         }
       
   468         try {
       
   469             g.setFont(getTargetFont());
       
   470             FontMetrics fm = g.getFontMetrics();
       
   471             String str = getTargetLabel();
       
   472             int width = fm.stringWidth(str);
       
   473             int height = fm.getHeight();
       
   474             Dimension textDimension = new Dimension(width, height);
       
   475             int textBaseline = fm.getHeight() - fm.getAscent();
       
   476             String sc = getShortcutText();
       
   477             int shortcutWidth = (sc == null) ? 0 : fm.stringWidth(sc);
       
   478             return new TextMetrics(textDimension, shortcutWidth, textBaseline);
       
   479         } finally {
       
   480             g.dispose();
       
   481         }
       
   482     }
       
   483 
       
   484     void resetTextMetrics() {
       
   485         textMetrics = null;
       
   486         if (container != null) {
       
   487             container.updateSize();
       
   488         }
       
   489     }
       
   490 
       
   491     /************************************************
       
   492      *
       
   493      * Mapping utility functions
       
   494      *
       
   495      ************************************************/
       
   496 
       
   497     /**
       
   498      * Sets mapping of item to window.
       
   499      * @param bounds bounds of item in container's coordinates
       
   500      * @param textOrigin point for drawString in container's coordinates
       
   501      * @see XBaseMenuWindow.map()
       
   502      */
       
   503     void map(Rectangle bounds, Point textOrigin) {
       
   504         this.bounds = bounds;
       
   505         this.textOrigin = textOrigin;
       
   506     }
       
   507 
       
   508     /**
       
   509      * returns bounds of item that were previously set by map() function
       
   510      */
       
   511     Rectangle getBounds() {
       
   512         return bounds;
       
   513     }
       
   514 
       
   515     /**
       
   516      * returns origin of item's text that was previously set by map() function
       
   517      */
       
   518     Point getTextOrigin() {
       
   519         return textOrigin;
       
   520     }
       
   521 
       
   522 }