bug6462008.java revision 11111:4ef86895869c
1/* 2 * Copyright (c) 2011, 2012, 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 * @bug 6462008 27 * @summary Tests that mouse/keyboard work properly on JList with lead < 0 or > list.getModel().getSize() 28 * @author Shannon Hickey 29 * @run main bug6462008 30 */ 31import java.awt.*; 32import java.awt.event.*; 33import javax.swing.*; 34import java.util.*; 35 36public class bug6462008 { 37 38 private static final int DONT_CARE = -2; 39 private static int anchorLead; 40 private static boolean isAquaLAF; 41 private static int controlKey; 42 private static JList list; 43 private static Robot robot; 44 45 public static void main(String[] args) throws Exception { 46 robot = new Robot(); 47 robot.setAutoDelay(100); 48 49 isAquaLAF = "Aqua".equals(UIManager.getLookAndFeel().getID()); 50 controlKey = isAquaLAF ? KeyEvent.VK_META : KeyEvent.VK_CONTROL; 51 52 SwingUtilities.invokeAndWait(new Runnable() { 53 54 @Override 55 public void run() { 56 createAndShowGUI(); 57 } 58 }); 59 60 robot.waitForIdle(); 61 62 setAnchorLead(-1); 63 robot.waitForIdle(); 64 65 testListSelection(); 66 67 setAnchorLead(100); 68 robot.waitForIdle(); 69 70 testListSelection(); 71 } 72 73 public static void testListSelection() throws Exception { 74 75 // Space 76 robot.keyPress(KeyEvent.VK_SPACE); 77 robot.keyRelease(KeyEvent.VK_SPACE); 78 79 robot.waitForIdle(); 80 checkSelection(); 81 resetList(); 82 robot.waitForIdle(); 83 84 // Control + Space 85 robot.keyPress(KeyEvent.VK_CONTROL); 86 robot.keyPress(KeyEvent.VK_SPACE); 87 robot.keyRelease(KeyEvent.VK_SPACE); 88 robot.keyRelease(KeyEvent.VK_CONTROL); 89 90 robot.waitForIdle(); 91 checkSelection(); 92 resetList(); 93 robot.waitForIdle(); 94 95 // Shift + Space 96 robot.keyPress(KeyEvent.VK_SHIFT); 97 robot.keyPress(KeyEvent.VK_SPACE); 98 robot.keyRelease(KeyEvent.VK_SPACE); 99 robot.keyRelease(KeyEvent.VK_SHIFT); 100 101 robot.waitForIdle(); 102 checkSelection(); 103 resetList(); 104 robot.waitForIdle(); 105 106 // Control + Shift + Space 107 robot.keyPress(KeyEvent.VK_CONTROL); 108 robot.keyPress(KeyEvent.VK_SHIFT); 109 robot.keyPress(KeyEvent.VK_SPACE); 110 robot.keyRelease(KeyEvent.VK_SPACE); 111 robot.keyRelease(KeyEvent.VK_SHIFT); 112 robot.keyRelease(KeyEvent.VK_CONTROL); 113 114 robot.waitForIdle(); 115 checkSelection(); 116 resetList(); 117 robot.waitForIdle(); 118 119 120 // Control + A Multiple Selection 121 122 robot.keyPress(controlKey); 123 robot.keyPress(KeyEvent.VK_A); 124 robot.keyRelease(KeyEvent.VK_A); 125 robot.keyRelease(controlKey); 126 127 robot.waitForIdle(); 128 checkSelectionAL(-1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); 129 resetList(); 130 setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 131 robot.waitForIdle(); 132 133 // Control + A Single Selection 134 robot.keyPress(controlKey); 135 robot.keyPress(KeyEvent.VK_A); 136 robot.keyRelease(KeyEvent.VK_A); 137 robot.keyRelease(controlKey); 138 139 robot.waitForIdle(); 140 checkSelectionAL(0, 0, 0); 141 resetList(); 142 setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 143 setSelectionInterval(5, 5); 144 robot.waitForIdle(); 145 146 147 // Control + A Selection interval (5, 5) 148 robot.keyPress(controlKey); 149 robot.keyPress(KeyEvent.VK_A); 150 robot.keyRelease(KeyEvent.VK_A); 151 robot.keyRelease(controlKey); 152 153 robot.waitForIdle(); 154 checkSelection(5); 155 resetList(); 156 robot.waitForIdle(); 157 158 // Page Down 159 // Not applicable for the Aqua L&F 160 if (!isAquaLAF) { 161 robot.keyPress(KeyEvent.VK_PAGE_DOWN); 162 robot.keyRelease(KeyEvent.VK_PAGE_DOWN); 163 164 robot.waitForIdle(); 165 checkSelection(9, 9, 9); 166 resetList(); 167 robot.waitForIdle(); 168 } 169 170 // Shift + Page Down 171 /* 172 * We really want to use robot here, but there seems to be a bug in AWT's 173 * robot implementation (see 6463168). For now, we'll invoke the action 174 * directly instead. When the bug is fixed, we'll use the following four 175 * lines instead: 176 * robot.keyPress(KeyEvent.VK_SHIFT); 177 * robot.keyPress(KeyEvent.VK_PAGE_DOWN); 178 * robot.keyRelease(KeyEvent.VK_PAGE_DOWN); 179 * robot.keyRelease(KeyEvent.VK_SHIFT); 180 */ 181 182 scrollDownExtendSelection(); 183 184 robot.waitForIdle(); 185 checkSelection(0, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); 186 resetList(); 187 robot.waitForIdle(); 188 189 // Down 190 robot.keyPress(KeyEvent.VK_DOWN); 191 robot.keyRelease(KeyEvent.VK_DOWN); 192 193 robot.waitForIdle(); 194 checkSelectionAL(0, 0, 0); 195 resetList(); 196 robot.waitForIdle(); 197 198 // L 199 robot.keyPress(KeyEvent.VK_L); 200 robot.keyRelease(KeyEvent.VK_L); 201 202 robot.waitForIdle(); 203 checkSelectionAL(0, 0, 0); 204 resetList(); 205 robot.waitForIdle(); 206 207 // Click item 4 208 Point p = clickItem4(); 209 robot.mouseMove(p.x, p.y); 210 robot.mousePress(InputEvent.BUTTON1_MASK); 211 robot.mouseRelease(InputEvent.BUTTON1_MASK); 212 213 214 robot.waitForIdle(); 215 checkSelectionAL(4, 4, 4); 216 resetList(); 217 robot.waitForIdle(); 218 219 220 // Control + Click item 4 221 robot.keyPress(controlKey); 222 p = clickItem4(); 223 robot.mouseMove(p.x, p.y); 224 robot.mousePress(InputEvent.BUTTON1_MASK); 225 robot.mouseRelease(InputEvent.BUTTON1_MASK); 226 robot.keyRelease(controlKey); 227 228 229 robot.waitForIdle(); 230 checkSelectionAL(4, 4, 4); 231 resetList(); 232 robot.waitForIdle(); 233 234 // Shift + Click item 4 235 robot.keyPress(KeyEvent.VK_SHIFT); 236 p = clickItem4(); 237 robot.mouseMove(p.x, p.y); 238 robot.mousePress(InputEvent.BUTTON1_MASK); 239 robot.mouseRelease(InputEvent.BUTTON1_MASK); 240 robot.keyRelease(KeyEvent.VK_SHIFT); 241 242 243 robot.waitForIdle(); 244 checkSelectionAL(0, 4, 0, 1, 2, 3, 4); 245 resetList(); 246 robot.waitForIdle(); 247 248 249 // Control + Shift + Click item 4 250 robot.keyPress(controlKey); 251 robot.keyPress(KeyEvent.VK_SHIFT); 252 p = clickItem4(); 253 robot.mouseMove(p.x, p.y); 254 robot.mousePress(InputEvent.BUTTON1_MASK); 255 robot.mouseRelease(InputEvent.BUTTON1_MASK); 256 robot.keyRelease(KeyEvent.VK_SHIFT); 257 robot.keyRelease(controlKey); 258 259 robot.waitForIdle(); 260 checkSelectionAL(0, 4); 261 resetList(); 262 robot.waitForIdle(); 263 } 264 265 private static DefaultListModel getModel() { 266 DefaultListModel listModel = new DefaultListModel(); 267 for (int i = 0; i < 10; i++) { 268 listModel.addElement("List Item " + i); 269 } 270 return listModel; 271 } 272 273 private static Point clickItem4() throws Exception { 274 275 final Point[] result = new Point[1]; 276 SwingUtilities.invokeAndWait(new Runnable() { 277 278 @Override 279 public void run() { 280 Rectangle r = list.getCellBounds(4, 4); 281 Point p = new Point(r.x + r.width / 2, r.y + r.height / 2); 282 SwingUtilities.convertPointToScreen(p, list); 283 result[0] = p; 284 } 285 }); 286 287 return result[0]; 288 } 289 290 private static void resetList() throws Exception { 291 SwingUtilities.invokeAndWait(new Runnable() { 292 293 @Override 294 public void run() { 295 list.getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 296 list.getSelectionModel().clearSelection(); 297 setAnchorLeadNonThreadSafe(); 298 } 299 }); 300 } 301 302 private static void scrollDownExtendSelection() throws Exception { 303 SwingUtilities.invokeAndWait(new Runnable() { 304 305 @Override 306 public void run() { 307 list.getActionMap().get("scrollDownExtendSelection"). 308 actionPerformed(new ActionEvent(list, 309 ActionEvent.ACTION_PERFORMED, null)); 310 } 311 }); 312 } 313 314 private static void setSelectionMode(final int selectionMode) throws Exception { 315 SwingUtilities.invokeAndWait(new Runnable() { 316 317 @Override 318 public void run() { 319 list.getSelectionModel().setSelectionMode(selectionMode); 320 setAnchorLeadNonThreadSafe(); 321 } 322 }); 323 } 324 325 private static void setSelectionInterval(final int index0, final int index1) throws Exception { 326 SwingUtilities.invokeAndWait(new Runnable() { 327 328 @Override 329 public void run() { 330 list.getSelectionModel().setSelectionInterval(index0, index1); 331 setAnchorLeadNonThreadSafe(); 332 } 333 }); 334 } 335 336 private static void setAnchorLead(final int anchorLeadValue) throws Exception { 337 SwingUtilities.invokeAndWait(new Runnable() { 338 339 @Override 340 public void run() { 341 anchorLead = anchorLeadValue; 342 setAnchorLeadNonThreadSafe(); 343 } 344 }); 345 } 346 347 private static void setAnchorLeadNonThreadSafe() { 348 list.getSelectionModel().setAnchorSelectionIndex(anchorLead); 349 ((DefaultListSelectionModel) list.getSelectionModel()).moveLeadSelectionIndex(anchorLead); 350 } 351 352 private static void createAndShowGUI() { 353 JFrame frame = new JFrame("bug6462008"); 354 frame.setSize(200, 500); 355 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 356 357 list = new JList(getModel()); 358 JPanel panel = new JPanel(new BorderLayout()); 359 panel.add(list); 360 frame.getContentPane().add(panel); 361 362 frame.setVisible(true); 363 } 364 365 private static void checkSelection(int... sels) throws Exception { 366 checkSelectionAL(DONT_CARE, DONT_CARE, sels); 367 } 368 369 private static void checkSelectionAL(final int anchor, final int lead, final int... sels) throws Exception { 370 SwingUtilities.invokeAndWait(new Runnable() { 371 372 @Override 373 public void run() { 374 checkSelectionNonThreadSafe(anchor, lead, sels); 375 } 376 }); 377 } 378 379 private static void checkSelectionNonThreadSafe(int anchor, int lead, int... sels) { 380 ListSelectionModel lsm = list.getSelectionModel(); 381 382 int actualAnchor = lsm.getAnchorSelectionIndex(); 383 int actualLead = lsm.getLeadSelectionIndex(); 384 385 if (anchor != DONT_CARE && actualAnchor != anchor) { 386 throw new RuntimeException("anchor is " + actualAnchor + ", should be " + anchor); 387 } 388 389 if (lead != DONT_CARE && actualLead != lead) { 390 throw new RuntimeException("lead is " + actualLead + ", should be " + lead); 391 } 392 393 Arrays.sort(sels); 394 boolean[] checks = new boolean[list.getModel().getSize()]; 395 for (int i : sels) { 396 checks[i] = true; 397 } 398 399 int index0 = Math.min(lsm.getMinSelectionIndex(), 0); 400 int index1 = Math.max(lsm.getMaxSelectionIndex(), list.getModel().getSize() - 1); 401 402 for (int i = index0; i <= index1; i++) { 403 if (lsm.isSelectedIndex(i)) { 404 if (i < 0 || i >= list.getModel().getSize() || !checks[i]) { 405 throw new RuntimeException(i + " is selected when it should not be"); 406 } 407 } else if (i >= 0 && i < list.getModel().getSize() && checks[i]) { 408 throw new RuntimeException(i + " is supposed to be selected"); 409 } 410 } 411 } 412} 413