001 /* MetalComboBoxUI.java
002 Copyright (C) 2005 Free Software Foundation, Inc.
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038
039 package javax.swing.plaf.metal;
040
041 import java.awt.Color;
042 import java.awt.Container;
043 import java.awt.Dimension;
044 import java.awt.Graphics;
045 import java.awt.Insets;
046 import java.awt.LayoutManager;
047 import java.awt.event.MouseEvent;
048 import java.beans.PropertyChangeEvent;
049 import java.beans.PropertyChangeListener;
050
051 import javax.swing.ComboBoxEditor;
052 import javax.swing.Icon;
053 import javax.swing.JButton;
054 import javax.swing.JComboBox;
055 import javax.swing.JComponent;
056 import javax.swing.plaf.ComponentUI;
057 import javax.swing.plaf.basic.BasicComboBoxUI;
058 import javax.swing.plaf.basic.BasicComboPopup;
059 import javax.swing.plaf.basic.ComboPopup;
060
061
062 /**
063 * A UI delegate for the {@link JComboBox} component.
064 */
065 public class MetalComboBoxUI extends BasicComboBoxUI
066 {
067 /**
068 * A layout manager that arranges the editor component (if active) and the
069 * button that make up the combo box.
070 */
071 public class MetalComboBoxLayoutManager
072 extends BasicComboBoxUI.ComboBoxLayoutManager
073 {
074 /**
075 * Creates a new instance of the layout manager.
076 */
077 public MetalComboBoxLayoutManager()
078 {
079 // Nothing to do here.
080 }
081
082 /**
083 * Arranges the editor (if visible) and button that comprise the combo
084 * box.
085 *
086 * @param parent the parent.
087 */
088 public void layoutContainer(Container parent)
089 {
090 layoutComboBox(parent, this);
091 }
092
093 /**
094 * Calls the <code>layoutContainer(Container)</code> method in the super
095 * class.
096 *
097 * @param parent the container.
098 */
099 public void superLayout(Container parent)
100 {
101 super.layoutContainer(parent);
102 }
103 }
104
105 /**
106 * A listener used to handle property changes in the {@link JComboBox}
107 * component, to ensure that the UI delegate accurately reflects the current
108 * state in the rendering onscreen.
109 */
110 public class MetalPropertyChangeListener
111 extends BasicComboBoxUI.PropertyChangeHandler
112 {
113 /**
114 * Creates a new listener.
115 */
116 public MetalPropertyChangeListener()
117 {
118 // Nothing to do here.
119 }
120
121 /**
122 * Handles a property change event, updating the UI components as
123 * appropriate.
124 *
125 * @param e the event.
126 */
127 public void propertyChange(PropertyChangeEvent e)
128 {
129 super.propertyChange(e);
130 String name = e.getPropertyName();
131 if (name.equals("editable"))
132 editablePropertyChanged(e);
133 else if (name.equals("enabled"))
134 {
135 if (arrowButton instanceof MetalComboBoxButton)
136 {
137 arrowButton.setFocusable(!comboBox.isEditable()
138 && comboBox.isEnabled());
139 comboBox.repaint();
140 }
141 }
142 else if (name.equals("background"))
143 {
144 Color c = (Color) e.getNewValue();
145 arrowButton.setBackground(c);
146 listBox.setBackground(c);
147 }
148 else if (name.equals("foreground"))
149 {
150 Color c = (Color) e.getNewValue();
151 arrowButton.setForeground(c);
152 listBox.setForeground(c);
153 }
154 }
155 }
156
157 /**
158 * A popup menu for the combo-box.
159 *
160 * @see #createPopup()
161 *
162 * @deprecated 1.4
163 */
164 public class MetalComboPopup extends BasicComboPopup
165 {
166 /**
167 * Creates a new popup.
168 *
169 * @param cBox the combo box.
170 */
171 public MetalComboPopup(JComboBox cBox)
172 {
173 super(cBox);
174 }
175
176 public void delegateFocus(MouseEvent e)
177 {
178 super.delegateFocus(e);
179 }
180 }
181
182 /**
183 * Constructs a new instance of MetalComboBoxUI.
184 */
185 public MetalComboBoxUI()
186 {
187 super();
188 }
189
190 /**
191 * Returns an instance of MetalComboBoxUI.
192 *
193 * @param component the component for which we return an UI instance
194 *
195 * @return an instance of MetalComboBoxUI
196 */
197 public static ComponentUI createUI(JComponent component)
198 {
199 return new MetalComboBoxUI();
200 }
201
202 /**
203 * Creates an editor for the combo box.
204 *
205 * @return An editor.
206 */
207 protected ComboBoxEditor createEditor()
208 {
209 return new MetalComboBoxEditor.UIResource();
210 }
211
212 /**
213 * Creates a popup for the combo box.
214 *
215 * @return A popup.
216 */
217 protected ComboPopup createPopup()
218 {
219 return super.createPopup();
220 }
221
222 /**
223 * Creates a new button for use in rendering the JComboBox.
224 *
225 * @return A button.
226 */
227 protected JButton createArrowButton()
228 {
229 JButton button = new MetalComboBoxButton(comboBox, new MetalComboBoxIcon(),
230 currentValuePane, listBox);
231 button.setMargin(new Insets(0, 1, 1, 3));
232 return button;
233 }
234
235 /**
236 * Creates a new property change listener.
237 *
238 * @return A new property change listener.
239 */
240 public PropertyChangeListener createPropertyChangeListener()
241 {
242 return new MetalPropertyChangeListener();
243 }
244
245 public void paint(Graphics g, JComponent c)
246 {
247 // do nothing, the button and text field are painted elsewhere
248 }
249
250 /**
251 * Updates the button and text field to reflect a change in the 'editable'
252 * property.
253 *
254 * @param e the event.
255 *
256 * @deprecated 1.4
257 */
258 protected void editablePropertyChanged(PropertyChangeEvent e)
259 {
260 if (arrowButton instanceof MetalComboBoxButton)
261 {
262 MetalComboBoxButton b = (MetalComboBoxButton) arrowButton;
263 b.setIconOnly(comboBox.isEditable());
264 b.setFocusable(!comboBox.isEditable() && comboBox.isEnabled());
265 comboBox.repaint();
266 }
267 }
268
269 /**
270 * Creates a new layout manager for the UI delegate.
271 *
272 * @return A new layout manager.
273 */
274 protected LayoutManager createLayoutManager()
275 {
276 return new MetalComboBoxLayoutManager();
277 }
278
279 /**
280 * Not used in Classpath.
281 *
282 * @deprecated 1.4
283 */
284 protected void removeListeners()
285 {
286 // no longer used in JDK 1.4
287 }
288
289 /**
290 * Returns the minimum size for the combo.
291 *
292 * @param c the component
293 *
294 * @return The minimum size for the combo box.
295 */
296 public Dimension getMinimumSize(JComponent c)
297 {
298 if (!isMinimumSizeDirty)
299 return new Dimension(cachedMinimumSize);
300
301 Dimension d;
302 if (!comboBox.isEditable() && arrowButton != null
303 && arrowButton instanceof MetalComboBoxButton)
304 {
305 MetalComboBoxButton b = (MetalComboBoxButton) arrowButton;
306 d = getDisplaySize();
307 Insets arrowInsets = b.getInsets();
308 Insets comboInsets = comboBox.getInsets();
309 Icon icon = b.getComboIcon();
310 d.width += comboInsets.left + comboInsets.right;
311 d.width += arrowInsets.left + arrowInsets.right;
312 d.width += arrowInsets.right + icon.getIconWidth();
313 d.height += comboInsets.top + comboInsets.bottom;
314 d.height += arrowInsets.top + arrowInsets.bottom;
315 }
316 else if (comboBox.isEditable() && arrowButton != null && editor != null)
317 {
318 d = super.getMinimumSize(c);
319 Insets arrowMargin = arrowButton.getMargin();
320 d.height += arrowMargin.top + arrowMargin.bottom;
321 d.width += arrowMargin.left + arrowMargin.right;
322 }
323 else
324 {
325 d = super.getMinimumSize(c);
326 }
327 cachedMinimumSize.setSize(d.width, d.height);
328 isMinimumSizeDirty = false;
329 return new Dimension(cachedMinimumSize);
330 }
331
332 /**
333 * Configures the editor for this combo box.
334 */
335 public void configureEditor()
336 {
337 super.configureEditor();
338 if (popupKeyListener != null)
339 editor.removeKeyListener(popupKeyListener);
340 if (focusListener != null)
341 editor.addFocusListener(focusListener);
342 }
343
344 /**
345 * Unconfigures the editor for this combo box.
346 */
347 public void unconfigureEditor()
348 {
349 super.unconfigureEditor();
350 if (focusListener != null)
351 editor.removeFocusListener(focusListener);
352 }
353
354 /**
355 * Lays out the ComboBox
356 */
357 public void layoutComboBox(Container parent,
358 MetalComboBoxUI.MetalComboBoxLayoutManager manager)
359 {
360 if (comboBox.isEditable())
361 manager.superLayout(parent);
362 else if (arrowButton != null)
363 {
364 Insets comboInsets = comboBox.getInsets();
365 int width = comboBox.getWidth();
366 int height = comboBox.getHeight();
367 arrowButton.setBounds(comboInsets.left, comboInsets.top,
368 width - (comboInsets.left + comboInsets.right),
369 height - (comboInsets.top + comboInsets.bottom));
370 }
371 }
372 }