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 javax.swing.SwingUtilities.getWindowAncestor;
018 import static org.fest.reflect.core.Reflection.field;
019 import static org.fest.swing.driver.ComponentStateValidator.validateIsEnabledAndShowing;
020 import static org.fest.swing.driver.JToolBarIsFloatingQuery.isJToolBarFloating;
021 import static org.fest.swing.edt.GuiActionRunner.execute;
022 import static org.fest.swing.exception.ActionFailedException.actionFailure;
023 import static org.fest.swing.format.Formatting.format;
024 import static org.fest.util.Strings.concat;
025 import static org.fest.util.Strings.quote;
026
027 import java.awt.*;
028
029 import javax.swing.JToolBar;
030
031 import org.fest.swing.annotation.RunsInCurrentThread;
032 import org.fest.swing.annotation.RunsInEDT;
033 import org.fest.swing.core.Robot;
034 import org.fest.swing.edt.GuiQuery;
035 import org.fest.swing.edt.GuiTask;
036 import org.fest.swing.exception.ActionFailedException;
037 import org.fest.swing.util.GenericRange;
038 import org.fest.swing.util.Pair;
039
040 /**
041 * Understands functional testing of <code>{@link JToolBar}</code>s:
042 * <ul>
043 * <li>user input simulation</li>
044 * <li>state verification</li>
045 * <li>property value query</li>
046 * </ul>
047 * This class is intended for internal use only. Please use the classes in the package
048 * <code>{@link org.fest.swing.fixture}</code> in your tests.
049 *
050 * @author Yvonne Wang
051 * @author Alex Ruiz
052 */
053 public class JToolBarDriver extends JComponentDriver {
054
055 private final JToolBarLocation location = new JToolBarLocation();
056
057 /**
058 * Creates a new </code>{@link JToolBarDriver}</code>.
059 * @param robot the robot to use to simulate user input.
060 */
061 public JToolBarDriver(Robot robot) {
062 super(robot);
063 }
064
065 /**
066 * Indicates whether the given <code>{@link JToolBar}</code> is floating or not.
067 * @param toolBar the target <code>JToolBar</code>.
068 * @return <code>true</code> if the <code>JToolBar</code> is floating, <code>false</code> otherwise.
069 */
070 @RunsInEDT
071 public boolean isFloating(JToolBar toolBar) {
072 return floating(toolBar);
073 }
074
075 private static boolean floating(final JToolBar toolBar) {
076 return execute(new GuiQuery<Boolean>() {
077 protected Boolean executeInEDT() {
078 return isJToolBarFloating(toolBar);
079 }
080 });
081 }
082
083 /**
084 * Makes the given <code>{@link JToolBar}</code> float.
085 * @param toolBar the target <code>JToolBar</code>.
086 * @throws IllegalStateException if the <code>JToolBar</code> is disabled.
087 * @throws IllegalStateException if the <code>JToolBar</code> is not showing on the screen.
088 * @throws IllegalStateException if the <code>JToolBar</code> is not floatable.
089 * @throws ActionFailedException if the <code>JToolBar</code> cannot be dragged.
090 */
091 public void makeFloat(JToolBar toolBar) {
092 Pair<Point, Pair<Window, Point>> floatInfo = floatInfo(toolBar, location);
093 Point p = floatInfo.ii.ii; // ancestor location
094 doFloat(toolBar, p.x, p.y, floatInfo);
095 }
096
097 /**
098 * Drags the <code>{@link JToolBar}</code> to the given location, causing it to float.
099 * @param toolBar the target <code>JToolBar</code>.
100 * @param x the horizontal coordinate of the location to drag the <code>JToolBar</code> to.
101 * @param y the vertical coordinate of the location to drag the <code>JToolBar</code> to.
102 * @throws IllegalStateException if the <code>JToolBar</code> is disabled.
103 * @throws IllegalStateException if the <code>JToolBar</code> is not showing on the screen.
104 * @throws IllegalStateException if the <code>JToolBar</code> is not floatable.
105 * @throws ActionFailedException if the <code>JToolBar</code> cannot be dragged.
106 */
107 @RunsInEDT
108 public void floatTo(JToolBar toolBar, int x, int y) {
109 doFloat(toolBar, x, y, floatInfo(toolBar, location));
110 }
111
112 @RunsInEDT
113 private static Pair<Point, Pair<Window, Point>> floatInfo(final JToolBar toolBar, final JToolBarLocation location) {
114 return execute(new GuiQuery<Pair<Point, Pair<Window, Point>>>() {
115 protected Pair<Point, Pair<Window, Point>> executeInEDT() {
116 validateIsEnabledAndShowing(toolBar);
117 validateIsFloatable(toolBar);
118 Pair<Window, Point> windowAndLocation = ancestorAndLocation(toolBar);
119 return new Pair<Point, Pair<Window,Point>>(location.pointToGrab(toolBar), windowAndLocation);
120 }
121 });
122 }
123
124 @RunsInCurrentThread
125 private static void validateIsFloatable(JToolBar toolBar) {
126 if (!toolBar.isFloatable())
127 throw new IllegalStateException(concat("JToolbar <", format(toolBar), "> is not floatable"));
128 }
129
130 @RunsInCurrentThread
131 private static Pair<Window, Point> ancestorAndLocation(final JToolBar toolBar) {
132 Window window = getWindowAncestor(toolBar);
133 return new Pair<Window, Point>(window, window.getLocation());
134 }
135
136 @RunsInEDT
137 private void doFloat(JToolBar toolBar, int x, int y, Pair<Point, Pair<Window, Point>> floatInfo) {
138 drag(toolBar, floatInfo.i);
139 Pair<Window, Point> locationAndAncestor = floatInfo.ii;
140 Point ancestorLocation = locationAndAncestor.ii;
141 drop(locationAndAncestor.i, new Point(x - ancestorLocation.x, y - ancestorLocation.y));
142 validateFloated(toolBar);
143 }
144
145 @RunsInEDT
146 private static void validateFloated(final JToolBar toolBar) {
147 execute(new GuiTask() {
148 protected void executeInEDT() {
149 if (!isJToolBarFloating(toolBar))
150 throw actionFailure(concat("Unable to float JToolbar <", format(toolBar), ">"));
151 }
152 });
153 }
154
155 /**
156 * Drop the {@link JToolBar} to the requested constraint position. The constraint position must be one of the
157 * constants <code>{@link BorderLayout#NORTH NORTH}</code>, <code>{@link BorderLayout#EAST EAST}</code>,
158 * <code>{@link BorderLayout#SOUTH SOUTH}</code>, or <code>{@link BorderLayout#WEST WEST}</code>.
159 * @param toolBar the target <code>JToolBar</code>.
160 * @param constraint the constraint position.
161 * @throws IllegalStateException if the <code>JToolBar</code> is disabled.
162 * @throws IllegalStateException if the <code>JToolBar</code> is not showing on the screen.
163 * @throws IllegalArgumentException if the constraint has an invalid value.
164 * @throws ActionFailedException if the dock container cannot be found.
165 */
166 @RunsInEDT
167 public void unfloat(JToolBar toolBar, String constraint) {
168 Pair<GenericRange<Point>, Container> unfloatInfo = unfloatInfo(toolBar, constraint, location);
169 GenericRange<Point> fromAndTo = unfloatInfo.i;
170 drag(toolBar, fromAndTo.from);
171 drop(unfloatInfo.ii, fromAndTo.to);
172 validateIsNotFloating(toolBar, constraint);
173 }
174
175 @RunsInEDT
176 private static Pair<GenericRange<Point>, Container> unfloatInfo(final JToolBar toolBar, final String constraint,
177 final JToolBarLocation location) {
178 return execute(new GuiQuery<Pair<GenericRange<Point>, Container>>() {
179 protected Pair<GenericRange<Point>, Container> executeInEDT() {
180 validateIsEnabledAndShowing(toolBar);
181 Container dock = dockFor(toolBar);
182 Point from = location.pointToGrab(toolBar);
183 Point to = location.dockLocation(toolBar, dock, constraint);
184 return new Pair<GenericRange<Point>, Container>(new GenericRange<Point>(from, to), dock);
185 }
186 });
187 }
188
189 @RunsInEDT
190 private static void validateIsNotFloating(final JToolBar toolBar, final String constraint) {
191 execute(new GuiTask() {
192 protected void executeInEDT() {
193 if (isJToolBarFloating(toolBar))
194 throw actionFailure(concat("Failed to dock <", format(toolBar), "> using constraint ", quote(constraint)));
195 }
196 });
197 }
198
199 @RunsInCurrentThread
200 private static Container dockFor(final JToolBar toolBar) {
201 try {
202 return field("dockingSource").ofType(Container.class).in(toolBar.getUI()).get();
203 } catch (RuntimeException e) {
204 throw actionFailure("Unabled to determine dock for JToolBar");
205 }
206 }
207
208 /**
209 * Closes a floating <code>{@link JToolBar}</code>, making it go back to its original container in its last known
210 * location.
211 * @param toolBar the target <code>JToolBar</code>.
212 * @throws IllegalStateException if the <code>JToolBar</code> is disabled.
213 * @throws IllegalStateException if the <code>JToolBar</code> is not showing on the screen.
214 */
215 @RunsInEDT
216 public void unfloat(JToolBar toolBar) {
217 Window w = windowAncestorOf(toolBar);
218 robot.close(w);
219 }
220
221 @RunsInEDT
222 private static Window windowAncestorOf(final JToolBar toolBar) {
223 return execute(new GuiQuery<Window>() {
224 protected Window executeInEDT() {
225 validateIsEnabledAndShowing(toolBar);
226 return getWindowAncestor(toolBar);
227 }
228 });
229 }
230 }