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 }