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 }