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.Choice;
26import java.awt.Component;
27import java.awt.Container;
28import java.awt.event.ItemListener;
29import java.util.Hashtable;
30
31import org.netbeans.jemmy.ComponentChooser;
32import org.netbeans.jemmy.JemmyException;
33import org.netbeans.jemmy.Outputable;
34import org.netbeans.jemmy.TestOut;
35import org.netbeans.jemmy.TimeoutExpiredException;
36import org.netbeans.jemmy.drivers.DriverManager;
37import org.netbeans.jemmy.drivers.ListDriver;
38
39/**
40 *
41 * <BR><BR>Timeouts used: <BR>
42 * ButtonOperator.PushButtonTimeout - time between choice pressing and
43 * releasing<BR>
44 * ComponentOperator.WaitComponentTimeout - time to wait choice displayed <BR>
45 * ComponentOperator.WaitComponentEnabledTimeout - time to wait choice enabled
46 * <BR>.
47 *
48 * @see org.netbeans.jemmy.Timeouts
49 *
50 * @author Alexandre Iline (alexandre.iline@oracle.com)
51 *
52 */
53public class ChoiceOperator extends ComponentOperator implements Outputable {
54
55    /**
56     * Identifier for a selected item property.
57     *
58     * @see #getDump
59     */
60    public static final String SELECTED_ITEM_DPROP = "Selected item";
61
62    /**
63     * Identifier for a items properties.
64     *
65     * @see #getDump
66     */
67    public static final String ITEM_PREFIX_DPROP = "Item";
68
69    private TestOut output;
70    private ListDriver driver;
71
72    /**
73     * Constructor.
74     *
75     * @param b a component
76     */
77    public ChoiceOperator(Choice b) {
78        super(b);
79        driver = DriverManager.getListDriver(getClass());
80    }
81
82    /**
83     * Constructs a ChoiceOperator object.
84     *
85     * @param cont container
86     * @param chooser a component chooser specifying searching criteria.
87     * @param index an index between appropriate ones.
88     */
89    public ChoiceOperator(ContainerOperator<?> cont, ComponentChooser chooser, int index) {
90        this((Choice) cont.
91                waitSubComponent(new ChoiceFinder(chooser),
92                        index));
93        copyEnvironment(cont);
94    }
95
96    /**
97     * Constructs a ChoiceOperator object.
98     *
99     * @param cont container
100     * @param chooser a component chooser specifying searching criteria.
101     */
102    public ChoiceOperator(ContainerOperator<?> cont, ComponentChooser chooser) {
103        this(cont, chooser, 0);
104    }
105
106    /**
107     * Constructor. Waits component in container first. Uses cont's timeout and
108     * output for waiting and to init operator.
109     *
110     * @param cont container
111     * @param text Choice text.
112     * @param index Ordinal component index.
113     * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
114     * @throws TimeoutExpiredException
115     */
116    public ChoiceOperator(ContainerOperator<?> cont, String text, int index) {
117        this((Choice) waitComponent(cont,
118                new ChoiceBySelectedItemFinder(text,
119                        cont.getComparator()),
120                index));
121        copyEnvironment(cont);
122    }
123
124    /**
125     * Constructor. Waits component in container first. Uses cont's timeout and
126     * output for waiting and to init operator.
127     *
128     * @param cont container
129     * @param text Choice text.
130     * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
131     * @throws TimeoutExpiredException
132     */
133    public ChoiceOperator(ContainerOperator<?> cont, String text) {
134        this(cont, text, 0);
135    }
136
137    /**
138     * Constructor. Waits component in container first. Uses cont's timeout and
139     * output for waiting and to init operator.
140     *
141     * @param cont container
142     * @param index Ordinal component index.
143     * @throws TimeoutExpiredException
144     */
145    public ChoiceOperator(ContainerOperator<?> cont, int index) {
146        this((Choice) waitComponent(cont,
147                new ChoiceFinder(),
148                index));
149        copyEnvironment(cont);
150    }
151
152    /**
153     * Constructor. Waits component in container first. Uses cont's timeout and
154     * output for waiting and to init operator.
155     *
156     * @param cont container
157     * @throws TimeoutExpiredException
158     */
159    public ChoiceOperator(ContainerOperator<?> cont) {
160        this(cont, 0);
161    }
162
163    /**
164     * Searches Choice in container.
165     *
166     * @param cont Container to search component in.
167     * @param chooser org.netbeans.jemmy.ComponentChooser implementation.
168     * @param index Ordinal component index.
169     * @return Choice instance or null if component was not found.
170     */
171    public static Choice findChoice(Container cont, ComponentChooser chooser, int index) {
172        return (Choice) findComponent(cont, new ChoiceFinder(chooser), index);
173    }
174
175    /**
176     * Searches 0'th Choice in container.
177     *
178     * @param cont Container to search component in.
179     * @param chooser org.netbeans.jemmy.ComponentChooser implementation.
180     * @return Choice instance or null if component was not found.
181     */
182    public static Choice findChoice(Container cont, ComponentChooser chooser) {
183        return findChoice(cont, chooser, 0);
184    }
185
186    /**
187     * Searches Choice by text.
188     *
189     * @param cont Container to search component in.
190     * @param text Choice text. If null, contents is not checked.
191     * @param ce Compare text exactly.
192     * @param ccs Compare text case sensitively.
193     * @param index Ordinal component index.
194     * @return Choice instance or null if component was not found.
195     * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
196     */
197    public static Choice findChoice(Container cont, String text, boolean ce, boolean ccs, int index) {
198        return (findChoice(cont,
199                new ChoiceBySelectedItemFinder(text,
200                        new DefaultStringComparator(ce, ccs)),
201                index));
202    }
203
204    /**
205     * Searches Choice by text.
206     *
207     * @param cont Container to search component in.
208     * @param text Choice text. If null, contents is not checked.
209     * @param ce Compare text exactly.
210     * @param ccs Compare text case sensitively.
211     * @return Choice instance or null if component was not found.
212     * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
213     */
214    public static Choice findChoice(Container cont, String text, boolean ce, boolean ccs) {
215        return findChoice(cont, text, ce, ccs, 0);
216    }
217
218    /**
219     * Waits Choice in container.
220     *
221     * @param cont Container to search component in.
222     * @param chooser org.netbeans.jemmy.ComponentChooser implementation.
223     * @param index Ordinal component index.
224     * @return Choice instance.
225     * @throws TimeoutExpiredException
226     */
227    public static Choice waitChoice(Container cont, ComponentChooser chooser, int index) {
228        return (Choice) waitComponent(cont, new ChoiceFinder(chooser), index);
229    }
230
231    /**
232     * Waits 0'th Choice in container.
233     *
234     * @param cont Container to search component in.
235     * @param chooser org.netbeans.jemmy.ComponentChooser implementation.
236     * @return Choice instance.
237     * @throws TimeoutExpiredException
238     */
239    public static Choice waitChoice(Container cont, ComponentChooser chooser) {
240        return waitChoice(cont, chooser, 0);
241    }
242
243    /**
244     * Waits Choice by text.
245     *
246     * @param cont Container to search component in.
247     * @param text Choice text. If null, contents is not checked.
248     * @param ce Compare text exactly.
249     * @param ccs Compare text case sensitively.
250     * @param index Ordinal component index.
251     * @return Choice instance.
252     * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
253     * @throws TimeoutExpiredException
254     */
255    public static Choice waitChoice(Container cont, String text, boolean ce, boolean ccs, int index) {
256        return (waitChoice(cont,
257                new ChoiceBySelectedItemFinder(text,
258                        new DefaultStringComparator(ce, ccs)),
259                index));
260    }
261
262    /**
263     * Waits Choice by text.
264     *
265     * @param cont Container to search component in.
266     * @param text Choice text. If null, contents is not checked.
267     * @param ce Compare text exactly.
268     * @param ccs Compare text case sensitively.
269     * @return Choice instance.
270     * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
271     * @throws TimeoutExpiredException
272     */
273    public static Choice waitChoice(Container cont, String text, boolean ce, boolean ccs) {
274        return waitChoice(cont, text, ce, ccs, 0);
275    }
276
277    @Override
278    public void setOutput(TestOut out) {
279        output = out;
280        super.setOutput(output.createErrorOutput());
281    }
282
283    @Override
284    public TestOut getOutput() {
285        return output;
286    }
287
288    @Override
289    public void copyEnvironment(Operator anotherOperator) {
290        super.copyEnvironment(anotherOperator);
291        driver
292                = (ListDriver) DriverManager.
293                getDriver(DriverManager.LIST_DRIVER_ID,
294                        getClass(),
295                        anotherOperator.getProperties());
296    }
297
298    /**
299     * Finds an item between choice items.
300     *
301     * @param item a text pattern.
302     * @param index an ordinal index between appropriate items.
303     * @return an item index.
304     */
305    public int findItemIndex(String item, int index) {
306        return findItemIndex(item, getComparator(), index);
307    }
308
309    /**
310     * Finds an item between choice items.
311     *
312     * @param item a text pattern.
313     * @return an item index.
314     */
315    public int findItemIndex(String item) {
316        return findItemIndex(item, 0);
317    }
318
319    /**
320     * Selects an item by text.
321     *
322     * @param item a text pattern.
323     * @param index an ordinal index between appropriate items.
324     */
325    public void selectItem(String item, int index) {
326        selectItem(item, getComparator(), index);
327    }
328
329    /**
330     * Selects an item by text.
331     *
332     * @param item a text pattern.
333     */
334    public void selectItem(String item) {
335        selectItem(item, 0);
336    }
337
338    /**
339     * Selects an item by index.
340     *
341     * @param index an item index.
342     */
343    public void selectItem(int index) {
344        output.printLine("Select " + Integer.toString(index) + "`th item in combobox\n    : "
345                + toStringSource());
346        output.printGolden("Select " + Integer.toString(index) + "`th item in combobox");
347        makeComponentVisible();
348        try {
349            waitComponentEnabled();
350        } catch (InterruptedException e) {
351            throw (new JemmyException("Interrupted!", e));
352        }
353        driver.selectItem(this, index);
354        if (getVerification()) {
355            waitItemSelected(index);
356        }
357    }
358
359    /**
360     * Waits for item to be selected.
361     *
362     * @param index Item index.
363     */
364    public void waitItemSelected(final int index) {
365        getOutput().printLine("Wait " + Integer.toString(index)
366                + "'th item to be selected in component \n    : "
367                + toStringSource());
368        getOutput().printGolden("Wait " + Integer.toString(index)
369                + "'th item to be selected");
370        waitState(new ComponentChooser() {
371            @Override
372            public boolean checkComponent(Component comp) {
373                return getSelectedIndex() == index;
374            }
375
376            @Override
377            public String getDescription() {
378                return "Has " + Integer.toString(index) + "'th item selected";
379            }
380
381            @Override
382            public String toString() {
383                return "ChoiceOperator.waitItemSelected.ComponentChooser{description = " + getDescription() + '}';
384            }
385        });
386    }
387
388    /**
389     * Returns information about component.
390     */
391    @Override
392    public Hashtable<String, Object> getDump() {
393        Hashtable<String, Object> result = super.getDump();
394        if (((Choice) getSource()).getSelectedItem() != null) {
395            result.put(SELECTED_ITEM_DPROP, ((Choice) getSource()).getSelectedItem());
396        }
397        String[] items = new String[((Choice) getSource()).getItemCount()];
398        for (int i = 0; i < ((Choice) getSource()).getItemCount(); i++) {
399            items[i] = ((Choice) getSource()).getItem(i);
400        }
401        addToDump(result, ITEM_PREFIX_DPROP, items);
402        return result;
403    }
404
405    ////////////////////////////////////////////////////////
406    //Mapping                                             //
407    /**
408     * Maps {@code Choice.add(String)} through queue
409     */
410    public void add(final String item) {
411        runMapping(new MapVoidAction("add") {
412            @Override
413            public void map() {
414                ((Choice) getSource()).add(item);
415            }
416        });
417    }
418
419    /**
420     * Maps {@code Choice.addItemListener(ItemListener)} through queue
421     */
422    public void addItemListener(final ItemListener itemListener) {
423        runMapping(new MapVoidAction("addItemListener") {
424            @Override
425            public void map() {
426                ((Choice) getSource()).addItemListener(itemListener);
427            }
428        });
429    }
430
431    /**
432     * Maps {@code Choice.addNotify()} through queue
433     */
434    @Override
435    public void addNotify() {
436        runMapping(new MapVoidAction("addNotify") {
437            @Override
438            public void map() {
439                getSource().addNotify();
440            }
441        });
442    }
443
444    /**
445     * Maps {@code Choice.getItem(int)} through queue
446     */
447    public String getItem(final int index) {
448        return (runMapping(new MapAction<String>("getItem") {
449            @Override
450            public String map() {
451                return ((Choice) getSource()).getItem(index);
452            }
453        }));
454    }
455
456    /**
457     * Maps {@code Choice.getItemCount()} through queue
458     */
459    public int getItemCount() {
460        return (runMapping(new MapIntegerAction("getItemCount") {
461            @Override
462            public int map() {
463                return ((Choice) getSource()).getItemCount();
464            }
465        }));
466    }
467
468    /**
469     * Maps {@code Choice.getSelectedIndex()} through queue
470     */
471    public int getSelectedIndex() {
472        return (runMapping(new MapIntegerAction("getSelectedIndex") {
473            @Override
474            public int map() {
475                return ((Choice) getSource()).getSelectedIndex();
476            }
477        }));
478    }
479
480    /**
481     * Maps {@code Choice.getSelectedItem()} through queue
482     */
483    public String getSelectedItem() {
484        return (runMapping(new MapAction<String>("getSelectedItem") {
485            @Override
486            public String map() {
487                return ((Choice) getSource()).getSelectedItem();
488            }
489        }));
490    }
491
492    /**
493     * Maps {@code Choice.insert(String)} through queue
494     */
495    public void insert(final String item, final int index) {
496        runMapping(new MapVoidAction("insert") {
497            @Override
498            public void map() {
499                ((Choice) getSource()).insert(item, index);
500            }
501        });
502    }
503
504    /**
505     * Maps {@code Choice.remove(int)} through queue
506     */
507    public void remove(final int position) {
508        runMapping(new MapVoidAction("remove") {
509            @Override
510            public void map() {
511                ((Choice) getSource()).remove(position);
512            }
513        });
514    }
515
516    /**
517     * Maps {@code Choice.remove(String)} through queue
518     */
519    public void remove(final String item) {
520        runMapping(new MapVoidAction("remove") {
521            @Override
522            public void map() {
523                ((Choice) getSource()).remove(item);
524            }
525        });
526    }
527
528    /**
529     * Maps {@code Choice.removeAll()} through queue
530     */
531    public void removeAll() {
532        runMapping(new MapVoidAction("removeAll") {
533            @Override
534            public void map() {
535                ((Choice) getSource()).removeAll();
536            }
537        });
538    }
539
540    /**
541     * Maps {@code Choice.removeItemListener(ItemListener)} through queue
542     */
543    public void removeItemListener(final ItemListener itemListener) {
544        runMapping(new MapVoidAction("removeItemListener") {
545            @Override
546            public void map() {
547                ((Choice) getSource()).removeItemListener(itemListener);
548            }
549        });
550    }
551
552    /**
553     * Maps {@code Choice.select(int)} through queue
554     */
555    public void select(final int pos) {
556        runMapping(new MapVoidAction("select") {
557            @Override
558            public void map() {
559                ((Choice) getSource()).select(pos);
560            }
561        });
562    }
563
564    /**
565     * Maps {@code Choice.select(String)} through queue
566     */
567    public void setState(final String str) {
568        runMapping(new MapVoidAction("select") {
569            @Override
570            public void map() {
571                ((Choice) getSource()).select(str);
572            }
573        });
574    }
575
576    //End of mapping                                      //
577    ////////////////////////////////////////////////////////
578    private int findItemIndex(String item, StringComparator comparator, int index) {
579        int count = 0;
580        for (int i = 0; i < getItemCount(); i++) {
581            if (comparator.equals(getItem(i), item)) {
582                if (count == index) {
583                    return i;
584                } else {
585                    count++;
586                }
587            }
588        }
589        return -1;
590    }
591
592    private void selectItem(String item, StringComparator comparator, int index) {
593        selectItem(findItemIndex(item, comparator, index));
594    }
595
596    /**
597     * Allows to find component by label.
598     */
599    public static class ChoiceBySelectedItemFinder implements ComponentChooser {
600
601        String label;
602        StringComparator comparator;
603
604        /**
605         * Constructs ChoiceBySelectedItemFinder.
606         *
607         * @param lb a text pattern
608         * @param comparator specifies string comparision algorithm.
609         */
610        public ChoiceBySelectedItemFinder(String lb, StringComparator comparator) {
611            label = lb;
612            this.comparator = comparator;
613        }
614
615        /**
616         * Constructs ChoiceBySelectedItemFinder.
617         *
618         * @param lb a text pattern
619         */
620        public ChoiceBySelectedItemFinder(String lb) {
621            this(lb, Operator.getDefaultStringComparator());
622        }
623
624        @Override
625        public boolean checkComponent(Component comp) {
626            if (comp instanceof Choice) {
627                if (((Choice) comp).getSelectedItem() != null) {
628                    return (comparator.equals(((Choice) comp).getSelectedItem(),
629                            label));
630                }
631            }
632            return false;
633        }
634
635        @Override
636        public String getDescription() {
637            return "Choice with label \"" + label + "\"";
638        }
639
640        @Override
641        public String toString() {
642            return "ChoiceBySelectedItemFinder{" + "label=" + label + ", comparator=" + comparator + '}';
643        }
644    }
645
646    /**
647     * Checks component type.
648     */
649    public static class ChoiceFinder extends Finder {
650
651        /**
652         * Constructs ChoiceFinder.
653         *
654         * @param sf other searching criteria.
655         */
656        public ChoiceFinder(ComponentChooser sf) {
657            super(Choice.class, sf);
658        }
659
660        /**
661         * Constructs ChoiceFinder.
662         */
663        public ChoiceFinder() {
664            super(Choice.class);
665        }
666    }
667}
668