001    /*
002     * Created on Oct 29, 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.finder;
017    
018    import static org.fest.swing.timing.Pause.pause;
019    import static org.fest.util.Strings.concat;
020    
021    import java.awt.Component;
022    import java.util.concurrent.TimeUnit;
023    
024    import org.fest.swing.core.*;
025    import org.fest.swing.exception.WaitTimedOutError;
026    import org.fest.swing.fixture.ComponentFixture;
027    
028    /**
029     * Understands a template for <code>{@link Component}</code> finders.
030     * @param <T> the type of component this finder can search.
031     *
032     * @author Yvonne Wang
033     * @author Alex Ruiz
034     */
035    public abstract class ComponentFinderTemplate<T extends Component> {
036    
037      static final long TIMEOUT = 5000;
038    
039      private long timeout = TIMEOUT;
040    
041      private final ComponentMatcher matcher;
042      private final String searchDescription;
043    
044      /**
045       * Creates a new </code>{@link ComponentFinderTemplate}</code>.
046       * @param componentName the name of the {@code Component} to find.
047       * @param componentType the type of the {@code Component} to find.
048       */
049      protected ComponentFinderTemplate(String componentName, Class<? extends T> componentType) {
050        this(new NameMatcher(componentName, componentType, true));
051      }
052    
053      /**
054       * Creates a new </code>{@link ComponentFinderTemplate}</code>.
055       * @param matcher specifies the search criteria to use when looking up a {@code Component}.
056       */
057      protected ComponentFinderTemplate(GenericTypeMatcher<? extends T> matcher) {
058        this((ComponentMatcher)matcher);
059      }
060    
061      /**
062       * Creates a new </code>{@link ComponentFinderTemplate}</code>.
063       * @param componentType the type of the {@code Component} to find.
064       */
065      protected ComponentFinderTemplate(Class<? extends T> componentType) {
066        this(new TypeMatcher(componentType, true));
067      }
068    
069      private ComponentFinderTemplate(ComponentMatcher matcher) {
070        if (matcher == null) throw new NullPointerException("The matcher should not be null");
071        this.matcher = matcher;
072        searchDescription = concat("component to be found using matcher ", matcher);
073      }
074    
075      /**
076       * Sets the timeout for this finder. The {@code Component} to find should be found within the given time period.
077       * @param newTimeout the period of time the search should be performed.
078       * @param unit the time unit for <code>timeout</code>.
079       * @return this finder.
080       * @throws NullPointerException if the time unit is <code>null</code>.
081       * @throws IllegalArgumentException if the timeout is a negative number.
082       */
083      protected ComponentFinderTemplate<T> withTimeout(long newTimeout, TimeUnit unit) {
084        if (unit == null) throw new NullPointerException("Time unit cannot be null");
085        return withTimeout(unit.toMillis(newTimeout));
086      }
087    
088      /**
089       * Sets the timeout for this finder. The {@code Component} to find should be found within the given time period.
090       * @param newTimeout the number of milliseconds before stopping the search.
091       * @return this finder.
092       * @throws IllegalArgumentException if the timeout is a negative number.
093       */
094      protected ComponentFinderTemplate<T> withTimeout(long newTimeout) {
095        if (newTimeout < 0) throw new IllegalArgumentException("Timeout cannot be a negative number");
096        this.timeout = newTimeout;
097        return this;
098      }
099    
100      /**
101       * Finds a component by name or type using the given robot.
102       * @param robot contains the underlying finding to delegate the search to.
103       * @return a fixture capable of managing the found component.
104       * @throws WaitTimedOutError if a component with the given name or of the given type could not be found.
105       */
106      public abstract ComponentFixture<T> using(Robot robot);
107    
108      /**
109       * Finds the component using either by name or type.
110       * @param robot contains the underlying finding to delegate the search to.
111       * @return the found component.
112       * @throws WaitTimedOutError if a component with the given name or of the given type could not be found.
113       */
114      protected final T findComponentWith(Robot robot) {
115        ComponentFoundCondition condition = new ComponentFoundCondition(searchDescription, robot.finder(), matcher);
116        pause(condition, timeout);
117        return cast(condition.found());
118      }
119    
120      /**
121       * Casts the given {@code Component} to the type supported by this finder.
122       * @param c the given {@code Component}.
123       * @return the given {@code Component} casted to the type supported by this finder.
124       */
125      protected abstract T cast(Component c);
126    }