001 /* 002 * Created on Jan 19, 2008 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 005 * in compliance with the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License 010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 011 * or implied. See the License for the specific language governing permissions and limitations under 012 * the License. 013 * 014 * Copyright @2008-2010 the original author or authors. 015 */ 016 package org.fest.swing.driver; 017 018 import static java.awt.event.KeyEvent.VK_SHIFT; 019 import static java.util.Arrays.sort; 020 import static org.fest.assertions.Assertions.assertThat; 021 import static org.fest.assertions.Fail.fail; 022 import static org.fest.swing.awt.AWT.visibleCenterOf; 023 import static org.fest.swing.core.MouseButton.LEFT_BUTTON; 024 import static org.fest.swing.driver.CommonValidations.validateCellReader; 025 import static org.fest.swing.driver.JListContentQuery.contents; 026 import static org.fest.swing.driver.JListItemCountQuery.itemCountIn; 027 import static org.fest.swing.driver.JListItemIndexValidator.validateIndices; 028 import static org.fest.swing.driver.JListItemValueQuery.itemValue; 029 import static org.fest.swing.driver.JListMatchingItemQuery.centerOfMatchingItemCell; 030 import static org.fest.swing.driver.JListMatchingItemQuery.matchingItemIndex; 031 import static org.fest.swing.driver.JListMatchingItemQuery.matchingItemIndices; 032 import static org.fest.swing.driver.JListMatchingItemQuery.matchingItemValues; 033 import static org.fest.swing.driver.JListScrollToItemTask.ITEM_NOT_FOUND; 034 import static org.fest.swing.driver.JListScrollToItemTask.scrollToItem; 035 import static org.fest.swing.driver.JListScrollToItemTask.scrollToItemIfNotSelectedYet; 036 import static org.fest.swing.driver.JListSelectedIndexQuery.selectedIndexOf; 037 import static org.fest.swing.driver.JListSelectionIndicesQuery.selectedIndices; 038 import static org.fest.swing.driver.JListSelectionValueQuery.NO_SELECTION_VALUE; 039 import static org.fest.swing.driver.JListSelectionValueQuery.singleSelectionValue; 040 import static org.fest.swing.driver.JListSelectionValuesQuery.selectionValues; 041 import static org.fest.swing.driver.TextAssert.verifyThat; 042 import static org.fest.swing.edt.GuiActionRunner.execute; 043 import static org.fest.swing.util.Arrays.isEmptyIntArray; 044 import static org.fest.util.Arrays.format; 045 import static org.fest.util.Strings.concat; 046 047 import java.awt.Point; 048 import java.util.List; 049 import java.util.regex.Pattern; 050 051 import javax.swing.JList; 052 import javax.swing.JPopupMenu; 053 054 import org.fest.assertions.Description; 055 import org.fest.swing.annotation.RunsInEDT; 056 import org.fest.swing.cell.JListCellReader; 057 import org.fest.swing.core.MouseButton; 058 import org.fest.swing.core.Robot; 059 import org.fest.swing.edt.GuiQuery; 060 import org.fest.swing.edt.GuiTask; 061 import org.fest.swing.exception.ActionFailedException; 062 import org.fest.swing.exception.ComponentLookupException; 063 import org.fest.swing.exception.LocationUnavailableException; 064 import org.fest.swing.util.Pair; 065 import org.fest.swing.util.PatternTextMatcher; 066 import org.fest.swing.util.StringTextMatcher; 067 import org.fest.swing.util.TextMatcher; 068 import org.fest.swing.util.Range.From; 069 import org.fest.swing.util.Range.To; 070 071 /** 072 * Understands functional testing of <code>{@link JList}</code>s: 073 * <ul> 074 * <li>user input simulation</li> 075 * <li>state verification</li> 076 * <li>property value query</li> 077 * </ul> 078 * This class is intended for internal use only. Please use the classes in the package 079 * <code>{@link org.fest.swing.fixture}</code> in your tests. 080 * 081 * @author Alex Ruiz 082 * @author Yvonne Wang 083 */ 084 public class JListDriver extends JComponentDriver { 085 086 private static final String SELECTED_INDICES_PROPERTY = "selectedIndices"; 087 private static final String SELECTED_INDEX_PROPERTY = "selectedIndex"; 088 089 private JListCellReader cellReader; 090 091 /** 092 * Creates a new </code>{@link JListDriver}</code>. 093 * @param robot the robot to use to simulate user input. 094 */ 095 public JListDriver(Robot robot) { 096 super(robot); 097 cellReader(new BasicJListCellReader()); 098 } 099 100 /** 101 * Returns an array of <code>String</code>s that represents the contents of the given <code>{@link JList}</code>, 102 * using this driver's <code>{@link JListCellReader}</code>. 103 * @param list the target <code>JList</code>. 104 * @return an array of <code>String</code>s that represents the contents of the given <code>JList</code>. 105 * @see #cellReader(JListCellReader) 106 */ 107 @RunsInEDT 108 public String[] contentsOf(JList list) { 109 return contents(list, cellReader); 110 } 111 112 /** 113 * Selects the items matching the given values. 114 * @param list the target <code>JList</code>. 115 * @param values the values to match. Each <code>String</code> can be a regular expression. 116 * @throws NullPointerException if the given array is <code>null</code>. 117 * @throws IllegalArgumentException if the given array is empty. 118 * @throws IllegalStateException if the <code>JList</code> is disabled. 119 * @throws IllegalStateException if the <code>JList</code> is not showing on the screen. 120 * @throws LocationUnavailableException if an element matching the any of the given values cannot be found. 121 */ 122 @RunsInEDT 123 public void selectItems(JList list, String[] values) { 124 selectItems(list, new StringTextMatcher(values)); 125 } 126 127 /** 128 * Selects the items matching the given regular expression patterns. 129 * @param list the target <code>JList</code>. 130 * @param patterns the regular expression patterns to match. 131 * @throws NullPointerException if the given array is <code>null</code>. 132 * @throws NullPointerException if any of the regular expression patterns is <code>null</code>. 133 * @throws IllegalArgumentException if the given array is empty. 134 * @throws IllegalStateException if the <code>JList</code> is disabled. 135 * @throws IllegalStateException if the <code>JList</code> is not showing on the screen. 136 * @throws LocationUnavailableException if an element matching the any of the given regular expression patterns cannot 137 * be found. 138 * @since 1.2 139 */ 140 @RunsInEDT 141 public void selectItems(JList list, Pattern[] patterns) { 142 selectItems(list, new PatternTextMatcher(patterns)); 143 } 144 145 @RunsInEDT 146 private void selectItems(final JList list, final TextMatcher matcher) { 147 final List<Integer> indices = matchingItemIndices(list, matcher, cellReader); 148 if (indices.isEmpty()) throw failMatchingNotFound(list, matcher); 149 clearSelection(list); 150 new MultipleSelectionTemplate(robot) { 151 int elementCount() { return indices.size(); } 152 void selectElement(int index) { selectItem(list, indices.get(index)); } 153 }.multiSelect(); 154 } 155 156 /** 157 * Selects the item in the given <code>{@link JList}</code> whose value matches the given one. 158 * @param list the target <code>JList</code>. 159 * @param value the value to match. 160 * @throws IllegalStateException if the <code>JList</code> is disabled. 161 * @throws IllegalStateException if the <code>JList</code> is not showing on the screen. 162 * @throws LocationUnavailableException if an element matching the given value cannot be found. 163 */ 164 @RunsInEDT 165 public void selectItem(JList list, String value) { 166 selectItem(list, new StringTextMatcher(value)); 167 } 168 169 /** 170 * Selects the item in the given <code>{@link JList}</code> whose value matches the given regular expression pattern. 171 * @param list the target <code>JList</code>. 172 * @param pattern the regular expression to match. 173 * @throws IllegalStateException if the <code>JList</code> is disabled. 174 * @throws IllegalStateException if the <code>JList</code> is not showing on the screen. 175 * @throws LocationUnavailableException if an element matching the given value cannot be found. 176 * @throws NullPointerException if the given regular expression pattern is <code>null</code>. 177 * @since 1.2 178 */ 179 @RunsInEDT 180 public void selectItem(JList list, Pattern pattern) { 181 selectItem(list, new PatternTextMatcher(pattern)); 182 } 183 184 @RunsInEDT 185 private void selectItem(JList list, TextMatcher matcher) { 186 Pair<Integer, Point> scrollInfo = scrollToItemIfNotSelectedYet(list, matcher, cellReader); 187 robot.waitForIdle(); 188 verify(list, scrollInfo, matcher); 189 if (scrollInfo.ii == null) return; // already selected cell. 190 robot.click(list, cellCenterIn(scrollInfo)); 191 } 192 193 /** 194 * Clicks the first item matching the given value, using the specified mouse button, the given number times. 195 * @param list the target <code>JList</code>. 196 * @param value the value to match. 197 * @param button the button to use. 198 * @param times the number of times to click. 199 * @throws IllegalStateException if the <code>JList</code> is disabled. 200 * @throws IllegalStateException if the <code>JList</code> is not showing on the screen. 201 * @throws LocationUnavailableException if an element matching the given value cannot be found. 202 */ 203 public void clickItem(JList list, String value, MouseButton button, int times) { 204 clickItem(list, new StringTextMatcher(value), button, times); 205 } 206 207 /** 208 * Clicks the first item matching the given regular expression pattern, using the specified mouse button, the given 209 * number times. 210 * @param list the target <code>JList</code>. 211 * @param pattern the regular expression pattern to match. 212 * @param button the button to use. 213 * @param times the number of times to click. 214 * @throws IllegalStateException if the <code>JList</code> is disabled. 215 * @throws IllegalStateException if the <code>JList</code> is not showing on the screen. 216 * @throws NullPointerException if the given regular expression pattern is <code>null</code>. 217 * @throws LocationUnavailableException if an element matching the given regular expression pattern cannot be found. 218 * @since 1.2 219 */ 220 public void clickItem(JList list, Pattern pattern, MouseButton button, int times) { 221 clickItem(list, new PatternTextMatcher(pattern), button, times); 222 } 223 224 private void clickItem(JList list, TextMatcher matcher, MouseButton button, int times) { 225 Pair<Integer, Point> scrollInfo = scrollToItem(list, matcher, cellReader); 226 robot.waitForIdle(); 227 verify(list, scrollInfo, matcher); 228 robot.click(list, cellCenterIn(scrollInfo), button, times); 229 } 230 231 /** 232 * Selects the items under the given indices. 233 * @param list the target <code>JList</code>. 234 * @param indices the indices of the items to select. 235 * @throws NullPointerException if the given array is <code>null</code>. 236 * @throws IllegalArgumentException if the given array is empty. 237 * @throws IllegalStateException if the <code>JList</code> is disabled. 238 * @throws IllegalStateException if the <code>JList</code> is not showing on the screen. 239 * @throws IndexOutOfBoundsException if any of the indices is negative or greater than the index of the last item in 240 * the <code>JList</code>. 241 */ 242 public void selectItems(final JList list, final int[] indices) { 243 validateArrayOfIndices(indices); 244 clearSelection(list); 245 new MultipleSelectionTemplate(robot) { 246 int elementCount() { return indices.length; } 247 void selectElement(int index) { selectItem(list, indices[index]); } 248 }.multiSelect(); 249 } 250 251 /** 252 * Clears the selection in the given <code>{@link JList}</code>. Since this method does not simulate user input, it 253 * does not verifies that the <code>JList</code> is enabled and showing. 254 * @param list the target <code>JList</code>. 255 * @since 1.2 256 */ 257 public void clearSelection(JList list) { 258 clearSelectionOf(list); 259 robot.waitForIdle(); 260 } 261 262 @RunsInEDT 263 private static void clearSelectionOf(final JList list) { 264 execute(new GuiTask() { 265 protected void executeInEDT() { 266 list.clearSelection(); 267 } 268 }); 269 } 270 271 /** 272 * Selects the items in the specified range. 273 * @param list the target <code>JList</code>. 274 * @param from the starting point of the selection. 275 * @param to the last item to select. 276 * @throws IllegalStateException if the <code>JList</code> is disabled. 277 * @throws IllegalStateException if the <code>JList</code> is not showing on the screen. 278 * @throws IndexOutOfBoundsException if the any index is negative or greater than the index of the last item in the 279 * <code>JList</code>. 280 */ 281 @RunsInEDT 282 public void selectItems(JList list, From from, To to) { 283 selectItems(list, from.value, to.value); 284 } 285 286 /** 287 * Selects the items in the specified range. 288 * @param list the target <code>JList</code>. 289 * @param start the starting point of the selection. 290 * @param end the last item to select (inclusive.) 291 * @throws IllegalStateException if the <code>JList</code> is disabled. 292 * @throws IllegalStateException if the <code>JList</code> is not showing on the screen. 293 * @throws IndexOutOfBoundsException if the any index is negative or greater than the index of the last item in the 294 * <code>JList</code>. 295 */ 296 @RunsInEDT 297 public void selectItems(JList list, int start, int end) { 298 validateIndicesAndClearSelection(list, start, end); 299 selectItem(list, start); 300 robot.pressKey(VK_SHIFT); 301 try { 302 clickItem(list, end, LEFT_BUTTON, 1); 303 } finally { 304 robot.releaseKey(VK_SHIFT); 305 } 306 } 307 308 @RunsInEDT 309 private static void validateIndicesAndClearSelection(final JList list, final int...indices) { 310 execute(new GuiTask() { 311 protected void executeInEDT() { 312 validateIndices(list, indices); 313 list.clearSelection(); 314 } 315 }); 316 } 317 318 /** 319 * Selects the item under the given index using left mouse button once. 320 * @param list the target <code>JList</code>. 321 * @param index the index of the item to click. 322 * @throws IllegalStateException if the <code>JList</code> is disabled. 323 * @throws IllegalStateException if the <code>JList</code> is not showing on the screen. 324 * @throws IndexOutOfBoundsException if the given index is negative or greater than the index of the last item in the 325 * <code>JList</code>. 326 */ 327 @RunsInEDT 328 public void selectItem(JList list, int index) { 329 Point cellCenter = scrollToItemIfNotSelectedYet(list, index); 330 robot.waitForIdle(); 331 if (cellCenter == null) return; // cell already selected 332 robot.click(list, cellCenter); 333 } 334 335 /** 336 * Clicks the item under the given index, using the specified mouse button, the given number times. 337 * @param list the target <code>JList</code>. 338 * @param index the index of the item to click. 339 * @param button the button to use. 340 * @param times the number of times to click. 341 * @throws IllegalStateException if the <code>JList</code> is disabled. 342 * @throws IllegalStateException if the <code>JList</code> is not showing on the screen. 343 * @throws IndexOutOfBoundsException if the given index is negative or greater than the index of the last item in the 344 * <code>JList</code>. 345 */ 346 @RunsInEDT 347 public void clickItem(JList list, int index, MouseButton button, int times) { 348 Point cellCenter = scrollToItem(list, index); 349 robot.waitForIdle(); 350 robot.click(list, cellCenter, button, times); 351 } 352 353 /** 354 * Verifies that the selected item in the <code>{@link JList}</code> matches the given value. 355 * @param list the target <code>JList</code>. 356 * @param value the value to match. It can be a regular expression pattern. 357 * @throws AssertionError if the selected item does not match the value. 358 * @see #cellReader(JListCellReader) 359 */ 360 @RunsInEDT 361 public void requireSelection(final JList list, String value) { 362 String selection = requiredSelection(list); 363 verifyThat(selection).as(selectedIndexProperty(list)).isEqualOrMatches(value); 364 } 365 366 /** 367 * Verifies that the selected item in the <code>{@link JList}</code> matches the given regular expression pattern. 368 * @param list the target <code>JList</code>. 369 * @param pattern the regular expression pattern to match. 370 * @throws AssertionError if the selected item does not match the given regular expression pattern. 371 * @throws NullPointerException if the given regular expression pattern is <code>null</code>. 372 * @see #cellReader(JListCellReader) 373 * @since 1.2 374 */ 375 @RunsInEDT 376 public void requireSelection(JList list, Pattern pattern) { 377 String selection = requiredSelection(list); 378 verifyThat(selection).as(selectedIndexProperty(list)).matches(pattern); 379 } 380 381 private String requiredSelection(final JList list) { 382 Object selection = singleSelectionValue(list, cellReader); 383 if (NO_SELECTION_VALUE == selection) failNoSelection(list); 384 return (String)selection; 385 } 386 387 /** 388 * Verifies that the selected index in the <code>{@link JList}</code> matches the given value. 389 * @param list the target <code>JList</code>. 390 * @param index the selection index to match. 391 * @throws AssertionError if the selected index does not match the value. 392 * @since 1.2 393 */ 394 @RunsInEDT 395 public void requireSelection(final JList list, int index) { 396 int selectedIndex = selectedIndexOf(list); 397 if (selectedIndex == -1) failNoSelection(list); 398 assertThat(selectedIndex).as(selectedIndexProperty(list)).isEqualTo(index); 399 } 400 401 /** 402 * Returns an array of <code>String</code>s that represents the selection in the given <code>{@link JList}</code>, 403 * using this driver's <code>{@link JListCellReader}</code>. 404 * @param list the target <code>JList</code>. 405 * @return an array of <code>String</code>s that represents the selection in the given <code>JList</code>. 406 * @see #cellReader(JListCellReader) 407 */ 408 @RunsInEDT 409 public String[] selectionOf(JList list) { 410 List<String> selection = selectionValues(list, cellReader); 411 return selection.toArray(new String[selection.size()]); 412 } 413 414 /** 415 * Verifies that the selected items in the <code>{@link JList}</code> match the given values. 416 * @param list the target <code>JList</code>. 417 * @param items the values to match. Each value can be a regular expression pattern. 418 * @throws NullPointerException if the given array is <code>null</code>. 419 * @throws IllegalArgumentException if the given array is empty. 420 * @throws AssertionError if the selected items do not match the given values. 421 */ 422 @RunsInEDT 423 public void requireSelectedItems(JList list, String... items) { 424 requireSelectedItems(list, new StringTextMatcher(items)); 425 } 426 427 /** 428 * Verifies that the selected items in the <code>{@link JList}</code> match the given regular expression patterns. 429 * @param list the target <code>JList</code>. 430 * @param patterns the regular expression patterns to match. 431 * @throws NullPointerException if the given array is <code>null</code>. 432 * @throws IllegalArgumentException if the given array is empty. 433 * @throws NullPointerException if any of the patterns in the array is <code>null</code>. 434 * @throws AssertionError if the selected items do not match the given values. 435 * @see #cellReader(JListCellReader) 436 * @since 1.2 437 */ 438 @RunsInEDT 439 public void requireSelectedItems(JList list, Pattern... patterns) { 440 requireSelectedItems(list, new PatternTextMatcher(patterns)); 441 } 442 443 @RunsInEDT 444 private void requireSelectedItems(JList list, TextMatcher matcher) { 445 List<String> matchingValues = matchingItemValues(list, matcher, cellReader); 446 assertThat(selectionValues(list, cellReader)).as(propertyName(list, SELECTED_INDICES_PROPERTY)).isEqualTo(matchingValues); 447 } 448 449 /** 450 * Verifies that the given item indices are selected in the <code>{@link JList}</code>. 451 * @param list the target <code>JList</code>. 452 * @param indices the expected indices of the selected items. 453 * @throws NullPointerException if the given array is <code>null</code>. 454 * @throws IllegalArgumentException if the given array is empty. 455 * @throws AssertionError if the selection in the <code>JList</code> does not match the given one. 456 */ 457 @RunsInEDT 458 public void requireSelectedItems(JList list, int... indices) { 459 validateArrayOfIndices(indices); 460 sort(indices); 461 assertThat(selectedIndices(list)).as(propertyName(list, SELECTED_INDICES_PROPERTY)).isEqualTo(indices); 462 } 463 464 private void validateArrayOfIndices(int[] indices) { 465 if (indices == null) throw new NullPointerException("The array of indices should not be null"); 466 if (isEmptyIntArray(indices)) throw new IllegalArgumentException("The array of indices should not be empty"); 467 } 468 469 /** 470 * Verifies that the <code>{@link JList}</code> does not have a selection. 471 * @param list the target <code>JList</code>. 472 * @throws AssertionError if the <code>JList</code> has a selection. 473 */ 474 @RunsInEDT 475 public void requireNoSelection(JList list) { 476 assertThat(selectedIndexOf(list)).as(selectedIndexProperty(list)).isEqualTo(-1); 477 } 478 479 @RunsInEDT 480 private void failNoSelection(JList list) { 481 fail(concat("[", selectedIndexProperty(list).value(), "] No selection")); 482 } 483 484 @RunsInEDT 485 private Description selectedIndexProperty(JList list) { 486 return propertyName(list, SELECTED_INDEX_PROPERTY); 487 } 488 489 /** 490 * Starts a drag operation at the location of the first item matching the given value. 491 * @param list the target <code>JList</code>. 492 * @param value the value to match. It can be a regular expression. 493 * @throws IllegalStateException if the <code>JList</code> is disabled. 494 * @throws IllegalStateException if the <code>JList</code> is not showing on the screen. 495 * @throws LocationUnavailableException if an element matching the given value cannot be found. 496 * @see #cellReader(JListCellReader) 497 */ 498 @RunsInEDT 499 public void drag(JList list, String value) { 500 drag(list, new StringTextMatcher(value)); 501 } 502 503 /** 504 * Starts a drag operation at the location of the first item matching the given regular expression pattern. 505 * @param list the target <code>JList</code>. 506 * @param pattern the regular expression pattern to match. 507 * @throws IllegalStateException if the <code>JList</code> is disabled. 508 * @throws IllegalStateException if the <code>JList</code> is not showing on the screen. 509 * @throws NullPointerException if the regular expression pattern is <code>null</code>. 510 * @throws LocationUnavailableException if an element matching the given regular expression pattern cannot be found. 511 * @see #cellReader(JListCellReader) 512 * @since 1.2 513 */ 514 @RunsInEDT 515 public void drag(JList list, Pattern pattern) { 516 drag(list, new PatternTextMatcher(pattern)); 517 } 518 519 private void drag(JList list, TextMatcher matcher) { 520 Pair<Integer, Point> scrollInfo = scrollToItem(list, matcher, cellReader); 521 robot.waitForIdle(); 522 verify(list, scrollInfo, matcher); 523 super.drag(list, cellCenterIn(scrollInfo)); 524 } 525 526 /** 527 * Ends a drag operation at the location of the first item matching the given value. 528 * @param list the target <code>JList</code>. 529 * @param value the value to match. It can be a regular expression. 530 * @throws IllegalStateException if the <code>JList</code> is disabled. 531 * @throws IllegalStateException if the <code>JList</code> is not showing on the screen. 532 * @throws LocationUnavailableException if an element matching the given value cannot be found. 533 * @throws ActionFailedException if there is no drag action in effect. 534 */ 535 @RunsInEDT 536 public void drop(JList list, String value) { 537 drop(list, new StringTextMatcher(value)); 538 } 539 540 /** 541 * Ends a drag operation at the location of the first item matching the given regular expression pattern. 542 * @param list the target <code>JList</code>. 543 * @param pattern the regular expression pattern to match. 544 * @throws IllegalStateException if the <code>JList</code> is disabled. 545 * @throws IllegalStateException if the <code>JList</code> is not showing on the screen. 546 * @throws NullPointerException if the given regular expression pattern is <code>null</code>. 547 * @throws LocationUnavailableException if an element matching the given value cannot be found. 548 * @throws ActionFailedException if there is no drag action in effect. 549 * @since 1.2 550 */ 551 public void drop(JList list, Pattern pattern) { 552 drop(list, new PatternTextMatcher(pattern)); 553 } 554 555 private void drop(JList list, TextMatcher matcher) { 556 Pair<Integer, Point> scrollInfo = scrollToItem(list, matcher, cellReader); 557 robot.waitForIdle(); 558 verify(list, scrollInfo, matcher); 559 super.drop(list, cellCenterIn(scrollInfo)); 560 } 561 562 private void verify(JList list, Pair<Integer, Point> scrollInfo, TextMatcher matcher) { 563 if (ITEM_NOT_FOUND.equals(scrollInfo)) throw failMatchingNotFound(list, matcher); 564 } 565 566 /** 567 * Starts a drag operation at the location of the given index. 568 * @param list the target <code>JList</code>. 569 * @param index the given index. 570 * @throws IllegalStateException if the <code>JList</code> is disabled. 571 * @throws IllegalStateException if the <code>JList</code> is not showing on the screen. 572 * @throws IndexOutOfBoundsException if the given index is negative or greater than the index of the last item in the 573 * <code>JList</code>. 574 */ 575 @RunsInEDT 576 public void drag(JList list, int index) { 577 Point cellCenter = scrollToItem(list, index); 578 robot.waitForIdle(); 579 super.drag(list, cellCenter); 580 } 581 582 /** 583 * Ends a drag operation at the location of the given index. 584 * @param list the target <code>JList</code>. 585 * @param index the given index. 586 * @throws IllegalStateException if the <code>JList</code> is disabled. 587 * @throws IllegalStateException if the <code>JList</code> is not showing on the screen. 588 * @throws IndexOutOfBoundsException if the given index is negative or greater than the index of the last item in the 589 * <code>JList</code>. 590 * @throws ActionFailedException if there is no drag action in effect. 591 */ 592 @RunsInEDT 593 public void drop(JList list, int index) { 594 Point cellCenter = scrollToItem(list, index); 595 robot.waitForIdle(); 596 super.drop(list, cellCenter); 597 } 598 599 600 /** 601 * Ends a drag operation at the center of the <code>{@link JList}</code>. 602 * @param list the target <code>JList</code>. 603 * @throws IllegalStateException if the <code>JList</code> is disabled. 604 * @throws IllegalStateException if the <code>JList</code> is not showing on the screen. 605 * @throws ActionFailedException if there is no drag action in effect. 606 */ 607 @RunsInEDT 608 public void drop(JList list) { 609 assertIsEnabledAndShowing(list); 610 super.drop(list, visibleCenterOf(list)); 611 } 612 613 /** 614 * Shows a pop-up menu at the location of the specified item in the <code>{@link JList}</code>. 615 * @param list the target <code>JList</code>. 616 * @param value the value to match. It can be a regular expression pattern. 617 * @return a fixture that manages the displayed pop-up menu. 618 * @throws IllegalStateException if the <code>JList</code> is disabled. 619 * @throws IllegalStateException if the <code>JList</code> is not showing on the screen. 620 * @throws ComponentLookupException if a pop-up menu cannot be found. 621 * @throws LocationUnavailableException if an element matching the given value cannot be found. 622 */ 623 @RunsInEDT 624 public JPopupMenu showPopupMenu(JList list, String value) { 625 return showPopupMenu(list, new StringTextMatcher(value)); 626 } 627 628 /** 629 * Shows a pop-up menu at the location of the specified item in the <code>{@link JList}</code>. 630 * @param list the target <code>JList</code>. 631 * @param pattern the regular expression pattern to match. 632 * @return a fixture that manages the displayed pop-up menu. 633 * @throws IllegalStateException if the <code>JList</code> is disabled. 634 * @throws IllegalStateException if the <code>JList</code> is not showing on the screen. 635 * @throws NullPointerException if the regular expression pattern is <code>null</code>. 636 * @throws ComponentLookupException if a pop-up menu cannot be found. 637 * @throws LocationUnavailableException if an element matching the given value cannot be found. 638 * @since 1.2 639 */ 640 @RunsInEDT 641 public JPopupMenu showPopupMenu(JList list, Pattern pattern) { 642 return showPopupMenu(list, new PatternTextMatcher(pattern)); 643 } 644 645 @RunsInEDT 646 private JPopupMenu showPopupMenu(JList list, TextMatcher matcher) { 647 Pair<Integer, Point> scrollInfo = scrollToItem(list, matcher, cellReader); 648 robot.waitForIdle(); 649 verify(list, scrollInfo, matcher); 650 return robot.showPopupMenu(list, cellCenterIn(scrollInfo)); 651 } 652 653 private Point cellCenterIn(Pair<Integer, Point> scrollInfo) { 654 return scrollInfo.ii; 655 } 656 657 /** 658 * Shows a pop-up menu at the location of the specified item in the <code>{@link JList}</code>. 659 * @param list the target <code>JList</code>. 660 * @param index the index of the item. 661 * @return a driver that manages the displayed pop-up menu. 662 * @throws IllegalStateException if the <code>JList</code> is disabled. 663 * @throws IllegalStateException if the <code>JList</code> is not showing on the screen. 664 * @throws ComponentLookupException if a pop-up menu cannot be found. 665 * @throws IndexOutOfBoundsException if the given index is negative or greater than the index of the last item in the 666 * <code>JList</code>. 667 */ 668 @RunsInEDT 669 public JPopupMenu showPopupMenu(JList list, int index) { 670 Point cellCenter = scrollToItem(list, index); 671 robot.waitForIdle(); 672 return robot.showPopupMenu(list, cellCenter); 673 } 674 675 /** 676 * Returns the coordinates of the first item matching the given value. 677 * @param list the target <code>JList</code>. 678 * @param value the value to match. 679 * @return the coordinates of the item at the given item. 680 * @throws LocationUnavailableException if an element matching the given value cannot be found. 681 */ 682 @RunsInEDT 683 public Point pointAt(JList list, String value) { 684 return centerOfMatchingItemCell(list, value, cellReader); 685 } 686 687 /** 688 * Returns the index of the first item matching the given value. 689 * @param list the target <code>JList</code> 690 * @param value the value to match. It can be a regular expression. 691 * @return the index of the first item matching the given value. 692 * @throws LocationUnavailableException if an element matching the given value cannot be found. 693 */ 694 @RunsInEDT 695 public int indexOf(JList list, String value) { 696 return indexOf(list, new StringTextMatcher(value)); 697 } 698 699 /** 700 * Returns the index of the first item matching the given regular expression pattern. 701 * @param list the target <code>JList</code>. 702 * @param pattern the regular expression pattern to match. 703 * @return the index of the first item matching the given regular expression pattern. 704 * @throws LocationUnavailableException if an element matching the given value cannot be found. 705 * @throws NullPointerException if the given regular expression pattern is <code>null</code>. 706 * @since 1.2 707 */ 708 @RunsInEDT 709 public int indexOf(JList list, Pattern pattern) { 710 return indexOf(list, new PatternTextMatcher(pattern)); 711 } 712 713 @RunsInEDT 714 private int indexOf(JList list, TextMatcher matcher) { 715 int index = itemIndex(list, matcher, cellReader); 716 if (index >= 0) return index; 717 throw failMatchingNotFound(list, matcher); 718 } 719 720 @RunsInEDT 721 private static int itemIndex(final JList list, final TextMatcher matcher, final JListCellReader cellReader) { 722 return execute(new GuiQuery<Integer>() { 723 protected Integer executeInEDT() { 724 return matchingItemIndex(list, matcher, cellReader); 725 } 726 }); 727 } 728 729 private LocationUnavailableException failMatchingNotFound(JList list, TextMatcher matcher) { 730 throw new LocationUnavailableException(concat( 731 "Unable to find item matching the ", matcher.description(), " ", matcher.formattedValues(), 732 " among the JList contents ", format(contents(list, cellReader)))); 733 } 734 735 /** 736 * Returns the <code>String</code> representation of the element under the given index, using this driver's 737 * <code>{@link JListCellReader}</code>. 738 * @param list the target <code>JList</code>. 739 * @param index the given index. 740 * @return the value of the element under the given index. 741 * @throws IndexOutOfBoundsException if the given index is negative or greater than the index of the last item in the 742 * <code>JList</code>. 743 * @see #cellReader(JListCellReader) 744 */ 745 @RunsInEDT 746 public String value(JList list, int index) { 747 return itemValue(list, index, cellReader); 748 } 749 750 /** 751 * Updates the implementation of <code>{@link JListCellReader}</code> to use when comparing internal values of a 752 * <code>{@link JList}</code> and the values expected in a test. 753 * @param newCellReader the new <code>JListCellValueReader</code> to use. 754 * @throws NullPointerException if <code>newCellReader</code> is <code>null</code>. 755 */ 756 public void cellReader(JListCellReader newCellReader) { 757 validateCellReader(newCellReader); 758 cellReader = newCellReader; 759 } 760 761 /** 762 * Verifies that number of items in the given <code>{@link JList}</code> is equal to the expected one. 763 * @param list the target <code>JList</code>. 764 * @param expected the expected number of items. 765 * @throws AssertionError if the number of items in the given <code>{@link JList}</code> is not equal to the expected 766 * one. 767 * @since 1.2 768 */ 769 @RunsInEDT 770 public void requireItemCount(JList list, int expected) { 771 int actual = itemCountIn(list); 772 assertThat(actual).as(propertyName(list, "itemCount")).isEqualTo(expected); 773 } 774 }