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&trade;
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      */
getComboBox()84     public final JComboBox<Object> getComboBox() { return comboBox;}
85 
86     /**
87      * Sets the {@code JComboBox}.
88      *
89      * @param cb the {@code JComboBox}
90      */
setComboBox( JComboBox<Object> cb )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      */
getComboIcon()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      */
setComboIcon( Icon i )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      */
isIconOnly()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      */
setIconOnly( boolean isIconOnly )119     public final void setIconOnly( boolean isIconOnly ) { iconOnly = isIconOnly;}
120 
MetalComboBoxButton()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      */
MetalComboBoxButton( JComboBox<Object> cb, Icon i, CellRendererPane pane, JList<Object> list )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      */
MetalComboBoxButton( JComboBox<Object> cb, Icon i, boolean onlyIcon, CellRendererPane pane, JList<Object> list )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")
isFocusTraversable()165     public boolean isFocusTraversable() {
166         return false;
167     }
168 
setEnabled(boolean enabled)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 
paintComponent( Graphics g )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 
getMinimumSize()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 }
297