001 /*
002 * Created on Jan 12, 2009
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 @2009-2010 the original author or authors.
015 */
016 package org.fest.swing.core.matcher;
017
018 import static org.fest.swing.util.Strings.areEqualOrMatch;
019 import static org.fest.swing.util.Strings.match;
020 import static org.fest.util.Objects.areEqual;
021 import static org.fest.util.Strings.quote;
022
023 import java.awt.Component;
024 import java.util.regex.Pattern;
025
026 import org.fest.swing.core.GenericTypeMatcher;
027
028 /**
029 * Understands a template for matching components by name. Subclasses are free to add other properties to use as search
030 * criteria.
031 * @param <T> the type of <code>Component</code> supported by this matcher.
032 *
033 * @author Alex Ruiz
034 */
035 public abstract class NamedComponentMatcherTemplate<T extends Component> extends GenericTypeMatcher<T> {
036
037 /**
038 * Indicates that a property value to use as search criteria has not been set.
039 */
040 protected static final Object ANY = new Object() {
041 @Override public String toString() { return "<Any>"; }
042 };
043
044 /** The component name to match. **/
045 protected final Object name;
046
047 /**
048 * Creates a new </code>{@link NamedComponentMatcherTemplate}</code>.
049 * @param supportedType the type supported by this matcher.
050 * @throws NullPointerException if the given type is <code>null</code>.
051 */
052 protected NamedComponentMatcherTemplate(Class<T> supportedType) {
053 super(supportedType);
054 this.name = ANY;
055 }
056
057 /**
058 * Creates a new </code>{@link NamedComponentMatcherTemplate}</code>.
059 * @param supportedType the type supported by this matcher.
060 * @param name the component name to match.
061 * @throws NullPointerException if the given type is <code>null</code>.
062 */
063 protected NamedComponentMatcherTemplate(Class<T> supportedType, Object name) {
064 super(supportedType);
065 this.name = name;
066 }
067
068 /**
069 * Returns the component name to match surrounded by double quotes. If the component name has not been set, it will
070 * return <code>{@link #ANY}</code>. This method is commonly used in implementations of <code>toString</code>.
071 * @return the component name to match surrounded by double quotes, or <code>{@link #ANY}</code> if the component name
072 * has not been set.
073 */
074 protected final Object quotedName() {
075 return quoted(name);
076 }
077
078 /**
079 * Returns the given property value to match surrounded by double quotes. If the property has not been set, it will
080 * return <code>{@link #ANY}</code>. This method is commonly used in implementations of <code>toString</code>.
081 * @param propertyValue the given property value.
082 * @return the given property value to match surrounded by double quotes, or <code>{@link #ANY}</code> if the property
083 * value has not been set.
084 */
085 protected final Object quoted(Object propertyValue) {
086 if (ANY.equals(propertyValue)) return ANY;
087 if (propertyValue instanceof Pattern) return quote(((Pattern)propertyValue).pattern());
088 return quote(propertyValue);
089 }
090
091 /**
092 * Indicates whether the given value matches the name in this matcher. It always returns <code>true</code> if this
093 * matcher's name is <code>{@link #ANY}</code>.
094 * @param actual the actual component name.
095 * @return <code>true</code> if this matcher's name is <code>ANY</code> or if both the actual name is equal to the one
096 * in this matcher. Otherwise <code>false</code>.
097 */
098 protected final boolean isNameMatching(String actual) {
099 if (ANY.equals(name)) return true;
100 return areEqual(name, actual);
101 }
102
103 /**
104 * Indicates whether the given value matches the expected value in this matcher. Matching is performed as follows:
105 * <ol>
106 * <li>it always returns <code>true</code> if the expected value is <code>{@link #ANY}</code></li>
107 * <li>if both the expected and actual values are <code>String</code>s, it checks for equality first. If this fails,
108 * it tries to match the values assuming the expected value can be a regular expression</li>
109 * <li>if the expected value is a <code>{@link Pattern}</code> and the actual value is a
110 * <code>{@link CharSequence}</code>, regular expression matching is performed</li>
111 * <li>otherwise, it checks that both the expected and actual values are equal</li>
112 * </ol>
113 * @param expected the expected value in this matcher.
114 * @param actual the actual property value.
115 * @return <code>true</code> if the values match, otherwise <code>false</code>.
116 */
117 protected final boolean arePropertyValuesMatching(Object expected, Object actual) {
118 if (ANY.equals(expected)) return true;
119 if (expected instanceof String && actual instanceof String)
120 return areEqualOrMatch((String)expected, (String)actual);
121 if (expected instanceof Pattern && actual instanceof CharSequence)
122 return match((Pattern)expected, (CharSequence)actual);
123 return areEqual(expected, actual);
124 }
125
126 }