001 /* 002 * Created on Nov 15, 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.core; 017 018 import static java.util.Collections.emptyList; 019 import static org.fest.util.Strings.concat; 020 import static org.fest.util.Systems.LINE_SEPARATOR; 021 022 import java.awt.Component; 023 import java.awt.Container; 024 import java.util.Collection; 025 import java.util.concurrent.atomic.AtomicReference; 026 027 import org.fest.assertions.BasicDescription; 028 import org.fest.assertions.Description; 029 import org.fest.swing.exception.ComponentLookupException; 030 import org.fest.swing.timing.Condition; 031 032 /** 033 * Understands a condition that is satisfied if a GUI component that matches certain search criteria can be found. 034 * 035 * @author Yvonne Wang 036 * @author Alex Ruiz 037 */ 038 public final class ComponentFoundCondition extends Condition { 039 040 private final ComponentFinder finder; 041 private final ComponentMatcher matcher; 042 private final Container root; 043 044 private Component found; 045 046 private final AtomicReference<ComponentLookupException> notFoundError = new AtomicReference<ComponentLookupException>(); 047 048 /** 049 * Creates a new <code>{@link ComponentFoundCondition}</code> 050 * @param description the description of this condition. 051 * @param finder performs the component search. 052 * @param matcher specifies the condition that the component we are looking for needs to match. 053 */ 054 public ComponentFoundCondition(String description, ComponentFinder finder, ComponentMatcher matcher) { 055 this(description, finder, matcher, null); 056 } 057 058 /** 059 * Creates a new <code>{@link ComponentFoundCondition}</code> 060 * @param description the description of this condition. 061 * @param finder performs the component search. 062 * @param matcher specifies the condition that the component we are looking for needs to match. 063 * @param root the root used as the starting point of the search. 064 */ 065 public ComponentFoundCondition(String description, ComponentFinder finder, ComponentMatcher matcher, Container root) { 066 this(new BasicDescription(description), finder, matcher, root); 067 } 068 069 /** 070 * Creates a new <code>{@link ComponentFoundCondition}</code> 071 * @param description the description of this condition. 072 * @param finder performs the component search. 073 * @param matcher specifies the condition that the component we are looking for needs to match. 074 */ 075 public ComponentFoundCondition(Description description, ComponentFinder finder, ComponentMatcher matcher) { 076 this(description, finder, matcher, null); 077 } 078 079 /** 080 * Creates a new <code>{@link ComponentFoundCondition}</code> 081 * @param description the description of this condition. 082 * @param finder performs the component search. 083 * @param matcher specifies the condition that the component we are looking for needs to match. 084 * @param root the root used as the starting point of the search. 085 */ 086 public ComponentFoundCondition(Description description, ComponentFinder finder, ComponentMatcher matcher, Container root) { 087 super(description); 088 this.finder = finder; 089 this.matcher = matcher; 090 this.root = root; 091 } 092 093 /** 094 * Returns <code>true</code> if a component that matches the search criteria in this condition's 095 * <code>{@link ComponentMatcher}</code> can be found. Otherwise, this method returns <code>false</code>. 096 * @return <code>true</code> if a matching component can be found, <code>false</code> otherwise. 097 */ 098 public boolean test() { 099 boolean matchFound = false; 100 try { 101 found = finder.find(root, matcher); 102 matchFound = true; 103 } catch (ComponentLookupException e) { 104 notFoundError.set(e); 105 } 106 resetMatcher(matchFound); 107 if (matchFound) notFoundError.set(null); 108 return matchFound; 109 } 110 111 private void resetMatcher(boolean matchFound) { 112 if (!(matcher instanceof ResettableComponentMatcher)) return; 113 ((ResettableComponentMatcher)matcher).reset(matchFound); 114 } 115 116 /** 117 * Returns the component hierarchy to be added to this condition's description in case of a component lookup failure. 118 * @return the component hierarchy to be added to this condition's description in case of a component lookup failure. 119 */ 120 @Override protected String descriptionAddendum() { 121 ComponentLookupException error = notFoundError.get(); 122 if (error == null) return EMPTY_TEXT; 123 return concat(LINE_SEPARATOR, error.getMessage()); 124 } 125 126 /** 127 * Returns the component found (if any.) 128 * @return the component found. 129 */ 130 public Component found() { return found; } 131 132 /** 133 * Returns all the components that satisfied the search criteria specified by this condition's 134 * <code>{@link ComponentMatcher}</code>. 135 * @return all the components that satisfied the search criteria specified by this condition's 136 * {@code ComponentMatcher}. 137 */ 138 public Collection<? extends Component> duplicatesFound() { 139 ComponentLookupException error = notFoundError.get(); 140 if (error == null) return emptyList(); 141 return error.found(); 142 } 143 }