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