1 /* 2 * Copyright (c) 2015, 2017, 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 /test/lib 31 * @build jdk.test.lib.Platform 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 58 import jdk.test.lib.Platform; 59 60 public class CustomComboBoxFocusTest { 61 62 private static CustomComboBoxFocusTest test = null; 63 64 public static void main(String[] args) { 65 if (!Platform.isOSX()) { 66 System.out.println("Only Mac platform test. Test is skipped for other OS."); 67 return; 68 } 69 70 try { 71 SwingUtilities.invokeAndWait(new Runnable() { 72 public void run() { 73 test = new CustomComboBoxFocusTest(); 74 } 75 }); 76 } catch (InterruptedException | InvocationTargetException e ) { 77 throw new RuntimeException("Test failed.", e); 78 } 79 80 SwingUtilities.invokeLater(test.init); 81 82 try { 83 System.out.println("Wait for screenshots..."); 84 test.testDone.await(); 85 } catch (InterruptedException e) { 86 throw new RuntimeException("Test failed.", e); 87 } 88 System.out.println("Compare screenshots..."); 89 if (!test.match()) { 90 throw new RuntimeException("Test failed."); 91 } 92 System.out.println("Test passed."); 93 } 94 95 private final JComboBox<String> ref = new JComboBox<String>() { 96 public String toString() { 97 return "reference"; 98 } 99 }; 100 101 private final JComboBox<String> custom = new JComboBox<String>() { 102 public String toString() { 103 return "custom"; 104 } 105 }; 106 107 private final JFrame frame; 108 109 private CountDownLatch testDone = new CountDownLatch(1); 110 111 private Robot robot; 112 113 public CustomComboBoxFocusTest() { 114 frame = new JFrame(System.getProperty("java.version")); 115 116 try { 117 robot = new Robot(frame.getGraphicsConfiguration().getDevice()); 118 119 } catch (AWTException e) { 120 throw new RuntimeException("Test failed.", e); 121 } 122 } 123 124 private boolean match() { 125 final BufferedImage a = captureRef.img; 126 final BufferedImage b = captureCustom.img; 127 128 final int w = Math.min(a.getWidth(), b.getWidth()); 129 final int h = Math.min(a.getHeight(), b.getHeight()); 130 131 for (int y = 0; y < h; y++) { 132 for (int x = 0; x < w; x++) { 133 if (a.getRGB(x, y) != b.getRGB(x, y)) { 134 return false; 135 } 136 } 137 } 138 return true; 139 } 140 141 private JComboBox<String> getReference() { 142 return ref; 143 } 144 145 private JComboBox<String> getCustom() { 146 return custom; 147 } 148 149 private JFrame getFrame() { 150 return frame; 151 } 152 153 private static abstract class Step implements Runnable { 154 final public void run() { 155 doStep(); 156 157 final Step next = nextStep(); 158 159 if (next != null) { 160 SwingUtilities.invokeLater(next); 161 } 162 } 163 164 public abstract void doStep(); 165 166 public abstract Step nextStep(); 167 } 168 169 private final Step init = new Step() { 170 public void doStep() { 171 final JFrame f = getFrame(); 172 173 final JPanel p = new JPanel(new GridLayout(4, 1, 20, 20)); 174 175 JComboBox<String> r = getReference(); 176 r.setEditable(true); 177 r.addItem("One"); 178 179 JComboBox<String> c = getCustom(); 180 c.setEditable(true); 181 c.addItem("One"); 182 final ComboBoxEditor e = new ComboBoxEditor() { 183 private JTextField text = new JTextField(); 184 185 @Override 186 public Component getEditorComponent() { 187 return this.text; 188 } 189 190 @Override 191 public void setItem(Object o) { 192 text.setText(o == null ? "" : o.toString()); 193 } 194 195 @Override 196 public Object getItem() { 197 return text.getText(); 198 } 199 200 @Override 201 public void selectAll() { 202 text.selectAll(); 203 } 204 205 @Override 206 public void addActionListener(ActionListener actionListener) { 207 text.addActionListener(actionListener); 208 } 209 210 @Override 211 public void removeActionListener(ActionListener actionListener) { 212 text.removeActionListener(actionListener); 213 } 214 }; 215 c.setEditor(e); 216 217 p.add(new JLabel("Reference")); 218 p.add(r); 219 p.add(c); 220 p.add(new JLabel("Custom")); 221 222 f.add(p); 223 224 f.pack(); 225 f.setVisible(true); 226 } 227 228 public Step nextStep() { 229 return focusRef; 230 } 231 }; 232 233 private class FocusStep extends Step { 234 private final JComboBox<String> target; 235 private final Step focusHandler; 236 private final Step next; 237 238 public FocusStep(JComboBox<String> t, Step h, Step n) { 239 target = t; 240 focusHandler = h; 241 next = n; 242 } 243 244 public void doStep() { 245 System.out.println("Request focus on " + target); 246 final Component c = target.getEditor().getEditorComponent(); 247 248 c.addFocusListener(new FocusListener() { 249 @Override 250 public void focusGained(FocusEvent e) { 251 SwingUtilities.invokeLater(focusHandler); 252 } 253 254 @Override 255 public void focusLost(FocusEvent e) { 256 257 } 258 }); 259 260 c.requestFocus(); 261 262 } 263 264 public Step nextStep() { 265 return next; 266 } 267 } 268 269 270 private class CaptureStep extends Step { 271 private final JComboBox<String> target; 272 private BufferedImage img; 273 private String fname; 274 private final Step next; 275 276 private final int timeout = 2000; 277 278 public CaptureStep(JComboBox<String> t, String name, Step n) { 279 target = t; 280 next = n; 281 fname = name; 282 } 283 284 public void doStep() { 285 try { 286 Thread.sleep(timeout); 287 } catch (InterruptedException e) { 288 } 289 System.out.println("Capture sceeenshot of " + target); 290 291 Rectangle bounds = target.getBounds(); 292 Point p = target.getLocationOnScreen(); 293 System.out.println("Target bounds: " + bounds); 294 System.out.println("Target location: " + p); 295 296 bounds.x = p.x; 297 bounds.y = p.y; 298 299 img = robot.createScreenCapture(bounds); 300 301 try { 302 ImageIO.write(img, "PNG", new File(fname + ".png")); 303 } catch (IOException ioe) { 304 ioe.printStackTrace(); 305 } 306 307 } 308 309 public Step nextStep() { 310 return next; 311 } 312 } 313 314 private final Step done = new Step() { 315 public void doStep() { 316 JFrame f = getFrame(); 317 if (f != null) { 318 f.dispose(); 319 } 320 System.out.println("Done"); 321 322 testDone.countDown(); 323 } 324 325 public Step nextStep() { 326 return null; 327 } 328 }; 329 330 private final CaptureStep captureCustom = new CaptureStep(getCustom(), "cb_custom", done); 331 332 private final FocusStep focusCustom = new FocusStep(getCustom(), captureCustom, null); 333 334 private final CaptureStep captureRef = new CaptureStep(getReference(), "cb_ref", focusCustom); 335 336 private final FocusStep focusRef = new FocusStep(getReference(), captureRef, null); 337 }