org.assertj.swing.driver.JListDriver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of assertj-swing Show documentation
Show all versions of assertj-swing Show documentation
Fluent interface for functional GUI testing
/*
* Created on Jan 19, 2008
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* Copyright @2008-2013 the original author or authors.
*/
package org.assertj.swing.driver;
import static java.awt.event.KeyEvent.VK_SHIFT;
import static java.util.Arrays.sort;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Fail.fail;
import static org.assertj.core.util.Preconditions.checkNotNull;
import static org.assertj.swing.awt.AWT.visibleCenterOf;
import static org.assertj.swing.core.MouseButton.LEFT_BUTTON;
import static org.assertj.swing.driver.JListContentQuery.contents;
import static org.assertj.swing.driver.JListItemCountQuery.itemCountIn;
import static org.assertj.swing.driver.JListItemPreconditions.checkIndicesInBounds;
import static org.assertj.swing.driver.JListItemValueQuery.itemValue;
import static org.assertj.swing.driver.JListMatchingItemQuery.centerOfMatchingItemCell;
import static org.assertj.swing.driver.JListMatchingItemQuery.matchingItemIndex;
import static org.assertj.swing.driver.JListMatchingItemQuery.matchingItemIndices;
import static org.assertj.swing.driver.JListMatchingItemQuery.matchingItemValues;
import static org.assertj.swing.driver.JListScrollToItemTask.ITEM_NOT_FOUND;
import static org.assertj.swing.driver.JListScrollToItemTask.scrollToItem;
import static org.assertj.swing.driver.JListScrollToItemTask.scrollToItemIfNotSelectedYet;
import static org.assertj.swing.driver.JListSelectedIndexQuery.selectedIndexOf;
import static org.assertj.swing.driver.JListSelectionIndicesQuery.selectedIndices;
import static org.assertj.swing.driver.JListSelectionValueQuery.NO_SELECTION_VALUE;
import static org.assertj.swing.driver.JListSelectionValueQuery.singleSelectionValue;
import static org.assertj.swing.driver.JListSelectionValuesQuery.selectionValues;
import static org.assertj.swing.driver.TextAssert.verifyThat;
import static org.assertj.swing.edt.GuiActionRunner.execute;
import static org.assertj.swing.util.ArrayPreconditions.checkNotNullOrEmpty;
import static org.assertj.swing.util.Arrays.format;
import java.awt.Point;
import java.util.List;
import java.util.regex.Pattern;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.swing.JList;
import javax.swing.JPopupMenu;
import org.assertj.core.description.Description;
import org.assertj.swing.annotation.RunsInEDT;
import org.assertj.swing.cell.JListCellReader;
import org.assertj.swing.core.MouseButton;
import org.assertj.swing.core.Robot;
import org.assertj.swing.edt.GuiQuery;
import org.assertj.swing.edt.GuiTask;
import org.assertj.swing.exception.ActionFailedException;
import org.assertj.swing.exception.ComponentLookupException;
import org.assertj.swing.exception.LocationUnavailableException;
import org.assertj.swing.internal.annotation.InternalApi;
import org.assertj.swing.util.Pair;
import org.assertj.swing.util.PatternTextMatcher;
import org.assertj.swing.util.Range.From;
import org.assertj.swing.util.Range.To;
import org.assertj.swing.util.StringTextMatcher;
import org.assertj.swing.util.TextMatcher;
/**
*
* Supports functional testing of {@code JList}s.
*
*
*
* Note: This class is intended for internal use only. Please use the classes in the package
* {@link org.assertj.swing.fixture} in your tests.
*
*
* @author Alex Ruiz
* @author Yvonne Wang
*/
@InternalApi
public class JListDriver extends JComponentDriver {
private static final String SELECTED_INDICES_PROPERTY = "selectedIndices";
private static final String SELECTED_INDEX_PROPERTY = "selectedIndex";
private JListCellReader cellReader;
/**
* Creates a new {@link JListDriver}.
*
* @param robot the robot to use to simulate user input.
*/
public JListDriver(@Nonnull Robot robot) {
super(robot);
replaceCellReader(new BasicJListCellReader());
}
/**
* Returns an array of {@code String}s that represents the contents of the given {@code JList}.
*
* @param list the target {@code JList}.
* @return an array of {@code String}s that represents the contents of the given {@code JList}.
* @see #replaceCellReader(JListCellReader)
*/
@RunsInEDT
public @Nonnull String[] contentsOf(@Nonnull JList list) {
return contents(list, cellReader());
}
/**
* Selects the items matching the given values.
*
* @param list the target {@code JList}.
* @param values the values to match. Each {@code String} can be a regular expression.
* @throws NullPointerException if the given array is {@code null}.
* @throws IllegalArgumentException if the given array is empty.
* @throws IllegalStateException if the {@code JList} is disabled.
* @throws IllegalStateException if the {@code JList} is not showing on the screen.
* @throws LocationUnavailableException if an element matching the any of the given values cannot be found.
*/
@RunsInEDT
public void selectItems(@Nonnull JList list, @Nonnull String[] values) {
selectItems(list, new StringTextMatcher(values));
}
/**
* Selects the items matching the given regular expression patterns.
*
* @param list the target {@code JList}.
* @param patterns the regular expression patterns to match.
* @throws NullPointerException if the given array is {@code null}.
* @throws NullPointerException if any of the regular expression patterns is {@code null}.
* @throws IllegalArgumentException if the given array is empty.
* @throws IllegalStateException if the {@code JList} is disabled.
* @throws IllegalStateException if the {@code JList} is not showing on the screen.
* @throws LocationUnavailableException if an element matching the any of the given regular expression patterns cannot
* be found.
*/
@RunsInEDT
public void selectItems(@Nonnull JList list, @Nonnull Pattern[] patterns) {
selectItems(list, new PatternTextMatcher(patterns));
}
@RunsInEDT
private void selectItems(final @Nonnull JList list, final @Nonnull TextMatcher matcher) {
final List indices = matchingItemIndices(list, matcher, cellReader());
if (indices.isEmpty()) {
throw failMatchingNotFound(list, matcher);
}
clearSelection(list);
new MultipleSelectionTemplate(robot) {
@Override
int elementCount() {
return indices.size();
}
@Override
void selectElement(int index) {
selectItem(list, indices.get(index));
}
}.multiSelect();
}
/**
* Selects the item in the given {@code JList} whose value matches the given one.
*
* @param list the target {@code JList}.
* @param value the value to match.
* @throws IllegalStateException if the {@code JList} is disabled.
* @throws IllegalStateException if the {@code JList} is not showing on the screen.
* @throws LocationUnavailableException if an element matching the given value cannot be found.
*/
@RunsInEDT
public void selectItem(@Nonnull JList list, @Nullable String value) {
selectItem(list, new StringTextMatcher(value));
}
/**
* Selects the item in the given {@code JList} whose value matches the given regular expression pattern.
*
* @param list the target {@code JList}.
* @param pattern the regular expression to match.
* @throws IllegalStateException if the {@code JList} is disabled.
* @throws IllegalStateException if the {@code JList} is not showing on the screen.
* @throws LocationUnavailableException if an element matching the given value cannot be found.
* @throws NullPointerException if the given regular expression pattern is {@code null}.
*/
@RunsInEDT
public void selectItem(@Nonnull JList list, @Nonnull Pattern pattern) {
selectItem(list, new PatternTextMatcher(pattern));
}
@RunsInEDT
private void selectItem(@Nonnull JList list, @Nonnull TextMatcher matcher) {
Pair scrollInfo = scrollToItemIfNotSelectedYet(list, matcher, cellReader());
robot.waitForIdle();
checkItemFound(list, scrollInfo, matcher);
if (scrollInfo.second == null) {
return; // already selected cell.
}
robot.click(list, cellCenterIn(scrollInfo));
}
/**
* Clicks the first item matching the given value, using the specified mouse button, the given number times.
*
* @param list the target {@code JList}.
* @param value the value to match.
* @param button the button to use.
* @param times the number of times to click.
* @throws IllegalStateException if the {@code JList} is disabled.
* @throws IllegalStateException if the {@code JList} is not showing on the screen.
* @throws LocationUnavailableException if an element matching the given value cannot be found.
*/
public void clickItem(@Nonnull JList list, @Nullable String value, @Nonnull MouseButton button, int times) {
clickItem(list, new StringTextMatcher(value), button, times);
}
/**
* Clicks the first item matching the given regular expression pattern, using the specified mouse button, the given
* number times.
*
* @param list the target {@code JList}.
* @param pattern the regular expression pattern to match.
* @param button the button to use.
* @param times the number of times to click.
* @throws IllegalStateException if the {@code JList} is disabled.
* @throws IllegalStateException if the {@code JList} is not showing on the screen.
* @throws NullPointerException if the given regular expression pattern is {@code null}.
* @throws LocationUnavailableException if an element matching the given regular expression pattern cannot be found.
*/
public void clickItem(@Nonnull JList list, @Nonnull Pattern pattern, @Nonnull MouseButton button, int times) {
clickItem(list, new PatternTextMatcher(pattern), button, times);
}
private void clickItem(@Nonnull JList list, @Nonnull TextMatcher matcher, @Nonnull MouseButton button, int times) {
Pair scrollInfo = scrollToItem(list, matcher, cellReader());
robot.waitForIdle();
checkItemFound(list, scrollInfo, matcher);
robot.click(list, cellCenterIn(scrollInfo), button, times);
}
/**
* Selects the items under the given indices.
*
* @param list the target {@code JList}.
* @param indices the indices of the items to select.
* @throws NullPointerException if the given array is {@code null}.
* @throws IllegalArgumentException if the given array is empty.
* @throws IllegalStateException if the {@code JList} is disabled.
* @throws IllegalStateException if the {@code JList} is not showing on the screen.
* @throws IndexOutOfBoundsException if any of the indices is negative or greater than the index of the last item in
* the {@code JList}.
*/
public void selectItems(final @Nonnull JList list, final @Nonnull int[] indices) {
checkNotNullOrEmpty(indices);
clearSelection(list);
new MultipleSelectionTemplate(robot) {
@Override
int elementCount() {
return indices.length;
}
@Override
void selectElement(int index) {
selectItem(list, indices[index]);
}
}.multiSelect();
}
/**
* Clears the selection in the given {@code JList}. Since this method does not simulate user input, it does not
* verifies that the {@code JList} is enabled and showing.
*
* @param list the target {@code JList}.
*/
public void clearSelection(@Nonnull JList list) {
clearSelectionOf(list);
robot.waitForIdle();
}
@RunsInEDT
private static void clearSelectionOf(final @Nonnull JList list) {
execute(new GuiTask() {
@Override
protected void executeInEDT() {
list.clearSelection();
}
});
}
/**
* Selects the items in the specified range.
*
* @param list the target {@code JList}.
* @param from the starting point of the selection.
* @param to the last item to select.
* @throws IllegalStateException if the {@code JList} is disabled.
* @throws IllegalStateException if the {@code JList} is not showing on the screen.
* @throws IndexOutOfBoundsException if the any index is negative or greater than the index of the last item in the
* {@code JList}.
*/
@RunsInEDT
public void selectItems(@Nonnull JList list, @Nonnull From from, @Nonnull To to) {
selectItems(list, from.value, to.value);
}
/**
* Selects the items in the specified range.
*
* @param list the target {@code JList}.
* @param start the starting point of the selection.
* @param end the last item to select (inclusive.)
* @throws IllegalStateException if the {@code JList} is disabled.
* @throws IllegalStateException if the {@code JList} is not showing on the screen.
* @throws IndexOutOfBoundsException if the any index is negative or greater than the index of the last item in the
* {@code JList}.
*/
@RunsInEDT
public void selectItems(@Nonnull JList list, int start, int end) {
validateIndicesAndClearSelection(list, start, end);
selectItem(list, start);
robot.pressKey(VK_SHIFT);
try {
clickItem(list, end, LEFT_BUTTON, 1);
} finally {
robot.releaseKey(VK_SHIFT);
}
}
@RunsInEDT
private static void validateIndicesAndClearSelection(final @Nonnull JList list, final @Nonnull int... indices) {
execute(new GuiTask() {
@Override
protected void executeInEDT() {
checkIndicesInBounds(list, indices);
list.clearSelection();
}
});
}
/**
* Selects the item under the given index using left mouse button once.
*
* @param list the target {@code JList}.
* @param index the index of the item to click.
* @throws IllegalStateException if the {@code JList} is disabled.
* @throws IllegalStateException if the {@code JList} is not showing on the screen.
* @throws IndexOutOfBoundsException if the given index is negative or greater than the index of the last item in the
* {@code JList}.
*/
@RunsInEDT
public void selectItem(@Nonnull JList list, int index) {
Point cellCenter = scrollToItemIfNotSelectedYet(list, index);
robot.waitForIdle();
if (cellCenter == null) {
return; // cell already selected
}
robot.click(list, cellCenter);
}
/**
* Clicks the item under the given index, using the specified mouse button, the given number times.
*
* @param list the target {@code JList}.
* @param index the index of the item to click.
* @param button the button to use.
* @param times the number of times to click.
* @throws IllegalStateException if the {@code JList} is disabled.
* @throws IllegalStateException if the {@code JList} is not showing on the screen.
* @throws IndexOutOfBoundsException if the given index is negative or greater than the index of the last item in the
* {@code JList}.
*/
@RunsInEDT
public void clickItem(@Nonnull JList list, int index, @Nonnull MouseButton button, int times) {
Point cellCenter = scrollToItem(list, index);
robot.waitForIdle();
robot.click(list, cellCenter, button, times);
}
/**
* Verifies that the selected item in the {@code JList} matches the given value.
*
* @param list the target {@code JList}.
* @param value the value to match. It can be a regular expression pattern.
* @throws AssertionError if the selected item does not match the value.
* @see #replaceCellReader(JListCellReader)
*/
@RunsInEDT
public void requireSelection(final @Nonnull JList list, @Nullable String value) {
String selection = requiredSelection(list);
verifyThat(selection).as(selectedIndexProperty(list)).isEqualOrMatches(value);
}
/**
* Verifies that the selected item in the {@code JList} matches the given regular expression pattern.
*
* @param list the target {@code JList}.
* @param pattern the regular expression pattern to match.
* @throws AssertionError if the selected item does not match the given regular expression pattern.
* @throws NullPointerException if the given regular expression pattern is {@code null}.
* @see #replaceCellReader(JListCellReader)
*/
@RunsInEDT
public void requireSelection(@Nonnull JList list, @Nonnull Pattern pattern) {
String selection = requiredSelection(list);
verifyThat(selection).as(selectedIndexProperty(list)).matches(pattern);
}
private @Nullable String requiredSelection(final @Nonnull JList list) {
Object selection = singleSelectionValue(list, cellReader());
if (NO_SELECTION_VALUE == selection) {
failNoSelection(list);
}
return (String) selection;
}
/**
* Verifies that the selected index in the {@code JList} matches the given value.
*
* @param list the target {@code JList}.
* @param index the selection index to match.
* @throws AssertionError if the selected index does not match the value.
*/
@RunsInEDT
public void requireSelection(final @Nonnull JList list, int index) {
int selectedIndex = selectedIndexOf(list);
if (selectedIndex == -1) {
failNoSelection(list);
}
assertThat(selectedIndex).as(selectedIndexProperty(list)).isEqualTo(index);
}
/**
* Returns an array of {@code String}s that represents the selection in the given {@code JList}, using this driver's
* {@link JListCellReader}.
*
* @param list the target {@code JList}.
* @return an array of {@code String}s that represents the selection in the given {@code JList}.
* @see #replaceCellReader(JListCellReader)
*/
@RunsInEDT
public @Nonnull String[] selectionOf(@Nonnull JList list) {
List selection = selectionValues(list, cellReader());
return selection.toArray(new String[selection.size()]);
}
/**
* Verifies that the selected items in the {@code JList} match the given values.
*
* @param list the target {@code JList}.
* @param items the values to match. Each value can be a regular expression pattern.
* @throws NullPointerException if the given array is {@code null}.
* @throws IllegalArgumentException if the given array is empty.
* @throws AssertionError if the selected items do not match the given values.
*/
@RunsInEDT
public void requireSelectedItems(@Nonnull JList list, @Nonnull String... items) {
requireSelectedItems(list, new StringTextMatcher(items));
}
/**
* Verifies that the selected items in the {@code JList} match the given regular expression patterns.
*
* @param list the target {@code JList}.
* @param patterns the regular expression patterns to match.
* @throws NullPointerException if the given array is {@code null}.
* @throws IllegalArgumentException if the given array is empty.
* @throws NullPointerException if any of the patterns in the array is {@code null}.
* @throws AssertionError if the selected items do not match the given values.
* @see #replaceCellReader(JListCellReader)
*/
@RunsInEDT
public void requireSelectedItems(@Nonnull JList list, @Nonnull Pattern... patterns) {
requireSelectedItems(list, new PatternTextMatcher(patterns));
}
@RunsInEDT
private void requireSelectedItems(@Nonnull JList list, @Nonnull TextMatcher matcher) {
List matchingValues = matchingItemValues(list, matcher, cellReader());
assertThat(selectionValues(list, cellReader())).as(propertyName(list, SELECTED_INDICES_PROPERTY)).isEqualTo(
matchingValues);
}
/**
* Verifies that the given item indices are selected in the {@code JList}.
*
* @param list the target {@code JList}.
* @param indices the expected indices of the selected items.
* @throws NullPointerException if the given array is {@code null}.
* @throws IllegalArgumentException if the given array is empty.
* @throws AssertionError if the selection in the {@code JList} does not match the given one.
*/
@RunsInEDT
public void requireSelectedItems(@Nonnull JList list, @Nonnull int... indices) {
checkNotNullOrEmpty(indices);
sort(indices);
assertThat(selectedIndices(list)).as(propertyName(list, SELECTED_INDICES_PROPERTY)).isEqualTo(indices);
}
/**
* Verifies that the {@code JList} does not have a selection.
*
* @param list the target {@code JList}.
* @throws AssertionError if the {@code JList} has a selection.
*/
@RunsInEDT
public void requireNoSelection(@Nonnull JList list) {
assertThat(selectedIndexOf(list)).as(selectedIndexProperty(list)).isEqualTo(-1);
}
@RunsInEDT
private void failNoSelection(@Nonnull JList list) {
fail(String.format("[%s] No selection", selectedIndexProperty(list).value()));
}
@RunsInEDT
private Description selectedIndexProperty(@Nonnull JList list) {
return propertyName(list, SELECTED_INDEX_PROPERTY);
}
/**
* Starts a drag operation at the location of the first item matching the given value.
*
* @param list the target {@code JList}.
* @param value the value to match. It can be a regular expression.
* @throws IllegalStateException if the {@code JList} is disabled.
* @throws IllegalStateException if the {@code JList} is not showing on the screen.
* @throws LocationUnavailableException if an element matching the given value cannot be found.
* @see #replaceCellReader(JListCellReader)
*/
@RunsInEDT
public void drag(@Nonnull JList list, @Nullable String value) {
drag(list, new StringTextMatcher(value));
}
/**
* Starts a drag operation at the location of the first item matching the given regular expression pattern.
*
* @param list the target {@code JList}.
* @param pattern the regular expression pattern to match.
* @throws IllegalStateException if the {@code JList} is disabled.
* @throws IllegalStateException if the {@code JList} is not showing on the screen.
* @throws NullPointerException if the regular expression pattern is {@code null}.
* @throws LocationUnavailableException if an element matching the given regular expression pattern cannot be found.
* @see #replaceCellReader(JListCellReader)
*/
@RunsInEDT
public void drag(@Nonnull JList list, @Nonnull Pattern pattern) {
drag(list, new PatternTextMatcher(pattern));
}
private void drag(@Nonnull JList list, @Nonnull TextMatcher matcher) {
Pair scrollInfo = scrollToItem(list, matcher, cellReader());
robot.waitForIdle();
checkItemFound(list, scrollInfo, matcher);
super.drag(list, cellCenterIn(scrollInfo));
}
/**
* Ends a drag operation at the location of the first item matching the given value.
*
* @param list the target {@code JList}.
* @param value the value to match. It can be a regular expression.
* @throws IllegalStateException if the {@code JList} is disabled.
* @throws IllegalStateException if the {@code JList} is not showing on the screen.
* @throws LocationUnavailableException if an element matching the given value cannot be found.
* @throws ActionFailedException if there is no drag action in effect.
*/
@RunsInEDT
public void drop(@Nonnull JList list, @Nullable String value) {
drop(list, new StringTextMatcher(value));
}
/**
* Ends a drag operation at the location of the first item matching the given regular expression pattern.
*
* @param list the target {@code JList}.
* @param pattern the regular expression pattern to match.
* @throws IllegalStateException if the {@code JList} is disabled.
* @throws IllegalStateException if the {@code JList} is not showing on the screen.
* @throws NullPointerException if the given regular expression pattern is {@code null}.
* @throws LocationUnavailableException if an element matching the given value cannot be found.
* @throws ActionFailedException if there is no drag action in effect.
*/
public void drop(@Nonnull JList list, @Nonnull Pattern pattern) {
drop(list, new PatternTextMatcher(pattern));
}
private void drop(@Nonnull JList list, @Nonnull TextMatcher matcher) {
Pair scrollInfo = scrollToItem(list, matcher, cellReader());
robot.waitForIdle();
checkItemFound(list, scrollInfo, matcher);
super.drop(list, cellCenterIn(scrollInfo));
}
private void checkItemFound(@Nonnull JList list, @Nonnull Pair scrollInfo,
@Nonnull TextMatcher matcher) {
if (ITEM_NOT_FOUND == scrollInfo) {
throw failMatchingNotFound(list, matcher);
}
}
/**
* Starts a drag operation at the location of the given index.
*
* @param list the target {@code JList}.
* @param index the given index.
* @throws IllegalStateException if the {@code JList} is disabled.
* @throws IllegalStateException if the {@code JList} is not showing on the screen.
* @throws IndexOutOfBoundsException if the given index is negative or greater than the index of the last item in the
* {@code JList}.
*/
@RunsInEDT
public void drag(@Nonnull JList list, int index) {
Point cellCenter = scrollToItem(list, index);
robot.waitForIdle();
super.drag(list, cellCenter);
}
/**
* Ends a drag operation at the location of the given index.
*
* @param list the target {@code JList}.
* @param index the given index.
* @throws IllegalStateException if the {@code JList} is disabled.
* @throws IllegalStateException if the {@code JList} is not showing on the screen.
* @throws IndexOutOfBoundsException if the given index is negative or greater than the index of the last item in the
* {@code JList}.
* @throws ActionFailedException if there is no drag action in effect.
*/
@RunsInEDT
public void drop(@Nonnull JList list, int index) {
Point cellCenter = scrollToItem(list, index);
robot.waitForIdle();
super.drop(list, cellCenter);
}
/**
* Ends a drag operation at the center of the {@code JList}.
*
* @param list the target {@code JList}.
* @throws IllegalStateException if the {@code JList} is disabled.
* @throws IllegalStateException if the {@code JList} is not showing on the screen.
* @throws ActionFailedException if there is no drag action in effect.
*/
@RunsInEDT
public void drop(@Nonnull JList list) {
checkInEdtEnabledAndShowing(list);
super.drop(list, visibleCenterOf(list));
}
/**
* Shows a pop-up menu at the location of the specified item in the {@code JList}.
*
* @param list the target {@code JList}.
* @param value the value to match. It can be a regular expression pattern.
* @return a fixture that manages the displayed pop-up menu.
* @throws IllegalStateException if the {@code JList} is disabled.
* @throws IllegalStateException if the {@code JList} is not showing on the screen.
* @throws ComponentLookupException if a pop-up menu cannot be found.
* @throws LocationUnavailableException if an element matching the given value cannot be found.
*/
@RunsInEDT
public JPopupMenu showPopupMenu(@Nonnull JList list, @Nullable String value) {
return showPopupMenu(list, new StringTextMatcher(value));
}
/**
* Shows a pop-up menu at the location of the specified item in the {@code JList}.
*
* @param list the target {@code JList}.
* @param pattern the regular expression pattern to match.
* @return a fixture that manages the displayed pop-up menu.
* @throws IllegalStateException if the {@code JList} is disabled.
* @throws IllegalStateException if the {@code JList} is not showing on the screen.
* @throws NullPointerException if the regular expression pattern is {@code null}.
* @throws ComponentLookupException if a pop-up menu cannot be found.
* @throws LocationUnavailableException if an element matching the given value cannot be found.
*/
@RunsInEDT
public JPopupMenu showPopupMenu(@Nonnull JList list, @Nonnull Pattern pattern) {
return showPopupMenu(list, new PatternTextMatcher(pattern));
}
@RunsInEDT
private @Nonnull JPopupMenu showPopupMenu(@Nonnull JList list, @Nonnull TextMatcher matcher) {
Pair scrollInfo = scrollToItem(list, matcher, cellReader());
robot.waitForIdle();
checkItemFound(list, scrollInfo, matcher);
return robot.showPopupMenu(list, cellCenterIn(scrollInfo));
}
private @Nonnull Point cellCenterIn(@Nonnull Pair scrollInfo) {
return checkNotNull(scrollInfo.second);
}
/**
* Shows a pop-up menu at the location of the specified item in the {@code JList}.
*
* @param list the target {@code JList}.
* @param index the index of the item.
* @return a driver that manages the displayed pop-up menu.
* @throws IllegalStateException if the {@code JList} is disabled.
* @throws IllegalStateException if the {@code JList} is not showing on the screen.
* @throws ComponentLookupException if a pop-up menu cannot be found.
* @throws IndexOutOfBoundsException if the given index is negative or greater than the index of the last item in the
* {@code JList}.
*/
@RunsInEDT
public @Nonnull JPopupMenu showPopupMenu(@Nonnull JList list, int index) {
Point cellCenter = scrollToItem(list, index);
robot.waitForIdle();
return robot.showPopupMenu(list, cellCenter);
}
/**
* Returns the coordinates of the first item matching the given value.
*
* @param list the target {@code JList}.
* @param value the value to match.
* @return the coordinates of the item at the given item.
* @throws LocationUnavailableException if an element matching the given value cannot be found.
*/
@RunsInEDT
public @Nonnull Point pointAt(@Nonnull JList list, @Nullable String value) {
return centerOfMatchingItemCell(list, value, cellReader());
}
/**
* Returns the index of the first item matching the given value.
*
* @param list the target {@code JList}
* @param value the value to match. It can be a regular expression.
* @return the index of the first item matching the given value.
* @throws LocationUnavailableException if an element matching the given value cannot be found.
*/
@RunsInEDT
public int indexOf(@Nonnull JList list, @Nullable String value) {
return indexOf(list, new StringTextMatcher(value));
}
/**
* Returns the index of the first item matching the given regular expression pattern.
*
* @param list the target {@code JList}.
* @param pattern the regular expression pattern to match.
* @return the index of the first item matching the given regular expression pattern.
* @throws LocationUnavailableException if an element matching the given value cannot be found.
* @throws NullPointerException if the given regular expression pattern is {@code null}.
*/
@RunsInEDT
public int indexOf(@Nonnull JList list, @Nonnull Pattern pattern) {
return indexOf(list, new PatternTextMatcher(pattern));
}
@RunsInEDT
private int indexOf(@Nonnull JList list, @Nonnull TextMatcher matcher) {
int index = itemIndex(list, matcher, cellReader());
if (index >= 0) {
return index;
}
throw failMatchingNotFound(list, matcher);
}
@RunsInEDT
private static int itemIndex(final @Nonnull JList list, final @Nonnull TextMatcher matcher,
final @Nonnull JListCellReader cellReader) {
Integer result = execute(new GuiQuery() {
@Override
protected Integer executeInEDT() {
return matchingItemIndex(list, matcher, cellReader);
}
});
return checkNotNull(result);
}
private @Nonnull LocationUnavailableException failMatchingNotFound(@Nonnull JList list, @Nonnull TextMatcher matcher) {
String format = "Unable to find item matching the %s %s among the JList contents %s";
String msg = String.format(format, matcher.description(), matcher.formattedValues(),
format(contents(list, cellReader())));
return new LocationUnavailableException(msg);
}
/**
* Returns the {@code String} representation of the element under the given index, using this driver's
* {@link JListCellReader}.
*
* @param list the target {@code JList}.
* @param index the given index.
* @return the value of the element under the given index.
* @throws IndexOutOfBoundsException if the given index is negative or greater than the index of the last item in the
* {@code JList}.
* @see #replaceCellReader(JListCellReader)
*/
@RunsInEDT
public @Nullable String value(@Nonnull JList list, int index) {
return itemValue(list, index, cellReader());
}
/**
* Updates the implementation of {@link JListCellReader} to use when comparing internal values of a {@code JList} and
* the values expected in a test.
*
* @param newCellReader the new {@code JListCellValueReader} to use.
* @throws NullPointerException if {@code newCellReader} is {@code null}.
*/
public void replaceCellReader(@Nonnull JListCellReader newCellReader) {
cellReader = checkNotNull(newCellReader);
}
/**
* Verifies that number of items in the given {@code JList} is equal to the expected one.
*
* @param list the target {@code JList}.
* @param expected the expected number of items.
* @throws AssertionError if the number of items in the given {@code JList} is not equal to the expected one.
*/
@RunsInEDT
public void requireItemCount(@Nonnull JList list, int expected) {
int actual = itemCountIn(list);
assertThat(actual).as(propertyName(list, "itemCount")).isEqualTo(expected);
}
private @Nonnull JListCellReader cellReader() {
return cellReader;
}
}