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 public boolean isFocusTraversable() { 165 return false; 166 } 167 168 public void setEnabled(boolean enabled) { 169 super.setEnabled(enabled); 170 171 // Set the background and foreground to the combobox colors. 172 if (enabled) { 173 setBackground(comboBox.getBackground()); 174 setForeground(comboBox.getForeground()); 175 } else { 176 setBackground(UIManager.getColor("ComboBox.disabledBackground")); 177 setForeground(UIManager.getColor("ComboBox.disabledForeground")); 178 } 179 } 180 181 public void paintComponent( Graphics g ) { 182 boolean leftToRight = MetalUtils.isLeftToRight(comboBox); 183 184 // Paint the button as usual 185 super.paintComponent( g ); 186 187 Insets insets = getInsets(); 188 189 int width = getWidth() - (insets.left + insets.right); 190 int height = getHeight() - (insets.top + insets.bottom); 191 192 if ( height <= 0 || width <= 0 ) { 193 return; 194 } 195 196 int left = insets.left; 197 int top = insets.top; 198 int right = left + (width - 1); 199 int bottom = top + (height - 1); 200 201 int iconWidth = 0; 202 int iconLeft = (leftToRight) ? right : left; 203 204 // Paint the icon 205 if ( comboIcon != null ) { 206 iconWidth = comboIcon.getIconWidth(); 207 int iconHeight = comboIcon.getIconHeight(); 208 int iconTop = 0; 209 210 if ( iconOnly ) { 211 iconLeft = (getWidth() / 2) - (iconWidth / 2); 212 iconTop = (getHeight() / 2) - (iconHeight / 2); 213 } 214 else { 215 if (leftToRight) { 216 iconLeft = (left + (width - 1)) - iconWidth; 217 } 218 else { 219 iconLeft = left; 220 } 221 iconTop = (top + ((bottom - top) / 2)) - (iconHeight / 2); 222 } 223 224 comboIcon.paintIcon( this, g, iconLeft, iconTop ); 225 226 // Paint the focus 227 if ( comboBox.hasFocus() && (!MetalLookAndFeel.usingOcean() || 228 comboBox.isEditable())) { 229 g.setColor( MetalLookAndFeel.getFocusColor() ); 230 g.drawRect( left - 1, top - 1, width + 3, height + 1 ); 231 } 232 } 233 234 if (MetalLookAndFeel.usingOcean()) { 235 // With Ocean the button only paints the arrow, bail. 236 return; 237 } 238 239 // Let the renderer paint 240 if ( ! iconOnly && comboBox != null ) { 241 ListCellRenderer<Object> renderer = comboBox.getRenderer(); 242 Component c; 243 boolean renderPressed = getModel().isPressed(); 244 c = renderer.getListCellRendererComponent(listBox, 245 comboBox.getSelectedItem(), 246 -1, 247 renderPressed, 248 false); 249 c.setFont(rendererPane.getFont()); 250 251 if ( model.isArmed() && model.isPressed() ) { 252 if ( isOpaque() ) { 253 c.setBackground(UIManager.getColor("Button.select")); 254 } 255 c.setForeground(comboBox.getForeground()); 256 } 257 else if ( !comboBox.isEnabled() ) { 258 if ( isOpaque() ) { 259 c.setBackground(UIManager.getColor("ComboBox.disabledBackground")); 260 } 261 c.setForeground(UIManager.getColor("ComboBox.disabledForeground")); 262 } 263 else { 264 c.setForeground(comboBox.getForeground()); 265 c.setBackground(comboBox.getBackground()); 266 } 267 268 269 int cWidth = width - (insets.right + iconWidth); 270 271 // Fix for 4238829: should lay out the JPanel. 272 boolean shouldValidate = false; 273 if (c instanceof JPanel) { 274 shouldValidate = true; 275 } 276 277 if (leftToRight) { 278 rendererPane.paintComponent( g, c, this, 279 left, top, cWidth, height, shouldValidate ); 280 } 281 else { 282 rendererPane.paintComponent( g, c, this, 283 left + iconWidth, top, cWidth, height, shouldValidate ); 284 } 285 } 286 } 287 288 public Dimension getMinimumSize() { 289 Dimension ret = new Dimension(); 290 Insets insets = getInsets(); 291 ret.width = insets.left + getComboIcon().getIconWidth() + insets.right; 292 ret.height = insets.bottom + getComboIcon().getIconHeight() + insets.top; 293 return ret; 294 } 295 }