View Javadoc
1   /*
2    * Copyright (c) 1997, 2006, 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  package com.sun.java.swing.plaf.motif;
26  
27  import java.awt.*;
28  import javax.swing.*;
29  import javax.swing.plaf.*;
30  import javax.swing.border.*;
31  import javax.swing.plaf.basic.*;
32  import java.io.Serializable;
33  import java.awt.event.*;
34  import java.beans.*;
35  
36  /**
37   * ComboBox motif look and feel
38   * <p> * <strong>Warning:</strong>
39   * Serialized objects of this class will not be compatible with
40   * future Swing releases.  The current serialization support is appropriate
41   * for short term storage or RMI between applications running the same
42   * version of Swing.  A future release of Swing will provide support for
43   * long term persistence.
44   *
45   * @author Arnaud Weber
46   */
47  public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable {
48      Icon arrowIcon;
49      static final int HORIZ_MARGIN = 3;
50  
51      public static ComponentUI createUI(JComponent c) {
52          return new MotifComboBoxUI();
53      }
54  
55      public void installUI(JComponent c) {
56          super.installUI(c);
57          arrowIcon = new MotifComboBoxArrowIcon(UIManager.getColor("controlHighlight"),
58                                                 UIManager.getColor("controlShadow"),
59                                                 UIManager.getColor("control"));
60  
61          Runnable initCode = new Runnable() {
62              public void run(){
63                  if ( motifGetEditor() != null ) {
64                      motifGetEditor().setBackground( UIManager.getColor( "text" ) );
65                  }
66              }
67          };
68  
69          SwingUtilities.invokeLater( initCode );
70      }
71  
72      public Dimension getMinimumSize( JComponent c ) {
73          if ( !isMinimumSizeDirty ) {
74              return new Dimension( cachedMinimumSize );
75          }
76          Dimension size;
77          Insets insets = getInsets();
78          size = getDisplaySize();
79          size.height += insets.top + insets.bottom;
80          int buttonSize = iconAreaWidth();
81          size.width +=  insets.left + insets.right + buttonSize;
82  
83          cachedMinimumSize.setSize( size.width, size.height );
84          isMinimumSizeDirty = false;
85  
86          return size;
87      }
88  
89      protected ComboPopup createPopup() {
90          return new MotifComboPopup( comboBox );
91      }
92  
93      /**
94       * Overriden to empty the MouseMotionListener.
95       */
96      protected class MotifComboPopup extends BasicComboPopup {
97  
98          public MotifComboPopup( JComboBox comboBox ) {
99              super( comboBox );
100         }
101 
102         /**
103          * Motif combo popup should not track the mouse in the list.
104          */
105         public MouseMotionListener createListMouseMotionListener() {
106            return new MouseMotionAdapter() {};
107         }
108 
109         public KeyListener createKeyListener() {
110             return super.createKeyListener();
111         }
112 
113         protected class InvocationKeyHandler extends BasicComboPopup.InvocationKeyHandler {
114             protected InvocationKeyHandler() {
115                 MotifComboPopup.this.super();
116             }
117         }
118     }
119 
120     protected void installComponents() {
121         if ( comboBox.isEditable() ) {
122             addEditor();
123         }
124 
125         comboBox.add( currentValuePane );
126     }
127 
128     protected void uninstallComponents() {
129         removeEditor();
130         comboBox.removeAll();
131     }
132 
133     public void paint(Graphics g, JComponent c) {
134         boolean hasFocus = comboBox.hasFocus();
135         Rectangle r;
136 
137         if (comboBox.isEnabled()) {
138             g.setColor(comboBox.getBackground());
139         } else {
140             g.setColor(UIManager.getColor("ComboBox.disabledBackground"));
141         }
142         g.fillRect(0,0,c.getWidth(),c.getHeight());
143 
144         if ( !comboBox.isEditable() ) {
145             r = rectangleForCurrentValue();
146             paintCurrentValue(g,r,hasFocus);
147         }
148         r = rectangleForArrowIcon();
149         arrowIcon.paintIcon(c,g,r.x,r.y);
150         if ( !comboBox.isEditable() ) {
151             Border border = comboBox.getBorder();
152             Insets in;
153             if ( border != null ) {
154                 in = border.getBorderInsets(comboBox);
155             }
156             else {
157                 in = new Insets( 0, 0, 0, 0 );
158             }
159             // Draw the separation
160             if(MotifGraphicsUtils.isLeftToRight(comboBox)) {
161                 r.x -= (HORIZ_MARGIN + 2);
162             }
163             else {
164                 r.x += r.width + HORIZ_MARGIN + 1;
165             }
166             r.y = in.top;
167             r.width = 1;
168             r.height = comboBox.getBounds().height - in.bottom - in.top;
169             g.setColor(UIManager.getColor("controlShadow"));
170             g.fillRect(r.x,r.y,r.width,r.height);
171             r.x++;
172             g.setColor(UIManager.getColor("controlHighlight"));
173             g.fillRect(r.x,r.y,r.width,r.height);
174         }
175     }
176 
177     public void paintCurrentValue(Graphics g,Rectangle bounds,boolean hasFocus) {
178         ListCellRenderer renderer = comboBox.getRenderer();
179         Component c;
180         Dimension d;
181         c = renderer.getListCellRendererComponent(listBox, comboBox.getSelectedItem(), -1, false, false);
182         c.setFont(comboBox.getFont());
183         if ( comboBox.isEnabled() ) {
184             c.setForeground(comboBox.getForeground());
185             c.setBackground(comboBox.getBackground());
186         }
187         else {
188             c.setForeground(UIManager.getColor("ComboBox.disabledForeground"));
189             c.setBackground(UIManager.getColor("ComboBox.disabledBackground"));
190         }
191         d  = c.getPreferredSize();
192         currentValuePane.paintComponent(g,c,comboBox,bounds.x,bounds.y,
193                                         bounds.width,d.height);
194     }
195 
196     protected Rectangle rectangleForArrowIcon() {
197         Rectangle b = comboBox.getBounds();
198         Border border = comboBox.getBorder();
199         Insets in;
200         if ( border != null ) {
201             in = border.getBorderInsets(comboBox);
202         }
203         else {
204             in = new Insets( 0, 0, 0, 0 );
205         }
206         b.x = in.left;
207         b.y = in.top;
208         b.width -= (in.left + in.right);
209         b.height -= (in.top + in.bottom);
210 
211         if(MotifGraphicsUtils.isLeftToRight(comboBox)) {
212             b.x = b.x + b.width - HORIZ_MARGIN - arrowIcon.getIconWidth();
213         }
214         else {
215             b.x += HORIZ_MARGIN;
216         }
217         b.y = b.y + (b.height - arrowIcon.getIconHeight()) / 2;
218         b.width = arrowIcon.getIconWidth();
219         b.height = arrowIcon.getIconHeight();
220         return b;
221     }
222 
223     protected Rectangle rectangleForCurrentValue() {
224         int width = comboBox.getWidth();
225         int height = comboBox.getHeight();
226         Insets insets = getInsets();
227         if(MotifGraphicsUtils.isLeftToRight(comboBox)) {
228             return new Rectangle(insets.left, insets.top,
229                                  (width - (insets.left + insets.right)) -
230                                                         iconAreaWidth(),
231                                  height - (insets.top + insets.bottom));
232         }
233         else {
234             return new Rectangle(insets.left + iconAreaWidth(), insets.top,
235                                  (width - (insets.left + insets.right)) -
236                                                         iconAreaWidth(),
237                                  height - (insets.top + insets.bottom));
238         }
239     }
240 
241     public int iconAreaWidth() {
242         if ( comboBox.isEditable() )
243             return arrowIcon.getIconWidth() + (2 * HORIZ_MARGIN);
244         else
245             return arrowIcon.getIconWidth() + (3 * HORIZ_MARGIN) + 2;
246     }
247 
248     public void configureEditor() {
249         super.configureEditor();
250         editor.setBackground( UIManager.getColor( "text" ) );
251     }
252 
253     protected LayoutManager createLayoutManager() {
254         return new ComboBoxLayoutManager();
255     }
256 
257     private Component motifGetEditor() {
258         return editor;
259     }
260 
261     /**
262      * This inner class is marked &quot;public&quot; due to a compiler bug.
263      * This class should be treated as a &quot;protected&quot; inner class.
264      * Instantiate it only within subclasses of <FooUI>.
265      */
266     public class ComboBoxLayoutManager extends BasicComboBoxUI.ComboBoxLayoutManager {
267         public ComboBoxLayoutManager() {
268             MotifComboBoxUI.this.super();
269         }
270         public void layoutContainer(Container parent) {
271             if ( motifGetEditor() != null ) {
272                 Rectangle cvb = rectangleForCurrentValue();
273                 cvb.x += 1;
274                 cvb.y += 1;
275                 cvb.width -= 1;
276                 cvb.height -= 2;
277                 motifGetEditor().setBounds(cvb);
278             }
279         }
280     }
281 
282     static class MotifComboBoxArrowIcon implements Icon, Serializable {
283         private Color lightShadow;
284         private Color darkShadow;
285         private Color fill;
286 
287         public MotifComboBoxArrowIcon(Color lightShadow, Color darkShadow, Color fill) {
288             this.lightShadow = lightShadow;
289             this.darkShadow = darkShadow;
290             this.fill = fill;
291         }
292 
293 
294         public void paintIcon(Component c, Graphics g, int xo, int yo) {
295             int w = getIconWidth();
296             int h = getIconHeight();
297 
298             g.setColor(lightShadow);
299             g.drawLine(xo, yo, xo+w-1, yo);
300             g.drawLine(xo, yo+1, xo+w-3, yo+1);
301             g.setColor(darkShadow);
302             g.drawLine(xo+w-2, yo+1, xo+w-1, yo+1);
303 
304             for ( int x = xo+1, y = yo+2, dx = w-6; y+1 < yo+h; y += 2 ) {
305                 g.setColor(lightShadow);
306                 g.drawLine(x, y,   x+1, y);
307                 g.drawLine(x, y+1, x+1, y+1);
308                 if ( dx > 0 ) {
309                     g.setColor(fill);
310                     g.drawLine(x+2, y,   x+1+dx, y);
311                     g.drawLine(x+2, y+1, x+1+dx, y+1);
312                 }
313                 g.setColor(darkShadow);
314                 g.drawLine(x+dx+2, y,   x+dx+3, y);
315                 g.drawLine(x+dx+2, y+1, x+dx+3, y+1);
316                 x += 1;
317                 dx -= 2;
318             }
319 
320             g.setColor(darkShadow);
321             g.drawLine(xo+(w/2), yo+h-1, xo+(w/2), yo+h-1);
322 
323         }
324 
325         public int getIconWidth() {
326             return 11;
327         }
328 
329         public int getIconHeight() {
330             return 11;
331         }
332     }
333 
334     /**
335      *{@inheritDoc}
336      *
337      * @since 1.6
338      */
339     protected PropertyChangeListener createPropertyChangeListener() {
340         return new MotifPropertyChangeListener();
341     }
342 
343     /**
344      * This class should be made &quot;protected&quot; in future releases.
345      */
346     private class MotifPropertyChangeListener
347             extends BasicComboBoxUI.PropertyChangeHandler {
348         public void propertyChange(PropertyChangeEvent e) {
349             super.propertyChange(e);
350             String propertyName = e.getPropertyName();
351             if (propertyName == "enabled") {
352                 if (comboBox.isEnabled()) {
353                     Component editor = motifGetEditor();
354                     if (editor != null) {
355                         editor.setBackground(UIManager.getColor("text"));
356                     }
357                 }
358             }
359         }
360     }
361 }