Source for javax.swing.plaf.basic.BasicPopupMenuUI

   1: /* 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 gnu.classpath.NotImplementedException;
  41: 
  42: import java.awt.Component;
  43: import java.awt.Dimension;
  44: import java.awt.event.ComponentEvent;
  45: import java.awt.event.ComponentListener;
  46: import java.awt.event.MouseEvent;
  47: 
  48: import javax.swing.BoxLayout;
  49: import javax.swing.JComponent;
  50: import javax.swing.JMenuItem;
  51: import javax.swing.JPopupMenu;
  52: import javax.swing.LookAndFeel;
  53: import javax.swing.MenuElement;
  54: import javax.swing.MenuSelectionManager;
  55: import javax.swing.SwingUtilities;
  56: import javax.swing.event.PopupMenuEvent;
  57: import javax.swing.event.PopupMenuListener;
  58: import javax.swing.plaf.ComponentUI;
  59: import javax.swing.plaf.PopupMenuUI;
  60: 
  61: 
  62: /**
  63:  * UI Delegate for JPopupMenu
  64:  */
  65: public class BasicPopupMenuUI extends PopupMenuUI
  66: {
  67:   /* popupMenu for which this UI delegate is for*/
  68:   protected JPopupMenu popupMenu;
  69: 
  70:   /* PopupMenuListener listens to popup menu events fired by JPopupMenu*/
  71:   private transient PopupMenuListener popupMenuListener;
  72: 
  73:   /* ComponentListener listening to popupMenu's invoker.
  74:    * This is package-private to avoid an accessor method.  */
  75:   TopWindowListener topWindowListener;
  76: 
  77:   /**
  78:    * Creates a new BasicPopupMenuUI object.
  79:    */
  80:   public BasicPopupMenuUI()
  81:   {
  82:     popupMenuListener = new PopupMenuHandler();
  83:     topWindowListener = new TopWindowListener();
  84:   }
  85: 
  86:   /**
  87:    * Factory method to create a BasicPopupMenuUI for the given {@link
  88:    * JComponent}, which should be a {@link JMenuItem}.
  89:    *
  90:    * @param x The {@link JComponent} a UI is being created for.
  91:    *
  92:    * @return A BasicPopupMenuUI for the {@link JComponent}.
  93:    */
  94:   public static ComponentUI createUI(JComponent x)
  95:   {
  96:     return new BasicPopupMenuUI();
  97:   }
  98: 
  99:   /**
 100:    * Installs and initializes all fields for this UI delegate. Any properties
 101:    * of the UI that need to be initialized and/or set to defaults will be
 102:    * done now. It will also install any listeners necessary.
 103:    *
 104:    * @param c The {@link JComponent} that is having this UI installed.
 105:    */
 106:   public void installUI(JComponent c)
 107:   {
 108:     super.installUI(c);
 109:     popupMenu = (JPopupMenu) c;
 110:     popupMenu.setLayout(new DefaultMenuLayout(popupMenu, BoxLayout.Y_AXIS));
 111:     popupMenu.setBorderPainted(true);
 112:     JPopupMenu.setDefaultLightWeightPopupEnabled(true);
 113: 
 114:     installDefaults();
 115:     installListeners();
 116:   }
 117: 
 118:   /**
 119:    * This method installs the defaults that are defined in  the Basic look
 120:    * and feel for this {@link JPopupMenu}.
 121:    */
 122:   public void installDefaults()
 123:   {
 124:     LookAndFeel.installColorsAndFont(popupMenu, "PopupMenu.background",
 125:                                      "PopupMenu.foreground", "PopupMenu.font");
 126:     LookAndFeel.installBorder(popupMenu, "PopupMenu.border");
 127:     popupMenu.setOpaque(true);
 128:   }
 129: 
 130:   /**
 131:    * This method installs the listeners for the {@link JMenuItem}.
 132:    */
 133:   protected void installListeners()
 134:   {
 135:     popupMenu.addPopupMenuListener(popupMenuListener);
 136:   }
 137: 
 138:   /**
 139:    * This method installs the keyboard actions for this {@link JPopupMenu}.
 140:    */
 141:   protected void installKeyboardActions()
 142:     throws NotImplementedException
 143:   {
 144:     // FIXME: Need to implement
 145:   }
 146: 
 147:   /**
 148:    * Performs the opposite of installUI. Any properties or resources that need
 149:    * to be cleaned up will be done now. It will also uninstall any listeners
 150:    * it has. In addition, any properties of this UI will be nulled.
 151:    *
 152:    * @param c The {@link JComponent} that is having this UI uninstalled.
 153:    */
 154:   public void uninstallUI(JComponent c)
 155:   {
 156:     uninstallListeners();
 157:     uninstallDefaults();
 158:     popupMenu = null;
 159:   }
 160: 
 161:   /**
 162:    * This method uninstalls the defaults and sets any objects created during
 163:    * install to null
 164:    */
 165:   protected void uninstallDefaults()
 166:   {
 167:     popupMenu.setBackground(null);
 168:     popupMenu.setBorder(null);
 169:     popupMenu.setFont(null);
 170:     popupMenu.setForeground(null);
 171:   }
 172: 
 173:   /**
 174:    * Unregisters all the listeners that this UI delegate was using.
 175:    */
 176:   protected void uninstallListeners()
 177:   {
 178:     popupMenu.removePopupMenuListener(popupMenuListener);
 179:   }
 180: 
 181:   /**
 182:    * Uninstalls any keyboard actions.
 183:    */
 184:   protected void uninstallKeyboardActions()
 185:     throws NotImplementedException
 186:   {
 187:     // FIXME: Need to implement
 188:   }
 189: 
 190:   /**
 191:    * This method returns the minimum size of the JPopupMenu.
 192:    *
 193:    * @param c The JComponent to find a size for.
 194:    *
 195:    * @return The minimum size.
 196:    */
 197:   public Dimension getMinimumSize(JComponent c)
 198:   {
 199:     return null;
 200:   }
 201: 
 202:   /**
 203:    * This method returns the preferred size of the JPopupMenu.
 204:    *
 205:    * @param c The JComponent to find a size for.
 206:    *
 207:    * @return The preferred size.
 208:    */
 209:   public Dimension getPreferredSize(JComponent c)
 210:   {
 211:     return null;
 212:   }
 213: 
 214:   /**
 215:    * This method returns the minimum size of the JPopupMenu.
 216:    *
 217:    * @param c The JComponent to find a size for.
 218:    *
 219:    * @return The minimum size.
 220:    */
 221:   public Dimension getMaximumSize(JComponent c)
 222:   {
 223:     return null;
 224:   }
 225: 
 226:   /**
 227:    * Return true if given mouse event is a platform popup trigger, and false
 228:    * otherwise
 229:    *
 230:    * @param e MouseEvent that is to be checked for popup trigger event
 231:    *
 232:    * @return true if given mouse event is a platform popup trigger, and false
 233:    *         otherwise
 234:    */
 235:   public boolean isPopupTrigger(MouseEvent e)
 236:   {
 237:     return false;
 238:   }
 239: 
 240:   /**
 241:    * This listener handles PopupMenuEvents fired by JPopupMenu
 242:    */
 243:   private class PopupMenuHandler implements PopupMenuListener
 244:   {
 245:     /**
 246:      * This method is invoked when JPopupMenu is cancelled.
 247:      *
 248:      * @param event the PopupMenuEvent
 249:      */
 250:     public void popupMenuCanceled(PopupMenuEvent event)
 251:     {
 252:       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
 253:       manager.clearSelectedPath();
 254:     }
 255: 
 256:     /**
 257:      * This method is invoked when JPopupMenu becomes invisible
 258:      *
 259:      * @param event the PopupMenuEvent
 260:      */
 261:     public void popupMenuWillBecomeInvisible(PopupMenuEvent event)
 262:     {
 263:       // remove listener that listens to component events fired 
 264:       // by the top - level window that this popup belongs to.
 265:       Component invoker = popupMenu.getInvoker();
 266:       Component rootContainer = SwingUtilities.getRoot(invoker);
 267:       if (rootContainer != null)
 268:         rootContainer.removeComponentListener(topWindowListener);
 269:     }
 270: 
 271:     /**
 272:      * This method is invoked when JPopupMenu becomes visible
 273:      *
 274:      * @param event the PopupMenuEvent
 275:      */
 276:     public void popupMenuWillBecomeVisible(PopupMenuEvent event)
 277:     {
 278:       // Adds topWindowListener to top-level window to listener to 
 279:       // ComponentEvents fired by it. We need to cancel this popup menu
 280:       // if topWindow to which this popup belongs was resized or moved.
 281:       Component invoker = popupMenu.getInvoker();
 282:       Component rootContainer = SwingUtilities.getRoot(invoker);
 283:       rootContainer.addComponentListener(topWindowListener);
 284: 
 285:       // if this popup menu is a free floating popup menu,
 286:       // then by default its first element should be always selected when
 287:       // this popup menu becomes visible. 
 288:       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
 289: 
 290:       if (manager.getSelectedPath().length == 0)
 291:         {
 292:       // Set selected path to point to the first item in the popup menu
 293:       MenuElement[] path = new MenuElement[2];
 294:       path[0] = popupMenu;
 295:       Component[] comps = popupMenu.getComponents();
 296:       if (comps.length != 0 && comps[0] instanceof MenuElement)
 297:         {
 298:           path[1] = (MenuElement) comps[0];
 299:           manager.setSelectedPath(path);
 300:         }
 301:         }
 302:     }
 303:   }
 304: 
 305:   /**
 306:    * ComponentListener that listens to Component Events fired by the top -
 307:    * level window to which popup menu belongs. If top-level window was
 308:    * resized, moved or hidded then popup menu will be hidded and selected
 309:    * path of current menu hierarchy will be set to null.
 310:    */
 311:   private class TopWindowListener implements ComponentListener
 312:   {
 313:     /**
 314:      * This method is invoked when top-level window is resized. This method
 315:      * closes current menu hierarchy.
 316:      *
 317:      * @param e The ComponentEvent
 318:      */
 319:     public void componentResized(ComponentEvent e)
 320:     {
 321:       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
 322:       manager.clearSelectedPath();
 323:     }
 324: 
 325:     /**
 326:      * This method is invoked when top-level window is moved. This method
 327:      * closes current menu hierarchy.
 328:      *
 329:      * @param e The ComponentEvent
 330:      */
 331:     public void componentMoved(ComponentEvent e)
 332:     {
 333:       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
 334:       manager.clearSelectedPath();
 335:     }
 336: 
 337:     /**
 338:      * This method is invoked when top-level window is shown This method
 339:      * does nothing by default.
 340:      *
 341:      * @param e The ComponentEvent
 342:      */
 343:     public void componentShown(ComponentEvent e)
 344:     {
 345:       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
 346:       manager.clearSelectedPath();
 347:     }
 348: 
 349:     /**
 350:      * This method is invoked when top-level window is hidden This method
 351:      * closes current menu hierarchy.
 352:      *
 353:      * @param e The ComponentEvent
 354:      */
 355:     public void componentHidden(ComponentEvent e)
 356:     {
 357:       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
 358:       manager.clearSelectedPath();
 359:     }
 360:   }
 361: 
 362: }