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 }