1 /* 2 * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.netbeans.jemmy; 24 25 import java.awt.Component; 26 import java.awt.Frame; 27 import java.awt.Window; 28 29 /** 30 * A WindowWaiter is a utility class used to look or wait for Windows. It 31 * contains methods to search for a Window among the currently showing Windows 32 * as well as methods that wait for a Window to show within an allotted time 33 * period. 34 * 35 * Searches and waits always involve search criteria applied by a 36 * ComponentChooser instance. Searches and waits can both be restricted to 37 * windows owned by a given window. 38 * 39 * <BR>Timeouts used: <BR> 40 * WindowWaiter.WaitWindowTimeout - time to wait window displayed <BR> 41 * WindowWaiter.AfterWindowTimeout - time to sleep after window has been 42 * dispayed <BR> 43 * 44 * @see org.netbeans.jemmy.Timeouts 45 * 46 * @author Alexandre Iline (alexandre.iline@oracle.com) 47 */ 48 public class WindowWaiter extends Waiter<Window, Void> implements Timeoutable { 49 50 public static boolean FIND_INVISIBLE_WINDOWS = false; 51 52 private final static long WAIT_TIME = 60000; 53 private final static long AFTER_WAIT_TIME = 0; 54 55 private ComponentChooser chooser; 56 private Window owner = null; 57 private int index = 0; 58 private Timeouts timeouts; 59 60 /** 61 * Constructor. 62 */ 63 public WindowWaiter() { 64 super(); 65 setTimeouts(JemmyProperties.getProperties().getTimeouts()); 66 } 67 68 /** 69 * Searches for a window. The search proceeds among the currently showing 70 * windows for the {@code index+1}'th window that is both owned by the 71 * {@code java.awt.Window} {@code owner} and that meets the 72 * criteria defined and applied by the {@code ComponentChooser} 73 * parameter. 74 * 75 * @param owner The owner window of all the windows to be searched. 76 * @param cc A component chooser used to define and apply the search 77 * criteria. 78 * @param index The ordinal index of the window in the set of currently 79 * displayed windows with the proper window ownership and a suitable title. 80 * The first index is 0. 81 * @return a reference to the {@code index+1}'th window that is 82 * showing, has the proper window ownership, and that meets the search 83 * criteria. If there are fewer than {@code index+1} windows, a 84 * {@code null} reference is returned. 85 */ 86 public static Window getWindow(Window owner, ComponentChooser cc, int index) { 87 return getAWindow(owner, new IndexChooser(cc, index)); 88 } 89 90 /** 91 * Searches for a window. Search among the currently showing windows for the 92 * first that is both owned by the {@code java.awt.Window} 93 * {@code owner} and that meets the search criteria applied by the 94 * {@code ComponentChooser} parameter. 95 * 96 * @param owner The owner window of the windows to be searched. 97 * @param cc A component chooser used to define and apply the search 98 * criteria. 99 * @return a reference to the first window that is showing, has a proper 100 * owner window, and that meets the search criteria. If no such window can 101 * be found, a {@code null} reference is returned. 102 */ 103 public static Window getWindow(Window owner, ComponentChooser cc) { 104 return getWindow(owner, cc, 0); 105 } 106 107 /** 108 * Searches for a window. The search proceeds among the currently showing 109 * windows for the {@code index+1}'th window that meets the criteria 110 * defined and applied by the {@code ComonentChooser} parameter. 111 * 112 * @param cc A component chooser used to define and apply the search 113 * criteria. 114 * @param index The ordinal index of the window in the set of currently 115 * displayed windows. The first index is 0. 116 * @return a reference to the {@code index+1}'th window that is showing 117 * and that meets the search criteria. If there are fewer than 118 * {@code index+1} windows, a {@code null} reference is returned. 119 */ 120 public static Window getWindow(ComponentChooser cc, int index) { 121 return getAWindow(new IndexChooser(cc, index)); 122 } 123 124 /** 125 * Searches for a window. Search among the currently showing windows for one 126 * that meets the search criteria applied by the 127 * {@code ComponentChooser} parameter. 128 * 129 * @param cc A component chooser used to define and apply the search 130 * criteria. 131 * @return a reference to the first window that is showing and that meets 132 * the search criteria. If no such window can be found, a {@code null} 133 * reference is returned. 134 */ 135 public static Window getWindow(ComponentChooser cc) { 136 return getWindow(cc, 0); 137 } 138 139 static { 140 Timeouts.initDefault("WindowWaiter.WaitWindowTimeout", WAIT_TIME); 141 Timeouts.initDefault("WindowWaiter.AfterWindowTimeout", AFTER_WAIT_TIME); 142 } 143 144 /** 145 * Defines current timeouts. 146 * 147 * @param timeouts A collection of timeout assignments. 148 * @see org.netbeans.jemmy.Timeoutable 149 * @see org.netbeans.jemmy.Timeouts 150 * @see #getTimeouts 151 */ 152 @Override 153 public void setTimeouts(Timeouts timeouts) { 154 this.timeouts = timeouts; 155 Timeouts times = timeouts.cloneThis(); 156 times.setTimeout("Waiter.WaitingTime", 157 timeouts.getTimeout("WindowWaiter.WaitWindowTimeout")); 158 times.setTimeout("Waiter.AfterWaitingTime", 159 timeouts.getTimeout("WindowWaiter.AfterWindowTimeout")); 160 setWaitingTimeOrigin("WindowWaiter.WaitWindowTimeout"); 161 super.setTimeouts(times); 162 } 163 164 /** 165 * Return current timeouts. 166 * 167 * @return the collection of current timeout assignments. 168 * @see org.netbeans.jemmy.Timeoutable 169 * @see org.netbeans.jemmy.Timeouts 170 * @see #setTimeouts 171 */ 172 @Override 173 public Timeouts getTimeouts() { 174 return timeouts; 175 } 176 177 /** 178 * Action producer--get a window. Get a window. The search uses constraints 179 * on window ownership, ordinal index, and search criteria defined by an 180 * instance of {@code org.netbeans.jemmy.ComponentChooser}. 181 * 182 * @param obj Not used. 183 * @return the window waited upon. If a window cannot be found then a 184 * {@code null} reference is returned. 185 * @see org.netbeans.jemmy.Action 186 */ 187 @Override 188 public Window actionProduced(Void obj) { 189 return WindowWaiter.getWindow(owner, chooser, index); 190 } 191 192 /** 193 * Waits for a window to show. Wait for the {@code index+1}'th window 194 * that meets the criteria defined and applied by the 195 * {@code ComonentChooser} parameter to show up. 196 * 197 * @param ch A component chooser used to define and apply the search 198 * criteria. 199 * @param index The ordinal index of the window in the set of currently 200 * displayed windows. The first index is 0. 201 * @return a reference to the {@code index+1}'th window that shows and 202 * that meets the search criteria. If fewer than {@code index+1} 203 * windows show up in the allotted time period then a {@code null} 204 * reference is returned. 205 * @throws TimeoutExpiredException 206 * @see #actionProduced(Object) 207 * @exception InterruptedException 208 */ 209 public Window waitWindow(ComponentChooser ch, int index) 210 throws InterruptedException { 211 chooser = ch; 212 owner = null; 213 this.index = index; 214 return waitWindow(); 215 } 216 217 /** 218 * Waits for a window to show. Wait for a window that meets the search 219 * criteria applied by the {@code ComponentChooser} parameter to show 220 * up. 221 * 222 * @param ch A component chooser used to define and apply the search 223 * criteria. 224 * @return a reference to the first window that shows and that meets the 225 * search criteria. If no such window can be found within the time period 226 * allotted, a {@code null} reference is returned. 227 * @throws TimeoutExpiredException 228 * @see #actionProduced(Object) 229 * @exception InterruptedException 230 */ 231 public Window waitWindow(ComponentChooser ch) 232 throws InterruptedException { 233 return waitWindow(ch, 0); 234 } 235 236 /** 237 * Waits for a window to show. Wait for the {@code index+1}'th window 238 * to show that is both owned by the {@code java.awt.Window} 239 * {@code o} and that meets the criteria defined and applied by the 240 * {@code ComponentChooser} parameter. 241 * 242 * @param o The owner window of all the windows to be searched. 243 * @param ch A component chooser used to define and apply the search 244 * criteria. 245 * @param index The ordinal index of the window in the set of currently 246 * displayed windows with the proper window ownership and a suitable title. 247 * The first index is 0. 248 * @return a reference to the {@code index+1}'th window to show that 249 * has the proper window ownership, and that meets the search criteria. If 250 * there are fewer than {@code index+1} windows, a {@code null} 251 * reference is returned. 252 * @throws TimeoutExpiredException 253 * @see #actionProduced(Object) 254 * @exception InterruptedException 255 */ 256 public Window waitWindow(Window o, ComponentChooser ch, int index) 257 throws InterruptedException { 258 owner = o; 259 chooser = ch; 260 this.index = index; 261 return waitAction(null); 262 } 263 264 /** 265 * Waits for a window to show. Wait for the first window to show that is 266 * both owned by the {@code java.awt.Window} {@code o} and that 267 * meets the criteria defined and applied by the 268 * {@code ComponentChooser} parameter. 269 * 270 * @param o The owner window of all the windows to be searched. 271 * @param ch A component chooser used to define and apply the search 272 * criteria. 273 * @return a reference to the first window to show that has the proper 274 * window ownership, and that meets the search criteria. If there is no such 275 * window, a {@code null} reference is returned. 276 * @throws TimeoutExpiredException 277 * @see #actionProduced(Object) 278 * @exception InterruptedException 279 */ 280 public Window waitWindow(Window o, ComponentChooser ch) 281 throws InterruptedException { 282 return waitWindow(o, ch, 0); 283 } 284 285 @Override 286 public String getDescription() { 287 return chooser.getDescription(); 288 } 289 290 @Override 291 public String toString() { 292 return "WindowWaiter{" + "chooser=" + chooser + ", owner=" + owner + ", index=" + index + '}'; 293 } 294 295 /** 296 * Method can be used by a subclass to define chooser. 297 * 298 * @param ch a chooser specifying searching criteria. 299 * @see #getComponentChooser 300 */ 301 protected void setComponentChooser(ComponentChooser ch) { 302 chooser = ch; 303 } 304 305 /** 306 * Method can be used by a subclass to define chooser. 307 * 308 * @return a chooser specifying searching criteria. 309 * @see #setComponentChooser 310 */ 311 protected ComponentChooser getComponentChooser() { 312 return chooser; 313 } 314 315 /** 316 * Method can be used by a subclass to define window owner. 317 * 318 * @param owner Window-owner of the set of windows. 319 * @see #getOwner 320 */ 321 protected void setOwner(Window owner) { 322 this.owner = owner; 323 } 324 325 /** 326 * Method can be used by a subclass to define window owner. 327 * 328 * @return Window-owner of the set of windows. 329 * @see #setOwner 330 */ 331 protected Window getOwner() { 332 return owner; 333 } 334 335 /** 336 * @see org.netbeans.jemmy.Waiter#getWaitingStartedMessage() 337 */ 338 @Override 339 protected String getWaitingStartedMessage() { 340 return "Start to wait window \"" + chooser.getDescription() + "\" opened"; 341 } 342 343 /** 344 * Overrides Waiter.getTimeoutExpiredMessage. 345 * 346 * @see org.netbeans.jemmy.Waiter#getTimeoutExpiredMessage(long) 347 * @param timeSpent time from waiting start (milliseconds) 348 * @return a message. 349 */ 350 @Override 351 protected String getTimeoutExpiredMessage(long timeSpent) { 352 return ("Window \"" + chooser.getDescription() + "\" has not been opened in " 353 + timeSpent + " milliseconds"); 354 } 355 356 /** 357 * Overrides Waiter.getActionProducedMessage. 358 * 359 * @see org.netbeans.jemmy.Waiter#getActionProducedMessage(long, Object) 360 * @param timeSpent time from waiting start (milliseconds) 361 * @param result result of Waitable.actionproduced method. 362 * @return a message. 363 */ 364 @Override 365 protected String getActionProducedMessage(long timeSpent, final Object result) { 366 String resultToString; 367 if (result instanceof Component) { 368 // run toString in dispatch thread 369 resultToString = new QueueTool().invokeSmoothly( 370 new QueueTool.QueueAction<String>("result.toString()") { 371 @Override 372 public String launch() { 373 return result.toString(); 374 } 375 } 376 ); 377 } else { 378 resultToString = result.toString(); 379 } 380 return ("Window \"" + chooser.getDescription() + "\" has been opened in " 381 + timeSpent + " milliseconds" 382 + "\n " + resultToString); 383 } 384 385 /** 386 * @return a message. 387 * @see org.netbeans.jemmy.Waiter#getGoldenWaitingStartedMessage() 388 */ 389 @Override 390 protected String getGoldenWaitingStartedMessage() { 391 return "Start to wait window \"" + chooser.getDescription() + "\" opened"; 392 } 393 394 /** 395 * @return a message. 396 * @see org.netbeans.jemmy.Waiter#getGoldenTimeoutExpiredMessage() 397 */ 398 @Override 399 protected String getGoldenTimeoutExpiredMessage() { 400 return "Window \"" + chooser.getDescription() + "\" has not been opened"; 401 } 402 403 /** 404 * @return a message. 405 * @see org.netbeans.jemmy.Waiter#getGoldenActionProducedMessage() 406 */ 407 @Override 408 protected String getGoldenActionProducedMessage() { 409 return "Window \"" + chooser.getDescription() + "\" has been opened"; 410 } 411 412 private static Window getAWindow(Window owner, ComponentChooser cc) { 413 if (owner == null) { 414 return WindowWaiter.getAWindow(cc); 415 } else { 416 Window result = null; 417 Window[] windows = owner.getOwnedWindows(); 418 for (Window window : windows) { 419 if (cc.checkComponent(window)) { 420 return window; 421 } 422 if ((result = WindowWaiter.getWindow(window, cc)) != null) { 423 return result; 424 } 425 } 426 return null; 427 } 428 } 429 430 private static Window getAWindow(ComponentChooser cc) { 431 Window result = null; 432 Frame[] frames = Frame.getFrames(); 433 for (Frame frame : frames) { 434 if (cc.checkComponent(frame)) { 435 return frame; 436 } 437 if ((result = WindowWaiter.getWindow(frame, cc)) != null) { 438 return result; 439 } 440 } 441 return null; 442 } 443 444 private Window waitWindow() 445 throws InterruptedException { 446 return waitAction(null); 447 } 448 449 private static class IndexChooser implements ComponentChooser { 450 451 private int curIndex = 0; 452 private int index; 453 private ComponentChooser chooser; 454 455 public IndexChooser(ComponentChooser ch, int i) { 456 index = i; 457 chooser = ch; 458 curIndex = 0; 459 } 460 461 @Override 462 public boolean checkComponent(Component comp) { 463 if ((FIND_INVISIBLE_WINDOWS || (comp.isShowing() && comp.isVisible())) 464 && chooser.checkComponent(comp)) { 465 if (curIndex == index) { 466 return true; 467 } 468 curIndex++; 469 } 470 return false; 471 } 472 473 @Override 474 public String getDescription() { 475 return chooser.getDescription(); 476 } 477 478 @Override 479 public String toString() { 480 return "IndexChooser{" + "curIndex=" + curIndex + ", index=" + index + ", chooser=" + chooser + '}'; 481 } 482 } 483 }