1 /* 2 * Copyright (c) 2015, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /** 25 * @test 26 * @key headful 27 * @bug 8073001 8081764 28 * @summary Test verifies that combo box with custom editor renders 29 * focus ring around arrow button correctly. 30 * @library /lib/testlibrary 31 * @build jdk.testlibrary.OSInfo 32 * @run main CustomComboBoxFocusTest 33 */ 34 35 import java.awt.AWTException; 36 import java.awt.Component; 37 import java.awt.GridLayout; 38 import java.awt.Point; 39 import java.awt.Rectangle; 40 import java.awt.Robot; 41 import java.awt.event.ActionListener; 42 import java.awt.event.FocusEvent; 43 import java.awt.event.FocusListener; 44 import java.awt.image.BufferedImage; 45 import java.io.File; 46 import java.io.IOException; 47 import java.lang.reflect.InvocationTargetException; 48 import java.util.concurrent.CountDownLatch; 49 import javax.imageio.ImageIO; 50 import javax.swing.ComboBoxEditor; 51 import javax.swing.JComboBox; 52 import javax.swing.JFrame; 53 import javax.swing.JLabel; 54 import javax.swing.JPanel; 55 import javax.swing.JTextField; 56 import javax.swing.SwingUtilities; 57 import jdk.testlibrary.OSInfo; 58 59 public class CustomComboBoxFocusTest { 60 61 private static CustomComboBoxFocusTest test = null; 62 63 public static void main(String[] args) { 64 if (OSInfo.getOSType() != OSInfo.OSType.MACOSX) { 65 System.out.println("Only Mac platform test. Test is skipped for other OS."); 66 return; 67 } 68 69 try { 70 SwingUtilities.invokeAndWait(new Runnable() { 71 public void run() { 72 test = new CustomComboBoxFocusTest(); 73 } 74 }); 75 } catch (InterruptedException | InvocationTargetException e ) { 76 throw new RuntimeException("Test failed.", e); 77 } 78 79 SwingUtilities.invokeLater(test.init); 80 81 try { 82 System.out.println("Wait for screenshots..."); 83 test.testDone.await(); 84 } catch (InterruptedException e) { 85 throw new RuntimeException("Test failed.", e); 86 } 87 System.out.println("Compare screenshots..."); 88 if (!test.match()) { 89 throw new RuntimeException("Test failed."); 90 } 91 System.out.println("Test passed."); 92 } 93 94 private final JComboBox<String> ref = new JComboBox<String>() { 95 public String toString() { 96 return "reference"; 97 } 98 }; 99 100 private final JComboBox<String> custom = new JComboBox<String>() { 101 public String toString() { 102 return "custom"; 103 } 104 }; 105 106 private final JFrame frame; 107 108 private CountDownLatch testDone = new CountDownLatch(1); 109 110 private Robot robot; 111 112 public CustomComboBoxFocusTest() { 113 frame = new JFrame(System.getProperty("java.version")); 114 115 try { 116 robot = new Robot(frame.getGraphicsConfiguration().getDevice()); 117 118 } catch (AWTException e) { 119 throw new RuntimeException("Test failed.", e); 120 } 121 } 122 123 private boolean match() { 124 final BufferedImage a = captureRef.img; 125 final BufferedImage b = captureCustom.img; 126 127 final int w = Math.min(a.getWidth(), b.getWidth()); 128 final int h = Math.min(a.getHeight(), b.getHeight()); 129 130 for (int y = 0; y < h; y++) { 131 for (int x = 0; x < w; x++) { 132 if (a.getRGB(x, y) != b.getRGB(x, y)) { 133 return false; 134 } 135 } 136 } 137 return true; 138 } 139 140 private JComboBox<String> getReference() { 141 return ref; 142 } 143 144 private JComboBox<String> getCustom() { 145 return custom; 146 } 147 148 private JFrame getFrame() { 149 return frame; 150 } 151 152 private static abstract class Step implements Runnable { 153 final public void run() { 154 doStep(); 155 156 final Step next = nextStep(); 157 158 if (next != null) { 159 SwingUtilities.invokeLater(next); 160 } 161 } 162 163 public abstract void doStep(); 164 165 public abstract Step nextStep(); 166 } 167 168 private final Step init = new Step() { 169 public void doStep() { 170 final JFrame f = getFrame(); 171 172 final JPanel p = new JPanel(new GridLayout(4, 1, 20, 20)); 173 174 JComboBox<String> r = getReference(); 175 r.setEditable(true); 176 r.addItem("One"); 177 178 JComboBox<String> c = getCustom(); 179 c.setEditable(true); 180 c.addItem("One"); 181 final ComboBoxEditor e = new ComboBoxEditor() { 182 private JTextField text = new JTextField(); 183 184 @Override 185 public Component getEditorComponent() { 186 return this.text; 187 } 188 189 @Override 190 public void setItem(Object o) { 191 text.setText(o == null ? "" : o.toString()); 192 } 193 194 @Override 195 public Object getItem() { 196 return text.getText(); 197 } 198 199 @Override 200 public void selectAll() { 201 text.selectAll(); 202 } 203 204 @Override 205 public void addActionListener(ActionListener actionListener) { 206 text.addActionListener(actionListener); 207 } 208 209 @Override 210 public void removeActionListener(ActionListener actionListener) { 211 text.removeActionListener(actionListener); 212 } 213 }; 214 c.setEditor(e); 215 216 p.add(new JLabel("Reference")); 217 p.add(r); 218 p.add(c); 219 p.add(new JLabel("Custom")); 220 221 f.add(p); 222 223 f.pack(); 224 f.setVisible(true); 225 } 226 227 public Step nextStep() { 228 return focusRef; 229 } 230 }; 231 232 private class FocusStep extends Step { 233 private final JComboBox<String> target; 234 private final Step focusHandler; 235 private final Step next; 236 237 public FocusStep(JComboBox<String> t, Step h, Step n) { 238 target = t; 239 focusHandler = h; 240 next = n; 241 } 242 243 public void doStep() { 244 System.out.println("Request focus on " + target); 245 final Component c = target.getEditor().getEditorComponent(); 246 247 c.addFocusListener(new FocusListener() { 248 @Override 249 public void focusGained(FocusEvent e) { 250 SwingUtilities.invokeLater(focusHandler); 251 } 252 253 @Override 254 public void focusLost(FocusEvent e) { 255 256 } 257 }); 258 259 c.requestFocus(); 260 261 } 262 263 public Step nextStep() { 264 return next; 265 } 266 } 267 268 269 private class CaptureStep extends Step { 270 private final JComboBox<String> target; 271 private BufferedImage img; 272 private String fname; 273 private final Step next; 274 275 private final int timeout = 2000; 276 277 public CaptureStep(JComboBox<String> t, String name, Step n) { 278 target = t; 279 next = n; 280 fname = name; 281 } 282 283 public void doStep() { 284 try { 285 Thread.sleep(timeout); 286 } catch (InterruptedException e) { 287 } 288 System.out.println("Capture sceeenshot of " + target); 289 290 Rectangle bounds = target.getBounds(); 291 Point p = target.getLocationOnScreen(); 292 System.out.println("Target bounds: " + bounds); 293 System.out.println("Target location: " + p); 294 295 bounds.x = p.x; 296 bounds.y = p.y; 297 298 img = robot.createScreenCapture(bounds); 299 300 try { 301 ImageIO.write(img, "PNG", new File(fname + ".png")); 302 } catch (IOException ioe) { 303 ioe.printStackTrace(); 304 } 305 306 } 307 308 public Step nextStep() { 309 return next; 310 } 311 } 312 313 private final Step done = new Step() { 314 public void doStep() { 315 JFrame f = getFrame(); 316 if (f != null) { 317 f.dispose(); 318 } 319 System.out.println("Done"); 320 321 testDone.countDown(); 322 } 323 324 public Step nextStep() { 325 return null; 326 } 327 }; 328 329 private final CaptureStep captureCustom = new CaptureStep(getCustom(), "cb_custom", done); 330 331 private final FocusStep focusCustom = new FocusStep(getCustom(), captureCustom, null); 332 333 private final CaptureStep captureRef = new CaptureStep(getReference(), "cb_ref", focusCustom); 334 335 private final FocusStep focusRef = new FocusStep(getReference(), captureRef, null); 336 }