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.operators;
24
25import java.awt.Component;
26import java.awt.Dialog;
27import java.awt.Window;
28import java.util.Hashtable;
29
30import org.netbeans.jemmy.ComponentChooser;
31import org.netbeans.jemmy.DialogWaiter;
32import org.netbeans.jemmy.JemmyProperties;
33import org.netbeans.jemmy.TestOut;
34import org.netbeans.jemmy.TimeoutExpiredException;
35import org.netbeans.jemmy.Timeouts;
36
37/**
38 * <BR><BR>Timeouts used: <BR>
39 * DialogWaiter.WaitDialogTimeout - time to wait dialog displayed <BR>
40 * DialogWaiter.AfterDialogTimeout - time to sleep after dialog has been
41 * dispayed <BR>
42 * ComponentOperator.WaitStateTimeout - time to wait for title <BR>.
43 *
44 * @see org.netbeans.jemmy.Timeouts
45 *
46 * @author Alexandre Iline (alexandre.iline@oracle.com)
47 *
48 */
49public class DialogOperator extends WindowOperator {
50
51    /**
52     * Identifier for a title property.
53     *
54     * @see #getDump
55     */
56    public static final String TITLE_DPROP = "Title";
57
58    /**
59     * Identifier for a modal property.
60     *
61     * @see #getDump
62     */
63    public static final String IS_MODAL_DPROP = "Modal";
64
65    /**
66     * Identifier for a resizable property.
67     *
68     * @see #getDump
69     */
70    public static final String IS_RESIZABLE_DPROP = "Resizable";
71
72    /**
73     * Constructs a DialogOperator object.
74     *
75     * @param w window
76     */
77    public DialogOperator(Dialog w) {
78        super(w);
79    }
80
81    /**
82     * Constructs a DialogOperator object.
83     *
84     * @param chooser a component chooser specifying searching criteria.
85     * @param index an index between appropriate ones.
86     * @param env an operator to copy environment from.
87     */
88    public DialogOperator(ComponentChooser chooser, int index, Operator env) {
89        this(waitDialog(new DialogFinder(chooser),
90                index,
91                env.getTimeouts(),
92                env.getOutput()));
93        copyEnvironment(env);
94    }
95
96    /**
97     * Constructs a DialogOperator object.
98     *
99     * @param chooser a component chooser specifying searching criteria.
100     * @param index an index between appropriate ones.
101     */
102    public DialogOperator(ComponentChooser chooser, int index) {
103        this(chooser, index, Operator.getEnvironmentOperator());
104    }
105
106    /**
107     * Constructs a DialogOperator object.
108     *
109     * @param chooser a component chooser specifying searching criteria.
110     */
111    public DialogOperator(ComponentChooser chooser) {
112        this(chooser, 0);
113    }
114
115    /**
116     * Constructs a DialogOperator object.
117     *
118     * @param owner window - owner
119     * @param chooser a component chooser specifying searching criteria.
120     * @param index an index between appropriate ones.
121     */
122    public DialogOperator(WindowOperator owner, ComponentChooser chooser, int index) {
123        this((Dialog) owner.
124                waitSubWindow(new DialogFinder(chooser),
125                        index));
126        copyEnvironment(owner);
127    }
128
129    /**
130     * Constructs a DialogOperator object.
131     *
132     * @param owner window - owner
133     * @param chooser a component chooser specifying searching criteria.
134     */
135    public DialogOperator(WindowOperator owner, ComponentChooser chooser) {
136        this(owner, chooser, 0);
137    }
138
139    /**
140     * Constructor. Waits for a dialog to show. The dialog is identified as the
141     * {@code index+1}'th {@code java.awt.Dialog} that shows, is owned
142     * by the window managed by the {@code WindowOperator}
143     * {@code owner}, and that has the desired title. Uses owner's timeout
144     * and output for waiting and to init this operator.
145     *
146     * @param owner Operator pointing to a window owner.
147     * @param title The desired title.
148     * @param index Ordinal index. The first dialog has {@code index} 0.
149     * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
150     * @throws TimeoutExpiredException
151     */
152    public DialogOperator(WindowOperator owner, String title, int index) {
153        this(waitDialog(owner,
154                new DialogByTitleFinder(title,
155                        owner.getComparator()),
156                index));
157        copyEnvironment(owner);
158    }
159
160    /**
161     * Uses owner's timeout and output for waiting and to init operator. Waits
162     * for a dialog to show. The dialog is identified as the first
163     * {@code java.awt.Dialog} that shows, is owned by the window managed
164     * by the {@code WindowOperator} {@code owner}, and that has the
165     * desired title. Uses owner's timeout and output for waiting and to init
166     * this operator.
167     *
168     * @param owner Operator pointing to a window owner.
169     * @param title The desired title.
170     * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
171     * @throws TimeoutExpiredException
172     */
173    public DialogOperator(WindowOperator owner, String title) {
174        this(owner, title, 0);
175    }
176
177    /**
178     * Constructor. Waits for the index'th dialog between owner's children. Uses
179     * owner'th timeout and output for waiting and to init operator.
180     *
181     * @param owner Operator pointing to a window owner.
182     * @param index Ordinal component index.
183     * @throws TimeoutExpiredException
184     */
185    public DialogOperator(WindowOperator owner, int index) {
186        this(waitDialog(owner,
187                new DialogFinder(),
188                index));
189        copyEnvironment(owner);
190    }
191
192    /**
193     * Constructor. Waits for the first dialog between owner's children. Uses
194     * owner'th timeout and output for waiting and to init operator.
195     *
196     * @param owner Operator pointing to a window owner.
197     * @throws TimeoutExpiredException
198     */
199    public DialogOperator(WindowOperator owner) {
200        this(owner, 0);
201    }
202
203    /**
204     * Constructor. Waits for the dialog with "title" subtitle. Constructor can
205     * be used in complicated cases when output or timeouts should differ from
206     * default.
207     *
208     * @param title a window title
209     * @param index Ordinal component index.
210     * @param env an operator to copy environment from.
211     * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
212     * @throws TimeoutExpiredException
213     */
214    public DialogOperator(String title, int index, Operator env) {
215        this(new DialogByTitleFinder(title,
216                env.getComparator()),
217                index,
218                env);
219    }
220
221    /**
222     * Constructor. Waits for the dialog with "title" subtitle. Uses current
223     * timeouts and output values.
224     *
225     * @param title a window title
226     * @param index Ordinal component index.
227     * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
228     * @see JemmyProperties#getCurrentTimeouts()
229     * @see JemmyProperties#getCurrentOutput()
230     * @throws TimeoutExpiredException
231     */
232    public DialogOperator(String title, int index) {
233        this(title, index,
234                ComponentOperator.getEnvironmentOperator());
235    }
236
237    /**
238     * Constructor. Waits for the dialog with "title" subtitle. Uses current
239     * timeouts and output values.
240     *
241     * @param title a window title
242     * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
243     * @see JemmyProperties#getCurrentTimeouts()
244     * @see JemmyProperties#getCurrentOutput()
245     * @throws TimeoutExpiredException
246     */
247    public DialogOperator(String title) {
248        this(title, 0);
249    }
250
251    /**
252     * Constructor. Waits for the index'th dialog. Uses current timeout and
253     * output for waiting and to init operator.
254     *
255     * @param index Ordinal component index.
256     * @throws TimeoutExpiredException
257     */
258    public DialogOperator(int index) {
259        this(waitDialog(new DialogFinder(),
260                index,
261                ComponentOperator.getEnvironmentOperator().getTimeouts(),
262                ComponentOperator.getEnvironmentOperator().getOutput()));
263        copyEnvironment(ComponentOperator.getEnvironmentOperator());
264    }
265
266    /**
267     * Constructor. Waits for the first dialog. Uses current timeout and output
268     * for waiting and to init operator.
269     *
270     * @throws TimeoutExpiredException
271     */
272    public DialogOperator() {
273        this(0);
274    }
275
276    /**
277     * Waits for title. Uses getComparator() comparator.
278     *
279     * @param title Title to wait for.
280     */
281    public void waitTitle(final String title) {
282        getOutput().printLine("Wait \"" + title + "\" title of dialog \n    : "
283                + toStringSource());
284        getOutput().printGolden("Wait \"" + title + "\" title");
285        waitState(new DialogByTitleFinder(title, getComparator()));
286    }
287
288    /**
289     * Returns information about component.
290     */
291    @Override
292    public Hashtable<String, Object> getDump() {
293        Hashtable<String, Object> result = super.getDump();
294        if (((Dialog) getSource()).getTitle() != null) {
295            result.put(TITLE_DPROP, ((Dialog) getSource()).getTitle());
296        }
297        result.put(IS_MODAL_DPROP, ((Dialog) getSource()).isModal() ? "true" : "false");
298        result.put(IS_RESIZABLE_DPROP, ((Dialog) getSource()).isResizable() ? "true" : "false");
299        return result;
300    }
301
302    ////////////////////////////////////////////////////////
303    //Mapping                                             //
304    /**
305     * Maps {@code Dialog.getTitle()} through queue
306     */
307    public String getTitle() {
308        return (runMapping(new MapAction<String>("getTitle") {
309            @Override
310            public String map() {
311                return ((Dialog) getSource()).getTitle();
312            }
313        }));
314    }
315
316    /**
317     * Maps {@code Dialog.isModal()} through queue
318     */
319    public boolean isModal() {
320        return (runMapping(new MapBooleanAction("isModal") {
321            @Override
322            public boolean map() {
323                return ((Dialog) getSource()).isModal();
324            }
325        }));
326    }
327
328    /**
329     * Maps {@code Dialog.isResizable()} through queue
330     */
331    public boolean isResizable() {
332        return (runMapping(new MapBooleanAction("isResizable") {
333            @Override
334            public boolean map() {
335                return ((Dialog) getSource()).isResizable();
336            }
337        }));
338    }
339
340    /**
341     * Maps {@code Dialog.setModal(boolean)} through queue
342     */
343    public void setModal(final boolean b) {
344        runMapping(new MapVoidAction("setModal") {
345            @Override
346            public void map() {
347                ((Dialog) getSource()).setModal(b);
348            }
349        });
350    }
351
352    /**
353     * Maps {@code Dialog.setResizable(boolean)} through queue
354     */
355    public void setResizable(final boolean b) {
356        runMapping(new MapVoidAction("setResizable") {
357            @Override
358            public void map() {
359                ((Dialog) getSource()).setResizable(b);
360            }
361        });
362    }
363
364    /**
365     * Maps {@code Dialog.setTitle(String)} through queue
366     */
367    public void setTitle(final String string) {
368        runMapping(new MapVoidAction("setTitle") {
369            @Override
370            public void map() {
371                ((Dialog) getSource()).setTitle(string);
372            }
373        });
374    }
375
376    //End of mapping                                      //
377    ////////////////////////////////////////////////////////
378    /**
379     * A method to be used from subclasses. Uses timeouts and output passed as
380     * parameters during the waiting.
381     *
382     * @param chooser org.netbeans.jemmy.ComponentChooser implementation.
383     * @param index Ordinal component index.
384     * @param timeouts timeouts to be used during the waiting.
385     * @param output an output to be used during the waiting.
386     * @return Component instance or null if component was not found.
387     */
388    protected static Dialog waitDialog(ComponentChooser chooser, int index,
389            Timeouts timeouts, TestOut output) {
390        try {
391            DialogWaiter waiter = new DialogWaiter();
392            waiter.setTimeouts(timeouts);
393            waiter.setOutput(output);
394            return waiter.waitDialog(new DialogFinder(chooser), index);
395        } catch (InterruptedException e) {
396            output.printStackTrace(e);
397            return null;
398        }
399    }
400
401    /**
402     * A method to be used from subclasses. Uses {@code owner}'s timeouts
403     * and output during the waiting.
404     *
405     * @param owner a window - dialog owner.
406     * @param chooser org.netbeans.jemmy.ComponentChooser implementation.
407     * @param index Ordinal component index.
408     * @return Component instance or null if component was not found.
409     */
410    protected static Dialog waitDialog(WindowOperator owner, ComponentChooser chooser, int index) {
411        return (waitDialog((Window) owner.getSource(),
412                chooser, index,
413                owner.getTimeouts(), owner.getOutput()));
414    }
415
416    /**
417     * A method to be used from subclasses. Uses timeouts and output passed as
418     * parameters during the waiting.
419     *
420     * @param owner a window - dialog owner.
421     * @param chooser org.netbeans.jemmy.ComponentChooser implementation.
422     * @param index Ordinal component index.
423     * @param timeouts timeouts to be used during the waiting.
424     * @param output an output to be used during the waiting.
425     * @return Component instance or null if component was not found.
426     */
427    protected static Dialog waitDialog(Window owner, ComponentChooser chooser, int index,
428            Timeouts timeouts, TestOut output) {
429        try {
430            DialogWaiter waiter = new DialogWaiter();
431            waiter.setTimeouts(timeouts);
432            waiter.setOutput(output);
433            return (waiter.
434                    waitDialog(owner, new DialogFinder(chooser), index));
435        } catch (InterruptedException e) {
436            JemmyProperties.getCurrentOutput().printStackTrace(e);
437            return null;
438        }
439    }
440
441    /**
442     * Checks component type.
443     */
444    public static class DialogFinder extends Finder {
445
446        /**
447         * Constructs DialogFinder.
448         *
449         * @param sf other searching criteria.
450         */
451        public DialogFinder(ComponentChooser sf) {
452            super(Dialog.class, sf);
453        }
454
455        /**
456         * Constructs DialogFinder.
457         */
458        public DialogFinder() {
459            super(Dialog.class);
460        }
461    }
462
463    /**
464     * Allows to find component by title.
465     */
466    public static class DialogByTitleFinder implements ComponentChooser {
467
468        String title;
469        StringComparator comparator;
470
471        /**
472         * Constructs DialogByTitleFinder.
473         *
474         * @param t a text pattern
475         * @param comparator specifies string comparision algorithm.
476         */
477        public DialogByTitleFinder(String t, StringComparator comparator) {
478            title = t;
479            this.comparator = comparator;
480        }
481
482        /**
483         * Constructs DialogByTitleFinder.
484         *
485         * @param t a text pattern
486         */
487        public DialogByTitleFinder(String t) {
488            this(t, Operator.getDefaultStringComparator());
489        }
490
491        @Override
492        public boolean checkComponent(Component comp) {
493            if (comp instanceof Dialog) {
494                if (comp.isShowing() && ((Dialog) comp).getTitle() != null) {
495                    return comparator.equals(((Dialog) comp).getTitle(), title);
496                }
497            }
498            return false;
499        }
500
501        @Override
502        public String getDescription() {
503            return "Dialog with title \"" + title + "\"";
504        }
505
506        @Override
507        public String toString() {
508            return "DialogByTitleFinder{" + "title=" + title + ", comparator=" + comparator + '}';
509        }
510    }
511}
512