1. /*
  2. * @(#)MetalComboBoxUI.java 1.49 04/05/18
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.plaf.metal;
  8. import java.awt.*;
  9. import java.awt.event.*;
  10. import javax.swing.*;
  11. import javax.swing.plaf.*;
  12. import javax.swing.border.*;
  13. import javax.swing.plaf.basic.*;
  14. import java.io.Serializable;
  15. import java.beans.*;
  16. /**
  17. * Metal UI for JComboBox
  18. * <p>
  19. * <strong>Warning:</strong>
  20. * Serialized objects of this class will not be compatible with
  21. * future Swing releases. The current serialization support is
  22. * appropriate for short term storage or RMI between applications running
  23. * the same version of Swing. As of 1.4, support for long term storage
  24. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  25. * has been added to the <code>java.beans</code> package.
  26. * Please see {@link java.beans.XMLEncoder}.
  27. *
  28. * @see MetalComboBoxEditor
  29. * @see MetalComboBoxButton
  30. * @version 1.49 05/18/04
  31. * @author Tom Santos
  32. */
  33. public class MetalComboBoxUI extends BasicComboBoxUI {
  34. public static ComponentUI createUI(JComponent c) {
  35. return new MetalComboBoxUI();
  36. }
  37. public void paint(Graphics g, JComponent c) {
  38. if (MetalLookAndFeel.usingOcean()) {
  39. super.paint(g, c);
  40. }
  41. }
  42. /**
  43. * If necessary paints the currently selected item.
  44. *
  45. * @param g Graphics to paint to
  46. * @param bounds Region to paint current value to
  47. * @param hasFocus whether or not the JComboBox has focus
  48. * @throws NullPointerException if any of the arguments are null.
  49. * @since 1.5
  50. */
  51. public void paintCurrentValue(Graphics g, Rectangle bounds,
  52. boolean hasFocus) {
  53. // This is really only called if we're using ocean.
  54. if (MetalLookAndFeel.usingOcean()) {
  55. bounds.x += 2;
  56. bounds.y += 2;
  57. bounds.width -= 3;
  58. bounds.height -= 4;
  59. super.paintCurrentValue(g, bounds, hasFocus);
  60. }
  61. else if (g == null || bounds == null) {
  62. throw new NullPointerException(
  63. "Must supply a non-null Graphics and Rectangle");
  64. }
  65. }
  66. /**
  67. * If necessary paints the background of the currently selected item.
  68. *
  69. * @param g Graphics to paint to
  70. * @param bounds Region to paint background to
  71. * @param hasFocus whether or not the JComboBox has focus
  72. * @throws NullPointerException if any of the arguments are null.
  73. * @since 1.5
  74. */
  75. public void paintCurrentValueBackground(Graphics g, Rectangle bounds,
  76. boolean hasFocus) {
  77. // This is really only called if we're using ocean.
  78. if (MetalLookAndFeel.usingOcean()) {
  79. g.setColor(MetalLookAndFeel.getControlDarkShadow());
  80. g.drawRect(bounds.x, bounds.y, bounds.width, bounds.height - 1);
  81. g.setColor(MetalLookAndFeel.getControlShadow());
  82. g.drawRect(bounds.x + 1, bounds.y + 1, bounds.width - 2,
  83. bounds.height - 3);
  84. }
  85. else if (g == null || bounds == null) {
  86. throw new NullPointerException(
  87. "Must supply a non-null Graphics and Rectangle");
  88. }
  89. }
  90. protected ComboBoxEditor createEditor() {
  91. return new MetalComboBoxEditor.UIResource();
  92. }
  93. protected ComboPopup createPopup() {
  94. return super.createPopup();
  95. }
  96. protected JButton createArrowButton() {
  97. boolean iconOnly = (comboBox.isEditable() ||
  98. MetalLookAndFeel.usingOcean());
  99. JButton button = new MetalComboBoxButton( comboBox,
  100. new MetalComboBoxIcon(),
  101. iconOnly,
  102. currentValuePane,
  103. listBox );
  104. button.setMargin( new Insets( 0, 1, 1, 3 ) );
  105. if (MetalLookAndFeel.usingOcean()) {
  106. // Disabled rollover effect.
  107. button.putClientProperty(MetalBorders.NO_BUTTON_ROLLOVER,
  108. Boolean.TRUE);
  109. }
  110. updateButtonForOcean(button);
  111. return button;
  112. }
  113. /**
  114. * Resets the necessary state on the ComboBoxButton for ocean.
  115. */
  116. private void updateButtonForOcean(JButton button) {
  117. if (MetalLookAndFeel.usingOcean()) {
  118. // Ocean renders the focus in a different way, this
  119. // would be redundant.
  120. button.setFocusPainted(comboBox.isEditable());
  121. }
  122. }
  123. public PropertyChangeListener createPropertyChangeListener() {
  124. return new MetalPropertyChangeListener();
  125. }
  126. /**
  127. * This inner class is marked "public" due to a compiler bug.
  128. * This class should be treated as a "protected" inner class.
  129. * Instantiate it only within subclasses of <FooUI>.
  130. */
  131. public class MetalPropertyChangeListener extends BasicComboBoxUI.PropertyChangeHandler {
  132. public void propertyChange(PropertyChangeEvent e) {
  133. super.propertyChange( e );
  134. String propertyName = e.getPropertyName();
  135. if ( propertyName == "editable" ) {
  136. MetalComboBoxButton button = (MetalComboBoxButton)arrowButton;
  137. button.setIconOnly( comboBox.isEditable() ||
  138. MetalLookAndFeel.usingOcean() );
  139. comboBox.repaint();
  140. updateButtonForOcean(button);
  141. } else if ( propertyName == "background" ) {
  142. Color color = (Color)e.getNewValue();
  143. arrowButton.setBackground(color);
  144. listBox.setBackground(color);
  145. } else if ( propertyName == "foreground" ) {
  146. Color color = (Color)e.getNewValue();
  147. arrowButton.setForeground(color);
  148. listBox.setForeground(color);
  149. }
  150. }
  151. }
  152. /**
  153. * As of Java 2 platform v1.4 this method is no longer used. Do not call or
  154. * override. All the functionality of this method is in the
  155. * MetalPropertyChangeListener.
  156. *
  157. * @deprecated As of Java 2 platform v1.4.
  158. */
  159. @Deprecated
  160. protected void editablePropertyChanged( PropertyChangeEvent e ) { }
  161. protected LayoutManager createLayoutManager() {
  162. return new MetalComboBoxLayoutManager();
  163. }
  164. /**
  165. * This inner class is marked "public" due to a compiler bug.
  166. * This class should be treated as a "protected" inner class.
  167. * Instantiate it only within subclasses of <FooUI>.
  168. */
  169. public class MetalComboBoxLayoutManager extends BasicComboBoxUI.ComboBoxLayoutManager {
  170. public void layoutContainer( Container parent ) {
  171. layoutComboBox( parent, this );
  172. }
  173. public void superLayout( Container parent ) {
  174. super.layoutContainer( parent );
  175. }
  176. }
  177. // This is here because of a bug in the compiler.
  178. // When a protected-inner-class-savvy compiler comes out we
  179. // should move this into MetalComboBoxLayoutManager.
  180. public void layoutComboBox( Container parent, MetalComboBoxLayoutManager manager ) {
  181. if (comboBox.isEditable() && !MetalLookAndFeel.usingOcean()) {
  182. manager.superLayout( parent );
  183. return;
  184. }
  185. if (arrowButton != null) {
  186. if (MetalLookAndFeel.usingOcean() &&
  187. (arrowButton instanceof MetalComboBoxButton)) {
  188. Icon icon = ((MetalComboBoxButton)arrowButton).getComboIcon();
  189. Insets buttonInsets = arrowButton.getInsets();
  190. Insets insets = comboBox.getInsets();
  191. int buttonWidth = icon.getIconWidth() + buttonInsets.left +
  192. buttonInsets.right;
  193. arrowButton.setBounds(MetalUtils.isLeftToRight(comboBox)
  194. ? (comboBox.getWidth() - insets.right - buttonWidth)
  195. : insets.left,
  196. insets.top, buttonWidth,
  197. comboBox.getHeight() - insets.top - insets.bottom);
  198. }
  199. else {
  200. Insets insets = comboBox.getInsets();
  201. int width = comboBox.getWidth();
  202. int height = comboBox.getHeight();
  203. arrowButton.setBounds( insets.left, insets.top,
  204. width - (insets.left + insets.right),
  205. height - (insets.top + insets.bottom) );
  206. }
  207. }
  208. if (editor != null && MetalLookAndFeel.usingOcean()) {
  209. Rectangle cvb = rectangleForCurrentValue();
  210. editor.setBounds(cvb);
  211. }
  212. }
  213. /**
  214. * As of Java 2 platform v1.4 this method is no
  215. * longer used.
  216. *
  217. * @deprecated As of Java 2 platform v1.4.
  218. */
  219. @Deprecated
  220. protected void removeListeners() {
  221. if ( propertyChangeListener != null ) {
  222. comboBox.removePropertyChangeListener( propertyChangeListener );
  223. }
  224. }
  225. // These two methods were overloaded and made public. This was probably a
  226. // mistake in the implementation. The functionality that they used to
  227. // provide is no longer necessary and should be removed. However,
  228. // removing them will create an uncompatible API change.
  229. public void configureEditor() {
  230. super.configureEditor();
  231. }
  232. public void unconfigureEditor() {
  233. super.unconfigureEditor();
  234. }
  235. public Dimension getMinimumSize( JComponent c ) {
  236. if ( !isMinimumSizeDirty ) {
  237. return new Dimension( cachedMinimumSize );
  238. }
  239. Dimension size = null;
  240. if ( !comboBox.isEditable() &&
  241. arrowButton != null &&
  242. arrowButton instanceof MetalComboBoxButton ) {
  243. MetalComboBoxButton button = (MetalComboBoxButton)arrowButton;
  244. Insets buttonInsets = button.getInsets();
  245. Insets insets = comboBox.getInsets();
  246. size = getDisplaySize();
  247. size.width += insets.left + insets.right;
  248. size.width += buttonInsets.left + buttonInsets.right;
  249. size.width += buttonInsets.right + button.getComboIcon().getIconWidth();
  250. size.height += insets.top + insets.bottom;
  251. size.height += buttonInsets.top + buttonInsets.bottom;
  252. }
  253. else if ( comboBox.isEditable() &&
  254. arrowButton != null &&
  255. editor != null ) {
  256. size = super.getMinimumSize( c );
  257. Insets margin = arrowButton.getMargin();
  258. size.height += margin.top + margin.bottom;
  259. size.width += margin.left + margin.right;
  260. }
  261. else {
  262. size = super.getMinimumSize( c );
  263. }
  264. cachedMinimumSize.setSize( size.width, size.height );
  265. isMinimumSizeDirty = false;
  266. return new Dimension( cachedMinimumSize );
  267. }
  268. /**
  269. * This inner class is marked "public" due to a compiler bug.
  270. * This class should be treated as a "protected" inner class.
  271. * Instantiate it only within subclasses of <FooUI>.
  272. *
  273. * This class is now obsolete and doesn't do anything and
  274. * is only included for backwards API compatibility. Do not call or
  275. * override.
  276. *
  277. * @deprecated As of Java 2 platform v1.4.
  278. */
  279. @Deprecated
  280. public class MetalComboPopup extends BasicComboPopup {
  281. public MetalComboPopup( JComboBox cBox) {
  282. super( cBox );
  283. }
  284. // This method was overloaded and made public. This was probably
  285. // mistake in the implementation. The functionality that they used to
  286. // provide is no longer necessary and should be removed. However,
  287. // removing them will create an uncompatible API change.
  288. public void delegateFocus(MouseEvent e) {
  289. super.delegateFocus(e);
  290. }
  291. }
  292. }