FrameWaiter.java revision 13978:1993af50385d
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 */
23package org.netbeans.jemmy;
24
25import java.awt.Component;
26import java.awt.Frame;
27
28/**
29 *
30 * Contains methods to search and wait Frame. A FrameWaiter is a utility class
31 * used to look or wait for Frames. It contains methods to search for a Frame
32 * among the currently showing Frames as well as methods that wait for a Frame
33 * to show within an allotted time period.
34 *
35 * <BR><BR>Timeouts used: <BR>
36 * FrameWaiter.WaitFrameTimeout - time to wait frame displayed. <BR>
37 * FrameWaiter.AfterFrameTimeout - time to sleep after frame has been displayed.
38 * <BR>
39 *
40 * @see org.netbeans.jemmy.Timeouts
41 *
42 * @author Alexandre Iline (alexandre.iline@oracle.com)
43 */
44public class FrameWaiter extends WindowWaiter implements Timeoutable, Outputable {
45
46    private final static long WAIT_TIME = 60000;
47    private final static long AFTER_WAIT_TIME = 0;
48
49    private Timeouts timeouts;
50    private TestOut output;
51
52    /**
53     * Constructor.
54     */
55    public FrameWaiter() {
56        super();
57        setTimeouts(JemmyProperties.getProperties().getTimeouts());
58        setOutput(JemmyProperties.getProperties().getOutput());
59    }
60
61    /**
62     * Searches for a Frame. Search among the currently showing Frames for one
63     * that meets the search criteria applied by the
64     * {@code ComponentChooser} parameter.
65     *
66     * @param cc A component chooser used to define and apply the search
67     * criteria.
68     * @return a reference to the first Frame that is showing and that meets the
69     * search criteria. If no such Frame can be found, a {@code null}
70     * reference is returned.
71     */
72    public static Frame getFrame(ComponentChooser cc) {
73        return (Frame) WindowWaiter.getWindow(new FrameSubChooser(cc));
74    }
75
76    /**
77     * Searches for a Frame. The search proceeds among the currently showing
78     * Frames for the {@code index+1}'th Frame that meets the criteria
79     * defined and applied by the {@code ComonentChooser} parameter.
80     *
81     * @param cc A component chooser used to define and apply the search
82     * criteria.
83     * @param index The ordinal index of the Frame in the set of currently
84     * displayed Frames. The first index is 0.
85     * @return a reference to the {@code index+1}'th Frame that is showing
86     * and that meets the search criteria. If there are fewer than
87     * {@code index+1} Frames, a {@code null} reference is returned.
88     */
89    public static Frame getFrame(ComponentChooser cc, int index) {
90        return (Frame) WindowWaiter.getWindow(new FrameSubChooser(cc), index);
91    }
92
93    /**
94     * Searches for a Frame by title. The search proceeds among the currently
95     * showing Frames for the first with a suitable title.
96     *
97     * @param title Frame title or subtitle.
98     * @param ce If {@code true} and the search is case sensitive, then a
99     * match occurs when the {@code title} argument is a substring of a
100     * Frame title. If {@code false} and the search is case sensitive, then
101     * the {@code title} argument and the Frame title must be the same. If
102     * {@code true} and the search is case insensitive, then a match occurs
103     * when the {@code title} argument is a substring of the Frame title
104     * after changing both to upper case. If {@code false} and the search
105     * is case insensitive, then a match occurs when the {@code title}
106     * argument is a substring of the Frame title after changing both to upper
107     * case.
108     * @param cc If {@code true} the search is case sensitive; otherwise,
109     * the search is case insensitive.
110     * @return a reference to the first Frame that is showing and that has a
111     * suitable title. If no such Frame can be found, a {@code null}
112     * reference is returned.
113     */
114    public static Frame getFrame(String title, boolean ce, boolean cc) {
115        return (Frame) WindowWaiter.getWindow(new FrameByTitleChooser(title, ce, cc));
116    }
117
118    /**
119     * Searches for a Frame by title. The search is for the
120     * {@code index+1}'th Frame among the currently showing Frames that
121     * possess a suitable title.
122     *
123     * @param title Frame title or subtitle.
124     * @param ce If {@code true} and the search is case sensitive, then a
125     * match occurs when the {@code title} argument is a substring of a
126     * Frame title. If {@code false} and the search is case sensitive, then
127     * the {@code title} argument and the Frame title must be the same. If
128     * {@code true} and the search is case insensitive, then a match occurs
129     * when the {@code title} argument is a substring of the Frame title
130     * after changing both to upper case. If {@code false} and the search
131     * is case insensitive, then a match occurs when the {@code title}
132     * argument is a substring of the Frame title after changing both to upper
133     * case.
134     * @param cc If {@code true} the search is case sensitive; otherwise,
135     * the search is case insensitive.
136     * @param index The ordinal index of the Frame in the set of currently
137     * displayed Frames. The first index is 0.
138     * @return a reference to the {@code index+1}'th Frame that is showing
139     * and that has a suitable title. If there are fewer than
140     * {@code index+1} Frames, a {@code null} reference is returned.
141     */
142    public static Frame getFrame(String title, boolean ce, boolean cc, int index) {
143        return (Frame) WindowWaiter.getWindow(new FrameByTitleChooser(title, ce, cc), index);
144    }
145
146    static {
147        Timeouts.initDefault("FrameWaiter.WaitFrameTimeout", WAIT_TIME);
148        Timeouts.initDefault("FrameWaiter.AfterFrameTimeout", AFTER_WAIT_TIME);
149    }
150
151    /**
152     * Defines current timeouts.
153     *
154     * @param timeouts A collection of timeout assignments.
155     * @see org.netbeans.jemmy.Timeoutable
156     * @see org.netbeans.jemmy.Timeouts
157     * @see #getTimeouts
158     */
159    @Override
160    public void setTimeouts(Timeouts timeouts) {
161        this.timeouts = timeouts;
162        Timeouts times = timeouts.cloneThis();
163        times.setTimeout("WindowWaiter.WaitWindowTimeout",
164                timeouts.getTimeout("FrameWaiter.WaitFrameTimeout"));
165        times.setTimeout("WindowWaiter.AfterWindowTimeout",
166                timeouts.getTimeout("FrameWaiter.AfterFrameTimeout"));
167        super.setTimeouts(times);
168    }
169
170    /**
171     * Return current timeouts.
172     *
173     * @return the collection of current timeout assignments.
174     * @see org.netbeans.jemmy.Timeoutable
175     * @see org.netbeans.jemmy.Timeouts
176     * @see #setTimeouts
177     */
178    @Override
179    public Timeouts getTimeouts() {
180        return timeouts;
181    }
182
183    /**
184     * Defines print output streams or writers.
185     *
186     * @param output Identify the streams or writers used for print output.
187     * @see org.netbeans.jemmy.Outputable
188     * @see org.netbeans.jemmy.TestOut
189     * @see #getOutput
190     */
191    @Override
192    public void setOutput(TestOut output) {
193        this.output = output;
194        super.setOutput(output);
195    }
196
197    /**
198     * Returns print output streams or writers.
199     *
200     * @return an object that contains references to objects for printing to
201     * output and err streams.
202     * @see org.netbeans.jemmy.Outputable
203     * @see org.netbeans.jemmy.TestOut
204     * @see #setOutput
205     */
206    @Override
207    public TestOut getOutput() {
208        return output;
209    }
210
211    /**
212     * Waits for a Frame to show. Wait for the {@code index+1}'th Frame
213     * that meets the criteria defined and applied by the
214     * {@code ComonentChooser} parameter to show up.
215     *
216     * @param ch A component chooser used to define and apply the search
217     * criteria.
218     * @param index The ordinal index of the Frame in the set of currently
219     * displayed Frames. The first index is 0.
220     * @return a reference to the {@code index+1}'th Frame that shows and
221     * that meets the search criteria. If fewer than {@code index+1} Frames
222     * show up in the allotted time period then a {@code null} reference is
223     * returned.
224     * @throws TimeoutExpiredException
225     * @see org.netbeans.jemmy.WindowWaiter#actionProduced(Object)
226     * @exception InterruptedException
227     */
228    public Frame waitFrame(ComponentChooser ch, int index)
229            throws InterruptedException {
230        setTimeouts(timeouts);
231        return (Frame) waitWindow(new FrameSubChooser(ch), index);
232    }
233
234    /**
235     * Waits for a Frame to show. Wait for a Frame that meets the search
236     * criteria applied by the {@code ComponentChooser} parameter to show
237     * up.
238     *
239     * @param ch A component chooser used to define and apply the search
240     * criteria.
241     * @return a reference to the first Frame that shows and that meets the
242     * search criteria. If no such Frame can be found within the time period
243     * allotted, a {@code null} reference is returned.
244     * @throws TimeoutExpiredException
245     * @see org.netbeans.jemmy.WindowWaiter#actionProduced(Object)
246     * @exception InterruptedException
247     */
248    public Frame waitFrame(ComponentChooser ch)
249            throws InterruptedException {
250        return waitFrame(ch, 0);
251    }
252
253    /**
254     * Waits for a Frame to show. Wait for the {@code index+1}'th Frame to
255     * show with a suitable title.
256     *
257     * @param title Frame title or subtitle.
258     * @param compareExactly If {@code true} and the search is case
259     * sensitive, then a match occurs when the {@code title} argument is a
260     * substring of a Frame title. If {@code false} and the search is case
261     * sensitive, then the {@code title} argument and the Frame title must
262     * be the same. If {@code true} and the search is case insensitive,
263     * then a match occurs when the {@code title} argument is a substring
264     * of the Frame title after changing both to upper case. If
265     * {@code false} and the search is case insensitive, then a match
266     * occurs when the {@code title} argument is a substring of the Frame
267     * title after changing both to upper case.
268     * @param compareCaseSensitive If {@code true} the search is case
269     * sensitive; otherwise, the search is case insensitive.
270     * @param index The ordinal index of the Frame in the set of currently
271     * displayed Frames with the proper window ownership and a suitable title.
272     * The first index is 0.
273     * @return a reference to the {@code index+1}'th Frame to show and that
274     * has a suitable title. If no such Frame can be found within the time
275     * period allotted, a {@code null} reference is returned.
276     * @throws TimeoutExpiredException
277     * @see org.netbeans.jemmy.WindowWaiter#actionProduced(Object)
278     * @exception InterruptedException
279     */
280    public Frame waitFrame(String title, boolean compareExactly, boolean compareCaseSensitive, int index)
281            throws InterruptedException {
282        return waitFrame(new FrameByTitleChooser(title, compareExactly, compareCaseSensitive), index);
283    }
284
285    /**
286     * Waits for a Frame to show. Wait for the first Frame to show with a
287     * suitable title.
288     *
289     * @param title Frame title or subtitle.
290     * @param compareExactly If {@code true} and the search is case
291     * sensitive, then a match occurs when the {@code title} argument is a
292     * substring of a Frame title. If {@code false} and the search is case
293     * sensitive, then the {@code title} argument and the Frame title must
294     * be the same. If {@code true} and the search is case insensitive,
295     * then a match occurs when the {@code title} argument is a substring
296     * of the Frame title after changing both to upper case. If
297     * {@code false} and the search is case insensitive, then a match
298     * occurs when the {@code title} argument is a substring of the Frame
299     * title after changing both to upper case.
300     * @param compareCaseSensitive If {@code true} the search is case
301     * sensitive; otherwise, the search is case insensitive.
302     * @return a reference to the first Frame to show and that has a suitable
303     * title. If no such Frame can be found within the time period allotted, a
304     * {@code null} reference is returned.
305     * @throws TimeoutExpiredException
306     * @see org.netbeans.jemmy.WindowWaiter#actionProduced(Object)
307     * @exception InterruptedException
308     */
309    public Frame waitFrame(String title, boolean compareExactly, boolean compareCaseSensitive)
310            throws InterruptedException {
311        return waitFrame(title, compareExactly, compareCaseSensitive, 0);
312    }
313
314    /**
315     * @see Waiter#getWaitingStartedMessage()
316     */
317    @Override
318    protected String getWaitingStartedMessage() {
319        return "Start to wait frame \"" + getComponentChooser().getDescription() + "\" opened";
320    }
321
322    /**
323     * Overrides WindowWaiter.getTimeoutExpiredMessage. Returns the timeout
324     * expired message value.
325     *
326     * @param timeSpent Time spent for waiting
327     * @return a message tring
328     * @see Waiter#getTimeoutExpiredMessage(long)
329     */
330    @Override
331    protected String getTimeoutExpiredMessage(long timeSpent) {
332        return ("Frame \"" + getComponentChooser().getDescription() + "\" has not been opened in "
333                + timeSpent + " milliseconds");
334    }
335
336    /**
337     * Overrides WindowWaiter.getActionProducedMessage. Returns the action
338     * produced message value.
339     *
340     * @param timeSpent Time spent for waiting.
341     * @param result A message string.
342     * @return a message tring
343     * @see Waiter#getActionProducedMessage(long, Object)
344     */
345    @Override
346    protected String getActionProducedMessage(long timeSpent, final Object result) {
347        String resultToString = null;
348        if (result instanceof Component) {
349            // run toString in dispatch thread
350            resultToString = new QueueTool().invokeSmoothly(
351                    new QueueTool.QueueAction<String>("result.toString()") {
352                @Override
353                public String launch() {
354                    return result.toString();
355                }
356            }
357            );
358        } else {
359            resultToString = result.toString();
360        }
361        return ("Frame \"" + getComponentChooser().getDescription() + "\" has been opened in "
362                + timeSpent + " milliseconds"
363                + "\n    " + resultToString);
364    }
365
366    /**
367     * @see Waiter#getGoldenWaitingStartedMessage()
368     */
369    @Override
370    protected String getGoldenWaitingStartedMessage() {
371        return "Start to wait frame \"" + getComponentChooser().getDescription() + "\" opened";
372    }
373
374    /**
375     * @see Waiter#getGoldenTimeoutExpiredMessage()
376     */
377    @Override
378    protected String getGoldenTimeoutExpiredMessage() {
379        return "Frame \"" + getComponentChooser().getDescription() + "\" has not been opened";
380    }
381
382    /**
383     * @see Waiter#getGoldenActionProducedMessage()
384     */
385    @Override
386    protected String getGoldenActionProducedMessage() {
387        return "Frame \"" + getComponentChooser().getDescription() + "\" has been opened";
388    }
389
390    private static class FrameSubChooser implements ComponentChooser {
391
392        private ComponentChooser chooser;
393
394        public FrameSubChooser(ComponentChooser c) {
395            super();
396            chooser = c;
397        }
398
399        @Override
400        public boolean checkComponent(Component comp) {
401            if (comp instanceof Frame) {
402                return ((FIND_INVISIBLE_WINDOWS || (comp.isShowing() && comp.isVisible()))
403                        && chooser.checkComponent(comp));
404            } else {
405                return false;
406            }
407        }
408
409        @Override
410        public String getDescription() {
411            return chooser.getDescription();
412        }
413
414        @Override
415        public String toString() {
416            return "FrameSubChooser{" + "chooser=" + chooser + '}';
417        }
418    }
419
420    private static class FrameByTitleChooser implements ComponentChooser {
421
422        String title;
423        boolean compareExactly;
424        boolean compareCaseSensitive;
425
426        public FrameByTitleChooser(String t, boolean ce, boolean cc) {
427            super();
428            title = t;
429            compareExactly = ce;
430            compareCaseSensitive = cc;
431        }
432
433        @Override
434        public boolean checkComponent(Component comp) {
435            if (comp instanceof Frame) {
436                if ((FIND_INVISIBLE_WINDOWS || (comp.isShowing() && comp.isVisible()))
437                        && ((Frame) comp).getTitle() != null) {
438                    String titleToComp = ((Frame) comp).getTitle();
439                    String contextToComp = title;
440                    if (compareCaseSensitive) {
441                        titleToComp = titleToComp.toUpperCase();
442                        contextToComp = contextToComp.toUpperCase();
443                    }
444                    if (compareExactly) {
445                        return titleToComp.equals(contextToComp);
446                    } else {
447                        return titleToComp.contains(contextToComp);
448                    }
449                }
450            }
451            return false;
452        }
453
454        @Override
455        public String getDescription() {
456            return title;
457        }
458
459        @Override
460        public String toString() {
461            return "FrameByTitleChooser{" + "title=" + title + ", compareExactly=" + compareExactly + ", compareCaseSensitive=" + compareCaseSensitive + '}';
462        }
463    }
464
465}
466