001 /*
002 * Copyright 1998-2005 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package javax.swing.plaf.metal;
027
028 import java.awt.*;
029 import java.awt.event.*;
030 import javax.swing.*;
031 import javax.swing.plaf.*;
032 import javax.swing.border.*;
033 import javax.swing.plaf.basic.*;
034 import java.io.Serializable;
035 import java.beans.*;
036
037 /**
038 * Metal UI for JComboBox
039 * <p>
040 * <strong>Warning:</strong>
041 * Serialized objects of this class will not be compatible with
042 * future Swing releases. The current serialization support is
043 * appropriate for short term storage or RMI between applications running
044 * the same version of Swing. As of 1.4, support for long term storage
045 * of all JavaBeans<sup><font size="-2">TM</font></sup>
046 * has been added to the <code>java.beans</code> package.
047 * Please see {@link java.beans.XMLEncoder}.
048 *
049 * @see MetalComboBoxEditor
050 * @see MetalComboBoxButton
051 * @version 1.59 05/05/07
052 * @author Tom Santos
053 */
054 public class MetalComboBoxUI extends BasicComboBoxUI {
055
056 public static ComponentUI createUI(JComponent c) {
057 return new MetalComboBoxUI();
058 }
059
060 public void paint(Graphics g, JComponent c) {
061 if (MetalLookAndFeel.usingOcean()) {
062 super .paint(g, c);
063 }
064 }
065
066 /**
067 * If necessary paints the currently selected item.
068 *
069 * @param g Graphics to paint to
070 * @param bounds Region to paint current value to
071 * @param hasFocus whether or not the JComboBox has focus
072 * @throws NullPointerException if any of the arguments are null.
073 * @since 1.5
074 */
075 public void paintCurrentValue(Graphics g, Rectangle bounds,
076 boolean hasFocus) {
077 // This is really only called if we're using ocean.
078 if (MetalLookAndFeel.usingOcean()) {
079 bounds.x += 2;
080 bounds.width -= 3;
081 if (arrowButton != null) {
082 Insets buttonInsets = arrowButton.getInsets();
083 bounds.y += buttonInsets.top;
084 bounds.height -= (buttonInsets.top + buttonInsets.bottom);
085 } else {
086 bounds.y += 2;
087 bounds.height -= 4;
088 }
089 super .paintCurrentValue(g, bounds, hasFocus);
090 } else if (g == null || bounds == null) {
091 throw new NullPointerException(
092 "Must supply a non-null Graphics and Rectangle");
093 }
094 }
095
096 /**
097 * If necessary paints the background of the currently selected item.
098 *
099 * @param g Graphics to paint to
100 * @param bounds Region to paint background to
101 * @param hasFocus whether or not the JComboBox has focus
102 * @throws NullPointerException if any of the arguments are null.
103 * @since 1.5
104 */
105 public void paintCurrentValueBackground(Graphics g,
106 Rectangle bounds, boolean hasFocus) {
107 // This is really only called if we're using ocean.
108 if (MetalLookAndFeel.usingOcean()) {
109 g.setColor(MetalLookAndFeel.getControlDarkShadow());
110 g.drawRect(bounds.x, bounds.y, bounds.width,
111 bounds.height - 1);
112 g.setColor(MetalLookAndFeel.getControlShadow());
113 g.drawRect(bounds.x + 1, bounds.y + 1, bounds.width - 2,
114 bounds.height - 3);
115 if (hasFocus && !isPopupVisible(comboBox)
116 && arrowButton != null) {
117 g.setColor(listBox.getSelectionBackground());
118 Insets buttonInsets = arrowButton.getInsets();
119 if (buttonInsets.top > 2) {
120 g.fillRect(bounds.x + 2, bounds.y + 2,
121 bounds.width - 3, buttonInsets.top - 2);
122 }
123 if (buttonInsets.bottom > 2) {
124 g.fillRect(bounds.x + 2, bounds.y + bounds.height
125 - buttonInsets.bottom, bounds.width - 3,
126 buttonInsets.bottom - 2);
127 }
128 }
129 } else if (g == null || bounds == null) {
130 throw new NullPointerException(
131 "Must supply a non-null Graphics and Rectangle");
132 }
133 }
134
135 /**
136 * Returns the baseline.
137 *
138 * @throws NullPointerException {@inheritDoc}
139 * @throws IllegalArgumentException {@inheritDoc}
140 * @see javax.swing.JComponent#getBaseline(int, int)
141 * @since 1.6
142 */
143 public int getBaseline(JComponent c, int width, int height) {
144 int baseline;
145 if (MetalLookAndFeel.usingOcean()) {
146 height -= 4;
147 baseline = super .getBaseline(c, width, height);
148 if (baseline >= 0) {
149 baseline += 2;
150 }
151 } else {
152 baseline = super .getBaseline(c, width, height);
153 }
154 return baseline;
155 }
156
157 protected ComboBoxEditor createEditor() {
158 return new MetalComboBoxEditor.UIResource();
159 }
160
161 protected ComboPopup createPopup() {
162 return super .createPopup();
163 }
164
165 protected JButton createArrowButton() {
166 boolean iconOnly = (comboBox.isEditable() || MetalLookAndFeel
167 .usingOcean());
168 JButton button = new MetalComboBoxButton(comboBox,
169 new MetalComboBoxIcon(), iconOnly, currentValuePane,
170 listBox);
171 button.setMargin(new Insets(0, 1, 1, 3));
172 if (MetalLookAndFeel.usingOcean()) {
173 // Disabled rollover effect.
174 button.putClientProperty(MetalBorders.NO_BUTTON_ROLLOVER,
175 Boolean.TRUE);
176 }
177 updateButtonForOcean(button);
178 return button;
179 }
180
181 /**
182 * Resets the necessary state on the ComboBoxButton for ocean.
183 */
184 private void updateButtonForOcean(JButton button) {
185 if (MetalLookAndFeel.usingOcean()) {
186 // Ocean renders the focus in a different way, this
187 // would be redundant.
188 button.setFocusPainted(comboBox.isEditable());
189 }
190 }
191
192 public PropertyChangeListener createPropertyChangeListener() {
193 return new MetalPropertyChangeListener();
194 }
195
196 /**
197 * This inner class is marked "public" due to a compiler bug.
198 * This class should be treated as a "protected" inner class.
199 * Instantiate it only within subclasses of <FooUI>.
200 */
201 public class MetalPropertyChangeListener extends
202 BasicComboBoxUI.PropertyChangeHandler {
203 public void propertyChange(PropertyChangeEvent e) {
204 super .propertyChange(e);
205 String propertyName = e.getPropertyName();
206
207 if (propertyName == "editable") {
208 if (arrowButton instanceof MetalComboBoxButton) {
209 MetalComboBoxButton button = (MetalComboBoxButton) arrowButton;
210 button.setIconOnly(comboBox.isEditable()
211 || MetalLookAndFeel.usingOcean());
212 }
213 comboBox.repaint();
214 updateButtonForOcean(arrowButton);
215 } else if (propertyName == "background") {
216 Color color = (Color) e.getNewValue();
217 arrowButton.setBackground(color);
218 listBox.setBackground(color);
219
220 } else if (propertyName == "foreground") {
221 Color color = (Color) e.getNewValue();
222 arrowButton.setForeground(color);
223 listBox.setForeground(color);
224 }
225 }
226 }
227
228 /**
229 * As of Java 2 platform v1.4 this method is no longer used. Do not call or
230 * override. All the functionality of this method is in the
231 * MetalPropertyChangeListener.
232 *
233 * @deprecated As of Java 2 platform v1.4.
234 */
235 @Deprecated
236 protected void editablePropertyChanged(PropertyChangeEvent e) {
237 }
238
239 protected LayoutManager createLayoutManager() {
240 return new MetalComboBoxLayoutManager();
241 }
242
243 /**
244 * This inner class is marked "public" due to a compiler bug.
245 * This class should be treated as a "protected" inner class.
246 * Instantiate it only within subclasses of <FooUI>.
247 */
248 public class MetalComboBoxLayoutManager extends
249 BasicComboBoxUI.ComboBoxLayoutManager {
250 public void layoutContainer(Container parent) {
251 layoutComboBox(parent, this );
252 }
253
254 public void super Layout(Container parent) {
255 super .layoutContainer(parent);
256 }
257 }
258
259 // This is here because of a bug in the compiler.
260 // When a protected-inner-class-savvy compiler comes out we
261 // should move this into MetalComboBoxLayoutManager.
262 public void layoutComboBox(Container parent,
263 MetalComboBoxLayoutManager manager) {
264 if (comboBox.isEditable() && !MetalLookAndFeel.usingOcean()) {
265 manager.super Layout(parent);
266 return;
267 }
268
269 if (arrowButton != null) {
270 if (MetalLookAndFeel.usingOcean()) {
271 Insets insets = comboBox.getInsets();
272 int buttonWidth = arrowButton.getMinimumSize().width;
273 arrowButton.setBounds(MetalUtils
274 .isLeftToRight(comboBox) ? (comboBox.getWidth()
275 - insets.right - buttonWidth) : insets.left,
276 insets.top, buttonWidth, comboBox.getHeight()
277 - insets.top - insets.bottom);
278 } else {
279 Insets insets = comboBox.getInsets();
280 int width = comboBox.getWidth();
281 int height = comboBox.getHeight();
282 arrowButton.setBounds(insets.left, insets.top, width
283 - (insets.left + insets.right), height
284 - (insets.top + insets.bottom));
285 }
286 }
287
288 if (editor != null && MetalLookAndFeel.usingOcean()) {
289 Rectangle cvb = rectangleForCurrentValue();
290 editor.setBounds(cvb);
291 }
292 }
293
294 /**
295 * As of Java 2 platform v1.4 this method is no
296 * longer used.
297 *
298 * @deprecated As of Java 2 platform v1.4.
299 */
300 @Deprecated
301 protected void removeListeners() {
302 if (propertyChangeListener != null) {
303 comboBox
304 .removePropertyChangeListener(propertyChangeListener);
305 }
306 }
307
308 // These two methods were overloaded and made public. This was probably a
309 // mistake in the implementation. The functionality that they used to
310 // provide is no longer necessary and should be removed. However,
311 // removing them will create an uncompatible API change.
312
313 public void configureEditor() {
314 super .configureEditor();
315 }
316
317 public void unconfigureEditor() {
318 super .unconfigureEditor();
319 }
320
321 public Dimension getMinimumSize(JComponent c) {
322 if (!isMinimumSizeDirty) {
323 return new Dimension(cachedMinimumSize);
324 }
325
326 Dimension size = null;
327
328 if (!comboBox.isEditable() && arrowButton != null) {
329 Insets buttonInsets = arrowButton.getInsets();
330 Insets insets = comboBox.getInsets();
331
332 size = getDisplaySize();
333 size.width += insets.left + insets.right;
334 size.width += buttonInsets.right;
335 size.width += arrowButton.getMinimumSize().width;
336 size.height += insets.top + insets.bottom;
337 size.height += buttonInsets.top + buttonInsets.bottom;
338 } else if (comboBox.isEditable() && arrowButton != null
339 && editor != null) {
340 size = super .getMinimumSize(c);
341 Insets margin = arrowButton.getMargin();
342 size.height += margin.top + margin.bottom;
343 size.width += margin.left + margin.right;
344 } else {
345 size = super .getMinimumSize(c);
346 }
347
348 cachedMinimumSize.setSize(size.width, size.height);
349 isMinimumSizeDirty = false;
350
351 return new Dimension(cachedMinimumSize);
352 }
353
354 /**
355 * This inner class is marked "public" due to a compiler bug.
356 * This class should be treated as a "protected" inner class.
357 * Instantiate it only within subclasses of <FooUI>.
358 *
359 * This class is now obsolete and doesn't do anything and
360 * is only included for backwards API compatibility. Do not call or
361 * override.
362 *
363 * @deprecated As of Java 2 platform v1.4.
364 */
365 @Deprecated
366 public class MetalComboPopup extends BasicComboPopup {
367
368 public MetalComboPopup(JComboBox cBox) {
369 super (cBox);
370 }
371
372 // This method was overloaded and made public. This was probably
373 // mistake in the implementation. The functionality that they used to
374 // provide is no longer necessary and should be removed. However,
375 // removing them will create an uncompatible API change.
376
377 public void delegateFocus(MouseEvent e) {
378 super.delegateFocus(e);
379 }
380 }
381 }
|