Source for javax.swing.plaf.metal.MetalComboBoxUI

   1: /* MetalComboBoxUI.java
   2:    Copyright (C) 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.metal;
  40: 
  41: import java.awt.Color;
  42: import java.awt.Container;
  43: import java.awt.Dimension;
  44: import java.awt.Graphics;
  45: import java.awt.Insets;
  46: import java.awt.LayoutManager;
  47: import java.awt.event.MouseEvent;
  48: import java.beans.PropertyChangeEvent;
  49: import java.beans.PropertyChangeListener;
  50: 
  51: import javax.swing.CellRendererPane;
  52: import javax.swing.ComboBoxEditor;
  53: import javax.swing.Icon;
  54: import javax.swing.JButton;
  55: import javax.swing.JComboBox;
  56: import javax.swing.JComponent;
  57: import javax.swing.plaf.ComponentUI;
  58: import javax.swing.plaf.basic.BasicComboBoxUI;
  59: import javax.swing.plaf.basic.BasicComboPopup;
  60: import javax.swing.plaf.basic.ComboPopup;
  61: 
  62: 
  63: /**
  64:  * A UI delegate for the {@link JComboBox} component.
  65:  */
  66: public class MetalComboBoxUI extends BasicComboBoxUI
  67: {
  68:   /**
  69:    * A layout manager that arranges the editor component (if active) and the
  70:    * button that make up the combo box.
  71:    */
  72:   public class MetalComboBoxLayoutManager
  73:     extends BasicComboBoxUI.ComboBoxLayoutManager
  74:   {
  75:     /**
  76:      * Creates a new instance of the layout manager.
  77:      */
  78:     public MetalComboBoxLayoutManager()
  79:     {
  80:       // Nothing to do here.
  81:     }
  82:     
  83:     /**
  84:      * Arranges the editor (if visible) and button that comprise the combo
  85:      * box.
  86:      * 
  87:      * @param parent  the parent.
  88:      */
  89:     public void layoutContainer(Container parent)
  90:     {
  91:       layoutComboBox(parent, this);
  92:     }
  93:     
  94:     /**
  95:      * Calls the <code>layoutContainer(Container)</code> method in the super 
  96:      * class.
  97:      * 
  98:      * @param parent  the container.
  99:      */
 100:     public void superLayout(Container parent)
 101:     {
 102:       super.layoutContainer(parent);
 103:     }
 104:   }
 105:   
 106:   /**
 107:    * A listener used to handle property changes in the {@link JComboBox} 
 108:    * component, to ensure that the UI delegate accurately reflects the current
 109:    * state in the rendering onscreen.
 110:    */
 111:   public class MetalPropertyChangeListener
 112:     extends BasicComboBoxUI.PropertyChangeHandler
 113:   {
 114:     /**
 115:      * Creates a new listener.
 116:      */
 117:     public MetalPropertyChangeListener()
 118:     {
 119:       // Nothing to do here.
 120:     }
 121:     
 122:     /**
 123:      * Handles a property change event, updating the UI components as
 124:      * appropriate.
 125:      * 
 126:      * @param e  the event.
 127:      */
 128:     public void propertyChange(PropertyChangeEvent e)
 129:     {
 130:       super.propertyChange(e);
 131:       String name = e.getPropertyName();
 132:       if (name.equals("editable"))
 133:         editablePropertyChanged(e);
 134:       else if (name.equals("enabled"))
 135:         {
 136:           if (arrowButton instanceof MetalComboBoxButton)
 137:             {
 138:               arrowButton.setFocusable(!comboBox.isEditable()
 139:                                        && comboBox.isEnabled());
 140:               comboBox.repaint();
 141:             }
 142:         }
 143:       else if (name.equals("background"))
 144:         {
 145:           Color c = (Color) e.getNewValue();
 146:           arrowButton.setBackground(c);
 147:           listBox.setBackground(c);
 148:         }
 149:       else if (name.equals("foreground"))
 150:         {
 151:           Color c = (Color) e.getNewValue();
 152:           arrowButton.setForeground(c);
 153:           listBox.setForeground(c);
 154:         }
 155:     }
 156:   }
 157: 
 158:   /**
 159:    * A popup menu for the combo-box.
 160:    * 
 161:    * @see #createPopup()
 162:    *
 163:    * @deprecated 1.4
 164:    */
 165:   public class MetalComboPopup extends BasicComboPopup
 166:   {
 167:     /**
 168:      * Creates a new popup.
 169:      * 
 170:      * @param cBox  the combo box.
 171:      */
 172:     public MetalComboPopup(JComboBox cBox)
 173:     {
 174:       super(cBox); 
 175:     }
 176:     
 177:     public void delegateFocus(MouseEvent e)
 178:     {
 179:       super.delegateFocus(e);
 180:     }
 181:   }
 182:   
 183:   /**
 184:    * Constructs a new instance of MetalComboBoxUI.
 185:    */
 186:   public MetalComboBoxUI()
 187:   {
 188:     super();
 189:   }
 190: 
 191:   /**
 192:    * Returns an instance of MetalComboBoxUI.
 193:    *
 194:    * @param component the component for which we return an UI instance
 195:    *
 196:    * @return an instance of MetalComboBoxUI
 197:    */
 198:   public static ComponentUI createUI(JComponent component)
 199:   {
 200:     return new MetalComboBoxUI();
 201:   }
 202:   
 203:   /**
 204:    * Creates an editor for the combo box.
 205:    * 
 206:    * @return An editor.
 207:    */
 208:   protected ComboBoxEditor createEditor()
 209:   {
 210:     return new MetalComboBoxEditor.UIResource();   
 211:   }
 212:   
 213:   /**
 214:    * Creates a popup for the combo box.
 215:    * 
 216:    * @return A popup.
 217:    */
 218:   protected ComboPopup createPopup()
 219:   {
 220:     return new MetalComboPopup(comboBox);
 221:   }
 222:   
 223:   /**
 224:    * Creates a new button for use in rendering the JComboBox.
 225:    * 
 226:    * @return A button.
 227:    */
 228:   protected JButton createArrowButton()
 229:   {
 230:     JButton button = new MetalComboBoxButton(comboBox, new MetalComboBoxIcon(), 
 231:             new CellRendererPane(), listBox);  
 232:     button.setMargin(new Insets(0, 1, 1, 3));
 233:     return button;
 234:   }
 235:   
 236:   /**
 237:    * Creates a new property change listener.
 238:    * 
 239:    * @return A new property change listener.
 240:    */
 241:   public PropertyChangeListener createPropertyChangeListener()
 242:   {
 243:     return new MetalPropertyChangeListener();
 244:   }
 245:   
 246:   public void paint(Graphics g, JComponent c)
 247:   {
 248:     // do nothing, the button and text field are painted elsewhere
 249:   }
 250:   
 251:   /**
 252:    * Updates the button and text field to reflect a change in the 'editable'
 253:    * property.
 254:    * 
 255:    * @param e  the event.
 256:    * 
 257:    * @deprecated 1.4
 258:    */
 259:   protected void editablePropertyChanged(PropertyChangeEvent e)
 260:   {
 261:     if (arrowButton instanceof MetalComboBoxButton)
 262:       {
 263:         MetalComboBoxButton b = (MetalComboBoxButton) arrowButton;
 264:         b.setIconOnly(comboBox.isEditable());
 265:         b.setFocusable(!comboBox.isEditable() && comboBox.isEnabled());
 266:         comboBox.repaint();
 267:       }
 268:   }
 269:   
 270:   /**
 271:    * Creates a new layout manager for the UI delegate.
 272:    * 
 273:    * @return A new layout manager.
 274:    */
 275:   protected LayoutManager createLayoutManager()
 276:   {
 277:     return new MetalComboBoxLayoutManager();
 278:   }
 279:   
 280:   /**
 281:    * Not used in Classpath.
 282:    * 
 283:    * @deprecated 1.4
 284:    */
 285:   protected void removeListeners()
 286:   {
 287:     // no longer used in JDK 1.4 
 288:   }
 289:   
 290:   /**
 291:    * Returns the minimum size for the combo.
 292:    * 
 293:    * @param c  the component
 294:    * 
 295:    * @return The minimum size for the combo box.
 296:    */
 297:   public Dimension getMinimumSize(JComponent c)
 298:   {
 299:     if (!isMinimumSizeDirty)
 300:       return new Dimension(cachedMinimumSize);
 301: 
 302:     Dimension d;
 303:     if (!comboBox.isEditable() && arrowButton != null
 304:         && arrowButton instanceof MetalComboBoxButton)
 305:       {
 306:         MetalComboBoxButton b = (MetalComboBoxButton) arrowButton;
 307:         d = getDisplaySize();
 308:         Insets insets = b.getInsets();
 309:         Insets arrowInsets = b.getInsets();
 310:         Insets comboInsets = comboBox.getInsets();
 311:         Icon icon = b.getComboIcon();
 312:         d.width += comboInsets.left + comboInsets.right;
 313:         d.width += arrowInsets.left + arrowInsets.right;
 314:         d.width += arrowInsets.right + icon.getIconWidth();
 315:         d.height += comboInsets.top + comboInsets.bottom;
 316:         d.height += arrowInsets.top + arrowInsets.bottom;
 317:       }
 318:     else if (comboBox.isEditable() && arrowButton != null && editor != null)
 319:       {
 320:         d = super.getMinimumSize(c);
 321:         Insets arrowMargin = arrowButton.getMargin();
 322:         d.height += arrowMargin.top + arrowMargin.bottom;
 323:         d.width += arrowMargin.left + arrowMargin.right;
 324:       }
 325:     else
 326:       {
 327:         d = super.getMinimumSize(c);
 328:       }
 329:     cachedMinimumSize.setSize(d.width, d.height);
 330:     isMinimumSizeDirty = false;
 331:     return new Dimension(cachedMinimumSize);
 332:   }
 333:   
 334:   /**
 335:    * Configures the editor for this combo box.
 336:    */
 337:   public void configureEditor()
 338:   {
 339:     super.configureEditor();
 340:     if (popupKeyListener != null)
 341:       editor.removeKeyListener(popupKeyListener);
 342:     if (focusListener != null)
 343:       editor.addFocusListener(focusListener);
 344:   }
 345: 
 346:   /**
 347:    * Unconfigures the editor for this combo box.
 348:    */
 349:   public void unconfigureEditor()
 350:   {
 351:     super.unconfigureEditor();
 352:     if (focusListener != null)
 353:       editor.removeFocusListener(focusListener);
 354:   }
 355:   
 356:   /** 
 357:    * Lays out the ComboBox
 358:    */
 359:   public void layoutComboBox(Container parent,
 360:                              MetalComboBoxUI.MetalComboBoxLayoutManager manager)
 361:   {
 362:     if (comboBox.isEditable())
 363:       manager.superLayout(parent);
 364:     else if (arrowButton != null)
 365:       {
 366:         Insets comboInsets = comboBox.getInsets();
 367:         int width = comboBox.getWidth();
 368:         int height = comboBox.getHeight();
 369:         arrowButton.setBounds(comboInsets.left, comboInsets.top,
 370:                               width - (comboInsets.left + comboInsets.right),
 371:                               height - (comboInsets.top + comboInsets.bottom));
 372:       }
 373:   }
 374: }