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