001    /*
002     * Created on Oct 20, 2006
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 @2006-2010 the original author or authors.
015     */
016    package org.fest.swing.fixture;
017    
018    import java.awt.Point;
019    import java.util.regex.Pattern;
020    
021    import javax.swing.text.JTextComponent;
022    
023    import org.fest.swing.core.*;
024    import org.fest.swing.driver.JTextComponentDriver;
025    import org.fest.swing.exception.*;
026    import org.fest.swing.timing.Timeout;
027    
028    /**
029     * Understands functional testing of <code>{@link JTextComponent}</code>s:
030     * <ul>
031     * <li>user input simulation</li>
032     * <li>state verification</li>
033     * <li>property value query</li>
034     * </ul>
035     *
036     * @author Alex Ruiz
037     */
038    public class JTextComponentFixture extends ComponentFixture<JTextComponent>
039        implements CommonComponentFixture, JComponentFixture, JPopupMenuInvokerFixture, TextInputFixture {
040    
041      private JTextComponentDriver driver;
042    
043      /**
044       * Creates a new <code>{@link JTextComponentFixture}</code>.
045       * @param robot performs simulation of user events on the given <code>JTextComponent</code>.
046       * @param target the <code>JTextComponent</code> to be managed by this fixture.
047       * @throws NullPointerException if <code>robot</code> is <code>null</code>.
048       * @throws NullPointerException if <code>target</code> is <code>null</code>.
049       */
050      public JTextComponentFixture(Robot robot, JTextComponent target) {
051        super(robot, target);
052        createDriver();
053      }
054    
055      /**
056       * Creates a new <code>{@link JTextComponentFixture}</code>.
057       * @param robot performs simulation of user events on a <code>JTextComponent</code>.
058       * @param textComponentName the name of the <code>JTextComponent</code> to find using the given <code>Robot</code>.
059       * @throws NullPointerException if <code>robot</code> is <code>null</code>.
060       * @throws ComponentLookupException if a matching <code>JTextComponent</code> could not be found.
061       * @throws ComponentLookupException if more than one matching <code>JTextComponent</code> is found.
062       */
063      public JTextComponentFixture(Robot robot, String textComponentName) {
064        super(robot, textComponentName, JTextComponent.class);
065        createDriver();
066      }
067    
068      private void createDriver() {
069        driver(new JTextComponentDriver(robot));
070      }
071    
072      /**
073       * Sets the <code>{@link JTextComponentDriver}</code> to be used by this fixture.
074       * @param newDriver the new <code>JTextComponentDriver</code>.
075       * @throws NullPointerException if the given driver is <code>null</code>.
076       */
077      protected final void driver(JTextComponentDriver newDriver) {
078        validateNotNull(newDriver);
079        driver = newDriver;
080      }
081    
082      /**
083       * Returns the text of this fixture's <code>{@link JTextComponent}</code>.
084       * @return the text of this fixture's <code>JTextComponent</code>.
085       */
086      public String text() {
087        return driver.textOf(target);
088      }
089    
090      /**
091       * Simulates a user selecting the given text contained in this fixture's <code>{@link JTextComponent}</code>.
092       * @param text the text to select.
093       * @return this fixture.
094       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is disabled.
095       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is not showing on the screen.
096       * @throws IllegalArgumentException if this fixture's <code>JTextComponent</code> does not contain the given text to
097       * select.
098       * @throws ActionFailedException if the selecting the text in the given range fails.
099       */
100      public JTextComponentFixture select(String text) {
101        driver.selectText(target, text);
102        return this;
103      }
104    
105      /**
106       * Simulates a user selecting a portion of the text contained in this fixture's <code>{@link JTextComponent}</code>.
107       * @param start index where selection should start.
108       * @param end index where selection should end.
109       * @return this fixture.
110       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is disabled.
111       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is not showing on the screen.
112       * @throws ActionFailedException if the selecting the text in the given range fails.
113       */
114      public JTextComponentFixture selectText(int start, int end) {
115        driver.selectText(target, start, end);
116        return this;
117      }
118    
119      /**
120       * Simulates a user selecting all the text contained in this fixture's <code>{@link JTextComponent}</code>.
121       * @return this fixture.
122       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is disabled.
123       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is not showing on the screen.
124       */
125      public JTextComponentFixture selectAll() {
126        driver.selectAll(target);
127        return this;
128      }
129    
130      /**
131       * Simulates a user clicking this fixture's <code>{@link JTextComponent}</code>.
132       * @return this fixture.
133       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is disabled.
134       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is not showing on the screen.
135       */
136      public JTextComponentFixture click() {
137        driver.click(target);
138        return this;
139      }
140    
141      /**
142       * Simulates a user clicking this fixture's <code>{@link JTextComponent}</code>.
143       * @param button the button to click.
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>JTextComponent</code> is disabled.
147       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is not showing on the screen.
148       */
149      public JTextComponentFixture click(MouseButton button) {
150        driver.click(target, button);
151        return this;
152      }
153    
154      /**
155       * Simulates a user clicking this fixture's <code>{@link JTextComponent}</code>.
156       * @param mouseClickInfo specifies the button to click and the times the button should be clicked.
157       * @return this fixture.
158       * @throws NullPointerException if the given <code>MouseClickInfo</code> is <code>null</code>.
159       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is disabled.
160       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is not showing on the screen.
161       */
162      public JTextComponentFixture click(MouseClickInfo mouseClickInfo) {
163        driver.click(target, mouseClickInfo);
164        return this;
165      }
166    
167      /**
168       * Simulates a user double-clicking this fixture's <code>{@link JTextComponent}</code>.
169       * @return this fixture.
170       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is disabled.
171       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is not showing on the screen.
172       */
173      public JTextComponentFixture doubleClick() {
174        driver.doubleClick(target);
175        return this;
176      }
177    
178      /**
179       * Simulates a user right-clicking this fixture's <code>{@link JTextComponent}</code>.
180       * @return this fixture.
181       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is disabled.
182       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is not showing on the screen.
183       */
184      public JTextComponentFixture rightClick() {
185        driver.rightClick(target);
186        return this;
187      }
188    
189      /**
190       * Simulates a user deleting all the text in this fixture's <code>{@link JTextComponent}</code>.
191       * @return this fixture.
192       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is disabled.
193       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is not showing on the screen.
194       */
195      public JTextComponentFixture deleteText() {
196        driver.deleteText(target);
197        return this;
198      }
199    
200      /**
201       * Simulates a user entering the given text in this fixture's <code>{@link JTextComponent}</code>.
202       * @param text the text to enter.
203       * @return this fixture.
204       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is disabled.
205       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is not showing on the screen.
206       */
207      public JTextComponentFixture enterText(String text) {
208        driver.enterText(target, text);
209        return this;
210      }
211    
212      /**
213       * Sets the text in this fixture's <code>{@link JTextComponent}</code>. Unlike
214       * <code>{@link #enterText(String)}</code>, this method bypasses the event system and allows immediate updating on the
215       * underlying document model.
216       * <p>
217       * Primarily desired for speeding up tests when precise user event fidelity isn't necessary.
218       * </p>
219       * @param text the text to set.
220       * @return this fixture.
221       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is disabled.
222       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is not showing on the screen.
223       */
224      public JTextComponentFixture setText(String text) {
225        driver.setText(target, text);
226        return this;
227      }
228    
229      /**
230       * Gives input focus to this fixture's <code>{@link JTextComponent}</code>.
231       * @return this fixture.
232       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is disabled.
233       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is not showing on the screen.
234       */
235      public JTextComponentFixture focus() {
236        driver.focus(target);
237        return this;
238      }
239    
240      /**
241       * Simulates a user pressing given key with the given modifiers on this fixture's <code>{@link JTextComponent}</code>.
242       * Modifiers is a mask from the available <code>{@link java.awt.event.InputEvent}</code> masks.
243       * @param keyPressInfo specifies the key and modifiers to press.
244       * @return this fixture.
245       * @throws NullPointerException if the given <code>KeyPressInfo</code> is <code>null</code>.
246       * @throws IllegalArgumentException if the given code is not a valid key code.
247       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is disabled.
248       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is not showing on the screen.
249       * @see KeyPressInfo
250       */
251      public JTextComponentFixture pressAndReleaseKey(KeyPressInfo keyPressInfo) {
252        driver.pressAndReleaseKey(target, keyPressInfo);
253        return this;
254      }
255    
256      /**
257       * Simulates a user pressing and releasing the given keys in this fixture's <code>{@link JTextComponent}</code>. This
258       * method does not affect the current focus.
259       * @param keyCodes the codes of the keys to press.
260       * @return this fixture.
261       * @throws NullPointerException if the given array of codes is <code>null</code>.
262       * @throws IllegalArgumentException if any of the given code is not a valid key code.
263       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is disabled.
264       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is not showing on the screen.
265       * @see java.awt.event.KeyEvent
266       */
267      public JTextComponentFixture pressAndReleaseKeys(int...keyCodes) {
268        driver.pressAndReleaseKeys(target, keyCodes);
269        return this;
270      }
271    
272      /**
273       * Simulates a user pressing the given key on this fixture's <code>{@link JTextComponent}</code>.
274       * @param keyCode the code of the key to press.
275       * @return this fixture.
276       * @throws IllegalArgumentException if any of the given code is not a valid key code.
277       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is disabled.
278       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is not showing on the screen.
279       * @see java.awt.event.KeyEvent
280       */
281      public JTextComponentFixture pressKey(int keyCode) {
282        driver.pressKey(target, keyCode);
283        return this;
284      }
285    
286      /**
287       * Simulates a user releasing the given key on this fixture's <code>{@link JTextComponent}</code>.
288       * @param keyCode the code of the key to release.
289       * @return this fixture.
290       * @throws IllegalArgumentException if any of the given code is not a valid key code.
291       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is disabled.
292       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is not showing on the screen.
293       * @see java.awt.event.KeyEvent
294       */
295      public JTextComponentFixture releaseKey(int keyCode) {
296        driver.releaseKey(target, keyCode);
297        return this;
298      }
299    
300      /**
301       * Asserts that the text of this fixture's <code>{@link JTextComponent}</code> is equal to the specified value.
302       * @param expected the text to match. It can be a regular expression pattern.
303       * @return this fixture.
304       * @throws AssertionError if the text of this fixture's <code>JTextComponent</code> is not equal to the given one.
305       */
306      public JTextComponentFixture requireText(String expected) {
307        driver.requireText(target, expected);
308        return this;
309      }
310    
311      /**
312       * Asserts that the text of this fixture's <code>{@link JTextComponent}</code> matches the given regular expression
313       * pattern.
314       * @param pattern the regular expression pattern to match.
315       * @return this fixture.
316       * @throws NullPointerException if the given regular expression pattern is <code>null</code>.
317       * @throws AssertionError if the text of this fixture's <code>JTextComponent</code> is not eual to the given one.
318       * @since 1.2
319       */
320      public JTextComponentFixture requireText(Pattern pattern) {
321        driver.requireText(target, pattern);
322        return this;
323      }
324    
325      /**
326       * Asserts that the target text component does not contain any text.
327       * @return this fixture.
328       * @throws AssertionError if the target text component is not empty.
329       */
330      public JTextComponentFixture requireEmpty() {
331        driver.requireEmpty(target);
332        return this;
333      }
334    
335      /**
336       * Asserts that this fixture's <code>{@link JTextComponent}</code> has input focus.
337       * @return this fixture.
338       * @throws AssertionError if this fixture's <code>JTextComponent</code> does not have input focus.
339       */
340      public JTextComponentFixture requireFocused() {
341        driver.requireFocused(target);
342        return this;
343      }
344    
345      /**
346       * Asserts that this fixture's <code>{@link JTextComponent}</code> is enabled.
347       * @return this fixture.
348       * @throws AssertionError if this fixture's <code>JTextComponent</code> is disabled.
349       */
350      public JTextComponentFixture requireEnabled() {
351        driver.requireEnabled(target);
352        return this;
353      }
354    
355      /**
356       * Asserts that this fixture's <code>{@link JTextComponent}</code> is enabled.
357       * @param timeout the time this fixture will wait for the component to be enabled.
358       * @return this fixture.
359       * @throws WaitTimedOutError if this fixture's <code>JTextComponent</code> is never enabled.
360       */
361      public JTextComponentFixture requireEnabled(Timeout timeout) {
362        driver.requireEnabled(target, timeout);
363        return this;
364      }
365    
366      /**
367       * Asserts that this fixture's <code>{@link JTextComponent}</code> is disabled.
368       * @return this fixture.
369       * @throws AssertionError if this fixture's <code>JTextComponent</code> is enabled.
370       */
371      public JTextComponentFixture requireDisabled() {
372        driver.requireDisabled(target);
373        return this;
374      }
375    
376      /**
377       * Asserts that this fixture's <code>{@link JTextComponent}</code> is visible.
378       * @return this fixture.
379       * @throws AssertionError if this fixture's <code>JTextComponent</code> is not visible.
380       */
381      public JTextComponentFixture requireVisible() {
382        driver.requireVisible(target);
383        return this;
384      }
385    
386      /**
387       * Asserts that this fixture's <code>{@link JTextComponent}</code> is not visible.
388       * @return this fixture.
389       * @throws AssertionError if this fixture's <code>JTextComponent</code> is visible.
390       */
391      public JTextComponentFixture requireNotVisible() {
392        driver.requireNotVisible(target);
393        return this;
394      }
395    
396      /**
397       * Asserts that this fixture's <code>{@link JTextComponent}</code> is editable.
398       * @throws AssertionError if this fixture's <code>JTextComponent</code> is not editable.
399       * @return this fixture.
400       */
401      public JTextComponentFixture requireEditable() {
402        driver.requireEditable(target);
403        return this;
404      }
405    
406      /**
407       * Asserts that this fixture's <code>{@link JTextComponent}</code> is not editable.
408       * @throws AssertionError if this fixture's <code>JTextComponent</code> is editable.
409       * @return this fixture.
410       */
411      public JTextComponentFixture requireNotEditable() {
412        driver.requireNotEditable(target);
413        return this;
414      }
415    
416      /**
417       * Asserts that the toolTip in this fixture's <code>{@link JTextComponent}</code> matches the given value.
418       * @param expected the given value. It can be a regular expression.
419       * @return this fixture.
420       * @throws AssertionError if the toolTip in this fixture's <code>JTextComponent</code> does not match the given
421       * value.
422       * @since 1.2
423       */
424      public JTextComponentFixture requireToolTip(String expected) {
425        driver.requireToolTip(target, expected);
426        return this;
427      }
428    
429      /**
430       * Asserts that the toolTip in this fixture's <code>{@link JTextComponent}</code> matches the given regular expression
431       * pattern.
432       * @param pattern the regular expression pattern to match.
433       * @return this fixture.
434       * @throws NullPointerException if the given regular expression pattern is <code>null</code>.
435       * @throws AssertionError if the toolTip in this fixture's <code>JTextComponent</code> does not match the given
436       * regular expression pattern.
437       * @since 1.2
438       */
439      public JTextComponentFixture requireToolTip(Pattern pattern) {
440        driver.requireToolTip(target, pattern);
441        return this;
442      }
443    
444    
445      /**
446       * Returns the client property stored in this fixture's <code>{@link JTextComponent}</code>, under the given key.
447       * @param key the key to use to retrieve the client property.
448       * @return the value of the client property stored under the given key, or <code>null</code> if the property was
449       * not found.
450       * @throws NullPointerException if the given key is <code>null</code>.
451       * @since 1.2
452       */
453      public Object clientProperty(Object key) {
454        return driver.clientProperty(target, key);
455      }
456    
457      /**
458       * Shows a pop-up menu using this fixture's <code>{@link JTextComponent}</code> as the invoker of the pop-up menu.
459       * @return a fixture that manages the displayed pop-up menu.
460       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is disabled.
461       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is not showing on the screen.
462       * @throws ComponentLookupException if a pop-up menu cannot be found.
463       */
464      public JPopupMenuFixture showPopupMenu() {
465        return new JPopupMenuFixture(robot, driver.invokePopupMenu(target));
466      }
467    
468      /**
469       * Shows a pop-up menu at the given point using this fixture's <code>{@link JTextComponent}</code> as the invoker of
470       * the pop-up menu.
471       * @param p the given point where to show the pop-up menu.
472       * @return a fixture that manages the displayed pop-up menu.
473       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is disabled.
474       * @throws IllegalStateException if this fixture's <code>JTextComponent</code> is not showing on the screen.
475       * @throws ComponentLookupException if a pop-up menu cannot be found.
476       */
477      public JPopupMenuFixture showPopupMenuAt(Point p) {
478        return new JPopupMenuFixture(robot, driver.invokePopupMenu(target, p));
479      }
480    }