001 /*
002 * Created on Feb 2, 2008
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
005 * 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 is distributed on
010 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
011 * specific language governing permissions and limitations under the License.
012 *
013 * Copyright @2008-2010 the original author or authors.
014 */
015 package org.fest.swing.driver;
016
017 import static org.fest.assertions.Assertions.assertThat;
018 import static org.fest.swing.driver.ComponentStateValidator.validateIsEnabledAndShowing;
019 import static org.fest.swing.driver.JScrollBarSetValueTask.setValue;
020 import static org.fest.swing.driver.JScrollBarValueQuery.valueOf;
021 import static org.fest.swing.edt.GuiActionRunner.execute;
022 import static org.fest.util.Strings.concat;
023
024 import java.awt.Point;
025
026 import javax.swing.JScrollBar;
027
028 import org.fest.swing.annotation.RunsInCurrentThread;
029 import org.fest.swing.annotation.RunsInEDT;
030 import org.fest.swing.core.Robot;
031 import org.fest.swing.edt.GuiQuery;
032 import org.fest.swing.util.GenericRange;
033 import org.fest.swing.util.Pair;
034
035 /**
036 * Understands functional testing of <code>{@link JScrollBar}</code>s:
037 * <ul>
038 * <li>user input simulation</li>
039 * <li>state verification</li>
040 * <li>property value query</li>
041 * </ul>
042 * This class is intended for internal use only. Please use the classes in the package
043 * <code>{@link org.fest.swing.fixture}</code> in your tests.
044 *
045 * @author Yvonne Wang
046 * @author Alex Ruiz
047 */
048 public class JScrollBarDriver extends JComponentDriver {
049
050 private static final String VALUE_PROPERTY = "value";
051
052 private final JScrollBarLocation location = new JScrollBarLocation();
053
054 /**
055 * Creates a new </code>{@link JScrollBarDriver}</code>.
056 * @param robot the robot to use to simulate user input.
057 */
058 public JScrollBarDriver(Robot robot) {
059 super(robot);
060 }
061
062 /**
063 * Scrolls up (or left) one unit (usually a line).
064 * @param scrollBar the target <code>JScrollBar</code>.
065 */
066 public void scrollUnitUp(JScrollBar scrollBar) {
067 scrollUnitUp(scrollBar, 1);
068 }
069
070 /**
071 * Scrolls up (or left) one unit (usually a line,) the given number of times.
072 * @param scrollBar the target <code>JScrollBar</code>.
073 * @param times the number of times to scroll up one unit.
074 * @throws IllegalArgumentException if <code>times</code> is less than or equal to zero.
075 * @throws IllegalStateException if the <code>JScrollBar</code> is disabled.
076 * @throws IllegalStateException if the <code>JScrollBar</code> is not showing on the screen.
077 */
078 public void scrollUnitUp(JScrollBar scrollBar, int times) {
079 validateTimes(times, "scroll up one unit");
080 Pair<Point, Integer> scrollInfo = validateAndFindScrollUnitInfo(scrollBar, location, times * -1);
081 scroll(scrollBar, scrollInfo);
082 }
083
084 /**
085 * Scrolls down (or right) one unit (usually a line).
086 * @param scrollBar the target <code>JScrollBar</code>.
087 */
088 public void scrollUnitDown(JScrollBar scrollBar) {
089 scrollUnitDown(scrollBar, 1);
090 }
091
092 /**
093 * Scrolls down (or right) one unit (usually a line,) the given number of times.
094 * @param scrollBar the target <code>JScrollBar</code>.
095 * @param times the number of times to scroll down one unit.
096 * @throws IllegalArgumentException if <code>times</code> is less than or equal to zero.
097 * @throws IllegalStateException if the <code>JScrollBar</code> is disabled.
098 * @throws IllegalStateException if the <code>JScrollBar</code> is not showing on the screen.
099 */
100 public void scrollUnitDown(JScrollBar scrollBar, int times) {
101 validateTimes(times, "scroll down one unit");
102 Pair<Point, Integer> scrollInfo = validateAndFindScrollUnitInfo(scrollBar, location, times);
103 scroll(scrollBar, scrollInfo);
104 }
105
106 @RunsInEDT
107 private static Pair<Point, Integer> validateAndFindScrollUnitInfo(final JScrollBar scrollBar,
108 final JScrollBarLocation location, final int times) {
109 return execute(new GuiQuery<Pair<Point, Integer>>() {
110 protected Pair<Point, Integer> executeInEDT() {
111 validateIsEnabledAndShowing(scrollBar);
112 return scrollUnitInfo(scrollBar, location, times);
113 }
114 });
115 }
116
117 @RunsInCurrentThread
118 private static Pair<Point, Integer> scrollUnitInfo(JScrollBar scrollBar, JScrollBarLocation location, int times) {
119 Point where = blockLocation(scrollBar, location, times);
120 int count = times * scrollBar.getUnitIncrement();
121 return new Pair<Point, Integer>(where, scrollBar.getValue() + count);
122 }
123
124 /**
125 * Scrolls up (or left) one block (usually a page).
126 * @param scrollBar the target <code>JScrollBar</code>.
127 */
128 @RunsInEDT
129 public void scrollBlockUp(JScrollBar scrollBar) {
130 scrollBlockUp(scrollBar, 1);
131 }
132
133 /**
134 * Scrolls up (or left) one block (usually a page,) the given number of times.
135 * @param scrollBar the target <code>JScrollBar</code>.
136 * @param times the number of times to scroll up one block.
137 * @throws IllegalArgumentException if <code>times</code> is less than or equal to zero.
138 * @throws IllegalStateException if the <code>JScrollBar</code> is disabled.
139 * @throws IllegalStateException if the <code>JScrollBar</code> is not showing on the screen.
140 */
141 @RunsInEDT
142 public void scrollBlockUp(JScrollBar scrollBar, int times) {
143 validateTimes(times, "scroll up one block");
144 Pair<Point, Integer> scrollInfo = validateAndFindScrollBlockInfo(scrollBar, location, times * -1);
145 scroll(scrollBar, scrollInfo);
146 }
147
148 /**
149 * Scrolls down (or right) one block (usually a page).
150 * @param scrollBar the target <code>JScrollBar</code>.
151 */
152 @RunsInEDT
153 public void scrollBlockDown(JScrollBar scrollBar) {
154 scrollBlockDown(scrollBar, 1);
155 }
156
157 /**
158 * Scrolls down (or right) one block (usually a page,) the given number of times.
159 * @param scrollBar the target <code>JScrollBar</code>.
160 * @param times the number of times to scroll down one block.
161 * @throws IllegalArgumentException if <code>times</code> is less than or equal to zero.
162 * @throws IllegalStateException if the <code>JScrollBar</code> is disabled.
163 * @throws IllegalStateException if the <code>JScrollBar</code> is not showing on the screen.
164 */
165 @RunsInEDT
166 public void scrollBlockDown(JScrollBar scrollBar, int times) {
167 validateTimes(times, "scroll down one block");
168 Pair<Point, Integer> scrollInfo = validateAndFindScrollBlockInfo(scrollBar, location, times);
169 scroll(scrollBar, scrollInfo);
170 }
171
172 private void validateTimes(int times, String action) {
173 if (times > 0) return;
174 String message = concat(
175 "The number of times to ", action, " should be greater than zero, but was <", times, ">");
176 throw new IllegalArgumentException(message);
177 }
178
179 @RunsInEDT
180 private static Pair<Point, Integer> validateAndFindScrollBlockInfo(final JScrollBar scrollBar,
181 final JScrollBarLocation location, final int times) {
182 return execute(new GuiQuery<Pair<Point, Integer>>() {
183 protected Pair<Point, Integer> executeInEDT() {
184 validateIsEnabledAndShowing(scrollBar);
185 return scrollBlockInfo(scrollBar, location, times);
186 }
187 });
188 }
189
190 @RunsInCurrentThread
191 private static Pair<Point, Integer> scrollBlockInfo(JScrollBar scrollBar, JScrollBarLocation location, int times) {
192 Point where = blockLocation(scrollBar, location, times);
193 int count = times * scrollBar.getBlockIncrement();
194 return new Pair<Point, Integer>(where, scrollBar.getValue() + count);
195 }
196
197 @RunsInCurrentThread
198 private static Point blockLocation(JScrollBar scrollBar, JScrollBarLocation location, int times) {
199 if (times > 0) return location.blockLocationToScrollDown(scrollBar);
200 return location.blockLocationToScrollUp(scrollBar);
201 }
202
203 @RunsInEDT
204 private void scroll(JScrollBar scrollBar, Pair<Point, Integer> scrollInfo) {
205 // For now, do it programmatically, faking the mouse movement and clicking
206 robot.moveMouse(scrollBar, scrollInfo.i);
207 setValueProperty(scrollBar, scrollInfo.ii);
208 }
209
210 /**
211 * Scrolls to the maximum position of the given <code>{@link JScrollBar}</code>.
212 * @param scrollBar the target <code>JScrollBar</code>.
213 * @throws IllegalStateException if the <code>JScrollBar</code> is disabled.
214 * @throws IllegalStateException if the <code>JScrollBar</code> is not showing on the screen.
215 */
216 @RunsInEDT
217 public void scrollToMaximum(JScrollBar scrollBar) {
218 Pair<Integer, GenericRange<Point>> scrollInfo = validateAndFindScrollToMaximumInfo(scrollBar, location);
219 scroll(scrollBar, scrollInfo.i, scrollInfo.ii);
220 }
221
222 @RunsInEDT
223 private static Pair<Integer, GenericRange<Point>> validateAndFindScrollToMaximumInfo(final JScrollBar scrollBar,
224 final JScrollBarLocation location) {
225 return execute(new GuiQuery<Pair<Integer, GenericRange<Point>>>() {
226 protected Pair<Integer, GenericRange<Point>> executeInEDT() {
227 validateIsEnabledAndShowing(scrollBar);
228 int position = scrollBar.getMaximum();
229 GenericRange<Point> scrollInfo = scrollInfo(scrollBar, location, position);
230 return new Pair<Integer, GenericRange<Point>>(position, scrollInfo);
231 }
232 });
233 }
234
235 /**
236 * Scrolls to the minimum position of the given <code>{@link JScrollBar}</code>.
237 * @param scrollBar the target <code>JScrollBar</code>.
238 * @throws IllegalStateException if the <code>JScrollBar</code> is disabled.
239 * @throws IllegalStateException if the <code>JScrollBar</code> is not showing on the screen.
240 */
241 @RunsInEDT
242 public void scrollToMinimum(JScrollBar scrollBar) {
243 Pair<Integer, GenericRange<Point>> scrollInfo = validateAndFindScrollToMinimumInfo(scrollBar, location);
244 scroll(scrollBar, scrollInfo.i, scrollInfo.ii);
245 }
246
247 @RunsInEDT
248 private static Pair<Integer, GenericRange<Point>> validateAndFindScrollToMinimumInfo(final JScrollBar scrollBar,
249 final JScrollBarLocation location) {
250 return execute(new GuiQuery<Pair<Integer, GenericRange<Point>>>() {
251 protected Pair<Integer, GenericRange<Point>> executeInEDT() {
252 validateIsEnabledAndShowing(scrollBar);
253 int position = scrollBar.getMinimum();
254 GenericRange<Point> scrollInfo = scrollInfo(scrollBar, location, position);
255 return new Pair<Integer, GenericRange<Point>>(position, scrollInfo);
256 }
257 });
258 }
259
260 /**
261 * Scrolls to the given position.
262 * @param scrollBar the target <code>JScrollBar</code>.
263 * @param position the position to scroll to.
264 * @throws IllegalStateException if the <code>JScrollBar</code> is disabled.
265 * @throws IllegalStateException if the <code>JScrollBar</code> is not showing on the screen.
266 * @throws IllegalArgumentException if the given position is not within the <code>JScrollBar</code> bounds.
267 */
268 @RunsInEDT
269 public void scrollTo(JScrollBar scrollBar, int position) {
270 GenericRange<Point> scrollInfo = validateAndFindScrollInfo(scrollBar, location, position);
271 scroll(scrollBar, position, scrollInfo);
272 }
273
274 @RunsInEDT
275 private static GenericRange<Point> validateAndFindScrollInfo(final JScrollBar scrollBar,
276 final JScrollBarLocation location, final int position) {
277 return execute(new GuiQuery<GenericRange<Point>>() {
278 protected GenericRange<Point> executeInEDT() {
279 validatePosition(scrollBar, position);
280 validateIsEnabledAndShowing(scrollBar);
281 return scrollInfo(scrollBar, location, position);
282 }
283 });
284 }
285
286 @RunsInCurrentThread
287 private static void validatePosition(JScrollBar scrollBar, int position) {
288 int min = scrollBar.getMinimum();
289 int max = scrollBar.getMaximum();
290 if (position >= min && position <= max) return;
291 throw new IllegalArgumentException(concat(
292 "Position <", position, "> is not within the JScrollBar bounds of <", min, "> and <", max, ">"));
293 }
294
295 @RunsInCurrentThread
296 private static GenericRange<Point> scrollInfo(JScrollBar scrollBar, JScrollBarLocation location, int position) {
297 Point from = location.thumbLocation(scrollBar, scrollBar.getValue());
298 Point to = location.thumbLocation(scrollBar, position);
299 return new GenericRange<Point>(from, to);
300 }
301
302 private void scroll(JScrollBar scrollBar, int position, GenericRange<Point> points) {
303 simulateScrolling(scrollBar, points);
304 setValueProperty(scrollBar, position);
305 }
306
307 @RunsInEDT
308 private void simulateScrolling(JScrollBar scrollBar, GenericRange<Point> points) {
309 robot.moveMouse(scrollBar, points.from);
310 robot.moveMouse(scrollBar, points.to);
311 }
312
313 @RunsInEDT
314 private void setValueProperty(JScrollBar scrollBar, int value) {
315 setValue(scrollBar, value);
316 robot.waitForIdle();
317 }
318
319 /**
320 * Asserts that the value of the <code>{@link JScrollBar}</code> is equal to the given one.
321 * @param scrollBar the target <code>JScrollBar</code>.
322 * @param value the expected value.
323 * @throws AssertionError if the value of the <code>JScrollBar</code> is not equal to the given one.
324 */
325 @RunsInEDT
326 public void requireValue(JScrollBar scrollBar, int value) {
327 assertThat(valueOf(scrollBar)).as(propertyName(scrollBar, VALUE_PROPERTY)).isEqualTo(value);
328 }
329 }