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 }