1. /*
  2. * @(#)MetalComboBoxUI.java 1.29 00/02/02
  3. *
  4. * Copyright 1998-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package javax.swing.plaf.metal;
  11. import java.awt.*;
  12. import java.awt.event.*;
  13. import javax.swing.*;
  14. import javax.swing.plaf.*;
  15. import javax.swing.border.*;
  16. import javax.swing.plaf.basic.*;
  17. import java.io.Serializable;
  18. import java.beans.*;
  19. /**
  20. * Metal UI for JComboBox
  21. * <p>
  22. * <strong>Warning:</strong>
  23. * Serialized objects of this class will not be compatible with
  24. * future Swing releases. The current serialization support is appropriate
  25. * for short term storage or RMI between applications running the same
  26. * version of Swing. A future release of Swing will provide support for
  27. * long term persistence.
  28. *
  29. * @see MetalComboBoxListCellRenderer
  30. * @see MetalPopupMenuBorder
  31. * @version 1.29 02/02/00
  32. * @author Tom Santos
  33. */
  34. public class MetalComboBoxUI extends BasicComboBoxUI {
  35. FocusListener focusDelegator;
  36. public static ComponentUI createUI(JComponent c) {
  37. return new MetalComboBoxUI();
  38. }
  39. public void installUI(JComponent c) {
  40. super.installUI(c);
  41. comboBox.setRequestFocusEnabled( true );
  42. }
  43. public void uninstallUI( JComponent c ) {
  44. super.uninstallUI( c );
  45. }
  46. public void paint(Graphics g, JComponent c) {
  47. }
  48. protected ComboBoxEditor createEditor() {
  49. return new MetalComboBoxEditor.UIResource();
  50. }
  51. protected ComboPopup createPopup() {
  52. return new MetalComboPopup( comboBox );
  53. }
  54. protected JButton createArrowButton() {
  55. JButton button = new MetalComboBoxButton( comboBox,
  56. new MetalComboBoxIcon(),
  57. comboBox.isEditable() ? true : false,
  58. currentValuePane,
  59. listBox );
  60. button.setMargin( new Insets( 0, 1, 1, 3 ) );
  61. return button;
  62. }
  63. FocusListener createFocusDelegator() {
  64. return new FocusDelegator();
  65. }
  66. class FocusDelegator extends FocusAdapter {
  67. public void focusGained( FocusEvent e ) {
  68. if ( metalGetComboBox().isEditable() ) {
  69. metalGetEditor().requestFocus();
  70. }
  71. else {
  72. metalGetArrowButton().requestFocus();
  73. }
  74. }
  75. }
  76. public PropertyChangeListener createPropertyChangeListener() {
  77. return new MetalPropertyChangeListener();
  78. }
  79. /**
  80. * This inner class is marked "public" due to a compiler bug.
  81. * This class should be treated as a "protected" inner class.
  82. * Instantiate it only within subclasses of <FooUI>.
  83. */
  84. public class MetalPropertyChangeListener extends BasicComboBoxUI.PropertyChangeHandler {
  85. public void propertyChange(PropertyChangeEvent e) {
  86. super.propertyChange( e );
  87. metalGetComboBox().setRequestFocusEnabled( true );
  88. String propertyName = e.getPropertyName();
  89. if ( propertyName.equals( "editable" ) ) {
  90. editablePropertyChanged( e );
  91. }
  92. else if ( propertyName.equals( "enabled" ) ) {
  93. enabledPropertyChanged( e );
  94. }
  95. }
  96. }
  97. protected void editablePropertyChanged( PropertyChangeEvent e ) {
  98. if ( arrowButton instanceof MetalComboBoxButton ) {
  99. MetalComboBoxButton button = (MetalComboBoxButton)arrowButton;
  100. button.setIconOnly( comboBox.isEditable() );
  101. button.setRequestFocusEnabled( (!comboBox.isEditable()) && comboBox.isEnabled() );
  102. comboBox.repaint();
  103. }
  104. }
  105. void enabledPropertyChanged( PropertyChangeEvent e ) {
  106. if ( arrowButton instanceof MetalComboBoxButton ) {
  107. arrowButton.setRequestFocusEnabled( (!comboBox.isEditable()) && comboBox.isEnabled() );
  108. comboBox.repaint();
  109. }
  110. }
  111. protected LayoutManager createLayoutManager() {
  112. return new MetalComboBoxLayoutManager();
  113. }
  114. /**
  115. * This inner class is marked "public" due to a compiler bug.
  116. * This class should be treated as a "protected" inner class.
  117. * Instantiate it only within subclasses of <FooUI>.
  118. */
  119. public class MetalComboBoxLayoutManager extends BasicComboBoxUI.ComboBoxLayoutManager {
  120. public void layoutContainer( Container parent ) {
  121. layoutComboBox( parent, this );
  122. }
  123. public void superLayout( Container parent ) {
  124. super.layoutContainer( parent );
  125. }
  126. }
  127. // This is here because of a bug in the compiler. When a protected-inner-class-savvy compiler comes out we
  128. // should move this into MetalComboBoxLayoutManager.
  129. public void layoutComboBox( Container parent, MetalComboBoxLayoutManager manager ) {
  130. if ( comboBox.isEditable() ) {
  131. manager.superLayout( parent );
  132. }
  133. else {
  134. if ( arrowButton != null ) {
  135. Insets insets = comboBox.getInsets();
  136. int width = comboBox.getWidth();
  137. int height = comboBox.getHeight();
  138. arrowButton.setBounds( insets.left, insets.top,
  139. width - (insets.left + insets.right),
  140. height - (insets.top + insets.bottom) );
  141. }
  142. }
  143. }
  144. public boolean isFocusTraversable( JComboBox c ) {
  145. return false;
  146. }
  147. protected void installListeners() {
  148. if ( (itemListener = createItemListener()) != null ) {
  149. comboBox.addItemListener( itemListener );
  150. }
  151. if ( (propertyChangeListener = createPropertyChangeListener()) != null ) {
  152. comboBox.addPropertyChangeListener( propertyChangeListener );
  153. }
  154. keyListener = createKeyListener();
  155. focusListener = createFocusListener();
  156. popupKeyListener = popup.getKeyListener();
  157. popupMouseListener = popup.getMouseListener();
  158. popupMouseMotionListener = popup.getMouseMotionListener();
  159. if ( comboBox.getModel() != null ) {
  160. if ( (listDataListener = createListDataListener()) != null ) {
  161. comboBox.getModel().addListDataListener( listDataListener );
  162. }
  163. }
  164. if ( (focusDelegator = createFocusDelegator()) != null ) {
  165. comboBox.addFocusListener( focusDelegator );
  166. }
  167. }
  168. protected void uninstallListeners() {
  169. if ( itemListener != null ) {
  170. comboBox.removeItemListener( itemListener );
  171. }
  172. if ( propertyChangeListener != null ) {
  173. comboBox.removePropertyChangeListener( propertyChangeListener );
  174. }
  175. if ( comboBox.getModel() != null ) {
  176. if ( listDataListener != null ) {
  177. comboBox.getModel().removeListDataListener( listDataListener );
  178. }
  179. }
  180. if ( focusDelegator != null ) {
  181. comboBox.removeFocusListener( focusDelegator );
  182. }
  183. }
  184. protected void removeListeners() {
  185. if ( itemListener != null ) {
  186. comboBox.removeItemListener( itemListener );
  187. }
  188. if ( propertyChangeListener != null ) {
  189. comboBox.removePropertyChangeListener( propertyChangeListener );
  190. }
  191. }
  192. public void configureEditor() {
  193. super.configureEditor();
  194. if ( popupKeyListener != null ) {
  195. editor.removeKeyListener( popupKeyListener );
  196. }
  197. if ( focusListener != null ) {
  198. editor.addFocusListener( focusListener );
  199. }
  200. }
  201. public void unconfigureEditor() {
  202. super.unconfigureEditor();
  203. if ( focusListener != null ) {
  204. editor.removeFocusListener( focusListener );
  205. }
  206. }
  207. public void configureArrowButton() {
  208. if ( arrowButton != null ) {
  209. arrowButton.setRequestFocusEnabled( (!comboBox.isEditable()) && comboBox.isEnabled() );
  210. if ( keyListener != null ) {
  211. arrowButton.addKeyListener( keyListener );
  212. }
  213. if ( popupKeyListener != null ) {
  214. arrowButton.addKeyListener( popupKeyListener );
  215. }
  216. if ( focusListener != null ) {
  217. arrowButton.addFocusListener( focusListener );
  218. }
  219. if ( popupMouseListener != null ) {
  220. arrowButton.addMouseListener( popupMouseListener );
  221. }
  222. if ( popupMouseMotionListener != null ) {
  223. arrowButton.addMouseMotionListener( popupMouseMotionListener );
  224. }
  225. }
  226. }
  227. public void unconfigureArrowButton() {
  228. if ( arrowButton != null ) {
  229. super.unconfigureArrowButton();
  230. if ( keyListener != null ) {
  231. arrowButton.removeKeyListener( keyListener );
  232. }
  233. if ( popupKeyListener != null ) {
  234. arrowButton.removeKeyListener( popupKeyListener );
  235. }
  236. if ( focusListener != null ) {
  237. arrowButton.removeFocusListener( focusListener );
  238. }
  239. }
  240. }
  241. public Dimension getMinimumSize( JComponent c ) {
  242. if ( !isMinimumSizeDirty ) {
  243. return new Dimension( cachedMinimumSize );
  244. }
  245. Dimension size = null;
  246. if ( !comboBox.isEditable() &&
  247. arrowButton != null &&
  248. arrowButton instanceof MetalComboBoxButton ) {
  249. MetalComboBoxButton button = (MetalComboBoxButton)arrowButton;
  250. Insets buttonInsets = button.getInsets();
  251. Insets insets = comboBox.getInsets();
  252. size = getDisplaySize();
  253. size.width += insets.left + insets.right;
  254. size.width += buttonInsets.left + buttonInsets.right;
  255. size.width += buttonInsets.right + button.getComboIcon().getIconWidth();
  256. size.height += insets.top + insets.bottom;
  257. size.height += buttonInsets.top + buttonInsets.bottom;
  258. }
  259. else if ( comboBox.isEditable() &&
  260. arrowButton != null &&
  261. editor != null ) {
  262. size = super.getMinimumSize( c );
  263. Insets margin = arrowButton.getMargin();
  264. Insets insets = comboBox.getInsets();
  265. if ( editor instanceof JComponent ) {
  266. Insets editorInsets = ((JComponent)editor).getInsets();
  267. size.height += editorInsets.top + editorInsets.bottom;
  268. }
  269. size.height += margin.top + margin.bottom;
  270. size.height += insets.top + insets.bottom;
  271. }
  272. else {
  273. size = super.getMinimumSize( c );
  274. }
  275. cachedMinimumSize.setSize( size.width, size.height );
  276. isMinimumSizeDirty = false;
  277. return new Dimension( cachedMinimumSize );
  278. }
  279. protected void selectNextPossibleValue() { super.selectNextPossibleValue();}
  280. protected void selectPreviousPossibleValue() { super.selectPreviousPossibleValue();}
  281. /**
  282. * This method is here as a workaround for a bug in the javac compiler.
  283. */
  284. JComboBox metalGetComboBox() {
  285. return comboBox;
  286. }
  287. /**
  288. * This method is here as a workaround for a bug in the javac compiler.
  289. */
  290. JButton getArrowButton() {
  291. return arrowButton;
  292. }
  293. boolean isPopupVisible() {
  294. return super.isPopupVisible( comboBox );
  295. }
  296. void togglePopup() {
  297. toggleOpenClose();
  298. }
  299. Component metalGetEditor() {
  300. return editor;
  301. }
  302. JButton metalGetArrowButton() {
  303. return arrowButton;
  304. }
  305. /**
  306. * This inner class is marked "public" due to a compiler bug.
  307. * This class should be treated as a "protected" inner class.
  308. * Instantiate it only within subclasses of <FooUI>.
  309. */
  310. public class MetalComboPopup extends BasicComboPopup {
  311. public MetalComboPopup( JComboBox cBox ) {
  312. super( cBox );
  313. }
  314. public void delegateFocus( MouseEvent e ) {
  315. if ( metalGetComboBox().isEditable() ) {
  316. metalGetEditor().requestFocus();
  317. }
  318. }
  319. }
  320. }