001    /*
002     * Created on Mar 16, 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.swing.core.MouseButton.LEFT_BUTTON;
019    import static org.fest.swing.driver.ComponentStateValidator.validateIsEnabledAndShowing;
020    import static org.fest.swing.edt.GuiActionRunner.execute;
021    import static org.fest.swing.timing.Pause.pause;
022    
023    import java.awt.Point;
024    import java.util.regex.Pattern;
025    
026    import javax.swing.JPopupMenu;
027    import javax.swing.table.JTableHeader;
028    
029    import org.fest.swing.annotation.RunsInEDT;
030    import org.fest.swing.core.MouseButton;
031    import org.fest.swing.core.Robot;
032    import org.fest.swing.edt.GuiQuery;
033    import org.fest.swing.exception.ComponentLookupException;
034    import org.fest.swing.exception.LocationUnavailableException;
035    import org.fest.swing.util.*;
036    
037    /**
038     * Understands functional testing of <code>{@link JTableHeader}</code>s:
039     * <ul>
040     * <li>user input simulation</li>
041     * <li>state verification</li>
042     * <li>property value query</li>
043     * </ul>
044     * This class is intended for internal use only. Please use the classes in the package
045     * <code>{@link org.fest.swing.fixture}</code> in your tests.
046     *
047     * @author Yvonne Wang
048     * @author Alex Ruiz
049     */
050    public class JTableHeaderDriver extends JComponentDriver {
051    
052      private final JTableHeaderLocation location = new JTableHeaderLocation();
053    
054      /**
055       * Creates a new </code>{@link JTableHeaderDriver}</code>.
056       * @param robot the robot to use to simulate user input.
057       */
058      public JTableHeaderDriver(Robot robot) {
059        super(robot);
060      }
061    
062      /**
063       * Clicks the column under the given index.
064       * @param tableHeader the target <code>JTableHeader</code>.
065       * @param columnIndex the given index.
066       * @throws IllegalStateException if the <code>JTableHeader</code> is disabled.
067       * @throws IllegalStateException if the <code>JTableHeader</code> is not showing on the screen.
068       * @throws IndexOutOfBoundsException if the index is out of bounds.
069       */
070      @RunsInEDT
071      public void clickColumn(JTableHeader tableHeader, int columnIndex) {
072        clickColumn(tableHeader, columnIndex, LEFT_BUTTON, 1);
073      }
074    
075      /**
076       * Clicks the column under the given index using the given mouse button the given number of times.
077       * @param tableHeader the target <code>JTableHeader</code>.
078       * @param columnIndex the given index.
079       * @param button the mouse button to use.
080       * @param times the number of times to click.
081       * @throws IllegalStateException if the <code>JTableHeader</code> is disabled.
082       * @throws IllegalStateException if the <code>JTableHeader</code> is not showing on the screen.
083       * @throws IndexOutOfBoundsException if the index is out of bounds.
084       */
085      @RunsInEDT
086      public void clickColumn(JTableHeader tableHeader, int columnIndex, MouseButton button, int times) {
087        Point p = pointAtIndex(tableHeader, columnIndex, location);
088        robot.click(tableHeader, p, button, times);
089        pause(300); // needs more time when sorting a column (JDK 1.6)
090      }
091    
092      /**
093       * Clicks the column which name matches the given value.
094       * @param tableHeader the target <code>JTableHeader</code>.
095       * @param columnName the column name to match. It can be a regular expression.
096       * @throws IllegalStateException if the <code>JTableHeader</code> is disabled.
097       * @throws IllegalStateException if the <code>JTableHeader</code> is not showing on the screen.
098       * @throws LocationUnavailableException if a column with a matching name cannot be found.
099       */
100      @RunsInEDT
101      public void clickColumn(JTableHeader tableHeader, String columnName) {
102        clickColumn(tableHeader, columnName, LEFT_BUTTON, 1);
103      }
104    
105      /**
106       * Clicks the column which name matches the given regular expression pattern.
107       * @param tableHeader the target <code>JTableHeader</code>.
108       * @param columnNamePattern the the regular expression pattern to match.
109       * @throws IllegalStateException if the <code>JTableHeader</code> is disabled.
110       * @throws IllegalStateException if the <code>JTableHeader</code> is not showing on the screen.
111       * @throws NullPointerException if the given regular expression pattern is <code>null</code>.
112       * @throws LocationUnavailableException if a column with a matching name cannot be found.
113       * @since 1.2
114       */
115      @RunsInEDT
116      public void clickColumn(JTableHeader tableHeader, Pattern columnNamePattern) {
117        clickColumn(tableHeader, columnNamePattern, LEFT_BUTTON, 1);
118      }
119    
120      /**
121       * Clicks the column which name matches the given one using the given mouse button the given number of times.
122       * @param tableHeader the target <code>JTableHeader</code>.
123       * @param columnName the column name to match. It can be a regular expression.
124       * @param button the mouse button to use.
125       * @param times the number of times to click.
126       * @throws IllegalStateException if the <code>JTableHeader</code> is disabled.
127       * @throws IllegalStateException if the <code>JTableHeader</code> is not showing on the screen.
128       * @throws LocationUnavailableException if a column with a matching name cannot be found.
129       */
130      @RunsInEDT
131      public void clickColumn(JTableHeader tableHeader, String columnName, MouseButton button, int times) {
132        clickColumn(tableHeader, new StringTextMatcher(columnName), button, times);
133      }
134    
135      /**
136       * Clicks the column which name matches the given regular expression pattern using the given mouse button the given
137       * number of times.
138       * @param tableHeader the target <code>JTableHeader</code>.
139       * @param columnNamePattern the regular expression pattern to match.
140       * @param button the mouse button to use.
141       * @param times the number of times to click.
142       * @throws IllegalStateException if the <code>JTableHeader</code> is disabled.
143       * @throws IllegalStateException if the <code>JTableHeader</code> is not showing on the screen.
144       * @throws NullPointerException if the given regular expression pattern is <code>null</code>.
145       * @throws LocationUnavailableException if a column with a matching name cannot be found.
146       * @since 1.2
147       */
148      @RunsInEDT
149      public void clickColumn(JTableHeader tableHeader, Pattern columnNamePattern, MouseButton button, int times) {
150        clickColumn(tableHeader, new PatternTextMatcher(columnNamePattern), button, times);
151      }
152    
153      @RunsInEDT
154      private void clickColumn(JTableHeader tableHeader, TextMatcher matcher, MouseButton button, int times) {
155        Point p = pointAtName(tableHeader, matcher, location);
156        robot.click(tableHeader, p, button, times);
157      }
158    
159      /**
160       * Shows a pop-up menu at the given column.
161       * @param tableHeader the target <code>JTableHeader</code>.
162       * @param columnIndex the index of the column.
163       * @return the displayed pop-up menu.
164       * @throws IllegalStateException if the <code>JTableHeader</code> is disabled.
165       * @throws IllegalStateException if the <code>JTableHeader</code> is not showing on the screen.
166       * @throws IndexOutOfBoundsException if the index is out of bounds.
167       * @throws ComponentLookupException if a pop-up menu cannot be found.
168       */
169      @RunsInEDT
170      public JPopupMenu showPopupMenu(JTableHeader tableHeader, int columnIndex) {
171        return robot.showPopupMenu(tableHeader, pointAtIndex(tableHeader, columnIndex, location));
172      }
173    
174      @RunsInEDT
175      private static Point pointAtIndex(final JTableHeader tableHeader, final int columnIndex,
176          final JTableHeaderLocation location) {
177        return execute(new GuiQuery<Point>() {
178          protected Point executeInEDT() {
179            Point p = location.pointAt(tableHeader, columnIndex);
180            validateIsEnabledAndShowing(tableHeader);
181            tableHeader.getTable().scrollRectToVisible(tableHeader.getHeaderRect(columnIndex));
182            return p;
183          }
184        });
185      }
186    
187      /**
188       * Shows a pop-up menu at the given column.
189       * @param tableHeader the target <code>JTableHeader</code>.
190       * @param columnName the name of the column. It can be a regular expression.
191       * @return the displayed pop-up menu.
192       * @throws IllegalStateException if the <code>JTableHeader</code> is disabled.
193       * @throws IllegalStateException if the <code>JTableHeader</code> is not showing on the screen.
194       * @throws ComponentLookupException if a pop-up menu cannot be found.
195       */
196      @RunsInEDT
197      public JPopupMenu showPopupMenu(JTableHeader tableHeader, String columnName) {
198        return robot.showPopupMenu(tableHeader, pointAtName(tableHeader, new StringTextMatcher(columnName), location));
199      }
200    
201      /**
202       * Shows a pop-up menu at the column whose name matches the given regular expression pattern.
203       * @param tableHeader the target <code>JTableHeader</code>.
204       * @param pattern the regular expression pattern  to match.
205       * @return the displayed pop-up menu.
206       * @throws IllegalStateException if the <code>JTableHeader</code> is disabled.
207       * @throws IllegalStateException if the <code>JTableHeader</code> is not showing on the screen.
208       * @throws NullPointerException if the given regular expression pattern is <code>null</code>.
209       * @throws ComponentLookupException if a pop-up menu cannot be found.
210       * @since 1.2
211       */
212      @RunsInEDT
213      public JPopupMenu showPopupMenu(JTableHeader tableHeader, Pattern pattern) {
214        return robot.showPopupMenu(tableHeader, pointAtName(tableHeader, new PatternTextMatcher(pattern), location));
215      }
216    
217      @RunsInEDT
218      private static Point pointAtName(final JTableHeader tableHeader, final TextMatcher matcher,
219          final JTableHeaderLocation location) {
220        return execute(new GuiQuery<Point>() {
221          protected Point executeInEDT() {
222            Pair<Integer, Point> indexAndLocation = location.pointAt(tableHeader, matcher);
223            validateIsEnabledAndShowing(tableHeader);
224            tableHeader.getTable().scrollRectToVisible(tableHeader.getHeaderRect(indexAndLocation.i));
225            return indexAndLocation.ii;
226          }
227        });
228      }
229    }