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