001    /*
002     * Created on Jul 12, 2007
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 @2007-2010 the original author or authors.
014     */
015    package org.fest.swing.fixture;
016    
017    import static org.fest.assertions.Assertions.assertThat;
018    import static org.fest.swing.driver.ComponentDriver.propertyName;
019    import static org.fest.util.Strings.concat;
020    
021    import java.awt.Color;
022    import java.awt.Font;
023    import java.awt.Point;
024    import java.util.regex.Pattern;
025    
026    import javax.swing.JTable;
027    import javax.swing.table.JTableHeader;
028    
029    import org.fest.assertions.Description;
030    import org.fest.swing.cell.JTableCellReader;
031    import org.fest.swing.cell.JTableCellWriter;
032    import org.fest.swing.core.KeyPressInfo;
033    import org.fest.swing.core.MouseButton;
034    import org.fest.swing.core.MouseClickInfo;
035    import org.fest.swing.core.Robot;
036    import org.fest.swing.data.TableCell;
037    import org.fest.swing.data.TableCellFinder;
038    import org.fest.swing.driver.BasicJTableCellReader;
039    import org.fest.swing.driver.BasicJTableCellWriter;
040    import org.fest.swing.driver.JTableDriver;
041    import org.fest.swing.exception.ActionFailedException;
042    import org.fest.swing.exception.ComponentLookupException;
043    import org.fest.swing.exception.WaitTimedOutError;
044    import org.fest.swing.timing.Timeout;
045    
046    /**
047     * Understands functional testing of <code>{@link JTable}</code>s:
048     * <ul>
049     * <li>user input simulation</li>
050     * <li>state verification</li>
051     * <li>property value query</li>
052     * </ul>
053     * <p>
054     * The conversion between the values given in tests and the values being displayed by a <code>{@link JTable}</code>
055     * renderer is performed by a <code>{@link JTableCellReader}</code>. This fixture uses a
056     * <code>{@link BasicJTableCellReader}</code> by default.
057     * </p>
058     *
059     * @author Alex Ruiz
060     * @author Yvonne Wang
061     * @author Fabien Barbero
062     * @author Andriy Tsykholyas
063     */
064    public class JTableFixture extends ComponentFixture<JTable> implements CommonComponentFixture,
065        JComponentFixture, JPopupMenuInvokerFixture {
066    
067      private JTableDriver driver;
068    
069      /**
070       * Creates a new <code>{@link JTableFixture}</code>.
071       * @param robot performs simulation of user events on the given <code>JTable</code>.
072       * @param target the <code>JTable</code> to be managed by this fixture.
073       * @throws NullPointerException if <code>robot</code> is <code>null</code>.
074       * @throws NullPointerException if <code>target</code> is <code>null</code>.
075       */
076      public JTableFixture(Robot robot, JTable target) {
077        super(robot, target);
078        createDriver();
079      }
080    
081      /**
082       * Creates a new <code>{@link JTableFixture}</code>.
083       * @param robot performs simulation of user events on a <code>JTable</code>.
084       * @param tableName the name of the <code>JTable</code> to find using the given <code>Robot</code>.
085       * @throws NullPointerException if <code>robot</code> is <code>null</code>.
086       * @throws ComponentLookupException if a matching <code>JTable</code> could not be found.
087       * @throws ComponentLookupException if more than one matching <code>JTable</code> is found.
088       */
089      public JTableFixture(Robot robot, String tableName) {
090        super(robot, tableName, JTable.class);
091        createDriver();
092      }
093    
094      private void createDriver() {
095        driver(new JTableDriver(robot));
096      }
097    
098      /**
099       * Sets the <code>{@link JTableDriver}</code> to be used by this fixture.
100       * @param newDriver the new <code>JTableDriver</code>.
101       * @throws NullPointerException if the given driver is <code>null</code>.
102       */
103      protected final void driver(JTableDriver newDriver) {
104        validateNotNull(newDriver);
105        driver = newDriver;
106      }
107    
108      /**
109       * Returns the <code>{@link JTableDriver}</code> used by this fixture.
110       * @return the <code>JTableDriver</code> used by this fixture.
111       */
112      protected final JTableDriver driver() {
113        return driver;
114      }
115    
116      /**
117       * Returns a fixture that verifies the font of the given table cell.
118       * @param cell the given table cell.
119       * @return a fixture that verifies the font of the given table cell.
120       * @throws NullPointerException if the cell is <code>null</code>.
121       * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds.
122       */
123      public FontFixture fontAt(TableCell cell) {
124        Font font = driver.font(target, cell);
125        return new FontFixture(font, cellProperty(cell, FONT_PROPERTY));
126      }
127    
128      /**
129       * Returns a fixture that verifies the background color of the given table cell.
130       * @param cell the given table cell.
131       * @return a fixture that verifies the background color of the given table cell.
132       * @throws NullPointerException if the cell is <code>null</code>.
133       * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds.
134       */
135      public ColorFixture backgroundAt(TableCell cell) {
136        Color background = driver.background(target, cell);
137        return new ColorFixture(background, cellProperty(cell, BACKGROUND_PROPERTY));
138      }
139    
140      /**
141       * Returns a fixture that verifies the foreground color of the given table cell.
142       * @param cell the given table cell.
143       * @return a fixture that verifies the foreground color of the given table cell.
144       * @throws NullPointerException if the cell is <code>null</code>.
145       * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds.
146       */
147      public ColorFixture foregroundAt(TableCell cell) {
148        Color foreground = driver.foreground(target, cell);
149        return new ColorFixture(foreground, cellProperty(cell, FOREGROUND_PROPERTY));
150      }
151    
152      private Description cellProperty(TableCell cell, String propertyName) {
153        return propertyName(target, concat(propertyName, " ", cell));
154      }
155    
156      /**
157       * Returns a fixture that manages the table cell whose value matches the given one.
158       * @param value the value of the cell to look for. It can be a regular expression.
159       * @return a fixture that manages the table cell whose value matches the given one.
160       * @throws ActionFailedException if a cell with a matching value cannot be found.
161       */
162      public TableCell cell(String value) {
163        return driver.cell(target, value);
164      }
165    
166      /**
167       * Returns a fixture that manages the table cell whose value matches the given regular expression pattern.
168       * @param valuePattern the regular expression pattern to match.
169       * @return a fixture that manages the table cell whose value matches the given one.
170       * @throws NullPointerException if the given regular expression pattern is <code>null</code>.
171       * @throws ActionFailedException if a cell with a matching value cannot be found.
172       * @since 1.2
173       */
174      public TableCell cell(Pattern valuePattern) {
175        return driver.cell(target, valuePattern);
176      }
177    
178      /**
179       * Returns a fixture that manages the table cell found by the given <code>{@link TableCellFinder}</code>.
180       * @param cellFinder knows how to find a cell.
181       * @return a fixture that manages the found table cell.
182       * @throws NullPointerException if the <code>TableCellFinder</code> is <code>null</code>.
183       * @throws ActionFailedException if a matching cell could not be found.
184       * @throws IndexOutOfBoundsException if the row or column indices in the found cell are out of bounds.
185       */
186      public JTableCellFixture cell(TableCellFinder cellFinder) {
187        return new JTableCellFixture(this, driver.cell(target, cellFinder));
188      }
189    
190      /**
191       * Returns a fixture that manages the table cell specified by the given row and column.
192       * @param cell the cell of interest.
193       * @return a fixture that manages the table cell specified by the given row and column.
194       * @throws NullPointerException if the cell is <code>null</code>.
195       * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds.
196       */
197      public JTableCellFixture cell(TableCell cell) {
198        driver.validate(target, cell);
199        return new JTableCellFixture(this, cell);
200      }
201    
202      /**
203       * Returns a <code>{@link JTableHeaderFixture}</code> wrapping the <code>{@link JTableHeader}</code> in this fixture's
204       * <code>{@link JTable}</code>.
205       * @return a <code>JTableHeaderFixture</code> wrapping the <code>JTableHeader</code> in this fixture's
206       * <code>JTable</code>.
207       * @throws AssertionError if the <code>JTableHeader</code> in this fixture's <code>JTable</code> is <code>null</code>.
208       */
209      public JTableHeaderFixture tableHeader() {
210        JTableHeader tableHeader = driver.tableHeaderOf(target);
211        assertThat(tableHeader).isNotNull();
212        return new JTableHeaderFixture(robot, tableHeader);
213      }
214    
215      /**
216       * Returns the <code>String</code> representation of the selected cell in this fixture's <code>{@link JTable}</code>,
217       * using this fixture's <code>{@link JTableCellReader}</code>. Returns <code>null</code> if one can not be obtained or
218       * if the <code>{@link JTable}</code> does not have any selected cell.
219       * @return the <code>String</code> representation of the selected cell.
220       * @see #cellReader(JTableCellReader)
221       */
222      public String selectionValue() {
223        return driver.selectionValue(target);
224      }
225    
226      /**
227       * Converts the given cell into a coordinate pair.
228       * @param cell the given cell.
229       * @return the coordinates of the given cell.
230       * @throws NullPointerException if the cell is <code>null</code>.
231       * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds.
232       */
233      public Point pointAt(TableCell cell) {
234        return driver.pointAt(target, cell);
235      }
236    
237      /**
238       * Returns the <code>String</code> representation of the cells in the in this fixture's <code>{@link JTable}</code>,
239       * using this fixture's <code>{@link JTableCellReader}</code>.
240       * @return the <code>String</code> representation of the cells in thi fixture's <code>JTable</code>.
241       * @see #cellReader(JTableCellReader)
242       */
243      public String[][] contents() {
244        return driver.contents(target);
245      }
246    
247      /**
248       * Returns the number of rows that can be shown in this fixture's <code>{@link JTable}</code>, given unlimited space.
249       * @return the number of rows shown in this fixture's <code>JTable</code>.
250       * @see JTable#getRowCount()
251       */
252      public int rowCount() {
253        return driver.rowCountOf(target);
254      }
255    
256      /**
257       * Returns the <code>String</code> representation of the value of a cell in this fixture's
258       * <code>{@link JTable}</code>, using this fixture's <code>{@link JTableCellReader}</code>.
259       * @param cell the given cell.
260       * @return the <code>String</code> representation of the value of a cell in this fixture's <code>JTable</code>.
261       * @throws NullPointerException if the cell is <code>null</code>.
262       * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds.
263       * @see #cellReader(JTableCellReader)
264       */
265      public String valueAt(TableCell cell) {
266        return driver.value(target, cell);
267      }
268    
269      /**
270       * Simulates a user selecting the given cell (row and column) of this fixture's <code>{@link JTable}</code>.
271       * @param cell the cell to select.
272       * @return this fixture.
273       * @throws NullPointerException if the cell is <code>null</code>.
274       * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
275       * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
276       * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds.
277       */
278      public JTableFixture selectCell(TableCell cell) {
279        driver.selectCell(target, cell);
280        return this;
281      }
282    
283      /**
284       * Simulates a user selecting the given cells of this fixture's <code>{@link JTable}</code>.
285       * @param cells the cells to select.
286       * @return this fixture.
287       * @throws NullPointerException if <code>cells</code> is <code>null</code> or empty.
288       * @throws IllegalArgumentException if <code>cells</code> is <code>null</code> or empty.
289       * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
290       * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
291       * @throws NullPointerException if any element in <code>cells</code> is <code>null</code>.
292       * @throws IndexOutOfBoundsException if any of the indices of any of the <code>cells</code> are out of bounds.
293       */
294      public JTableFixture selectCells(TableCell... cells) {
295        driver.selectCells(target, cells);
296        return this;
297      }
298    
299    
300      /**
301       * Simulates a user selecting the given rows in this fixture's <code>{@link JTable}</code>.
302       * @param rows the indices of the row to select.
303       * @return this fixture.
304       * @throws NullPointerException if the given array of indices is <code>null</code>.
305       * @throws IllegalArgumentException if the given array of indices is empty.
306       * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
307       * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
308       * @throws IndexOutOfBoundsException if any of the given indices is out of bounds.
309       * @since 1.2
310       */
311      public JTableFixture selectRows(int... rows) {
312        driver.selectRows(target, rows);
313        return this;
314      }
315    
316      /**
317       * Simulates a user dragging an item from this fixture's <code>{@link JTable}</code>.
318       * @param cell the cell to drag.
319       * @return this fixture.
320       * @throws NullPointerException if the cell is <code>null</code>.
321       * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
322       * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
323       * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds.
324       */
325      public JTableFixture drag(TableCell cell) {
326        driver.drag(target, cell);
327        return this;
328      }
329    
330      /**
331       * Simulates a user dropping an item to this fixture's <code>{@link JTable}</code>.
332       * @param cell the cell to drop the dragging item into.
333       * @return this fixture.
334       * @throws NullPointerException if the cell is <code>null</code>.
335       * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
336       * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
337       * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds.
338       */
339      public JTableFixture drop(TableCell cell) {
340        driver.drop(target, cell);
341        return this;
342      }
343    
344      /**
345       * Simulates a user clicking this fixture's <code>{@link JTable}</code>.
346       * @return this fixture.
347       * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
348       * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
349       */
350      public JTableFixture click() {
351        driver.click(target);
352        return this;
353      }
354    
355      /**
356       * Simulates a user clicking this fixture's <code>{@link JTable}</code>.
357       * @param button the button to click.
358       * @return this fixture.
359       * @throws NullPointerException if the given <code>MouseButton</code> is <code>null</code>.
360       * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
361       * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
362       */
363      public JTableFixture click(MouseButton button) {
364        driver.click(target, button);
365        return this;
366      }
367    
368      /**
369       * Simulates a user clicking this fixture's <code>{@link JTable}</code>.
370       * @param mouseClickInfo specifies the button to click and the times the button should be clicked.
371       * @return this fixture.
372       * @throws NullPointerException if the given <code>MouseClickInfo</code> is <code>null</code>.
373       * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
374       * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
375       */
376      public JTableFixture click(MouseClickInfo mouseClickInfo) {
377        driver.click(target, mouseClickInfo);
378        return this;
379      }
380    
381      /**
382       * Simulates a user clicking a cell in this fixture's <code>{@link JTable}</code> once, using the specified mouse
383       * button.
384       * @param cell the cell to click.
385       * @param button the mouse button to use.
386       * @return this fixture.
387       * @throws NullPointerException if the cell is <code>null</code>.
388       * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
389       * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
390       * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds.
391       */
392      public JTableFixture click(TableCell cell, MouseButton button) {
393        click(cell, button, 1);
394        return this;
395      }
396    
397      /**
398       * Simulates a user clicking a cell in this fixture's <code>{@link JTable}</code>, using the specified mouse button
399       * the given number of times.
400       * @param cell the cell to click.
401       * @param mouseClickInfo specifies the mouse button to use and how many times to click.
402       * @return this fixture.
403       * @throws NullPointerException if the given <code>MouseClickInfo</code> is <code>null</code>.
404       * @throws NullPointerException if the cell is <code>null</code>.
405       * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
406       * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
407       * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds.
408       */
409      public JTableFixture click(TableCell cell, MouseClickInfo mouseClickInfo) {
410        if (mouseClickInfo == null) throw new NullPointerException("The given MouseClickInfo should not be null");
411        click(cell, mouseClickInfo.button(), mouseClickInfo.times());
412        return this;
413      }
414    
415      void click(TableCell cell, MouseButton button, int times) {
416        driver.click(target, cell, button, times);
417      }
418    
419      /**
420       * Simulates a user double-clicking this fixture's <code>{@link JTable}</code>.
421       * <p>
422       * <b>Note:</b> This method will not be successful if the double-clicking occurs on an editable table cell. For this
423       * particular case, this method will start edition of the table cell located under the mouse pointer.
424       * </p>
425       * @return this fixture.
426       * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
427       * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
428       */
429      public JTableFixture doubleClick() {
430        driver.doubleClick(target);
431        return this;
432      }
433    
434      /**
435       * Simulates a user right-clicking this fixture's <code>{@link JTable}</code>.
436       * @return this fixture.
437       * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
438       * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
439       */
440      public JTableFixture rightClick() {
441        driver.rightClick(target);
442        return this;
443      }
444    
445      /**
446       * Simulates a user pressing given key with the given modifiers on this fixture's <code>{@link JTable}</code>.
447       * Modifiers is a mask from the available <code>{@link java.awt.event.InputEvent}</code> masks.
448       * @param keyPressInfo specifies the key and modifiers to press.
449       * @return this fixture.
450       * @throws NullPointerException if the given <code>KeyPressInfo</code> is <code>null</code>.
451       * @throws IllegalArgumentException if the given code is not a valid key code.
452       * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
453       * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
454       * @see KeyPressInfo
455       */
456      public JTableFixture pressAndReleaseKey(KeyPressInfo keyPressInfo) {
457        driver.pressAndReleaseKey(target, keyPressInfo);
458        return this;
459      }
460    
461      /**
462       * Simulates a user pressing and releasing the given keys on this fixture's <code>{@link JTable}</code>. This method
463       * does not affect the current focus.
464       * @param keyCodes one or more codes of the keys to press.
465       * @return this fixture.
466       * @throws NullPointerException if the given array of codes is <code>null</code>.
467       * @throws IllegalArgumentException if any of the given code is not a valid key code.
468       * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
469       * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
470       * @see java.awt.event.KeyEvent
471       */
472      public JTableFixture pressAndReleaseKeys(int... keyCodes) {
473        driver.pressAndReleaseKeys(target, keyCodes);
474        return this;
475      }
476    
477      /**
478       * Simulates a user pressing the given key on this fixture's <code>{@link JTable}</code>.
479       * @param keyCode the code of the key to press.
480       * @return this fixture.
481       * @throws IllegalArgumentException if any of the given code is not a valid key code.
482       * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
483       * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
484       * @see java.awt.event.KeyEvent
485       */
486      public JTableFixture pressKey(int keyCode) {
487        driver.pressKey(target, keyCode);
488        return this;
489      }
490    
491      /**
492       * Simulates a user releasing the given key on this fixture's <code>{@link JTable}</code>.
493       * @param keyCode the code of the key to release.
494       * @return this fixture.
495       * @throws IllegalArgumentException if any of the given code is not a valid key code.
496       * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
497       * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
498       * @see java.awt.event.KeyEvent
499       */
500      public JTableFixture releaseKey(int keyCode) {
501        driver.releaseKey(target, keyCode);
502        return this;
503      }
504    
505      /**
506       * Gives input focus to this fixture's <code>{@link JTable}</code>.
507       * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
508       * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
509       * @return this fixture.
510       */
511      public JTableFixture focus() {
512        driver.focus(target);
513        return this;
514      }
515    
516      /**
517       * Enters the given value in the given cell of this fixture's <code>{@link JTable}</code>, using this fixture's
518       * <code>{@link JTableCellWriter}</code>. If you need more flexibility for editing cell, please see
519       * <code>{@link JTableCellFixture#editor()}</code>.
520       * @param cell the given cell.
521       * @param value the given value.
522       * @return this fixture.
523       * @throws NullPointerException if the cell is <code>null</code>.
524       * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
525       * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
526       * @throws IllegalStateException if this fixture's <code>JTable</code> is not editable.
527       * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds.
528       * @throws ActionFailedException if this fixture's <code>JTableCellValueReader</code> is unable to enter the given
529       * value.
530       * @see #cellWriter(JTableCellWriter)
531       * @see JTableCellFixture#editor()
532       */
533      public JTableFixture enterValue(TableCell cell, String value) {
534        driver.enterValueInCell(target, cell, value);
535        return this;
536      }
537    
538      /**
539       * Updates the implementation of <code>{@link JTableCellReader}</code> to use when comparing internal values of this
540       * fixture's <code>{@link JTable}</code> and the values expected in a test. The default implementation to use is
541       * <code>{@link BasicJTableCellReader}</code>.
542       * @param cellReader the new <code>JTableCellValueReader</code> to use.
543       * @throws NullPointerException if <code>cellReader</code> is <code>null</code>.
544       * @return this fixture.
545       */
546      public JTableFixture cellReader(JTableCellReader cellReader) {
547        driver.cellReader(cellReader);
548        return this;
549      }
550    
551      /**
552       * Asserts that this fixture's <code>{@link JTable}</code> has the given number of rows.
553       * @param expected the expected number of rows.
554       * @return this fixture.
555       * @throws AssertionError if this fixture's <code>JTable</code> does not have the given number of rows.
556       */
557      public JTableFixture requireRowCount(int expected) {
558        driver.requireRowCount(target, expected);
559        return this;
560      }
561    
562      /**
563       * Asserts that the set of selected rows in this fixture's <code>{@link JTable}</code> contains to the given row
564       * indices. The given row indices can be a subset of all the selected rows in a <code>JTable</code>.
565       * @param rows the indices of the rows expected to be selected.
566       * @return this fixture.
567       * @throws AssertionError if the set of selected rows in this fixture's <code>JTable</code> (if any) do not contain
568       * the given indices.
569       * @since 1.2
570       */
571      public JTableFixture requireSelectedRows(int... rows) {
572        driver.requireSelectedRows(target, rows);
573        return this;
574      }
575    
576      /**
577       * Asserts that this fixture's <code>{@link JTable}</code> has the given number of columns.
578       * @param expected the expected number of columns.
579       * @return this fixture.
580       * @throws AssertionError if this fixture's <code>JTable</code> does not have the given number of columns.
581       */
582      public JTableFixture requireColumnCount(int expected) {
583        driver.requireColumnCount(target, expected);
584        return this;
585      }
586    
587      /**
588       * Asserts that this fixture's <code>{@link JTable}</code> has input focus.
589       * @return this fixture.
590       * @throws AssertionError if this fixture's <code>JTable</code> does not have input focus.
591       */
592      public JTableFixture requireFocused() {
593        driver.requireFocused(target);
594        return this;
595      }
596    
597      /**
598       * Asserts that this fixture's <code>{@link JTable}</code> is enabled.
599       * @return this fixture.
600       * @throws AssertionError is the managed <code>JTable</code> is disabled.
601       */
602      public JTableFixture requireEnabled() {
603        driver.requireEnabled(target);
604        return this;
605      }
606    
607      /**
608       * Asserts that this fixture's <code>{@link JTable}</code> is enabled.
609       * @param timeout the time this fixture will wait for the component to be enabled.
610       * @return this fixture.
611       * @throws WaitTimedOutError if the managed <code>JTable</code> is never enabled.
612       */
613      public JTableFixture requireEnabled(Timeout timeout) {
614        driver.requireEnabled(target, timeout);
615        return this;
616      }
617    
618      /**
619       * Asserts that this fixture's <code>{@link JTable}</code> is disabled.
620       * @return this fixture.
621       * @throws AssertionError is the managed <code>JTable</code> is enabled.
622       */
623      public JTableFixture requireDisabled() {
624        driver.requireDisabled(target);
625        return this;
626      }
627    
628      /**
629       * Asserts that this fixture's <code>{@link JTable}</code> is visible.
630       * @return this fixture.
631       * @throws AssertionError if the managed <code>JTable</code> is not visible.
632       */
633      public JTableFixture requireVisible() {
634        driver.requireVisible(target);
635        return this;
636      }
637    
638      /**
639       * Asserts that this fixture's <code>{@link JTable}</code> is not visible.
640       * @return this fixture.
641       * @throws AssertionError if the managed <code>JTable</code> is visible.
642       */
643      public JTableFixture requireNotVisible() {
644        driver.requireNotVisible(target);
645        return this;
646      }
647    
648      /**
649       * Asserts that the toolTip in this fixture's <code>{@link JTable}</code> matches the given value.
650       * @param expected the given value. It can be a regular expression.
651       * @return this fixture.
652       * @throws AssertionError if the toolTip in this fixture's <code>JTable</code> does not match the given value.
653       * @since 1.2
654       */
655      public JTableFixture requireToolTip(String expected) {
656        driver.requireToolTip(target, expected);
657        return this;
658      }
659    
660      /**
661       * Asserts that the toolTip in this fixture's <code>{@link JTable}</code> matches the given regular expression
662       * pattern.
663       * @param pattern the regular expression pattern to match.
664       * @return this fixture.
665       * @throws NullPointerException if the given regular expression pattern is <code>null</code>.
666       * @throws AssertionError if the toolTip in this fixture's <code>JTable</code> does not match the given regular
667       * expression pattern.
668       * @since 1.2
669       */
670      public JTableFixture requireToolTip(Pattern pattern) {
671        driver.requireToolTip(target, pattern);
672        return this;
673      }
674    
675      /**
676       * Asserts that the given cell in this fixture's <code>{@link JTable}</code> is editable.
677       * @param cell the given cell.
678       * @return this fixture.
679       * @throws NullPointerException if the cell is <code>null</code>.
680       * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds.
681       * @throws AssertionError if the given cell is not editable.
682       */
683      public JTableFixture requireEditable(TableCell cell) {
684        driver.requireEditable(target, cell);
685        return this;
686      }
687    
688      /**
689       * Asserts that the given cell in this fixture's <code>{@link JTable}</code> is not editable.
690       * @param cell the given cell.
691       * @return this fixture.
692       * @throws NullPointerException if the cell is <code>null</code>.
693       * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds.
694       * @throws AssertionError if the given cell is editable.
695       */
696      public JTableFixture requireNotEditable(TableCell cell) {
697        driver.requireNotEditable(target, cell);
698        return this;
699      }
700    
701      /**
702       * Verifies that this fixture's <code>{@link JTable}</code> does not have any selection.
703       * @return this fixture.
704       * @throws AssertionError if this fixture's <code>JTable</code> has a selection.
705       */
706      public JTableFixture requireNoSelection() {
707        driver.requireNoSelection(target);
708        return this;
709      }
710    
711      /**
712       * Asserts that the value of the given cell matches the given value.
713       * @param cell the given table cell.
714       * @param value the expected value. It can be a regular expression.
715       * @return this fixture.
716       * @throws NullPointerException if the cell is <code>null</code>.
717       * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds.
718       * @throws AssertionError if the value of the given cell does not match the given value.
719       */
720      public JTableFixture requireCellValue(TableCell cell, String value) {
721        driver.requireCellValue(target, cell, value);
722        return this;
723      }
724    
725      /**
726       * Asserts that the value of the given cell matches the given regular expression pattern.
727       * @param cell the given table cell.
728       * @param pattern the regular expression pattern to match.
729       * @return this fixture.
730       * @throws NullPointerException if the cell is <code>null</code>.
731       * @throws NullPointerException if the given regular expression pattern is <code>null</code>.
732       * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds.
733       * @throws AssertionError if the value of the given cell does not match the given regular expression pattern.
734       * @since 1.2
735       */
736      public JTableFixture requireCellValue(TableCell cell, Pattern pattern) {
737        driver.requireCellValue(target, cell, pattern);
738        return this;
739      }
740    
741      /**
742       * Asserts that the <code>String</code> representation of the cell values in this fixture's
743       * <code>{@link JTable}</code> is equal to the given <code>String</code> array. This method uses this fixture's
744       * <code>{@link JTableCellReader}</code> to read the values of the table cells as <code>String</code>s.
745       * @param contents the expected <code>String</code> representation of the cell values in this fixture's
746       * <code>JTable</code>.
747       * @return this fixture.
748       * @see #cellReader(JTableCellReader)
749       */
750      public JTableFixture requireContents(String[][] contents) {
751        driver.requireContents(target, contents);
752        return this;
753      }
754    
755      /**
756       * Updates the implementation of <code>{@link JTableCellWriter}</code> to use when comparing internal values of this
757       * fixture's <code>{@link JTable}</code> and the values expected in a test. The default implementation to use is
758       * <code>{@link BasicJTableCellWriter}</code>.
759       * @param cellWriter the new <code>JTableCellValueWriter</code> to use.
760       * @throws NullPointerException if <code>cellWriter</code> is <code>null</code>.
761       * @return this fixture.
762       */
763      public JTableFixture cellWriter(JTableCellWriter cellWriter) {
764        driver.cellWriter(cellWriter);
765        return this;
766      }
767    
768      /**
769       * Returns the index of the column in this fixture's <code>{@link JTable}</code> whose name matches the given one.
770       * @param columnName the name of the column to look for.
771       * @return the index of the column whose name matches the given one.
772       * @throws ActionFailedException if a column with a matching name could not be found.
773       */
774      public int columnIndexFor(Object columnName) {
775        return driver.columnIndex(target, columnName);
776      }
777    
778      /**
779       * Returns the client property stored in this fixture's <code>{@link JTable}</code>, under the given key.
780       * @param key the key to use to retrieve the client property.
781       * @return the value of the client property stored under the given key, or <code>null</code> if the property was
782       * not found.
783       * @throws NullPointerException if the given key is <code>null</code>.
784       * @since 1.2
785       */
786      public Object clientProperty(Object key) {
787        return driver.clientProperty(target, key);
788      }
789    
790      /**
791       * Shows a pop-up menu using this fixture's <code>{@link JTable}</code> as the invoker of the pop-up menu.
792       * @return a fixture that manages the displayed pop-up menu.
793       * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
794       * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
795       * @throws ComponentLookupException if a pop-up menu cannot be found.
796       */
797      public JPopupMenuFixture showPopupMenu() {
798        return new JPopupMenuFixture(robot, driver.invokePopupMenu(target));
799      }
800    
801      /**
802       * Shows a pop-up menu at the given point using this fixture's <code>{@link JTable}</code> as the invoker of the
803       * pop-up menu.
804       * @param p the given point where to show the pop-up menu.
805       * @return a fixture that manages the displayed pop-up menu.
806       * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
807       * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
808       * @throws ComponentLookupException if a pop-up menu cannot be found.
809       */
810      public JPopupMenuFixture showPopupMenuAt(Point p) {
811        return new JPopupMenuFixture(robot, driver.invokePopupMenu(target, p));
812      }
813    
814      /**
815       * Shows a pop-up menu at the given cell.
816       * @param cell the table cell where to show the pop-up menu.
817       * @return a fixture that manages the displayed pop-up menu.
818       * @throws NullPointerException if the cell is <code>null</code>.
819       * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled.
820       * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen.
821       * @throws ComponentLookupException if a pop-up menu cannot be found.
822       */
823      public JPopupMenuFixture showPopupMenuAt(TableCell cell) {
824        return new JPopupMenuFixture(robot, driver.showPopupMenuAt(target, cell));
825      }
826    }