1 /* 2 * Copyright (c) 1998, 2014, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.swing.plaf.metal; 27 28 import java.awt.*; 29 import java.awt.event.*; 30 import javax.swing.plaf.basic.*; 31 import javax.swing.*; 32 import javax.swing.plaf.*; 33 import javax.swing.border.*; 34 import java.io.Serializable; 35 36 /** 37 * JButton subclass to help out MetalComboBoxUI 38 * <p> 39 * <strong>Warning:</strong> 40 * Serialized objects of this class will not be compatible with 41 * future Swing releases. The current serialization support is 42 * appropriate for short term storage or RMI between applications running 43 * the same version of Swing. As of 1.4, support for long term storage 44 * of all JavaBeans™ 45 * has been added to the <code>java.beans</code> package. 46 * Please see {@link java.beans.XMLEncoder}. 47 * 48 * @see MetalComboBoxButton 49 * @author Tom Santos 50 */ 51 @SuppressWarnings("serial") // Same-version serialization only 52 public class MetalComboBoxButton extends JButton { 53 54 /** 55 * The instance of {@code JComboBox}. 56 */ 57 protected JComboBox<Object> comboBox; 58 59 /** 60 * The instance of {@code JList}. 61 */ 62 protected JList<Object> listBox; 63 64 /** 65 * The instance of {@code CellRendererPane}. 66 */ 67 protected CellRendererPane rendererPane; 68 69 /** 70 * The icon. 71 */ 72 protected Icon comboIcon; 73 74 /** 75 * The {@code iconOnly} value. 76 */ 77 protected boolean iconOnly = false; 78 79 /** 80 * Returns the {@code JComboBox}. 81 * 82 * @return the {@code JComboBox} 83 */ 84 public final JComboBox<Object> getComboBox() { return comboBox;} 85 86 /** 87 * Sets the {@code JComboBox}. 88 * 89 * @param cb the {@code JComboBox} 90 */ 91 public final void setComboBox( JComboBox<Object> cb ) { comboBox = cb;} 92 93 /** 94 * Returns the icon of the {@code JComboBox}. 95 * 96 * @return the icon of the {@code JComboBox} 97 */ 98 public final Icon getComboIcon() { return comboIcon;} 99 100 /** 101 * Sets the icon of the {@code JComboBox}. 102 * 103 * @param i the icon of the {@code JComboBox} 104 */ 105 public final void setComboIcon( Icon i ) { comboIcon = i;} 106 107 /** 108 * Returns the {@code isIconOnly} value. 109 * 110 * @return the {@code isIconOnly} value 111 */ 112 public final boolean isIconOnly() { return iconOnly;} 113 114 /** 115 * If {@code isIconOnly} is {@code true} then only icon is painted. 116 * 117 * @param isIconOnly if {@code true} then only icon is painted 118 */ 119 public final void setIconOnly( boolean isIconOnly ) { iconOnly = isIconOnly;} 120 121 MetalComboBoxButton() { 122 super( "" ); 123 DefaultButtonModel model = new DefaultButtonModel() { 124 public void setArmed( boolean armed ) { 125 super.setArmed( isPressed() ? true : armed ); 126 } 127 }; 128 setModel( model ); 129 } 130 131 /** 132 * Constructs a new instance of {@code MetalComboBoxButton}. 133 * 134 * @param cb an instance of {@code JComboBox} 135 * @param i an icon 136 * @param pane an instance of {@code CellRendererPane} 137 * @param list an instance of {@code JList} 138 */ 139 public MetalComboBoxButton( JComboBox<Object> cb, Icon i, 140 CellRendererPane pane, JList<Object> list ) { 141 this(); 142 comboBox = cb; 143 comboIcon = i; 144 rendererPane = pane; 145 listBox = list; 146 setEnabled( comboBox.isEnabled() ); 147 } 148 149 /** 150 * Constructs a new instance of {@code MetalComboBoxButton}. 151 * 152 * @param cb an instance of {@code JComboBox} 153 * @param i an icon 154 * @param onlyIcon if {@code true} only icon is painted 155 * @param pane an instance of {@code CellRendererPane} 156 * @param list an instance of {@code JList} 157 */ 158 public MetalComboBoxButton( JComboBox<Object> cb, Icon i, boolean onlyIcon, 159 CellRendererPane pane, JList<Object> list ) { 160 this( cb, i, pane, list ); 161 iconOnly = onlyIcon; 162 } 163 164 @SuppressWarnings("deprecation") 165 public boolean isFocusTraversable() { 166 return false; 167 } 168 169 public void setEnabled(boolean enabled) { 170 super.setEnabled(enabled); 171 172 // Set the background and foreground to the combobox colors. 173 if (enabled) { 174 setBackground(comboBox.getBackground()); 175 setForeground(comboBox.getForeground()); 176 } else { 177 setBackground(UIManager.getColor("ComboBox.disabledBackground")); 178 setForeground(UIManager.getColor("ComboBox.disabledForeground")); 179 } 180 } 181 182 public void paintComponent( Graphics g ) { 183 boolean leftToRight = MetalUtils.isLeftToRight(comboBox); 184 185 // Paint the button as usual 186 super.paintComponent( g ); 187 188 Insets insets = getInsets(); 189 190 int width = getWidth() - (insets.left + insets.right); 191 int height = getHeight() - (insets.top + insets.bottom); 192 193 if ( height <= 0 || width <= 0 ) { 194 return; 195 } 196 197 int left = insets.left; 198 int top = insets.top; 199 int right = left + (width - 1); 200 int bottom = top + (height - 1); 201 202 int iconWidth = 0; 203 int iconLeft = (leftToRight) ? right : left; 204 205 // Paint the icon 206 if ( comboIcon != null ) { 207 iconWidth = comboIcon.getIconWidth(); 208 int iconHeight = comboIcon.getIconHeight(); 209 int iconTop = 0; 210 211 if ( iconOnly ) { 212 iconLeft = (getWidth() / 2) - (iconWidth / 2); 213 iconTop = (getHeight() / 2) - (iconHeight / 2); 214 } 215 else { 216 if (leftToRight) { 217 iconLeft = (left + (width - 1)) - iconWidth; 218 } 219 else { 220 iconLeft = left; 221 } 222 iconTop = (top + ((bottom - top) / 2)) - (iconHeight / 2); 223 } 224 225 comboIcon.paintIcon( this, g, iconLeft, iconTop ); 226 227 // Paint the focus 228 if ( comboBox.hasFocus() && (!MetalLookAndFeel.usingOcean() || 229 comboBox.isEditable())) { 230 g.setColor( MetalLookAndFeel.getFocusColor() ); 231 g.drawRect( left - 1, top - 1, width + 3, height + 1 ); 232 } 233 } 234 235 if (MetalLookAndFeel.usingOcean()) { 236 // With Ocean the button only paints the arrow, bail. 237 return; 238 } 239 240 // Let the renderer paint 241 if ( ! iconOnly && comboBox != null ) { 242 ListCellRenderer<Object> renderer = comboBox.getRenderer(); 243 Component c; 244 boolean renderPressed = getModel().isPressed(); 245 c = renderer.getListCellRendererComponent(listBox, 246 comboBox.getSelectedItem(), 247 -1, 248 renderPressed, 249 false); 250 c.setFont(rendererPane.getFont()); 251 252 if ( model.isArmed() && model.isPressed() ) { 253 if ( isOpaque() ) { 254 c.setBackground(UIManager.getColor("Button.select")); 255 } 256 c.setForeground(comboBox.getForeground()); 257 } 258 else if ( !comboBox.isEnabled() ) { 259 if ( isOpaque() ) { 260 c.setBackground(UIManager.getColor("ComboBox.disabledBackground")); 261 } 262 c.setForeground(UIManager.getColor("ComboBox.disabledForeground")); 263 } 264 else { 265 c.setForeground(comboBox.getForeground()); 266 c.setBackground(comboBox.getBackground()); 267 } 268 269 270 int cWidth = width - (insets.right + iconWidth); 271 272 // Fix for 4238829: should lay out the JPanel. 273 boolean shouldValidate = false; 274 if (c instanceof JPanel) { 275 shouldValidate = true; 276 } 277 278 if (leftToRight) { 279 rendererPane.paintComponent( g, c, this, 280 left, top, cWidth, height, shouldValidate ); 281 } 282 else { 283 rendererPane.paintComponent( g, c, this, 284 left + iconWidth, top, cWidth, height, shouldValidate ); 285 } 286 } 287 } 288 289 public Dimension getMinimumSize() { 290 Dimension ret = new Dimension(); 291 Insets insets = getInsets(); 292 ret.width = insets.left + getComboIcon().getIconWidth() + insets.right; 293 ret.height = insets.bottom + getComboIcon().getIconHeight() + insets.top; 294 return ret; 295 } 296 }