001 /*
002 * Created on Jan 27, 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 org.fest.assertions.Assertions.assertThat;
019 import static org.fest.swing.driver.ComponentStateValidator.validateIsEnabledAndShowing;
020 import static org.fest.swing.driver.JTabbedPaneSelectTabTask.setSelectedTab;
021 import static org.fest.swing.driver.JTabbedPaneTabTitlesQuery.tabTitlesOf;
022 import static org.fest.swing.driver.TextAssert.verifyThat;
023 import static org.fest.swing.edt.GuiActionRunner.execute;
024
025 import java.awt.Component;
026 import java.awt.Point;
027 import java.util.ArrayList;
028 import java.util.List;
029 import java.util.regex.Pattern;
030
031 import javax.swing.JTabbedPane;
032
033 import org.fest.assertions.Description;
034 import org.fest.swing.annotation.RunsInEDT;
035 import org.fest.swing.core.Robot;
036 import org.fest.swing.data.Index;
037 import org.fest.swing.edt.GuiQuery;
038 import org.fest.swing.exception.ActionFailedException;
039 import org.fest.swing.exception.LocationUnavailableException;
040 import org.fest.swing.util.*;
041 import org.fest.util.VisibleForTesting;
042
043 /**
044 * Understands functional testing of <code>{@link JTabbedPane}</code>s:
045 * <ul>
046 * <li>user input simulation</li>
047 * <li>state verification</li>
048 * <li>property value query</li>
049 * </ul>
050 * This class is intended for internal use only. Please use the classes in the package
051 * <code>{@link org.fest.swing.fixture}</code> in your tests.
052 *
053 * @author Alex Ruiz
054 * @author Yvonne Wang
055 */
056 public class JTabbedPaneDriver extends JComponentDriver {
057
058 private final JTabbedPaneLocation location;
059
060 /**
061 * Creates a new </code>{@link JTabbedPaneDriver}</code>.
062 * @param robot the robot to use to simulate user input.
063 */
064 public JTabbedPaneDriver(Robot robot) {
065 this(robot, new JTabbedPaneLocation());
066 }
067
068 /**
069 * Creates a new </code>{@link JTabbedPaneDriver}</code>.
070 * @param robot the robot to use to simulate user input.
071 * @param location knows how to find the location of a tab.
072 */
073 @VisibleForTesting
074 JTabbedPaneDriver(Robot robot, JTabbedPaneLocation location) {
075 super(robot);
076 this.location = location;
077 }
078
079 /**
080 * Returns the titles of all the tabs.
081 * @param tabbedPane the target <code>JTabbedPane</code>.
082 * @return the titles of all the tabs.
083 */
084 @RunsInEDT
085 public String[] tabTitles(JTabbedPane tabbedPane) {
086 return tabTitlesOf(tabbedPane);
087 }
088
089 /**
090 * Simulates a user selecting the tab containing the given title.
091 * @param tabbedPane the target <code>JTabbedPane</code>.
092 * @param title the given text to match. It can be a regular expression.
093 * @throws IllegalStateException if the <code>JTabbedPane</code> is disabled.
094 * @throws IllegalStateException if the <code>JTabbedPane</code> is not showing on the screen.
095 * @throws LocationUnavailableException if a tab matching the given title could not be found.
096 */
097 @RunsInEDT
098 public void selectTab(JTabbedPane tabbedPane, String title) {
099 selectTab(tabbedPane, new StringTextMatcher(title));
100 }
101
102
103 /**
104 * Simulates a user selecting the tab whose title matches the given regular expression pattern.
105 * @param tabbedPane the target <code>JTabbedPane</code>.
106 * @param pattern the regular expression pattern to match.
107 * @throws IllegalStateException if the <code>JTabbedPane</code> is disabled.
108 * @throws IllegalStateException if the <code>JTabbedPane</code> is not showing on the screen.
109 * @throws NullPointerException if the given regular expression pattern is <code>null</code>.
110 * @throws LocationUnavailableException if a tab matching the given regular expression pattern could not be found.
111 * @since 1.2
112 */
113 @RunsInEDT
114 public void selectTab(JTabbedPane tabbedPane, Pattern pattern) {
115 selectTab(tabbedPane, new PatternTextMatcher(pattern));
116 }
117
118 @RunsInEDT
119 private void selectTab(JTabbedPane tabbedPane, TextMatcher matcher) {
120 Pair<Integer, Point> tabToSelectInfo = tabToSelectInfo(location, tabbedPane, matcher);
121 Point target = tabToSelectInfo.ii;
122 if (target != null) {
123 click(tabbedPane, target);
124 return;
125 }
126 setTabDirectly(tabbedPane, tabToSelectInfo.i);
127 }
128
129 @RunsInEDT
130 private static Pair<Integer, Point> tabToSelectInfo(final JTabbedPaneLocation location,
131 final JTabbedPane tabbedPane, final TextMatcher matcher) {
132 return execute(new GuiQuery<Pair<Integer, Point>>() {
133 protected Pair<Integer, Point> executeInEDT() {
134 validateIsEnabledAndShowing(tabbedPane);
135 int index = location.indexOf(tabbedPane, matcher);
136 location.validateIndex(tabbedPane, index);
137 Point point = null;
138 try {
139 point = location.pointAt(tabbedPane, index);
140 } catch (LocationUnavailableException e) {}
141 return new Pair<Integer, Point>(index, point);
142 }
143 });
144 }
145
146 /**
147 * Simulates a user selecting the tab located at the given index.
148 * @param tabbedPane the target <code>JTabbedPane</code>.
149 * @param index the index of the tab to select.
150 * @throws IllegalStateException if the <code>JTabbedPane</code> is disabled.
151 * @throws IllegalStateException if the <code>JTabbedPane</code> is not showing on the screen.
152 * @throws IndexOutOfBoundsException if the given index is not within the <code>JTabbedPane</code> bounds.
153 */
154 public void selectTab(JTabbedPane tabbedPane, int index) {
155 try {
156 Point p = validateAndGetPoint(location, tabbedPane, index);
157 click(tabbedPane, p);
158 } catch (LocationUnavailableException e) {
159 setTabDirectly(tabbedPane, index);
160 } catch (ActionFailedException e) {
161 setTabDirectly(tabbedPane, index);
162 }
163 }
164
165 @RunsInEDT
166 private static Point validateAndGetPoint(final JTabbedPaneLocation location, final JTabbedPane tabbedPane, final int index) {
167 return execute(new GuiQuery<Point>() {
168 protected Point executeInEDT() {
169 location.validateIndex(tabbedPane, index);
170 validateIsEnabledAndShowing(tabbedPane);
171 return location.pointAt(tabbedPane, index);
172 }
173 });
174 }
175
176 @VisibleForTesting
177 @RunsInEDT
178 void setTabDirectly(JTabbedPane tabbedPane, int index) {
179 setSelectedTab(tabbedPane, index);
180 robot.waitForIdle();
181 moveMouseToTab(tabbedPane, index);
182 }
183
184 private void moveMouseToTab(JTabbedPane tabbedPane, int index) {
185 try {
186 Point p = pointAtTab(location, tabbedPane, index);
187 robot.moveMouse(tabbedPane, p);
188 robot.waitForIdle();
189 } catch (LocationUnavailableException ignored) {}
190 }
191
192 @RunsInEDT
193 private static Point pointAtTab(final JTabbedPaneLocation location, final JTabbedPane tabbedPane, final int index) {
194 return execute(new GuiQuery<Point>() {
195 protected Point executeInEDT() {
196 return location.pointAt(tabbedPane, index);
197 }
198 });
199 }
200
201 /**
202 * Returns the currently selected component for the given <code>{@link JTabbedPane}</code>.
203 * @param tabbedPane the target <code>JTabbedPane</code>.
204 * @return the currently selected component for the given <code>JTabbedPane</code>.
205 */
206 @RunsInEDT
207 public Component selectedComponentOf(JTabbedPane tabbedPane) {
208 return selectedComponent(tabbedPane);
209 }
210
211 @RunsInEDT
212 private static Component selectedComponent(final JTabbedPane tabbedPane) {
213 return execute(new GuiQuery<Component>() {
214 protected Component executeInEDT() {
215 return tabbedPane.getSelectedComponent();
216 }
217 });
218 }
219
220 /**
221 * Asserts that the title of the tab at the given index matches the given value.
222 * @param tabbedPane the target <code>JTabbedPane</code>.
223 * @param title the expected title. It can be a regular expression.
224 * @param index the index of the tab.
225 * @throws IndexOutOfBoundsException if the given index is not within the <code>JTabbedPane</code> bounds.
226 * @throws AssertionError if the title of the tab at the given index does not match the given one.
227 */
228 @RunsInEDT
229 public void requireTabTitle(JTabbedPane tabbedPane, String title, Index index) {
230 String actualTitle = titleAt(tabbedPane, index);
231 verifyThat(actualTitle).as(titleAtProperty(tabbedPane)).isEqualOrMatches(title);
232 }
233
234 /**
235 * Asserts that the title of the tab at the given index matches the given regular expression pattern.
236 * @param tabbedPane the target <code>JTabbedPane</code>.
237 * @param pattern the regular expression pattern to match.
238 * @param index the index of the tab.
239 * @throws NullPointerException if the given regular expression pattern is <code>null</code>.
240 * @throws IndexOutOfBoundsException if the given index is not within the <code>JTabbedPane</code> bounds.
241 * @throws AssertionError if the title of the tab at the given index does not match the given one.
242 * @since 1.2
243 */
244 @RunsInEDT
245 public void requireTabTitle(JTabbedPane tabbedPane, Pattern pattern, Index index) {
246 String actualTitle = titleAt(tabbedPane, index);
247 verifyThat(actualTitle).as(titleAtProperty(tabbedPane)).matches(pattern);
248 }
249
250 @RunsInEDT
251 private Description titleAtProperty(JTabbedPane tabbedPane) {
252 return propertyName(tabbedPane, "titleAt");
253 }
254
255 @RunsInEDT
256 private static String titleAt(final JTabbedPane tabbedPane, final Index index) {
257 return execute(new GuiQuery<String>() {
258 protected String executeInEDT() {
259 return tabbedPane.getTitleAt(index.value);
260 }
261 });
262 }
263
264 /**
265 * Asserts that the tabs of the given <code>{@link JTabbedPane}</code> have the given titles. The tab titles are
266 * evaluated by index order, for example, the first tab is expected to have the first title in the given array, and so
267 * on.
268 * @param tabbedPane the target <code>JTabbedPane</code>.
269 * @param titles the expected titles.
270 * @throws AssertionError if the title of any of the tabs is not equal to the expected titles.
271 */
272 @RunsInEDT
273 public void requireTabTitles(JTabbedPane tabbedPane, String[] titles) {
274 String[] actualTitles = allTabTitlesIn(tabbedPane);
275 assertThat(actualTitles).as(propertyName(tabbedPane, "tabTitles")).isEqualTo(titles);
276 }
277
278 @RunsInEDT
279 private static String[] allTabTitlesIn(final JTabbedPane tabbedPane) {
280 return execute(new GuiQuery<String[]>() {
281 protected String[] executeInEDT() {
282 List<String> allTitles = new ArrayList<String>();
283 int tabCount = tabbedPane.getTabCount();
284 for (int i = 0; i < tabCount; i++)
285 allTitles.add(tabbedPane.getTitleAt(i));
286 return allTitles.toArray(new String[allTitles.size()]);
287 }
288 });
289 }
290 }