001 /*
002 * Created on Sep 10, 2007
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 @2007-2010 the original author or authors.
015 */
016 package org.fest.swing.fixture;
017
018 import static org.fest.swing.core.MouseButton.LEFT_BUTTON;
019 import static org.fest.swing.core.MouseButton.RIGHT_BUTTON;
020
021 import java.awt.Component;
022 import java.util.regex.Pattern;
023
024 import javax.swing.JTable;
025
026 import org.fest.swing.cell.JTableCellReader;
027 import org.fest.swing.cell.JTableCellWriter;
028 import org.fest.swing.core.MouseButton;
029 import org.fest.swing.core.MouseClickInfo;
030 import org.fest.swing.data.TableCell;
031 import org.fest.swing.driver.JTableDriver;
032 import org.fest.swing.exception.ActionFailedException;
033 import org.fest.swing.exception.ComponentLookupException;
034
035 /**
036 * Understands functional testing of single cells in <code>{@link JTable}</code>s:
037 * <ul>
038 * <li>user input simulation</li>
039 * <li>state verification</li>
040 * <li>property value query</li>
041 * </ul>
042 * <p>
043 * Example:
044 * <pre>
045 * // import static org.fest.swing.data.TableCell.row;
046 * {@link JTableCellFixture} cell = dialog.{@link JTableFixture table}("records").cell({@link TableCell#row(int) row}(3).column(0));
047 * cell.select().showPopupMenu();
048 * </pre>
049 * </p>
050 *
051 * @author Alex Ruiz
052 * @author Yvonne Wang
053 *
054 * @see TableCell
055 */
056 public class JTableCellFixture implements ItemFixture {
057
058 private final JTableFixture table;
059 private final TableCell cell;
060
061 /**
062 * Creates a new <code>{@link JTableCellFixture}</code>.
063 * @param table handles the <code>JTable</code> containing the cell in this fixture.
064 * @param cell row and column indices of the table cell to be managed by this fixture.
065 * @throws NullPointerException if <code>table</code> is <code>null</code>.
066 * @throws NullPointerException if <code>cell</code> is <code>null</code>.
067 */
068 protected JTableCellFixture(JTableFixture table, TableCell cell) {
069 validateNotNull(table);
070 validateNotNull(cell);
071 this.table = table;
072 this.cell = cell;
073 }
074
075 private void validateNotNull(JTableFixture newTable) {
076 if (newTable == null) throw new NullPointerException("The JTableFixture should not be null");
077 }
078
079 private void validateNotNull(TableCell newCell) {
080 if (newCell == null) throw new NullPointerException("The TableCell should not be null");
081 }
082
083 JTableFixture table() { return table; }
084 TableCell cell() { return cell; }
085
086 /**
087 * Simulates a user selecting this fixture's table cell.
088 * @return this fixture.
089 * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
090 * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
091 */
092 public JTableCellFixture select() {
093 table.selectCell(cell);
094 return this;
095 }
096
097 /**
098 * Simulates a user clicking this fixture's table cell.
099 * @return this fixture.
100 * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
101 * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
102 */
103 public JTableCellFixture click() {
104 table.click(cell, LEFT_BUTTON);
105 return this;
106 }
107
108 /**
109 * Simulates a user clicking this fixture's table cell.
110 * @param mouseClickInfo specifies the button to click and the times the button should be clicked.
111 * @return this fixture.
112 * @throws NullPointerException if the given <code>MouseClickInfo</code> is <code>null</code>.
113 * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
114 * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
115 */
116 public JTableCellFixture click(MouseClickInfo mouseClickInfo) {
117 table.click(cell, mouseClickInfo);
118 return this;
119 }
120
121 /**
122 * Simulates a user double-clicking this fixture's table cell.
123 * @return this fixture.
124 * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
125 * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
126 */
127 public JTableCellFixture doubleClick() {
128 return click(LEFT_BUTTON, 2);
129 }
130
131 /**
132 * Simulates a user right-clicking this fixture's table cell.
133 * @return this fixture.
134 * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
135 * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
136 */
137 public JTableCellFixture rightClick() {
138 return click(RIGHT_BUTTON);
139 }
140
141 /**
142 * Simulates a user clicking a cell in this fixture's table cell once, using the specified mouse button.
143 * @param button the mouse button to use.
144 * @return this fixture.
145 * @throws NullPointerException if the given <code>MouseButton</code> is <code>null</code>.
146 * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
147 * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
148 */
149 public JTableCellFixture click(MouseButton button) {
150 table.click(cell, button);
151 return this;
152 }
153
154 private JTableCellFixture click(MouseButton button, int times) {
155 table.click(cell, button, times);
156 return this;
157 }
158
159 /**
160 * Starts editing this fixture's table cell. This method should be called <strong>before</strong> manipulating the
161 * <code>{@link Component}</code> returned by <code>{@link #editor()}</code>.
162 * <p>
163 * This method uses the <code>{@link JTableCellWriter}</code> from the <code>{@link JTableFixture}</code> that
164 * created this fixture.
165 * </p>
166 * @return this fixture.
167 * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
168 * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
169 * @throws IllegalStateException if this cell is not editable.
170 * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds.
171 * @throws ActionFailedException if this writer is unable to handle the underlying cell editor.
172 * @see JTableFixture#cellWriter(JTableCellWriter)
173 * @see JTableCellWriter
174 * @see #editor()
175 */
176 public JTableCellFixture startEditing() {
177 driver().startCellEditing(target(), cell);
178 return this;
179 }
180
181 /**
182 * Stops editing this fixture's table cell. This method should be called <strong>after</strong> manipulating the
183 * <code>{@link Component}</code> returned by <code>{@link #editor()}</code>.
184 * <p>
185 * This method uses the <code>{@link JTableCellWriter}</code> from the <code>{@link JTableFixture}</code> that
186 * created this fixture.
187 * </p>
188 * @return this fixture.
189 * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
190 * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
191 * @throws IllegalStateException if this cell is not editable.
192 * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds.
193 * @throws ActionFailedException if this writer is unable to handle the underlying cell editor.
194 * @see JTableFixture#cellWriter(JTableCellWriter)
195 * @see JTableCellWriter
196 * @see #editor()
197 */
198 public JTableCellFixture stopEditing() {
199 driver().stopCellEditing(target(), cell);
200 return this;
201 }
202
203 /**
204 * Cancels editing this fixture's table cell. This method should be called <strong>after</strong> manipulating the
205 * <code>{@link Component}</code> returned by <code>{@link #editor()}</code>.
206 * <p>
207 *
208 * <pre>
209 * TableCellFixture cell = table.cell(row(6).column(8));
210 * Component editor = cell.editor();
211 * // assume editor is a JTextField
212 * JTextComponentFixture editorFixture = new JTextComponentFixture(robot, (JTextField) editor);
213 * cell.{@link #startEditing()};
214 * editorFixture.enterText("Hello");
215 * // discard any entered value
216 * cell.cancelEditing();
217 * </pre>
218 *
219 * </p>
220 * <p>
221 * This method uses the <code>{@link JTableCellWriter}</code> from the <code>{@link JTableFixture}</code> that
222 * created this fixture.
223 * </p>
224 * @return this fixture.
225 * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
226 * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
227 * @throws IllegalStateException if this cell is not editable.
228 * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds.
229 * @throws ActionFailedException if this writer is unable to handle the underlying cell editor.
230 * @see JTableFixture#cellWriter(JTableCellWriter)
231 * @see JTableCellWriter
232 * @see #editor()
233 */
234 public JTableCellFixture cancelEditing() {
235 driver().cancelCellEditing(target(), cell);
236 return this;
237 }
238
239 /**
240 * Returns the editor of this fixture's table cell. To manipulate the editor (e.g. wrapping it with a
241 * <code>ComponentFixture</code>,) the method <code>{@link #startEditing()}</code> should be called first. To
242 * apply any changes back to the table cell, the method <code>{@link #stopEditing()}</code> should be called. This
243 * method uses the <code>{@link JTableCellWriter}</code> from the <code>{@link JTableFixture}</code> that created
244 * this fixture.
245 * <p>
246 * Example:
247 *
248 * <pre>
249 * TableCellFixture cell = table.cell(row(6).column(8));
250 * Component editor = cell.editor();
251 * // assume editor is a JTextField
252 * JTextComponentFixture editorFixture = new JTextComponentFixture(robot, (JTextField) editor);
253 * cell.{@link #startEditing()};
254 * editorFixture.enterText("Hello");
255 * cell.{@link #stopEditing()};
256 * </pre>
257 *
258 * </p>
259 * @return the editor of this fixture's table cell.
260 * @see JTableFixture#cellWriter(JTableCellWriter)
261 * @see JTableCellWriter
262 */
263 public Component editor() {
264 return driver().cellEditor(target(), cell);
265 }
266
267 /**
268 * Enters the given value to this fixture's table cell. This method starts cell edition, enters the given value and
269 * stops cell edition. To change the value of a cell, only a call to this method is necessary. If you need more
270 * flexibility, you can retrieve the cell editor with <code>{@link #editor()}</code>.
271 * <p>
272 * This method uses the <code>{@link JTableCellWriter}</code> from the <code>{@link JTableFixture}</code> that
273 * created this fixture.
274 * </p>
275 * @param value the value to enter in the cell.
276 * @return this fixture.
277 * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
278 * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
279 * @throws IllegalStateException if this cell is not editable.
280 * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds.
281 * @throws ActionFailedException if this driver's <code>JTableCellValueReader</code> is unable to enter the given
282 * value.
283 * @see JTableFixture#cellWriter(JTableCellWriter)
284 * @see JTableCellWriter
285 */
286 public JTableCellFixture enterValue(String value) {
287 driver().enterValueInCell(target(), cell, value);
288 return this;
289 }
290
291 private JTableDriver driver() { return table.driver(); }
292 private JTable target() { return table.target; }
293
294 /**
295 * Asserts that the value of this fixture's table cell matches the given value.
296 * @param value the expected value of this fixture's table cell. It can be a regular expression.
297 * @return this fixture.
298 * @throws AssertionError if the value of this fixture's table cell does not match the expected one.
299 */
300 public JTableCellFixture requireValue(String value) {
301 table.requireCellValue(cell, value);
302 return this;
303 }
304
305 /**
306 * Asserts that the value of this fixture's table cell matches the given regular expression pattern.
307 * @param pattern the regular expression pattern to match.
308 * @return this fixture.
309 * @throws NullPointerException if the given regular expression pattern is <code>null</code>.
310 * @throws AssertionError if the value of this fixture's table cell does not match the expected the given regular
311 * expression pattern.
312 * @since 1.2
313 */
314 public JTableCellFixture requireValue(Pattern pattern) {
315 table.requireCellValue(cell, pattern);
316 return this;
317 }
318
319 /**
320 * Returns a fixture that verifies the font of this fixture's table cell. This method uses the
321 * <code>{@link JTableCellReader}</code> from the <code>{@link JTableFixture}</code> that created this fixture.
322 * @return a fixture that verifies the font of this fixture's table cell.
323 * @see JTableFixture#cellReader(JTableCellReader)
324 * @see JTableCellReader
325 */
326 public FontFixture font() {
327 return table.fontAt(cell);
328 }
329
330 /**
331 * Returns a fixture that verifies the background color of this fixture's table cell. This method uses the
332 * <code>{@link JTableCellReader}</code> from the <code>{@link JTableFixture}</code> that created this fixture.
333 * @return a fixture that verifies the background color of this fixture's table cell.
334 * @see JTableFixture#cellReader(JTableCellReader)
335 * @see JTableCellReader
336 */
337 public ColorFixture background() {
338 return table.backgroundAt(cell);
339 }
340
341 /**
342 * Returns a fixture that verifies the foreground color of this fixture's table cell. This method uses the
343 * <code>{@link JTableCellReader}</code> from the <code>{@link JTableFixture}</code> that created this fixture.
344 * @return a fixture that verifies the foreground color of this fixture's table cell.
345 * @see JTableFixture#cellReader(JTableCellReader)
346 * @see JTableCellReader
347 */
348 public ColorFixture foreground() {
349 return table.foregroundAt(cell);
350 }
351
352 /**
353 * Returns the <code>String</code> representation of the value of this fixture's table cell. This method uses the
354 * <code>{@link JTableCellReader}</code> from the <code>{@link JTableFixture}</code> that created this fixture.
355 * @return the <code>String</code> representation of the value of this fixture's table cell.
356 * @see JTableFixture#cellReader(JTableCellReader)
357 * @see JTableCellReader
358 */
359 public String value() {
360 return table.valueAt(cell);
361 }
362
363 /**
364 * Simulates a user dragging this fixture's table cell.
365 * @return this fixture.
366 */
367 public JTableCellFixture drag() {
368 table.drag(cell);
369 return this;
370 }
371
372 /**
373 * Simulates a user dropping into this fixture's table cell.
374 * @return this fixture.
375 */
376 public JTableCellFixture drop() {
377 table.drop(cell);
378 return this;
379 }
380
381 /**
382 * Shows a pop-up menu using this fixture's table cell as the invoker of the pop-up menu.
383 * @return a fixture that manages the displayed pop-up menu.
384 * @throws ComponentLookupException if a pop-up menu cannot be found.
385 */
386 public JPopupMenuFixture showPopupMenu() {
387 return table.showPopupMenuAt(cell);
388 }
389
390 /**
391 * Asserts that this fixture's table cell is editable.
392 * @return this fixture.
393 * @throws AssertionError if this fixture's table cell is not editable.
394 */
395 public JTableCellFixture requireEditable() {
396 table.requireEditable(cell);
397 return this;
398 }
399
400
401 /**
402 * Asserts that this fixture's table cell is not editable.
403 * @return this fixture.
404 * @throws AssertionError if this fixture's table cell is editable.
405 */
406 public JTableCellFixture requireNotEditable() {
407 table.requireNotEditable(cell);
408 return this;
409 }
410
411 /**
412 * Returns the row index of this fixture's table cell.
413 * @return the row index of this fixture's table cell.
414 */
415 public int row() { return cell.row; }
416
417 /**
418 * Returns the column index of this fixture's table cell.
419 * @return the column index of this fixture's table cell.
420 */
421 public int column() { return cell.column; }
422
423 }