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. Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package org.netbeans.jemmy.operators;
26 
27 import java.awt.Component;
28 import java.awt.Container;
29 import java.awt.Dimension;
30 import java.awt.Point;
31 import java.awt.Rectangle;
32 import java.util.Enumeration;
33 import java.util.Hashtable;
34 
35 import javax.swing.JPopupMenu;
36 import javax.swing.JScrollPane;
37 import javax.swing.JTree;
38 import javax.swing.event.TreeExpansionListener;
39 import javax.swing.event.TreeSelectionListener;
40 import javax.swing.event.TreeWillExpandListener;
41 import javax.swing.plaf.TreeUI;
42 import javax.swing.tree.ExpandVetoException;
43 import javax.swing.tree.TreeCellEditor;
44 import javax.swing.tree.TreeCellRenderer;
45 import javax.swing.tree.TreeModel;
46 import javax.swing.tree.TreePath;
47 import javax.swing.tree.TreeSelectionModel;
48 
49 import org.netbeans.jemmy.ComponentChooser;
50 import org.netbeans.jemmy.ComponentSearcher;
51 import org.netbeans.jemmy.JemmyException;
52 import org.netbeans.jemmy.JemmyInputException;
53 import org.netbeans.jemmy.Outputable;
54 import org.netbeans.jemmy.QueueTool;
55 import org.netbeans.jemmy.TestOut;
56 import org.netbeans.jemmy.TimeoutExpiredException;
57 import org.netbeans.jemmy.Timeoutable;
58 import org.netbeans.jemmy.Timeouts;
59 import org.netbeans.jemmy.Waitable;
60 import org.netbeans.jemmy.Waiter;
61 import org.netbeans.jemmy.drivers.DriverManager;
62 import org.netbeans.jemmy.drivers.TreeDriver;
63 import org.netbeans.jemmy.util.EmptyVisualizer;
64 
65 /**
66  * <BR><BR>Timeouts used: <BR>
67  * JTreeOperator.WaitNodeExpandedTimeout - time to wait node expanded <BR>
68  * JTreeOperator.WaitNodeCollapsedTimeout - time to wait node collapsed <BR>
69  * JTreeOperator.WaitAfterNodeExpandedTimeout - time to to sleep after node
70  * expanded <BR>
71  * JTreeOperator.WaitNextNodeTimeout - time to wait next node displayed <BR>
72  * JTreeOperator.WaitNodeVisibleTimeout - time to wait node visible <BR>
73  * JTreeOperator.BeforeEditTimeout - time to sleep before edit click <BR>
74  * JTreeOperator.WaitEditingTimeout - time to wait node editing <BR>
75  * ComponentOperator.WaitComponentTimeout - time to wait component displayed
76  * <BR>
77  * ComponentOperator.WaitStateTimeout - time to wait for path to be expanded,
78  * collapsed, selected, time to wait for a text in a row <BR>
79  * WindowWaiter.WaitWindowTimeout - time to wait popup window displayed <BR>
80  * JScrollBarOperator.WholeScrollTimeout - time for the whole scrolling <BR>.
81  *
82  * @see org.netbeans.jemmy.Timeouts
83  *
84  * @author Alexandre Iline (alexandre.iline@oracle.com)
85  *
86  */
87 public class JTreeOperator extends JComponentOperator
88         implements Timeoutable, Outputable {
89 
90     /**
91      * Identifier for a "root" property.
92      *
93      * @see #getDump
94      */
95     public static final String ROOT_DPROP = "Root";
96 
97     /**
98      * Identifier for a "node" properties.
99      *
100      * @see #getDump
101      */
102     public static final String NODE_PREFIX_DPROP = "Node";
103 
104     /**
105      * Identifier for a "first selected" property.
106      *
107      * @see #getDump
108      */
109     public static final String SELECTION_FIRST_DPROP = "First selected";
110 
111     /**
112      * Identifier for a "last selected" property.
113      *
114      * @see #getDump
115      */
116     public static final String SELECTION_LAST_DPROP = "Last selected";
117 
118     private final static long WAIT_NODE_EXPANDED_TIMEOUT = 60000;
119     private final static long WAIT_NODE_COLLAPSED_TIMEOUT = 60000;
120     private final static long WAIT_AFTER_NODE_EXPANDED_TIMEOUT = 0;
121     private final static long WAIT_NEXT_NODE_TIMEOUT = 60000;
122     private final static long WAIT_NODE_VISIBLE_TIMEOUT = 60000;
123     private final static long BEFORE_EDIT_TIMEOUT = 1000;
124     private final static long WAIT_EDITING_TIMEOUT = 60000;
125 
126     private TestOut output;
127     private Timeouts timeouts;
128     private TreeDriver driver;
129 
130     /**
131      * Constructor.
132      *
133      * @param b a component
134      */
JTreeOperator(JTree b)135     public JTreeOperator(JTree b) {
136         super(b);
137         driver = DriverManager.getTreeDriver(getClass());
138     }
139 
140     /**
141      * Constructs a JTreeOperator object.
142      *
143      * @param cont a container
144      * @param chooser a component chooser specifying searching criteria.
145      * @param index an index between appropriate ones.
146      */
JTreeOperator(ContainerOperator<?> cont, ComponentChooser chooser, int index)147     public JTreeOperator(ContainerOperator<?> cont, ComponentChooser chooser, int index) {
148         this((JTree) cont.
149                 waitSubComponent(new JTreeFinder(chooser),
150                         index));
151         copyEnvironment(cont);
152     }
153 
154     /**
155      * Constructs a JTreeOperator object.
156      *
157      * @param cont a container
158      * @param chooser a component chooser specifying searching criteria.
159      */
JTreeOperator(ContainerOperator<?> cont, ComponentChooser chooser)160     public JTreeOperator(ContainerOperator<?> cont, ComponentChooser chooser) {
161         this(cont, chooser, 0);
162     }
163 
164     /**
165      * Constructor. Waits component in container first. Uses cont's timeout and
166      * output for waiting and to init operator.
167      *
168      * @param cont a container
169      * @param text Text of a row which is currently selected.
170      * @param row a row index to check text in. If equals to -1, selected row is
171      * checked.
172      * @param index Ordinal component index.
173      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
174      * @throws TimeoutExpiredException
175      */
JTreeOperator(ContainerOperator<?> cont, String text, int row, int index)176     public JTreeOperator(ContainerOperator<?> cont, String text, int row, int index) {
177         this((JTree) waitComponent(cont,
178                 new JTreeByItemFinder(text, row,
179                         cont.getComparator()),
180                 index));
181         copyEnvironment(cont);
182     }
183 
184     /**
185      * Constructor. Waits component in container first. Uses cont's timeout and
186      * output for waiting and to init operator.
187      *
188      * @param cont a container
189      * @param text Text of a row which is currently selected.
190      * @param index Ordinal component index.
191      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
192      * @throws TimeoutExpiredException
193      */
JTreeOperator(ContainerOperator<?> cont, String text, int index)194     public JTreeOperator(ContainerOperator<?> cont, String text, int index) {
195         this(cont, text, -1, index);
196     }
197 
198     /**
199      * Constructor. Waits component in container first. Uses cont's timeout and
200      * output for waiting and to init operator.
201      *
202      * @param cont a container
203      * @param text Text of a row which is currently selected.
204      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
205      * @throws TimeoutExpiredException
206      */
JTreeOperator(ContainerOperator<?> cont, String text)207     public JTreeOperator(ContainerOperator<?> cont, String text) {
208         this(cont, text, 0);
209     }
210 
211     /**
212      * Constructor. Waits component in container first. Uses cont's timeout and
213      * output for waiting and to init operator.
214      *
215      * @param cont a container
216      * @param index Ordinal component index.
217      * @throws TimeoutExpiredException
218      */
JTreeOperator(ContainerOperator<?> cont, int index)219     public JTreeOperator(ContainerOperator<?> cont, int index) {
220         this((JTree) waitComponent(cont,
221                 new JTreeFinder(),
222                 index));
223         copyEnvironment(cont);
224     }
225 
226     /**
227      * Constructor. Waits component in container first. Uses cont's timeout and
228      * output for waiting and to init operator.
229      *
230      * @param cont a container
231      * @throws TimeoutExpiredException
232      */
JTreeOperator(ContainerOperator<?> cont)233     public JTreeOperator(ContainerOperator<?> cont) {
234         this(cont, 0);
235     }
236 
237     /**
238      * Searches JTree in container.
239      *
240      * @param cont Container to search component in.
241      * @param chooser org.netbeans.jemmy.ComponentChooser implementation.
242      * @param index Ordinal component index.
243      * @return JTree instance or null if component was not found.
244      */
findJTree(Container cont, ComponentChooser chooser, int index)245     public static JTree findJTree(Container cont, ComponentChooser chooser, int index) {
246         return (JTree) findComponent(cont, new JTreeFinder(chooser), index);
247     }
248 
249     /**
250      * Searches 0'th JTree in container.
251      *
252      * @param cont Container to search component in.
253      * @param chooser org.netbeans.jemmy.ComponentChooser implementation.
254      * @return JTree instance or null if component was not found.
255      */
findJTree(Container cont, ComponentChooser chooser)256     public static JTree findJTree(Container cont, ComponentChooser chooser) {
257         return findJTree(cont, chooser, 0);
258     }
259 
260     /**
261      * Searches JTree by item.
262      *
263      * @param cont Container to search component in.
264      * @param text Item text. If null, contents is not checked.
265      * @param ce Compare text exactly.
266      * @param ccs Compare text case sensitively.
267      * @param rowIndex Index of row to compare text. If -1, selected row is
268      * checked.
269      * @param index Ordinal component index.
270      * @return JTree instance or null if component was not found.
271      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
272      */
findJTree(Container cont, String text, boolean ce, boolean ccs, int rowIndex, int index)273     public static JTree findJTree(Container cont, String text, boolean ce, boolean ccs, int rowIndex, int index) {
274         return findJTree(cont, new JTreeByItemFinder(text, rowIndex, new DefaultStringComparator(ce, ccs)), index);
275     }
276 
277     /**
278      * Searches JTree by item.
279      *
280      * @param cont Container to search component in.
281      * @param text Item text. If null, contents is not checked.
282      * @param ce Compare text exactly.
283      * @param ccs Compare text case sensitively.
284      * @param rowIndex Index of row to compare text. If -1, selected row is
285      * checked.
286      * @return JTree instance or null if component was not found.
287      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
288      */
findJTree(Container cont, String text, boolean ce, boolean ccs, int rowIndex)289     public static JTree findJTree(Container cont, String text, boolean ce, boolean ccs, int rowIndex) {
290         return findJTree(cont, text, ce, ccs, rowIndex, 0);
291     }
292 
293     /**
294      * Waits JTree in container.
295      *
296      * @param cont Container to search component in.
297      * @param chooser org.netbeans.jemmy.ComponentChooser implementation.
298      * @param index Ordinal component index.
299      * @return JTree instance or null if component was not found.
300      * @throws TimeoutExpiredException
301      */
waitJTree(Container cont, ComponentChooser chooser, int index)302     public static JTree waitJTree(Container cont, ComponentChooser chooser, int index) {
303         return (JTree) waitComponent(cont, new JTreeFinder(chooser), index);
304     }
305 
306     /**
307      * Waits 0'th JTree in container.
308      *
309      * @param cont Container to search component in.
310      * @param chooser org.netbeans.jemmy.ComponentChooser implementation.
311      * @return JTree instance or null if component was not found.
312      * @throws TimeoutExpiredException
313      */
waitJTree(Container cont, ComponentChooser chooser)314     public static JTree waitJTree(Container cont, ComponentChooser chooser) {
315         return waitJTree(cont, chooser, 0);
316     }
317 
318     /**
319      * Waits JTree by item.
320      *
321      * @param cont Container to search component in.
322      * @param text Item text. If null, contents is not checked.
323      * @param ce Compare text exactly.
324      * @param ccs Compare text case sensitively.
325      * @param rowIndex Index of row to compare text. If -1, selected row is
326      * checked.
327      * @param index Ordinal component index.
328      * @return JTree instance or null if component was not found.
329      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
330      * @throws TimeoutExpiredException
331      */
waitJTree(Container cont, String text, boolean ce, boolean ccs, int rowIndex, int index)332     public static JTree waitJTree(Container cont, String text, boolean ce, boolean ccs, int rowIndex, int index) {
333         return waitJTree(cont, new JTreeByItemFinder(text, rowIndex, new DefaultStringComparator(ce, ccs)), index);
334     }
335 
336     /**
337      * Waits JTree by item.
338      *
339      * @param cont Container to search component in.
340      * @param text Item text. If null, contents is not checked.
341      * @param ce Compare text exactly.
342      * @param ccs Compare text case sensitively.
343      * @param rowIndex Index of row to compare text. If -1, selected row is
344      * checked.
345      * @return JTree instance or null if component was not found.
346      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
347      * @throws TimeoutExpiredException
348      */
waitJTree(Container cont, String text, boolean ce, boolean ccs, int rowIndex)349     public static JTree waitJTree(Container cont, String text, boolean ce, boolean ccs, int rowIndex) {
350         return waitJTree(cont, text, ce, ccs, rowIndex, 0);
351     }
352 
353     static {
354         Timeouts.initDefault("JTreeOperator.WaitNodeExpandedTimeout", WAIT_NODE_EXPANDED_TIMEOUT);
355         Timeouts.initDefault("JTreeOperator.WaitNodeCollapsedTimeout", WAIT_NODE_COLLAPSED_TIMEOUT);
356         Timeouts.initDefault("JTreeOperator.WaitAfterNodeExpandedTimeout", WAIT_AFTER_NODE_EXPANDED_TIMEOUT);
357         Timeouts.initDefault("JTreeOperator.WaitNextNodeTimeout", WAIT_NEXT_NODE_TIMEOUT);
358         Timeouts.initDefault("JTreeOperator.WaitNodeVisibleTimeout", WAIT_NODE_VISIBLE_TIMEOUT);
359         Timeouts.initDefault("JTreeOperator.BeforeEditTimeout", BEFORE_EDIT_TIMEOUT);
360         Timeouts.initDefault("JTreeOperator.WaitEditingTimeout", WAIT_EDITING_TIMEOUT);
361     }
362 
363     @Override
setTimeouts(Timeouts times)364     public void setTimeouts(Timeouts times) {
365         this.timeouts = times;
366         super.setTimeouts(timeouts);
367     }
368 
369     @Override
getTimeouts()370     public Timeouts getTimeouts() {
371         return timeouts;
372     }
373 
374     @Override
setOutput(TestOut out)375     public void setOutput(TestOut out) {
376         output = out;
377         super.setOutput(output.createErrorOutput());
378     }
379 
380     @Override
getOutput()381     public TestOut getOutput() {
382         return output;
383     }
384 
385     @Override
copyEnvironment(Operator anotherOperator)386     public void copyEnvironment(Operator anotherOperator) {
387         super.copyEnvironment(anotherOperator);
388         driver
389                 = (TreeDriver) DriverManager.
390                 getDriver(DriverManager.TREE_DRIVER_ID,
391                         getClass(),
392                         anotherOperator.getProperties());
393     }
394 
395     /**
396      * Expands path.
397      *
398      * @param path a path to be expanded.
399      * @throws TimeoutExpiredException
400      */
doExpandPath(TreePath path)401     public void doExpandPath(TreePath path) {
402         if (path != null) {
403             output.printLine("Expanding \"" + path.getPathComponent(path.getPathCount() - 1).toString()
404                     + "\" node");
405             output.printGolden("Expanding \"" + path.getPathComponent(path.getPathCount() - 1).toString()
406                     + "\" node");
407             driver.expandItem(this, getRowForPath(path));
408             waitExpanded(path);
409         } else {
410             throw (new NoSuchPathException());
411         }
412     }
413 
414     /**
415      * Expands path on row.
416      *
417      * @param row a row index to be expanded.
418      * @throws TimeoutExpiredException
419      */
doExpandRow(int row)420     public void doExpandRow(int row) {
421         output.printLine("Expanding " + Integer.toString(row)
422                 + " row");
423         output.printGolden("Expanding " + Integer.toString(row)
424                 + " row");
425         driver.expandItem(this, row);
426         waitExpanded(row);
427     }
428 
429     /**
430      * Ensures that the node identified by path is currently viewable.
431      *
432      * @param path a path to be made visible.
433      * @throws TimeoutExpiredException
434      */
doMakeVisible(TreePath path)435     public void doMakeVisible(TreePath path) {
436         if (path != null) {
437             output.printLine("Making \"" + path.toString() + "\" path visible");
438             output.printGolden("Making path visible");
439             makeVisible(path);
440             waitVisible(path);
441         } else {
442             throw (new NoSuchPathException());
443         }
444     }
445 
446     /**
447      * Returns number of child.
448      *
449      * @param node a node to count children of.
450      * @return a number of children.
451      */
getChildCount(final Object node)452     public int getChildCount(final Object node) {
453         return runMapping(new MapIntegerAction("getChildCount") {
454             @Override
455             public int map() {
456                 return ((JTree) getSource()).getModel().getChildCount(node);
457             }
458         });
459     }
460 
461     /**
462      * Returns node children.
463      *
464      * @param node a node to get children of.
465      * @return an array of node children.
466      */
467     public Object[] getChildren(final Object node) {
468         return (Object[]) runMapping(new MapAction<Object>("getChildren") {
469             @Override
470             public Object map() {
471                 TreeModel md = ((JTree) getSource()).getModel();
472                 Object[] result = new Object[md.getChildCount(node)];
473                 for (int i = 0; i < md.getChildCount(node); i++) {
474                     result[i] = md.getChild(node, i);
475                 }
476                 return result;
477             }
478         });
479     }
480 
481     /**
482      * Returns node child.
483      *
484      * @param node a node to get a child of.
485      * @param index a child index.
486      * @return a node child.
487      */
488     public Object getChild(final Object node, final int index) {
489         return runMapping(new MapAction<Object>("getChild") {
490             @Override
491             public Object map() {
492                 return ((JTree) getSource()).getModel().getChild(node, index);
493             }
494         });
495     }
496 
497     /**
498      * Returns number of child.
499      *
500      * @param path a path indicating a node to count children of.
501      * @return a number of children.
502      */
503     public int getChildCount(TreePath path) {
504         if (path != null) {
505             return (getChildCount(path.
506                     getLastPathComponent()));
507         } else {
508             throw (new NoSuchPathException());
509         }
510     }
511 
512     /**
513      * Constructs new path from a path and index's subnode of it last node.
514      *
515      * @param path a path indicating a node to get a child of.
516      * @param index a child node index.
517      * @return a number of children.
518      */
519     public TreePath getChildPath(TreePath path, int index) {
520         if (path != null) {
521             return (path.
522                     pathByAddingChild(getChild(path.
523                             getLastPathComponent(), index)));
524         } else {
525             throw (new NoSuchPathException());
526         }
527     }
528 
529     /**
530      * Constructs new paths from a path and all subnodes of it last node.
531      *
532      * @param path a path indicating a node to get children of.
533      * @return a number of children.
534      */
535     public TreePath[] getChildPaths(TreePath path) {
536         if (path != null) {
537             Object[] children = getChildren(path.
538                     getLastPathComponent());
539             TreePath[] result = new TreePath[children.length];
540             for (int i = 0; i < children.length; i++) {
541                 result[i] = path.
542                         pathByAddingChild(children[i]);
543             }
544             return result;
545         } else {
546             throw (new NoSuchPathException());
547         }
548     }
549 
550     /**
551      * Returns the root of the tree.
552      *
553      * @return tree root.
554      * @throws TimeoutExpiredException
555      */
556     public Object getRoot() {
557         Waiter<Object, Void> rootWaiter = new Waiter<>(new Waitable<Object, Void>() {
558             @Override
559             public Object actionProduced(Void obj) {
560                 Object root = getModel().getRoot();
561                 if (root == null || root.toString().equals("null")) {
562                     return null;
563                 } else {
564                     return root;
565                 }
566             }
567 
568             @Override
569             public String getDescription() {
570                 return "Wait root node";
571             }
572 
573             @Override
574             public String toString() {
575                 return "JTreeOperator.getRoot.Waitable{description = " + getDescription() + '}';
576             }
577         });
578         rootWaiter.setTimeoutsToCloneOf(timeouts, "JTreeOperator.WaitNodeVisibleTimeout");
579         rootWaiter.setOutput(output.createErrorOutput());
580         try {
581             return rootWaiter.waitAction(null);
582         } catch (InterruptedException e) {
583             output.printStackTrace(e);
584             return null;
585         }
586     }
587 
588     /**
589      * Searches path in tree.
590      *
591      * @param chooser TreePathChooser implementation.
592      * @return a path fitting the criteria.
593      * @see TreePathChooser
594      * @see #findPath
595      * @throws TimeoutExpiredException
596      */
597     public TreePath findPath(TreePathChooser chooser) {
598         output.printLine("Search for a tree path " + chooser.getDescription());
599         output.printGolden("Search for a tree path");
600         TreePath rootPath = new TreePath(getRoot());
601         if (chooser.checkPath(rootPath, 0)) {
602             return rootPath;
603         }
604         Waiter<Object[], Object[]> loadedWaiter = new Waiter<>(new Waitable<Object[], Object[]>() {
605             // fields used in getDescription() method
606             TreePath currentPath;
607             String requestedPath;
608 
609             @Override
610             public Object[] actionProduced(Object[] obj) {
611                 TreePathChooser chsr = (TreePathChooser) obj[0];
612                 requestedPath = chsr.getDescription();
613                 TreePath path = (TreePath) obj[1];
614                 currentPath = path;
615                 Object[] result = new Object[2];
616                 Object[] children = getChildren(path.getLastPathComponent());
617                 for (int j = 0; j < children.length; j++) {
618                     result[0] = path.pathByAddingChild(children[j]);
619                     if (chsr.checkPath((TreePath) result[0], j)) {
620                         result[1] = Boolean.TRUE;
621                         return result;
622                     }
623                     if (chsr.hasAsParent((TreePath) result[0], j)) {
624                         result[1] = Boolean.FALSE;
625                         return result;
626                     }
627                 }
628                 return null;
629             }
630 
631             @Override
632             public String getDescription() {
633                 return "Wait next node loaded under parent " + currentPath + " when requested was " + requestedPath;
634             }
635 
636             @Override
637             public String toString() {
638                 return "JTreeOperator.findPath.Waitable{description = " + getDescription() + '}';
639             }
640         });
641         loadedWaiter.setTimeoutsToCloneOf(timeouts, "JTreeOperator.WaitNextNodeTimeout");
642         loadedWaiter.setOutput(output.createErrorOutput());
643         return findPathPrimitive(rootPath, chooser, loadedWaiter);
644     }
645 
646     /**
647      * Searches index'th row by row chooser.
648      *
649      * @param chooser a path searching criteria.
650      * @param index a child index.
651      * @return Row index or -1 if search was insuccessful.
652      * @see JTreeOperator.TreeRowChooser
653      */
654     public int findRow(TreeRowChooser chooser, int index) {
655         int count = 0;
656         for (int i = 0; i < getRowCount(); i++) {
657             if (chooser.checkRow(this, i)) {
658                 if (count == index) {
659                     return i;
660                 } else {
661                     count++;
662                 }
663             }
664         }
665         return -1;
666     }
667 
668     /**
669      * Searches a row by row chooser.
670      *
671      * @param chooser a path searching criteria.
672      * @return Row index or -1 if search was insuccessful.
673      * @see JTreeOperator.TreeRowChooser
674      */
675     public int findRow(TreeRowChooser chooser) {
676         return findRow(chooser, 0);
677     }
678 
679     /**
680      * Searches index'th row by substring.
681      *
682      * @param item Substring.
683      * @param comparator a string comparision algorithm
684      * @param index an ordinal row index between ones matching the criteria
685      * @return Row index or -1 if search was insuccessful.
686      */
687     public int findRow(String item, StringComparator comparator, int index) {
688         return findRow(new BySubStringTreeRowChooser(item, comparator), index);
689     }
690 
691     /**
692      * Searches index'th row by substring.
693      *
694      * @param item Substring.
695      * @param ce Compare exactly
696      * @param cc Compare case sensitivelly.
697      * @param index an ordinal row index between ones matching the criteria
698      * @return Row index or -1 if search was insuccessful.
699      * @deprecated Use findRow(String, int) or findRow(String, StringComparator,
700      * int)
701      */
702     @Deprecated
703     public int findRow(String item, boolean ce, boolean cc, int index) {
704         return (findRow(item,
705                 new DefaultStringComparator(ce, cc),
706                 index));
707     }
708 
709     /**
710      * Searches index'th row by substring. Uses StringComparator assigned to
711      * this object.
712      *
713      * @param item Substring.
714      * @param index an ordinal row index between ones matching the criteria
715      * @return Row index or -1 if search was insuccessful.
716      */
717     public int findRow(String item, int index) {
718         return (findRow(item,
719                 getComparator(),
720                 index));
721     }
722 
723     /**
724      * Searches a row by substring.
725      *
726      * @param item Substring.
727      * @param comparator a string comparision algorithm
728      * @return Row index or -1 if search was insuccessful.
729      */
730     public int findRow(String item, StringComparator comparator) {
731         return findRow(item, comparator, 0);
732     }
733 
734     /**
735      * Searches a row by substring.
736      *
737      * @param item Substring.
738      * @param ce Compare exactly
739      * @param cc Compare case sensitivelly.
740      * @return Row index or -1 if search was insuccessful.
741      * @deprecated Use findRow(String) or findRow(String, StringComparator)
742      */
743     @Deprecated
744     public int findRow(String item, boolean ce, boolean cc) {
745         return findRow(item, ce, cc, 0);
746     }
747 
748     /**
749      * Searches a row by substring. Uses StringComparator assigned to this
750      * object.
751      *
752      * @param item Substring.
753      * @return Row index or -1 if search was insuccessful.
754      */
755     public int findRow(String item) {
756         return (findRow(item,
757                 getComparator(),
758                 0));
759     }
760 
761     /**
762      * Searches index'th row by rendered component.
763      *
764      * @param chooser Component checking object.
765      * @param index an ordinal row index between ones matching the criteria
766      * @return Row index or -1 if search was insuccessful.
767      */
768     public int findRow(ComponentChooser chooser, int index) {
769         return findRow(new ByRenderedComponentTreeRowChooser(chooser), index);
770     }
771 
772     /**
773      * Searches a row by rendered component.
774      *
775      * @param chooser Component checking object.
776      * @return Row index or -1 if search was insuccessful.
777      */
778     public int findRow(ComponentChooser chooser) {
779         return findRow(chooser, 0);
780     }
781 
782     /**
783      * Searches path in tree. Can be used to find one of the nodes with the same
784      * text. Example:<BR>
785      * <pre>
786      * root
787      * +-+node
788      * | +--subnode
789      * +-+node
790      * | +--subnode
791      * | +--subnode
792      * ...
793      * String[] names = {"node", "subnode"};<BR>
794      * int[] indexes = {1, 0};<BR>
795      * </pre> TreePath path = findPath(names, indexes, true, true);<BR>
796      * "path" will points to the second (from the top) "subnode" node.
797      *
798      * @param names Node texts array.
799      * @param indexes Nodes indexes.
800      * @param comparator a string comparision algorithm
801      * @return a tree path matching the criteria
802      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
803      * @see #findPath
804      * @throws TimeoutExpiredException
805      */
806     public TreePath findPath(String[] names, int[] indexes, StringComparator comparator) {
807         return findPath(new StringArrayPathChooser(names, indexes, comparator));
808     }
809 
810     /**
811      * Searches path in tree. Can be used to find one of the nodes with the same
812      * text. Example:<BR>
813      * <pre>
814      * root
815      * +-+node
816      * | +--subnode
817      * +-+node
818      * | +--subnode
819      * | +--subnode
820      * ...
821      * String[] names = {"node", "subnode"};<BR>
822      * int[] indexes = {1, 0};<BR>
823      * </pre> TreePath path = findPath(names, indexes, true, true);<BR>
824      * "path" will points to the second (from the top) "subnode" node.
825      *
826      * @param names Node texts array.
827      * @param indexes Nodes indexes.
828      * @param ce Compare exactly.
829      * @param ccs Compare case sensitively.
830      * @return a tree path matching the criteria
831      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
832      * @see #findPath
833      * @throws TimeoutExpiredException
834      * @deprecated Use findPath(String[], int[]) or findCellRow(String[], int[],
835      * StringComparator)
836      */
837     @Deprecated
838     public TreePath findPath(String[] names, int[] indexes, boolean ce, boolean ccs) {
839         return findPath(names, indexes, new DefaultStringComparator(ce, ccs));
840     }
841 
842     /**
843      * Searches path in tree. Uses StringComparator assigned to this object.
844      *
845      * @param names Node texts array.
846      * @param indexes Nodes indexes.
847      * @return a tree path matching the criteria
848      * @see #findPath
849      * @throws TimeoutExpiredException
850      */
851     public TreePath findPath(String[] names, int[] indexes) {
852         return findPath(names, indexes, getComparator());
853     }
854 
855     /**
856      * Searches path in tree.
857      *
858      * @param names Node texts array.
859      * @param comparator a string comparision algorithm
860      * @return a tree path matching the criteria
861      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
862      * @see #findPath
863      * @throws TimeoutExpiredException
864      */
865     public TreePath findPath(String[] names, StringComparator comparator) {
866         int[] indexes = new int[0];
867         return findPath(names, indexes, comparator);
868     }
869 
870     /**
871      * Searches path in tree.
872      *
873      * @param names Node texts array.
874      * @param ce Compare exactly.
875      * @param ccs Compare case sensitively.
876      * @return a tree path matching the criteria
877      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
878      * @see #findPath
879      * @throws TimeoutExpiredException
880      * @deprecated Use findPath(String[]) or findCellRow(String[],
881      * StringComparator)
882      */
883     @Deprecated
884     public TreePath findPath(String[] names, boolean ce, boolean ccs) {
885         int[] indexes = new int[0];
886         return findPath(names, indexes, ce, ccs);
887     }
888 
889     /**
890      * Searches path in tree. Uses StringComparator assigned to this object.
891      *
892      * @param names Node texts array.
893      * @return a tree path matching the criteria
894      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
895      * @see #findPath
896      * @throws TimeoutExpiredException
897      */
898     public TreePath findPath(String[] names) {
899         int[] indexes = new int[0];
900         return findPath(names, indexes, getComparator());
901     }
902 
903     /**
904      * Searches path in tree.
905      *
906      * @param path String representing tree path. Path components should be
907      * devided by "delim" parameter.
908      * @param indexes String representing indexes to search path components.
909      * Indexes should be devided by "delim" parameter.
910      * @param delim Path components delimiter.
911      * @param comparator a string comparision algorithm
912      * @return a tree path matching the criteria
913      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
914      * @see #findPath
915      * @throws TimeoutExpiredException
916      */
917     public TreePath findPath(String path, String indexes, String delim, StringComparator comparator) {
918         String[] indexStrings = parseString(indexes, delim);
919         int[] indInts = new int[indexStrings.length];
920         for (int i = 0; i < indexStrings.length; i++) {
921             indInts[i] = Integer.parseInt(indexStrings[i]);
922         }
923         return findPath(parseString(path, delim), indInts, comparator);
924     }
925 
926     /**
927      * Searches path in tree.
928      *
929      * @param path String representing tree path. Path components should be
930      * devided by "delim" parameter.
931      * @param indexes String representing indexes to search path components.
932      * Indexes should be devided by "delim" parameter.
933      * @param delim Path components delimiter.
934      * @param ce Compare exactly.
935      * @param ccs Compare case sensitively.
936      * @return a tree path matching the criteria
937      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
938      * @see #findPath
939      * @throws TimeoutExpiredException
940      * @deprecated Use findPath(String, String, String) or findCellRow(String,
941      * String, String, StringComparator)
942      */
943     @Deprecated
944     public TreePath findPath(String path, String indexes, String delim, boolean ce, boolean ccs) {
945         return findPath(path, indexes, delim, new DefaultStringComparator(ce, ccs));
946     }
947 
948     /**
949      * Searches path in tree. Uses StringComparator assigned to this object.
950      *
951      * @param path String representing tree path. Path components should be
952      * devided by "delim" parameter.
953      * @param indexes String representing indexes to search path components.
954      * Indexes should be devided by "delim" parameter.
955      * @param delim Path components delimiter.
956      * @return a tree path matching the criteria
957      * @see #findPath
958      * @throws TimeoutExpiredException
959      */
960     public TreePath findPath(String path, String indexes, String delim) {
961         return findPath(path, indexes, delim, getComparator());
962     }
963 
964     /**
965      * Searches path in tree.
966      *
967      * @param path String representing tree path. Path components should be
968      * devided by "delim" parameter.
969      * @param delim Path components delimiter.
970      * @param comparator a string comparision algorithm
971      * @return a tree path matching the criteria
972      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
973      * @see #findPath
974      * @throws TimeoutExpiredException
975      */
976     public TreePath findPath(String path, String delim, StringComparator comparator) {
977         return findPath(parseString(path, delim), comparator);
978     }
979 
980     /**
981      * Searches path in tree.
982      *
983      * @param path String representing tree path.
984      * @param comparator a string comparision algorithm
985      * @return a tree path matching the criteria
986      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
987      * @see #findPath
988      * @throws TimeoutExpiredException
989      */
990     public TreePath findPath(String path, StringComparator comparator) {
991         return findPath(parseString(path), comparator);
992     }
993 
994     /**
995      * Searches path in tree.
996      *
997      * @param path String representing tree path. Path components should be
998      * devided by "delim" parameter.
999      * @param delim Path components delimiter.
1000      * @param ce Compare exactly.
1001      * @param ccs Compare case sensitively.
1002      * @return a tree path matching the criteria
1003      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
1004      * @see #findPath
1005      * @throws TimeoutExpiredException
1006      * @deprecated Use findPath(String, String) or findCellRow(String, String,
1007      * StringComparator)
1008      */
1009     @Deprecated
1010     public TreePath findPath(String path, String delim, boolean ce, boolean ccs) {
1011         return findPath(parseString(path, delim), ce, ccs);
1012     }
1013 
1014     /**
1015      * Searches path in tree. Uses StringComparator assigned to this object.
1016      *
1017      * @param path String representing tree path. Path components should be
1018      * devided by "delim" parameter.
1019      * @param delim Path components delimiter.
1020      * @return a tree path matching the criteria
1021      * @see #findPath
1022      * @throws TimeoutExpiredException
1023      */
1024     public TreePath findPath(String path, String delim) {
1025         return findPath(parseString(path, delim));
1026     }
1027 
1028     /**
1029      * Searches path in tree. Uses StringComparator assigned to this object.
1030      * Uses PathParser assigned to this object.
1031      *
1032      * @param path String representing tree path.
1033      * @return a tree path matching the criteria
1034      * @see #findPath
1035      * @throws TimeoutExpiredException
1036      */
1037     public TreePath findPath(String path) {
1038         return findPath(parseString(path));
1039     }
1040 
1041     /**
1042      * Ensures that the node identified by the specified path is collapsed and
1043      * viewable.
1044      *
1045      * @param path a path to collapse.
1046      * @throws TimeoutExpiredException
1047      */
1048     public void doCollapsePath(TreePath path) {
1049         if (path != null) {
1050             output.printLine("Collapsing \"" + path.toString() + "\" path");
1051             output.printGolden("Collapsing path");
1052             driver.collapseItem(this, getRowForPath(path));
1053             if (getVerification()) {
1054                 waitCollapsed(path);
1055             }
1056         } else {
1057             throw (new NoSuchPathException());
1058         }
1059     }
1060 
1061     /**
1062      * Ensures that the node in the specified row is collapsed.
1063      *
1064      * @param row a row index to collapse.
1065      * @throws TimeoutExpiredException
1066      */
1067     public void doCollapseRow(int row) {
1068         output.printLine("Collapsing \"" + Integer.toString(row) + "\" row");
1069         output.printGolden("Collapsing path");
1070         driver.collapseItem(this, row);
1071         if (getVerification()) {
1072             waitCollapsed(row);
1073         }
1074     }
1075 
1076     /**
1077      * Selects the path.
1078      *
1079      * @param path a path to select.
1080      */
1081     public void selectPath(final TreePath path) {
1082         if (path != null) {
1083             output.printLine("Selecting \"" + path.toString() + "\" path");
1084             output.printGolden("Selecting path");
1085             scrollToPath(path);
1086             getQueueTool().invokeSmoothly(new QueueTool.QueueAction<Void>("Path selecting") {
1087                 @Override
1088                 public Void launch() {
1089                     driver.selectItem(JTreeOperator.this, getRowForPath(path));
1090                     return null;
1091                 }
1092             });
1093             if (getVerification()) {
1094                 waitSelected(path);
1095             }
1096         } else {
1097             throw (new NoSuchPathException());
1098         }
1099     }
1100 
1101     /**
1102      * Selects the node in the specified row.
1103      *
1104      * @param row an index of row to select.
1105      */
1106     public void selectRow(int row) {
1107         output.printLine("Collapsing \"" + Integer.toString(row) + "\" row");
1108         output.printGolden("Collapsing path");
1109         driver.selectItem(this, row);
1110         if (getVerification()) {
1111             waitSelected(row);
1112         }
1113     }
1114 
1115     /**
1116      * Selects some pathes. If verification mode is on, checks that right paths
1117      * have been selected.
1118      *
1119      * @param paths a paths to select.
1120      */
1121     public void selectPaths(TreePath[] paths) {
1122         output.printLine("Selecting paths:");
1123         int[] rows = new int[paths.length];
1124         for (int i = 0; i < paths.length; i++) {
1125             output.printLine("    " + paths[i].toString());
1126             rows[i] = getRowForPath(paths[i]);
1127         }
1128         output.printGolden("Selecting paths");
1129         driver.selectItems(this, rows);
1130         if (getVerification()) {
1131             waitSelected(paths);
1132         }
1133     }
1134 
1135     /**
1136      * Retuns points which can be used to click on path.
1137      *
1138      * @param path a tree path to click on.
1139      * @return a Point in component's coordinate system.
1140      */
1141     public Point getPointToClick(TreePath path) {
1142         if (path != null) {
1143             Rectangle rect = getPathBounds(path);
1144             if (rect != null) {
1145                 return (new Point((int) (rect.getX() + rect.getWidth() / 2),
1146                         (int) (rect.getY() + rect.getHeight() / 2)));
1147             } else {
1148                 throw (new NoSuchPathException(path));
1149             }
1150         } else {
1151             throw (new NoSuchPathException());
1152         }
1153     }
1154 
1155     /**
1156      * Retuns points which can be used to click on path.
1157      *
1158      * @param row a row index to click on.
1159      * @return a Point in component's coordinate system.
1160      */
1161     public Point getPointToClick(int row) {
1162         Rectangle rect = getRowBounds(row);
1163         if (rect != null) {
1164             return (new Point((int) (rect.getX() + rect.getWidth() / 2),
1165                     (int) (rect.getY() + rect.getHeight() / 2)));
1166         } else {
1167             throw (new NoSuchPathException(row));
1168         }
1169     }
1170 
1171     /**
1172      * Clicks on the node.
1173      *
1174      * @param path a path to click on.
1175      * @param clickCount a number of clicks
1176      * @param mouseButton InputEvent.BUTTON1/2/3_MASK value
1177      * @param modifiers Combination of InputEvent.*_MASK values
1178      * @throws TimeoutExpiredException
1179      */
1180     public void clickOnPath(TreePath path, int clickCount, int mouseButton, int modifiers) {
1181         if (path != null) {
1182             output.printLine("Click on \"" + path.toString()
1183                     + "\" path");
1184             output.printGolden("Click on path");
1185             makeComponentVisible();
1186             if (path.getParentPath() != null) {
1187                 expandPath(path.getParentPath());
1188             }
1189             makeVisible(path);
1190             scrollToPath(path);
1191             Point point = getPointToClick(path);
1192             clickMouse((int) point.getX(), (int) point.getY(), clickCount, mouseButton, modifiers);
1193         } else {
1194             throw (new NoSuchPathException());
1195         }
1196     }
1197 
1198     /**
1199      * Clicks on the node.
1200      *
1201      * @param path a path to click on.
1202      * @param clickCount a number of clicks
1203      * @param mouseButton InputEvent.BUTTON1/2/3_MASK value
1204      * @throws TimeoutExpiredException
1205      */
1206     public void clickOnPath(TreePath path, int clickCount, int mouseButton) {
1207         clickOnPath(path, clickCount, mouseButton, 0);
1208     }
1209 
1210     /**
1211      * Clicks on the node.
1212      *
1213      * @param path a path to click on.
1214      * @param clickCount a number of clicks
1215      * @throws TimeoutExpiredException
1216      */
1217     public void clickOnPath(TreePath path, int clickCount) {
1218         clickOnPath(path, clickCount, getDefaultMouseButton());
1219     }
1220 
1221     /**
1222      * Clicks on the node.
1223      *
1224      * @param path a path to click on.
1225      * @throws TimeoutExpiredException
1226      */
1227     public void clickOnPath(TreePath path) {
1228         clickOnPath(path, 1);
1229     }
1230 
1231     /**
1232      * Calls popup on the specified pathes.
1233      *
1234      * @param paths an array of paths to select before invoking popup on one of
1235      * them
1236      * @param mouseButton a mouse button tused to call popup.
1237      * @return an opened popup menu.
1238      * @throws TimeoutExpiredException
1239      */
1240     public JPopupMenu callPopupOnPaths(TreePath[] paths, int mouseButton) {
1241         if (paths.length == 1) {
1242             output.printLine("Call popup on \"" + paths[0].toString()
1243                     + "\" path");
1244             output.printGolden("Call popup on path");
1245         } else {
1246             output.printLine("Call popup on some pathes:");
1247             for (TreePath path : paths) {
1248                 output.printLine("    " + path.toString());
1249             }
1250             output.printGolden("Call popup on paths");
1251         }
1252         makeComponentVisible();
1253         for (TreePath path : paths) {
1254             if (path.getParentPath() != null) {
1255                 expandPath(path.getParentPath());
1256             }
1257         }
1258         selectPaths(paths);
1259         scrollToPath(paths[paths.length - 1]);
1260         Point point = getPointToClick(paths[paths.length - 1]);
1261         return (JPopupMenuOperator.callPopup(this,
1262                 (int) point.getX(),
1263                 (int) point.getY(),
1264                 mouseButton));
1265     }
1266 
1267     /**
1268      * Calls popup on the specified pathes.
1269      *
1270      * @param paths an array of paths to select before invoking popup on one of
1271      * them
1272      * @return an opened popup menu.
1273      * @throws TimeoutExpiredException
1274      */
1275     public JPopupMenu callPopupOnPaths(TreePath[] paths) {
1276         return callPopupOnPaths(paths, getPopupMouseButton());
1277     }
1278 
1279     /**
1280      * Calls popup on the specified path.
1281      *
1282      * @param path a path to invoking popup on.
1283      * @param mouseButton a mouse button tused to call popup.
1284      * @return an opened popup menu.
1285      * @throws TimeoutExpiredException
1286      */
1287     public JPopupMenu callPopupOnPath(TreePath path, int mouseButton) {
1288         if (path != null) {
1289             TreePath[] paths = {path};
1290             return callPopupOnPaths(paths, mouseButton);
1291         } else {
1292             throw (new NoSuchPathException());
1293         }
1294     }
1295 
1296     /**
1297      * Calls popup on the specified path.
1298      *
1299      * @param path a path to invoking popup on.
1300      * @return an opened popup menu.
1301      * @throws TimeoutExpiredException
1302      */
1303     public JPopupMenu callPopupOnPath(TreePath path) {
1304         return callPopupOnPath(path, getPopupMouseButton());
1305     }
1306 
1307     /**
1308      * Scrolls to a path if the tree is on a JScrollPane component.
1309      *
1310      * @param path a tree path to scroll to.
1311      */
1312     public void scrollToPath(TreePath path) {
1313         if (path != null) {
1314             output.printTrace("Scroll JTree to path \"" + path.toString() + "\"\n    : "
1315                     + toStringSource());
1316             output.printGolden("Scroll JTree to path \"" + path.toString() + "\"");
1317             makeComponentVisible();
1318             //try to find JScrollPane under.
1319             JScrollPane scroll = (JScrollPane) getContainer(new JScrollPaneOperator.JScrollPaneFinder(ComponentSearcher.
1320                     getTrueChooser("JScrollPane")));
1321             if (scroll == null) {
1322                 return;
1323             }
1324             JScrollPaneOperator scroller = new JScrollPaneOperator(scroll);
1325             scroller.copyEnvironment(this);
1326             scroller.setVisualizer(new EmptyVisualizer());
1327             Rectangle rect = getPathBounds(path);
1328             if (rect != null) {
1329                 scroller.scrollToComponentRectangle(getSource(),
1330                         (int) rect.getX(),
1331                         (int) rect.getY(),
1332                         (int) rect.getWidth(),
1333                         (int) rect.getHeight());
1334             } else {
1335                 throw (new NoSuchPathException(path));
1336             }
1337         } else {
1338             throw (new NoSuchPathException());
1339         }
1340     }
1341 
1342     /**
1343      * Scrolls to a row if the tree is on a JScrollPane component.
1344      *
1345      * @param row a row index to scroll to.
1346      */
1347     public void scrollToRow(int row) {
1348         scrollToPath(getPathForRow(row));
1349     }
1350 
1351     /**
1352      * Turns path to the editing mode.
1353      *
1354      * @param path a tree path to click on.
1355      * @throws TimeoutExpiredException
1356      */
1357     public void clickForEdit(TreePath path) {
1358         driver.startEditing(this, getRowForPath(path),
1359                 timeouts.create("JTreeOperator.WaitEditingTimeout"));
1360     }
1361 
1362     /**
1363      * Ask renderer for component to be displayed.
1364      *
1365      * @param path a path indicating the rendered node.
1366      * @param isSelected True if the specified cell is selected.
1367      * @param isExpanded True if the specified cell is expanded.
1368      * @param cellHasFocus True if the specified cell has the focus.
1369      * @return Component to be displayed.
1370      */
1371     public Component getRenderedComponent(TreePath path, boolean isSelected, boolean isExpanded, boolean cellHasFocus) {
1372         if (path != null) {
1373             return (getCellRenderer().
1374                     getTreeCellRendererComponent((JTree) getSource(),
1375                             path.getLastPathComponent(),
1376                             isSelected,
1377                             isExpanded,
1378                             getModel().isLeaf(path.getLastPathComponent()),
1379                             getRowForPath(path),
1380                             cellHasFocus));
1381         } else {
1382             throw (new NoSuchPathException());
1383         }
1384     }
1385 
1386     /**
1387      * Ask renderer for component to be displayed. Uses isPathSelected(TreePath)
1388      * to determine whether path is selected. Uses isExpanded(TreePath) to
1389      * determine whether path is expanded.
1390      *
1391      * @param path a path indicating the rendered node.
1392      * @return Component to be displayed.
1393      */
1394     public Component getRenderedComponent(TreePath path) {
1395         return (getRenderedComponent(path,
1396                 isPathSelected(path),
1397                 isExpanded(path),
1398                 false));
1399     }
1400 
1401     /**
1402      * Changes text of last path component.
1403      *
1404      * @param path a path indicating the node to change value for.
1405      * @param newNodeText a new node value
1406      * @deprecated Use changePathObject(TreePath, Object) instead.
1407      * @see #changePathObject(TreePath, Object)
1408      * @throws TimeoutExpiredException
1409      */
1410     @Deprecated
1411     public void changePathText(TreePath path, String newNodeText) {
1412         changePathObject(path, newNodeText);
1413     }
1414 
1415     /**
1416      * Changes last path component using getCellEditor() editor.
1417      *
1418      * @param path a path indicating the node to change value for.
1419      * @param newValue a new node value
1420      * @throws TimeoutExpiredException
1421      */
1422     public void changePathObject(TreePath path, Object newValue) {
1423         scrollToPath(path);
1424         driver.editItem(this, getRowForPath(path), newValue,
1425                 timeouts.create("JTreeOperator.WaitEditingTimeout"));
1426     }
1427 
1428     /**
1429      * Waits path to be expanded.
1430      *
1431      * @param path a path to wait expanded.
1432      */
1433     public void waitExpanded(final TreePath path) {
1434         if (path != null) {
1435             getOutput().printLine("Wait \"" + path.toString() + "\" path to be expanded in component \n    : "
1436                     + toStringSource());
1437             getOutput().printGolden("Wait \"" + path.toString() + "\" path to be expanded");
1438             waitState(new ComponentChooser() {
1439                 @Override
1440                 public boolean checkComponent(Component comp) {
1441                     return isExpanded(path);
1442                 }
1443 
1444                 @Override
1445                 public String getDescription() {
1446                     return "Has \"" + path.toString() + "\" path expanded";
1447                 }
1448 
1449                 @Override
1450                 public String toString() {
1451                     return "JTreeOperator.waitExpanded.ComponentChooser{description = " + getDescription() + '}';
1452                 }
1453             });
1454         } else {
1455             throw (new NoSuchPathException());
1456         }
1457     }
1458 
1459     /**
1460      * Waits row to be expanded.
1461      *
1462      * @param row a row index to wait expanded.
1463      */
1464     public void waitExpanded(final int row) {
1465         getOutput().printLine("Wait " + Integer.toString(row) + "'th row to be expanded in component \n    : "
1466                 + toStringSource());
1467         getOutput().printGolden("Wait " + Integer.toString(row) + "'th row to be expanded");
1468         waitState(new ComponentChooser() {
1469             @Override
1470             public boolean checkComponent(Component comp) {
1471                 return isExpanded(row);
1472             }
1473 
1474             @Override
1475             public String getDescription() {
1476                 return "Has " + Integer.toString(row) + "'th row expanded";
1477             }
1478 
1479             @Override
1480             public String toString() {
1481                 return "JTreeOperator.waitExpanded.ComponentChooser{description = " + getDescription() + '}';
1482             }
1483         });
1484     }
1485 
1486     /**
1487      * Waits path to be collapsed.
1488      *
1489      * @param path a path to wait collapsed.
1490      */
1491     public void waitCollapsed(final TreePath path) {
1492         if (path != null) {
1493             getOutput().printLine("Wait \"" + path.toString() + "\" path to be collapsed in component \n    : "
1494                     + toStringSource());
1495             getOutput().printGolden("Wait \"" + path.toString() + "\" path to be collapsed");
1496             waitState(new ComponentChooser() {
1497                 @Override
1498                 public boolean checkComponent(Component comp) {
1499                     return isCollapsed(path);
1500                 }
1501 
1502                 @Override
1503                 public String getDescription() {
1504                     return "Has \"" + path.toString() + "\" path collapsed";
1505                 }
1506 
1507                 @Override
1508                 public String toString() {
1509                     return "JTreeOperator.waitCollapsed.ComponentChooser{description = " + getDescription() + '}';
1510                 }
1511             });
1512         } else {
1513             throw (new NoSuchPathException());
1514         }
1515     }
1516 
1517     /**
1518      * Waits row to be collapsed.
1519      *
1520      * @param row a row index to wait collapsed.
1521      */
1522     public void waitCollapsed(final int row) {
1523         getOutput().printLine("Wait " + Integer.toString(row) + "'th row to be collapsed in component \n    : "
1524                 + toStringSource());
1525         getOutput().printGolden("Wait " + Integer.toString(row) + "'th row to be collapsed");
1526         waitState(new ComponentChooser() {
1527             @Override
1528             public boolean checkComponent(Component comp) {
1529                 return isCollapsed(row);
1530             }
1531 
1532             @Override
1533             public String getDescription() {
1534                 return "Has " + Integer.toString(row) + "'th row collapsed";
1535             }
1536 
1537             @Override
1538             public String toString() {
1539                 return "JTreeOperator.waitCollapsed.ComponentChooser{description = " + getDescription() + '}';
1540             }
1541         });
1542     }
1543 
1544     /**
1545      * Waits path to be visible.
1546      *
1547      * @param path a path to wait visible.
1548      */
1549     public void waitVisible(final TreePath path) {
1550         if (path != null) {
1551             getOutput().printLine("Wait \"" + path.toString() + "\" path to be visible in component \n    : "
1552                     + toStringSource());
1553             getOutput().printGolden("Wait \"" + path.toString() + "\" path to be visible");
1554             waitState(new ComponentChooser() {
1555                 @Override
1556                 public boolean checkComponent(Component comp) {
1557                     return isVisible(path);
1558                 }
1559 
1560                 @Override
1561                 public String getDescription() {
1562                     return "Has \"" + path.toString() + "\" path visible";
1563                 }
1564 
1565                 @Override
1566                 public String toString() {
1567                     return "JTreeOperator.waitVisible.ComponentChooser{description = " + getDescription() + '}';
1568                 }
1569             });
1570         } else {
1571             throw (new NoSuchPathException());
1572         }
1573     }
1574 
1575     /**
1576      * Waits some paths to be selected.
1577      *
1578      * @param paths an array of paths to be selected.
1579      */
1580     public void waitSelected(final TreePath[] paths) {
1581         getOutput().printLine("Wait right selection in component \n    : "
1582                 + toStringSource());
1583         getOutput().printGolden("Wait right selection");
1584         waitState(new ComponentChooser() {
1585             @Override
1586             public boolean checkComponent(Component comp) {
1587                 TreePath[] rpaths = getSelectionModel().getSelectionPaths();
1588                 if (rpaths != null) {
1589                     for (int i = 0; i < rpaths.length; i++) {
1590                         if (!rpaths[i].equals(paths[i])) {
1591                             return false;
1592                         }
1593                     }
1594                     return true;
1595                 } else {
1596                     return false;
1597                 }
1598             }
1599 
1600             @Override
1601             public String getDescription() {
1602                 return "Has right selection";
1603             }
1604 
1605             @Override
1606             public String toString() {
1607                 return "JTreeOperator.waitSelected.ComponentChooser{description = " + getDescription() + '}';
1608             }
1609         });
1610     }
1611 
1612     /**
1613      * Waits path to be selected.
1614      *
1615      * @param path a tree path to be selected.
1616      */
1617     public void waitSelected(final TreePath path) {
1618         waitSelected(new TreePath[]{path});
1619     }
1620 
1621     /**
1622      * Waits rows to be selected.
1623      *
1624      * @param rows an indices of rows to be selected.
1625      */
1626     public void waitSelected(int[] rows) {
1627         TreePath[] paths = new TreePath[rows.length];
1628         for (int i = 0; i < rows.length; i++) {
1629             paths[i] = getPathForRow(rows[i]);
1630         }
1631         waitSelected(paths);
1632     }
1633 
1634     /**
1635      * Waits row to be selected.
1636      *
1637      * @param row an index of a row to be selected.
1638      */
1639     public void waitSelected(int row) {
1640         waitSelected(new int[]{row});
1641     }
1642 
1643     /**
1644      * Wat for text in certain row.
1645      *
1646      * @param rowText Text to be compared with row text be
1647      * {@code getComparator()} comparator.
1648      * @param row Row index. If -1, selected one is checked.
1649      */
1650     public void waitRow(String rowText, int row) {
1651         getOutput().printLine("Wait \"" + rowText + "\" text in "
1652                 + Integer.toString(row) + "'th line in component \n    : "
1653                 + toStringSource());
1654         getOutput().printGolden("Wait \"" + rowText + " \" text in "
1655                 + Integer.toString(row) + "'th line");
1656         waitState(new JTreeByItemFinder(rowText, row, getComparator()));
1657     }
1658 
1659     public Object chooseSubnode(Object parent, String text, int index, StringComparator comparator) {
1660         int count = -1;
1661         Object node;
1662         for (int i = 0; i < getChildCount(parent); i++) {
1663             try {
1664                 node = getChild(parent, i);
1665             } catch (JemmyException e) {
1666                 if (e.getInnerThrowable() instanceof IndexOutOfBoundsException) {
1667                     // tree probably re-generated because we haven't found child with specified index
1668                     return null;
1669                 } else {
1670                     throw e;
1671                 }
1672             }
1673             if (comparator.equals(node.toString(),
1674                     text)) {
1675                 count++;
1676                 if (count == index) {
1677                     return node;
1678                 }
1679             }
1680         }
1681         return null;
1682     }
1683 
1684     public Object chooseSubnode(Object parent, String text, StringComparator comparator) {
1685         return chooseSubnode(parent, text, 0, comparator);
1686     }
1687 
1688     public Object chooseSubnode(Object parent, String text, int index) {
1689         return chooseSubnode(parent, text, index, getComparator());
1690     }
1691 
1692     public Object chooseSubnode(Object parent, String text) {
1693         return chooseSubnode(parent, text, 0, getComparator());
1694     }
1695 
1696     /**
1697      * Returns information about component.
1698      */
1699     @Override
1700     public Hashtable<String, Object> getDump() {
1701         Hashtable<String, Object> result = super.getDump();
1702         Object root = ((JTree) getSource()).getModel().getRoot();
1703         // only if root is not hidden
1704         result.put(ROOT_DPROP, root.toString());
1705         addChildrenToDump(result, NODE_PREFIX_DPROP, root, new TreePath(root));
1706         int minSelection = ((JTree) getSource()).getMinSelectionRow();
1707         if (minSelection >= 0) {
1708             Object minObject = ((JTree) getSource()).
1709                     getPathForRow(minSelection).
1710                     getLastPathComponent();
1711             result.put(SELECTION_FIRST_DPROP, minObject.toString());
1712             int maxSelection = ((JTree) getSource()).getMaxSelectionRow();
1713             if (maxSelection > minSelection) {
1714                 Object maxObject = ((JTree) getSource()).
1715                         getPathForRow(maxSelection).
1716                         getLastPathComponent();
1717                 result.put(SELECTION_LAST_DPROP, maxObject.toString());
1718             }
1719         }
1720         return result;
1721     }
1722 
1723     ////////////////////////////////////////////////////////
1724     //Mapping                                             //
1725     /**
1726      * Maps {@code JTree.addSelectionInterval(int, int)} through queue
1727      */
1728     public void addSelectionInterval(final int i, final int i1) {
1729         runMapping(new MapVoidAction("addSelectionInterval") {
1730             @Override
1731             public void map() {
1732                 ((JTree) getSource()).addSelectionInterval(i, i1);
1733             }
1734         });
1735     }
1736 
1737     /**
1738      * Maps {@code JTree.addSelectionPath(TreePath)} through queue
1739      */
1740     public void addSelectionPath(final TreePath treePath) {
1741         runMapping(new MapVoidAction("addSelectionPath") {
1742             @Override
1743             public void map() {
1744                 ((JTree) getSource()).addSelectionPath(treePath);
1745             }
1746         });
1747     }
1748 
1749     /**
1750      * Maps {@code JTree.addSelectionPaths(TreePath[])} through queue
1751      */
1752     public void addSelectionPaths(final TreePath[] treePath) {
1753         runMapping(new MapVoidAction("addSelectionPaths") {
1754             @Override
1755             public void map() {
1756                 ((JTree) getSource()).addSelectionPaths(treePath);
1757             }
1758         });
1759     }
1760 
1761     /**
1762      * Maps {@code JTree.addSelectionRow(int)} through queue
1763      */
1764     public void addSelectionRow(final int i) {
1765         runMapping(new MapVoidAction("addSelectionRow") {
1766             @Override
1767             public void map() {
1768                 ((JTree) getSource()).addSelectionRow(i);
1769             }
1770         });
1771     }
1772 
1773     /**
1774      * Maps {@code JTree.addSelectionRows(int[])} through queue
1775      */
1776     public void addSelectionRows(final int[] i) {
1777         runMapping(new MapVoidAction("addSelectionRows") {
1778             @Override
1779             public void map() {
1780                 ((JTree) getSource()).addSelectionRows(i);
1781             }
1782         });
1783     }
1784 
1785     /**
1786      * Maps {@code JTree.addTreeExpansionListener(TreeExpansionListener)}
1787      * through queue
1788      */
1789     public void addTreeExpansionListener(final TreeExpansionListener treeExpansionListener) {
1790         runMapping(new MapVoidAction("addTreeExpansionListener") {
1791             @Override
1792             public void map() {
1793                 ((JTree) getSource()).addTreeExpansionListener(treeExpansionListener);
1794             }
1795         });
1796     }
1797 
1798     /**
1799      * Maps {@code JTree.addTreeSelectionListener(TreeSelectionListener)}
1800      * through queue
1801      */
1802     public void addTreeSelectionListener(final TreeSelectionListener treeSelectionListener) {
1803         runMapping(new MapVoidAction("addTreeSelectionListener") {
1804             @Override
1805             public void map() {
1806                 ((JTree) getSource()).addTreeSelectionListener(treeSelectionListener);
1807             }
1808         });
1809     }
1810 
1811     /**
1812      * Maps {@code JTree.addTreeWillExpandListener(TreeWillExpandListener)}
1813      * through queue
1814      */
1815     public void addTreeWillExpandListener(final TreeWillExpandListener treeWillExpandListener) {
1816         runMapping(new MapVoidAction("addTreeWillExpandListener") {
1817             @Override
1818             public void map() {
1819                 ((JTree) getSource()).addTreeWillExpandListener(treeWillExpandListener);
1820             }
1821         });
1822     }
1823 
1824     /**
1825      * Maps {@code JTree.cancelEditing()} through queue
1826      */
1827     public void cancelEditing() {
1828         runMapping(new MapVoidAction("cancelEditing") {
1829             @Override
1830             public void map() {
1831                 ((JTree) getSource()).cancelEditing();
1832             }
1833         });
1834     }
1835 
1836     /**
1837      * Maps {@code JTree.clearSelection()} through queue
1838      */
1839     public void clearSelection() {
1840         runMapping(new MapVoidAction("clearSelection") {
1841             @Override
1842             public void map() {
1843                 ((JTree) getSource()).clearSelection();
1844             }
1845         });
1846     }
1847 
1848     /**
1849      * Maps {@code JTree.collapsePath(TreePath)} through queue
1850      */
1851     public void collapsePath(final TreePath treePath) {
1852         runMapping(new MapVoidAction("collapsePath") {
1853             @Override
1854             public void map() {
1855                 ((JTree) getSource()).collapsePath(treePath);
1856             }
1857         });
1858     }
1859 
1860     /**
1861      * Maps {@code JTree.collapseRow(int)} through queue
1862      */
1863     public void collapseRow(final int i) {
1864         runMapping(new MapVoidAction("collapseRow") {
1865             @Override
1866             public void map() {
1867                 ((JTree) getSource()).collapseRow(i);
1868             }
1869         });
1870     }
1871 
1872     /**
1873      * Maps
1874      * {@code JTree.convertValueToText(Object, boolean, boolean, boolean, int, boolean)}
1875      * through queue
1876      */
1877     public String convertValueToText(final Object object, final boolean b, final boolean b1, final boolean b2, final int i, final boolean b3) {
1878         return (runMapping(new MapAction<String>("convertValueToText") {
1879             @Override
1880             public String map() {
1881                 return ((JTree) getSource()).convertValueToText(object, b, b1, b2, i, b3);
1882             }
1883         }));
1884     }
1885 
1886     /**
1887      * Maps {@code JTree.expandPath(TreePath)} through queue
1888      */
1889     public void expandPath(final TreePath treePath) {
1890         runMapping(new MapVoidAction("expandPath") {
1891             @Override
1892             public void map() {
1893                 ((JTree) getSource()).expandPath(treePath);
1894             }
1895         });
1896     }
1897 
1898     /**
1899      * Maps {@code JTree.expandRow(int)} through queue
1900      */
1901     public void expandRow(final int i) {
1902         runMapping(new MapVoidAction("expandRow") {
1903             @Override
1904             public void map() {
1905                 ((JTree) getSource()).expandRow(i);
1906             }
1907         });
1908     }
1909 
1910     /**
1911      * Maps {@code JTree.fireTreeCollapsed(TreePath)} through queue
1912      */
1913     public void fireTreeCollapsed(final TreePath treePath) {
1914         runMapping(new MapVoidAction("fireTreeCollapsed") {
1915             @Override
1916             public void map() {
1917                 ((JTree) getSource()).fireTreeCollapsed(treePath);
1918             }
1919         });
1920     }
1921 
1922     /**
1923      * Maps {@code JTree.fireTreeExpanded(TreePath)} through queue
1924      */
1925     public void fireTreeExpanded(final TreePath treePath) {
1926         runMapping(new MapVoidAction("fireTreeExpanded") {
1927             @Override
1928             public void map() {
1929                 ((JTree) getSource()).fireTreeExpanded(treePath);
1930             }
1931         });
1932     }
1933 
1934     /**
1935      * Maps {@code JTree.fireTreeWillCollapse(TreePath)} through queue
1936      */
1937     public void fireTreeWillCollapse(final TreePath treePath) {
1938         runMapping(new MapVoidAction("fireTreeWillCollapse") {
1939             @Override
1940             public void map() throws ExpandVetoException {
1941                 ((JTree) getSource()).fireTreeWillCollapse(treePath);
1942             }
1943         });
1944     }
1945 
1946     /**
1947      * Maps {@code JTree.fireTreeWillExpand(TreePath)} through queue
1948      */
1949     public void fireTreeWillExpand(final TreePath treePath) {
1950         runMapping(new MapVoidAction("fireTreeWillExpand") {
1951             @Override
1952             public void map() throws ExpandVetoException {
1953                 ((JTree) getSource()).fireTreeWillExpand(treePath);
1954             }
1955         });
1956     }
1957 
1958     /**
1959      * Maps {@code JTree.getCellEditor()} through queue
1960      */
1961     public TreeCellEditor getCellEditor() {
1962         return (runMapping(new MapAction<TreeCellEditor>("getCellEditor") {
1963             @Override
1964             public TreeCellEditor map() {
1965                 return ((JTree) getSource()).getCellEditor();
1966             }
1967         }));
1968     }
1969 
1970     /**
1971      * Maps {@code JTree.getCellRenderer()} through queue
1972      */
1973     public TreeCellRenderer getCellRenderer() {
1974         return (runMapping(new MapAction<TreeCellRenderer>("getCellRenderer") {
1975             @Override
1976             public TreeCellRenderer map() {
1977                 return ((JTree) getSource()).getCellRenderer();
1978             }
1979         }));
1980     }
1981 
1982     /**
1983      * Maps {@code JTree.getClosestPathForLocation(int, int)} through queue
1984      */
1985     public TreePath getClosestPathForLocation(final int i, final int i1) {
1986         return (runMapping(new MapAction<TreePath>("getClosestPathForLocation") {
1987             @Override
1988             public TreePath map() {
1989                 return ((JTree) getSource()).getClosestPathForLocation(i, i1);
1990             }
1991         }));
1992     }
1993 
1994     /**
1995      * Maps {@code JTree.getClosestRowForLocation(int, int)} through queue
1996      */
1997     public int getClosestRowForLocation(final int i, final int i1) {
1998         return (runMapping(new MapIntegerAction("getClosestRowForLocation") {
1999             @Override
2000             public int map() {
2001                 return ((JTree) getSource()).getClosestRowForLocation(i, i1);
2002             }
2003         }));
2004     }
2005 
2006     /**
2007      * Maps {@code JTree.getEditingPath()} through queue
2008      */
2009     public TreePath getEditingPath() {
2010         return (runMapping(new MapAction<TreePath>("getEditingPath") {
2011             @Override
2012             public TreePath map() {
2013                 return ((JTree) getSource()).getEditingPath();
2014             }
2015         }));
2016     }
2017 
2018     /**
2019      * Maps {@code JTree.getExpandedDescendants(TreePath)} through queue
2020      */
2021     public Enumeration<TreePath> getExpandedDescendants(final TreePath treePath) {
2022         return (runMapping(new MapAction<Enumeration<TreePath>>("getExpandedDescendants") {
2023             @Override
2024             public Enumeration<TreePath> map() {
2025                 return ((JTree) getSource()).getExpandedDescendants(treePath);
2026             }
2027         }));
2028     }
2029 
2030     /**
2031      * Maps {@code JTree.getInvokesStopCellEditing()} through queue
2032      */
2033     public boolean getInvokesStopCellEditing() {
2034         return (runMapping(new MapBooleanAction("getInvokesStopCellEditing") {
2035             @Override
2036             public boolean map() {
2037                 return ((JTree) getSource()).getInvokesStopCellEditing();
2038             }
2039         }));
2040     }
2041 
2042     /**
2043      * Maps {@code JTree.getLastSelectedPathComponent()} through queue
2044      */
2045     public Object getLastSelectedPathComponent() {
2046         return (runMapping(new MapAction<Object>("getLastSelectedPathComponent") {
2047             @Override
2048             public Object map() {
2049                 return ((JTree) getSource()).getLastSelectedPathComponent();
2050             }
2051         }));
2052     }
2053 
2054     /**
2055      * Maps {@code JTree.getLeadSelectionPath()} through queue
2056      */
2057     public TreePath getLeadSelectionPath() {
2058         return (runMapping(new MapAction<TreePath>("getLeadSelectionPath") {
2059             @Override
2060             public TreePath map() {
2061                 return ((JTree) getSource()).getLeadSelectionPath();
2062             }
2063         }));
2064     }
2065 
2066     /**
2067      * Maps {@code JTree.getLeadSelectionRow()} through queue
2068      */
2069     public int getLeadSelectionRow() {
2070         return (runMapping(new MapIntegerAction("getLeadSelectionRow") {
2071             @Override
2072             public int map() {
2073                 return ((JTree) getSource()).getLeadSelectionRow();
2074             }
2075         }));
2076     }
2077 
2078     /**
2079      * Maps {@code JTree.getMaxSelectionRow()} through queue
2080      */
2081     public int getMaxSelectionRow() {
2082         return (runMapping(new MapIntegerAction("getMaxSelectionRow") {
2083             @Override
2084             public int map() {
2085                 return ((JTree) getSource()).getMaxSelectionRow();
2086             }
2087         }));
2088     }
2089 
2090     /**
2091      * Maps {@code JTree.getMinSelectionRow()} through queue
2092      */
2093     public int getMinSelectionRow() {
2094         return (runMapping(new MapIntegerAction("getMinSelectionRow") {
2095             @Override
2096             public int map() {
2097                 return ((JTree) getSource()).getMinSelectionRow();
2098             }
2099         }));
2100     }
2101 
2102     /**
2103      * Maps {@code JTree.getModel()} through queue
2104      */
2105     public TreeModel getModel() {
2106         return (runMapping(new MapAction<TreeModel>("getModel") {
2107             @Override
2108             public TreeModel map() {
2109                 return ((JTree) getSource()).getModel();
2110             }
2111         }));
2112     }
2113 
2114     /**
2115      * Maps {@code JTree.getPathBounds(TreePath)} through queue
2116      */
2117     public Rectangle getPathBounds(final TreePath treePath) {
2118         return (runMapping(new MapAction<Rectangle>("getPathBounds") {
2119             @Override
2120             public Rectangle map() {
2121                 return ((JTree) getSource()).getPathBounds(treePath);
2122             }
2123         }));
2124     }
2125 
2126     /**
2127      * Maps {@code JTree.getPathForLocation(int, int)} through queue
2128      */
2129     public TreePath getPathForLocation(final int i, final int i1) {
2130         return (runMapping(new MapAction<TreePath>("getPathForLocation") {
2131             @Override
2132             public TreePath map() {
2133                 return ((JTree) getSource()).getPathForLocation(i, i1);
2134             }
2135         }));
2136     }
2137 
2138     /**
2139      * Maps {@code JTree.getPathForRow(int)} through queue
2140      */
2141     public TreePath getPathForRow(final int i) {
2142         return (runMapping(new MapAction<TreePath>("getPathForRow") {
2143             @Override
2144             public TreePath map() {
2145                 return ((JTree) getSource()).getPathForRow(i);
2146             }
2147         }));
2148     }
2149 
2150     /**
2151      * Maps {@code JTree.getPreferredScrollableViewportSize()} through queue
2152      */
2153     public Dimension getPreferredScrollableViewportSize() {
2154         return (runMapping(new MapAction<Dimension>("getPreferredScrollableViewportSize") {
2155             @Override
2156             public Dimension map() {
2157                 return ((JTree) getSource()).getPreferredScrollableViewportSize();
2158             }
2159         }));
2160     }
2161 
2162     /**
2163      * Maps {@code JTree.getRowBounds(int)} through queue
2164      */
2165     public Rectangle getRowBounds(final int i) {
2166         return (runMapping(new MapAction<Rectangle>("getRowBounds") {
2167             @Override
2168             public Rectangle map() {
2169                 return ((JTree) getSource()).getRowBounds(i);
2170             }
2171         }));
2172     }
2173 
2174     /**
2175      * Maps {@code JTree.getRowCount()} through queue
2176      */
2177     public int getRowCount() {
2178         return (runMapping(new MapIntegerAction("getRowCount") {
2179             @Override
2180             public int map() {
2181                 return ((JTree) getSource()).getRowCount();
2182             }
2183         }));
2184     }
2185 
2186     /**
2187      * Maps {@code JTree.getRowForLocation(int, int)} through queue
2188      */
2189     public int getRowForLocation(final int i, final int i1) {
2190         return (runMapping(new MapIntegerAction("getRowForLocation") {
2191             @Override
2192             public int map() {
2193                 return ((JTree) getSource()).getRowForLocation(i, i1);
2194             }
2195         }));
2196     }
2197 
2198     /**
2199      * Maps {@code JTree.getRowForPath(TreePath)} through queue
2200      */
2201     public int getRowForPath(final TreePath treePath) {
2202         return (runMapping(new MapIntegerAction("getRowForPath") {
2203             @Override
2204             public int map() {
2205                 return ((JTree) getSource()).getRowForPath(treePath);
2206             }
2207         }));
2208     }
2209 
2210     /**
2211      * Maps {@code JTree.getRowHeight()} through queue
2212      */
2213     public int getRowHeight() {
2214         return (runMapping(new MapIntegerAction("getRowHeight") {
2215             @Override
2216             public int map() {
2217                 return ((JTree) getSource()).getRowHeight();
2218             }
2219         }));
2220     }
2221 
2222     /**
2223      * Maps {@code JTree.getScrollableBlockIncrement(Rectangle, int, int)}
2224      * through queue
2225      */
2226     public int getScrollableBlockIncrement(final Rectangle rectangle, final int i, final int i1) {
2227         return (runMapping(new MapIntegerAction("getScrollableBlockIncrement") {
2228             @Override
2229             public int map() {
2230                 return ((JTree) getSource()).getScrollableBlockIncrement(rectangle, i, i1);
2231             }
2232         }));
2233     }
2234 
2235     /**
2236      * Maps {@code JTree.getScrollableTracksViewportHeight()} through queue
2237      */
2238     public boolean getScrollableTracksViewportHeight() {
2239         return (runMapping(new MapBooleanAction("getScrollableTracksViewportHeight") {
2240             @Override
2241             public boolean map() {
2242                 return ((JTree) getSource()).getScrollableTracksViewportHeight();
2243             }
2244         }));
2245     }
2246 
2247     /**
2248      * Maps {@code JTree.getScrollableTracksViewportWidth()} through queue
2249      */
2250     public boolean getScrollableTracksViewportWidth() {
2251         return (runMapping(new MapBooleanAction("getScrollableTracksViewportWidth") {
2252             @Override
2253             public boolean map() {
2254                 return ((JTree) getSource()).getScrollableTracksViewportWidth();
2255             }
2256         }));
2257     }
2258 
2259     /**
2260      * Maps {@code JTree.getScrollableUnitIncrement(Rectangle, int, int)}
2261      * through queue
2262      */
2263     public int getScrollableUnitIncrement(final Rectangle rectangle, final int i, final int i1) {
2264         return (runMapping(new MapIntegerAction("getScrollableUnitIncrement") {
2265             @Override
2266             public int map() {
2267                 return ((JTree) getSource()).getScrollableUnitIncrement(rectangle, i, i1);
2268             }
2269         }));
2270     }
2271 
2272     /**
2273      * Maps {@code JTree.getScrollsOnExpand()} through queue
2274      */
2275     public boolean getScrollsOnExpand() {
2276         return (runMapping(new MapBooleanAction("getScrollsOnExpand") {
2277             @Override
2278             public boolean map() {
2279                 return ((JTree) getSource()).getScrollsOnExpand();
2280             }
2281         }));
2282     }
2283 
2284     /**
2285      * Maps {@code JTree.getSelectionCount()} through queue
2286      */
2287     public int getSelectionCount() {
2288         return (runMapping(new MapIntegerAction("getSelectionCount") {
2289             @Override
2290             public int map() {
2291                 return ((JTree) getSource()).getSelectionCount();
2292             }
2293         }));
2294     }
2295 
2296     /**
2297      * Maps {@code JTree.getSelectionModel()} through queue
2298      */
2299     public TreeSelectionModel getSelectionModel() {
2300         return (runMapping(new MapAction<TreeSelectionModel>("getSelectionModel") {
2301             @Override
2302             public TreeSelectionModel map() {
2303                 return ((JTree) getSource()).getSelectionModel();
2304             }
2305         }));
2306     }
2307 
2308     /**
2309      * Maps {@code JTree.getSelectionPath()} through queue
2310      */
2311     public TreePath getSelectionPath() {
2312         return (runMapping(new MapAction<TreePath>("getSelectionPath") {
2313             @Override
2314             public TreePath map() {
2315                 return ((JTree) getSource()).getSelectionPath();
2316             }
2317         }));
2318     }
2319 
2320     /**
2321      * Maps {@code JTree.getSelectionPaths()} through queue
2322      */
2323     public TreePath[] getSelectionPaths() {
2324         return ((TreePath[]) runMapping(new MapAction<Object>("getSelectionPaths") {
2325             @Override
2326             public Object map() {
2327                 return ((JTree) getSource()).getSelectionPaths();
2328             }
2329         }));
2330     }
2331 
2332     /**
2333      * Maps {@code JTree.getSelectionRows()} through queue
2334      */
2335     public int[] getSelectionRows() {
2336         return ((int[]) runMapping(new MapAction<Object>("getSelectionRows") {
2337             @Override
2338             public Object map() {
2339                 return ((JTree) getSource()).getSelectionRows();
2340             }
2341         }));
2342     }
2343 
2344     /**
2345      * Maps {@code JTree.getShowsRootHandles()} through queue
2346      */
2347     public boolean getShowsRootHandles() {
2348         return (runMapping(new MapBooleanAction("getShowsRootHandles") {
2349             @Override
2350             public boolean map() {
2351                 return ((JTree) getSource()).getShowsRootHandles();
2352             }
2353         }));
2354     }
2355 
2356     /**
2357      * Maps {@code JTree.getUI()} through queue
2358      */
2359     public TreeUI getUI() {
2360         return (runMapping(new MapAction<TreeUI>("getUI") {
2361             @Override
2362             public TreeUI map() {
2363                 return ((JTree) getSource()).getUI();
2364             }
2365         }));
2366     }
2367 
2368     /**
2369      * Maps {@code JTree.getVisibleRowCount()} through queue
2370      */
2371     public int getVisibleRowCount() {
2372         return (runMapping(new MapIntegerAction("getVisibleRowCount") {
2373             @Override
2374             public int map() {
2375                 return ((JTree) getSource()).getVisibleRowCount();
2376             }
2377         }));
2378     }
2379 
2380     /**
2381      * Maps {@code JTree.hasBeenExpanded(TreePath)} through queue
2382      */
2383     public boolean hasBeenExpanded(final TreePath treePath) {
2384         return (runMapping(new MapBooleanAction("hasBeenExpanded") {
2385             @Override
2386             public boolean map() {
2387                 return ((JTree) getSource()).hasBeenExpanded(treePath);
2388             }
2389         }));
2390     }
2391 
2392     /**
2393      * Maps {@code JTree.isCollapsed(int)} through queue
2394      */
2395     public boolean isCollapsed(final int i) {
2396         return (runMapping(new MapBooleanAction("isCollapsed") {
2397             @Override
2398             public boolean map() {
2399                 return ((JTree) getSource()).isCollapsed(i);
2400             }
2401         }));
2402     }
2403 
2404     /**
2405      * Maps {@code JTree.isCollapsed(TreePath)} through queue
2406      */
2407     public boolean isCollapsed(final TreePath treePath) {
2408         return (runMapping(new MapBooleanAction("isCollapsed") {
2409             @Override
2410             public boolean map() {
2411                 return ((JTree) getSource()).isCollapsed(treePath);
2412             }
2413         }));
2414     }
2415 
2416     /**
2417      * Maps {@code JTree.isEditable()} through queue
2418      */
2419     public boolean isEditable() {
2420         return (runMapping(new MapBooleanAction("isEditable") {
2421             @Override
2422             public boolean map() {
2423                 return ((JTree) getSource()).isEditable();
2424             }
2425         }));
2426     }
2427 
2428     /**
2429      * Maps {@code JTree.isEditing()} through queue
2430      */
2431     public boolean isEditing() {
2432         return (runMapping(new MapBooleanAction("isEditing") {
2433             @Override
2434             public boolean map() {
2435                 return ((JTree) getSource()).isEditing();
2436             }
2437         }));
2438     }
2439 
2440     /**
2441      * Maps {@code JTree.isExpanded(int)} through queue
2442      */
2443     public boolean isExpanded(final int i) {
2444         return (runMapping(new MapBooleanAction("isExpanded") {
2445             @Override
2446             public boolean map() {
2447                 return ((JTree) getSource()).isExpanded(i);
2448             }
2449         }));
2450     }
2451 
2452     /**
2453      * Maps {@code JTree.isExpanded(TreePath)} through queue
2454      */
2455     public boolean isExpanded(final TreePath treePath) {
2456         return (runMapping(new MapBooleanAction("isExpanded") {
2457             @Override
2458             public boolean map() {
2459                 return ((JTree) getSource()).isExpanded(treePath);
2460             }
2461         }));
2462     }
2463 
2464     /**
2465      * Maps {@code JTree.isFixedRowHeight()} through queue
2466      */
2467     public boolean isFixedRowHeight() {
2468         return (runMapping(new MapBooleanAction("isFixedRowHeight") {
2469             @Override
2470             public boolean map() {
2471                 return ((JTree) getSource()).isFixedRowHeight();
2472             }
2473         }));
2474     }
2475 
2476     /**
2477      * Maps {@code JTree.isLargeModel()} through queue
2478      */
2479     public boolean isLargeModel() {
2480         return (runMapping(new MapBooleanAction("isLargeModel") {
2481             @Override
2482             public boolean map() {
2483                 return ((JTree) getSource()).isLargeModel();
2484             }
2485         }));
2486     }
2487 
2488     /**
2489      * Maps {@code JTree.isPathEditable(TreePath)} through queue
2490      */
2491     public boolean isPathEditable(final TreePath treePath) {
2492         return (runMapping(new MapBooleanAction("isPathEditable") {
2493             @Override
2494             public boolean map() {
2495                 return ((JTree) getSource()).isPathEditable(treePath);
2496             }
2497         }));
2498     }
2499 
2500     /**
2501      * Maps {@code JTree.isPathSelected(TreePath)} through queue
2502      */
2503     public boolean isPathSelected(final TreePath treePath) {
2504         return (runMapping(new MapBooleanAction("isPathSelected") {
2505             @Override
2506             public boolean map() {
2507                 return ((JTree) getSource()).isPathSelected(treePath);
2508             }
2509         }));
2510     }
2511 
2512     /**
2513      * Maps {@code JTree.isRootVisible()} through queue
2514      */
2515     public boolean isRootVisible() {
2516         return (runMapping(new MapBooleanAction("isRootVisible") {
2517             @Override
2518             public boolean map() {
2519                 return ((JTree) getSource()).isRootVisible();
2520             }
2521         }));
2522     }
2523 
2524     /**
2525      * Maps {@code JTree.isRowSelected(int)} through queue
2526      */
2527     public boolean isRowSelected(final int i) {
2528         return (runMapping(new MapBooleanAction("isRowSelected") {
2529             @Override
2530             public boolean map() {
2531                 return ((JTree) getSource()).isRowSelected(i);
2532             }
2533         }));
2534     }
2535 
2536     /**
2537      * Maps {@code JTree.isSelectionEmpty()} through queue
2538      */
2539     public boolean isSelectionEmpty() {
2540         return (runMapping(new MapBooleanAction("isSelectionEmpty") {
2541             @Override
2542             public boolean map() {
2543                 return ((JTree) getSource()).isSelectionEmpty();
2544             }
2545         }));
2546     }
2547 
2548     /**
2549      * Maps {@code JTree.isVisible(TreePath)} through queue
2550      */
2551     public boolean isVisible(final TreePath treePath) {
2552         return (runMapping(new MapBooleanAction("isVisible") {
2553             @Override
2554             public boolean map() {
2555                 return ((JTree) getSource()).isVisible(treePath);
2556             }
2557         }));
2558     }
2559 
2560     /**
2561      * Maps {@code JTree.makeVisible(TreePath)} through queue
2562      */
2563     public void makeVisible(final TreePath treePath) {
2564         runMapping(new MapVoidAction("makeVisible") {
2565             @Override
2566             public void map() {
2567                 ((JTree) getSource()).makeVisible(treePath);
2568             }
2569         });
2570     }
2571 
2572     /**
2573      * Maps {@code JTree.removeSelectionInterval(int, int)} through queue
2574      */
2575     public void removeSelectionInterval(final int i, final int i1) {
2576         runMapping(new MapVoidAction("removeSelectionInterval") {
2577             @Override
2578             public void map() {
2579                 ((JTree) getSource()).removeSelectionInterval(i, i1);
2580             }
2581         });
2582     }
2583 
2584     /**
2585      * Maps {@code JTree.removeSelectionPath(TreePath)} through queue
2586      */
2587     public void removeSelectionPath(final TreePath treePath) {
2588         runMapping(new MapVoidAction("removeSelectionPath") {
2589             @Override
2590             public void map() {
2591                 ((JTree) getSource()).removeSelectionPath(treePath);
2592             }
2593         });
2594     }
2595 
2596     /**
2597      * Maps {@code JTree.removeSelectionPaths(TreePath[])} through queue
2598      */
2599     public void removeSelectionPaths(final TreePath[] treePath) {
2600         runMapping(new MapVoidAction("removeSelectionPaths") {
2601             @Override
2602             public void map() {
2603                 ((JTree) getSource()).removeSelectionPaths(treePath);
2604             }
2605         });
2606     }
2607 
2608     /**
2609      * Maps {@code JTree.removeSelectionRow(int)} through queue
2610      */
2611     public void removeSelectionRow(final int i) {
2612         runMapping(new MapVoidAction("removeSelectionRow") {
2613             @Override
2614             public void map() {
2615                 ((JTree) getSource()).removeSelectionRow(i);
2616             }
2617         });
2618     }
2619 
2620     /**
2621      * Maps {@code JTree.removeSelectionRows(int[])} through queue
2622      */
2623     public void removeSelectionRows(final int[] i) {
2624         runMapping(new MapVoidAction("removeSelectionRows") {
2625             @Override
2626             public void map() {
2627                 ((JTree) getSource()).removeSelectionRows(i);
2628             }
2629         });
2630     }
2631 
2632     /**
2633      * Maps
2634      * {@code JTree.removeTreeExpansionListener(TreeExpansionListener)}
2635      * through queue
2636      */
2637     public void removeTreeExpansionListener(final TreeExpansionListener treeExpansionListener) {
2638         runMapping(new MapVoidAction("removeTreeExpansionListener") {
2639             @Override
2640             public void map() {
2641                 ((JTree) getSource()).removeTreeExpansionListener(treeExpansionListener);
2642             }
2643         });
2644     }
2645 
2646     /**
2647      * Maps
2648      * {@code JTree.removeTreeSelectionListener(TreeSelectionListener)}
2649      * through queue
2650      */
2651     public void removeTreeSelectionListener(final TreeSelectionListener treeSelectionListener) {
2652         runMapping(new MapVoidAction("removeTreeSelectionListener") {
2653             @Override
2654             public void map() {
2655                 ((JTree) getSource()).removeTreeSelectionListener(treeSelectionListener);
2656             }
2657         });
2658     }
2659 
2660     /**
2661      * Maps
2662      * {@code JTree.removeTreeWillExpandListener(TreeWillExpandListener)}
2663      * through queue
2664      */
2665     public void removeTreeWillExpandListener(final TreeWillExpandListener treeWillExpandListener) {
2666         runMapping(new MapVoidAction("removeTreeWillExpandListener") {
2667             @Override
2668             public void map() {
2669                 ((JTree) getSource()).removeTreeWillExpandListener(treeWillExpandListener);
2670             }
2671         });
2672     }
2673 
2674     /**
2675      * Maps {@code JTree.scrollPathToVisible(TreePath)} through queue
2676      */
2677     public void scrollPathToVisible(final TreePath treePath) {
2678         runMapping(new MapVoidAction("scrollPathToVisible") {
2679             @Override
2680             public void map() {
2681                 ((JTree) getSource()).scrollPathToVisible(treePath);
2682             }
2683         });
2684     }
2685 
2686     /**
2687      * Maps {@code JTree.scrollRowToVisible(int)} through queue
2688      */
2689     public void scrollRowToVisible(final int i) {
2690         runMapping(new MapVoidAction("scrollRowToVisible") {
2691             @Override
2692             public void map() {
2693                 ((JTree) getSource()).scrollRowToVisible(i);
2694             }
2695         });
2696     }
2697 
2698     /**
2699      * Maps {@code JTree.setCellEditor(TreeCellEditor)} through queue
2700      */
2701     public void setCellEditor(final TreeCellEditor treeCellEditor) {
2702         runMapping(new MapVoidAction("setCellEditor") {
2703             @Override
2704             public void map() {
2705                 ((JTree) getSource()).setCellEditor(treeCellEditor);
2706             }
2707         });
2708     }
2709 
2710     /**
2711      * Maps {@code JTree.setCellRenderer(TreeCellRenderer)} through queue
2712      */
2713     public void setCellRenderer(final TreeCellRenderer treeCellRenderer) {
2714         runMapping(new MapVoidAction("setCellRenderer") {
2715             @Override
2716             public void map() {
2717                 ((JTree) getSource()).setCellRenderer(treeCellRenderer);
2718             }
2719         });
2720     }
2721 
2722     /**
2723      * Maps {@code JTree.setEditable(boolean)} through queue
2724      */
2725     public void setEditable(final boolean b) {
2726         runMapping(new MapVoidAction("setEditable") {
2727             @Override
2728             public void map() {
2729                 ((JTree) getSource()).setEditable(b);
2730             }
2731         });
2732     }
2733 
2734     /**
2735      * Maps {@code JTree.setInvokesStopCellEditing(boolean)} through queue
2736      */
2737     public void setInvokesStopCellEditing(final boolean b) {
2738         runMapping(new MapVoidAction("setInvokesStopCellEditing") {
2739             @Override
2740             public void map() {
2741                 ((JTree) getSource()).setInvokesStopCellEditing(b);
2742             }
2743         });
2744     }
2745 
2746     /**
2747      * Maps {@code JTree.setLargeModel(boolean)} through queue
2748      */
2749     public void setLargeModel(final boolean b) {
2750         runMapping(new MapVoidAction("setLargeModel") {
2751             @Override
2752             public void map() {
2753                 ((JTree) getSource()).setLargeModel(b);
2754             }
2755         });
2756     }
2757 
2758     /**
2759      * Maps {@code JTree.setModel(TreeModel)} through queue
2760      */
2761     public void setModel(final TreeModel treeModel) {
2762         runMapping(new MapVoidAction("setModel") {
2763             @Override
2764             public void map() {
2765                 ((JTree) getSource()).setModel(treeModel);
2766             }
2767         });
2768     }
2769 
2770     /**
2771      * Maps {@code JTree.setRootVisible(boolean)} through queue
2772      */
2773     public void setRootVisible(final boolean b) {
2774         runMapping(new MapVoidAction("setRootVisible") {
2775             @Override
2776             public void map() {
2777                 ((JTree) getSource()).setRootVisible(b);
2778             }
2779         });
2780     }
2781 
2782     /**
2783      * Maps {@code JTree.setRowHeight(int)} through queue
2784      */
2785     public void setRowHeight(final int i) {
2786         runMapping(new MapVoidAction("setRowHeight") {
2787             @Override
2788             public void map() {
2789                 ((JTree) getSource()).setRowHeight(i);
2790             }
2791         });
2792     }
2793 
2794     /**
2795      * Maps {@code JTree.setScrollsOnExpand(boolean)} through queue
2796      */
2797     public void setScrollsOnExpand(final boolean b) {
2798         runMapping(new MapVoidAction("setScrollsOnExpand") {
2799             @Override
2800             public void map() {
2801                 ((JTree) getSource()).setScrollsOnExpand(b);
2802             }
2803         });
2804     }
2805 
2806     /**
2807      * Maps {@code JTree.setSelectionInterval(int, int)} through queue
2808      */
2809     public void setSelectionInterval(final int i, final int i1) {
2810         runMapping(new MapVoidAction("setSelectionInterval") {
2811             @Override
2812             public void map() {
2813                 ((JTree) getSource()).setSelectionInterval(i, i1);
2814             }
2815         });
2816     }
2817 
2818     /**
2819      * Maps {@code JTree.setSelectionModel(TreeSelectionModel)} through queue
2820      */
2821     public void setSelectionModel(final TreeSelectionModel treeSelectionModel) {
2822         runMapping(new MapVoidAction("setSelectionModel") {
2823             @Override
2824             public void map() {
2825                 ((JTree) getSource()).setSelectionModel(treeSelectionModel);
2826             }
2827         });
2828     }
2829 
2830     /**
2831      * Maps {@code JTree.setSelectionPath(TreePath)} through queue
2832      */
2833     public void setSelectionPath(final TreePath treePath) {
2834         runMapping(new MapVoidAction("setSelectionPath") {
2835             @Override
2836             public void map() {
2837                 ((JTree) getSource()).setSelectionPath(treePath);
2838             }
2839         });
2840     }
2841 
2842     /**
2843      * Maps {@code JTree.setSelectionPaths(TreePath[])} through queue
2844      */
2845     public void setSelectionPaths(final TreePath[] treePath) {
2846         runMapping(new MapVoidAction("setSelectionPaths") {
2847             @Override
2848             public void map() {
2849                 ((JTree) getSource()).setSelectionPaths(treePath);
2850             }
2851         });
2852     }
2853 
2854     /**
2855      * Maps {@code JTree.setSelectionRow(int)} through queue
2856      */
2857     public void setSelectionRow(final int i) {
2858         runMapping(new MapVoidAction("setSelectionRow") {
2859             @Override
2860             public void map() {
2861                 ((JTree) getSource()).setSelectionRow(i);
2862             }
2863         });
2864     }
2865 
2866     /**
2867      * Maps {@code JTree.setSelectionRows(int[])} through queue
2868      */
2869     public void setSelectionRows(final int[] i) {
2870         runMapping(new MapVoidAction("setSelectionRows") {
2871             @Override
2872             public void map() {
2873                 ((JTree) getSource()).setSelectionRows(i);
2874             }
2875         });
2876     }
2877 
2878     /**
2879      * Maps {@code JTree.setShowsRootHandles(boolean)} through queue
2880      */
2881     public void setShowsRootHandles(final boolean b) {
2882         runMapping(new MapVoidAction("setShowsRootHandles") {
2883             @Override
2884             public void map() {
2885                 ((JTree) getSource()).setShowsRootHandles(b);
2886             }
2887         });
2888     }
2889 
2890     /**
2891      * Maps {@code JTree.setUI(TreeUI)} through queue
2892      */
2893     public void setUI(final TreeUI treeUI) {
2894         runMapping(new MapVoidAction("setUI") {
2895             @Override
2896             public void map() {
2897                 ((JTree) getSource()).setUI(treeUI);
2898             }
2899         });
2900     }
2901 
2902     /**
2903      * Maps {@code JTree.setVisibleRowCount(int)} through queue
2904      */
2905     public void setVisibleRowCount(final int i) {
2906         runMapping(new MapVoidAction("setVisibleRowCount") {
2907             @Override
2908             public void map() {
2909                 ((JTree) getSource()).setVisibleRowCount(i);
2910             }
2911         });
2912     }
2913 
2914     /**
2915      * Maps {@code JTree.startEditingAtPath(TreePath)} through queue
2916      */
2917     public void startEditingAtPath(final TreePath treePath) {
2918         runMapping(new MapVoidAction("startEditingAtPath") {
2919             @Override
2920             public void map() {
2921                 ((JTree) getSource()).startEditingAtPath(treePath);
2922             }
2923         });
2924     }
2925 
2926     /**
2927      * Maps {@code JTree.stopEditing()} through queue
2928      */
2929     public boolean stopEditing() {
2930         return (runMapping(new MapBooleanAction("stopEditing") {
2931             @Override
2932             public boolean map() {
2933                 return ((JTree) getSource()).stopEditing();
2934             }
2935         }));
2936     }
2937 
2938     /**
2939      * Maps {@code JTree.treeDidChange()} through queue
2940      */
2941     public void treeDidChange() {
2942         runMapping(new MapVoidAction("treeDidChange") {
2943             @Override
2944             public void map() {
2945                 ((JTree) getSource()).treeDidChange();
2946             }
2947         });
2948     }
2949 
2950     //End of mapping                                      //
2951     ////////////////////////////////////////////////////////
2952     /**
2953      * Iterface to choose tree row. Defines criteria to distinguish row.
2954      */
2955     public interface TreeRowChooser {
2956 
2957         /**
2958          * Should be true if row is good.
2959          *
2960          * @param oper Operator used to search item.
2961          * @param row Row be checked.
2962          * @return true if the row fits the criteria
2963          */
2964         public boolean checkRow(JTreeOperator oper, int row);
2965 
2966         /**
2967          * Row description.
2968          *
2969          * @return a criteria description.
2970          */
2971         public String getDescription();
2972     }
2973 
2974     private TreePath findPathPrimitive(TreePath path, TreePathChooser chooser, Waiter<Object[], Object[]> loadedWaiter) {
2975         if (!isExpanded(path)) {
2976             if (!isPathSelected(path)) {
2977                 clickOnPath(path);
2978             }
2979             expandPath(path);
2980         }
2981         Object[] waitParam = {chooser, path};
2982         Object[] waitResult = null;
2983         try {
2984             waitResult = loadedWaiter.waitAction(waitParam);
2985         } catch (InterruptedException e) {
2986             output.printStackTrace(e);
2987             return null;
2988         }
2989         TreePath nextPath = (TreePath) waitResult[0];
2990         boolean found = (Boolean) waitResult[1];
2991         if (found) {
2992             return nextPath;
2993         } else {
2994             return findPathPrimitive(nextPath, chooser, loadedWaiter);
2995         }
2996     }
2997 
2998     private String[] addChildrenToDump(Hashtable<String, Object> table, String title, Object node, TreePath path) {
2999         if (((JTree) getSource()).isExpanded(path)) {
3000             Object[] subNodes = getChildren(node);
3001             String[] names = addToDump(table, title, subNodes);
3002             for (int i = 0; i < subNodes.length; i++) {
3003                 addChildrenToDump(table, names[i], subNodes[i], path.pathByAddingChild(subNodes[i]));
3004             }
3005             return names;
3006         } else {
3007             return new String[0];
3008         }
3009     }
3010 
3011     private static String pathToString(String[] path) {
3012         StringBuilder desc = new StringBuilder("[ ");
3013         for (String aPath : path) {
3014             desc.append(aPath).append(", ");
3015         }
3016         if (desc.length() > 2) {
3017             desc.setLength(desc.length() - 2);
3018         }
3019         desc.append(" ]");
3020         return desc.toString();
3021     }
3022 
3023     /**
3024      * Can be throught during item selecting if list does not have item
3025      * requested.
3026      */
3027     public class NoSuchPathException extends JemmyInputException {
3028 
3029         private static final long serialVersionUID = 42L;
3030 
3031         /**
3032          * Constructor.
3033          */
3034         public NoSuchPathException() {
3035             super("Unknown/null/invalid tree path.", null);
3036         }
3037 
3038         /**
3039          * Constructor.
3040          *
3041          * @param path a nonexistent path.
3042          */
3043         public NoSuchPathException(String[] path) {
3044             super("No such path as \"" + pathToString(path) + "\"", getSource());
3045         }
3046 
3047         /**
3048          * Constructor.
3049          *
3050          * @param index a nonexistent line index.
3051          */
3052         public NoSuchPathException(int index) {
3053             super("Tree does not contain " + index + "'th line", getSource());
3054         }
3055 
3056         /**
3057          * Constructor.
3058          *
3059          * @param path a nonexistent path.
3060          */
3061         public NoSuchPathException(TreePath path) {
3062             super("No such path as \"" + path.toString() + "\"", getSource());
3063         }
3064     }
3065 
3066     /**
3067      * Specifies criteria for path searching.
3068      */
3069     public interface TreePathChooser {
3070 
3071         /**
3072          * Checks if the path fits the criteria.
3073          *
3074          * @param path TreePath to check.
3075          * @param indexInParent Index of the "path" in path's parent.
3076          * @return true if the path fits the criteria
3077          */
3078         public boolean checkPath(TreePath path, int indexInParent);
3079 
3080         /**
3081          * Checks if the path has another path as a parent.
3082          *
3083          * @param path TreePath to check.
3084          * @param indexInParent Index of the "path" in path's parent.
3085          * @return true if path looked for is a child/grandchild of a path
3086          * passed as a parameter.
3087          */
3088         public boolean hasAsParent(TreePath path, int indexInParent);
3089 
3090         /**
3091          * Returns the description.
3092          *
3093          * @return a description.
3094          */
3095         public String getDescription();
3096     }
3097 
3098     /**
3099      * Specifies searching criteria basing on nodes' text.
3100      */
3101     class StringArrayPathChooser implements TreePathChooser {
3102 
3103         String[] arr;
3104         int[] indices;
3105         StringComparator comparator;
3106 
3107         /**
3108          * Constructs StringArrayPathChooser.
3109          *
3110          * @param arr a node text array. First element defines a text of a first
3111          * node under a tree root, second element - a children of the first
3112          * node, ...
3113          * @param indices indexes of nodes in nodes' parents.
3114          * @param comparator String comparision criteria.
3115          */
3116         StringArrayPathChooser(String[] arr, int[] indices, StringComparator comparator) {
3117             this.arr = arr;
3118             this.comparator = comparator;
3119             this.indices = indices;
3120         }
3121 
3122         @Override
3123         public boolean checkPath(TreePath path, int indexInParent) {
3124             return (path.getPathCount() - 1 == arr.length
3125                     && hasAsParent(path, indexInParent));
3126         }
3127 
3128         @Override
3129         public boolean hasAsParent(TreePath path, int indexInParent) {
3130             Object[] comps = path.getPath();
3131             Object node;
3132             for (int i = 1; i < comps.length; i++) {
3133                 if (arr.length < path.getPathCount() - 1) {
3134                     return false;
3135                 }
3136                 /*
3137                 if(!comparator.equals(comps[i].toString(), arr[i - 1])) {
3138                     return false;
3139                 }
3140                  */
3141                 if (indices.length >= path.getPathCount() - 1) {
3142                     node = chooseSubnode(comps[i - 1], arr[i - 1], indices[i - 1], comparator);
3143                 } else {
3144                     node = chooseSubnode(comps[i - 1], arr[i - 1], comparator);
3145                 }
3146                 if (node != comps[i]) {
3147                     return false;
3148                 }
3149             }
3150             return true;
3151         }
3152 
3153         @Override
3154         public String getDescription() {
3155             return pathToString(arr);
3156         }
3157 
3158         @Override
3159         public String toString() {
3160             return "StringArrayPathChooser{" + "arr=" + arr + ", indices=" + indices + ", comparator=" + comparator + '}';
3161         }
3162     }
3163 
3164     private static class BySubStringTreeRowChooser implements TreeRowChooser {
3165 
3166         String subString;
3167         StringComparator comparator;
3168 
3169         public BySubStringTreeRowChooser(String subString, StringComparator comparator) {
3170             this.subString = subString;
3171             this.comparator = comparator;
3172         }
3173 
3174         @Override
3175         public boolean checkRow(JTreeOperator oper, int row) {
3176             return (comparator.equals(oper.getPathForRow(row).getLastPathComponent().toString(),
3177                     subString));
3178         }
3179 
3180         @Override
3181         public String getDescription() {
3182             return "Row containing \"" + subString + "\" string";
3183         }
3184 
3185         @Override
3186         public String toString() {
3187             return "BySubStringTreeRowChooser{" + "subString=" + subString + ", comparator=" + comparator + '}';
3188         }
3189     }
3190 
3191     private static class ByRenderedComponentTreeRowChooser implements TreeRowChooser {
3192 
3193         ComponentChooser chooser;
3194 
3195         public ByRenderedComponentTreeRowChooser(ComponentChooser chooser) {
3196             this.chooser = chooser;
3197         }
3198 
3199         @Override
3200         public boolean checkRow(JTreeOperator oper, int row) {
3201             return chooser.checkComponent(oper.getRenderedComponent(oper.getPathForRow(row)));
3202         }
3203 
3204         @Override
3205         public String getDescription() {
3206             return chooser.getDescription();
3207         }
3208 
3209         @Override
3210         public String toString() {
3211             return "ByRenderedComponentTreeRowChooser{" + "chooser=" + chooser + '}';
3212         }
3213     }
3214 
3215     /**
3216      * Checks component type.
3217      */
3218     public static class JTreeFinder extends Finder {
3219 
3220         /**
3221          * Constructs JTreeFinder.
3222          *
3223          * @param sf other searching criteria.
3224          */
3225         public JTreeFinder(ComponentChooser sf) {
3226             super(JTree.class, sf);
3227         }
3228 
3229         /**
3230          * Constructs JTreeFinder.
3231          */
3232         public JTreeFinder() {
3233             super(JTree.class);
3234         }
3235     }
3236 
3237     /**
3238      * Allows to find component by node text.
3239      */
3240     public static class JTreeByItemFinder implements ComponentChooser {
3241 
3242         String label;
3243         int rowIndex;
3244         StringComparator comparator;
3245 
3246         /**
3247          * Constructs JTreeByItemFinder.
3248          *
3249          * @param lb a text pattern
3250          * @param ii row index to check. If equal to -1, selected row is
3251          * checked.
3252          * @param comparator specifies string comparision algorithm.
3253          */
3254         public JTreeByItemFinder(String lb, int ii, StringComparator comparator) {
3255             label = lb;
3256             rowIndex = ii;
3257             this.comparator = comparator;
3258         }
3259 
3260         /**
3261          * Constructs JTreeByItemFinder.
3262          *
3263          * @param lb a text pattern
3264          * @param ii row index to check. If equal to -1, selected row is
3265          * checked.
3266          */
3267         public JTreeByItemFinder(String lb, int ii) {
3268             this(lb, ii, Operator.getDefaultStringComparator());
3269         }
3270 
3271         @Override
3272         public boolean checkComponent(Component comp) {
3273             if (comp instanceof JTree) {
3274                 if (label == null) {
3275                     return true;
3276                 }
3277                 if (((JTree) comp).getRowCount() > rowIndex) {
3278                     int ii = rowIndex;
3279                     if (ii == -1) {
3280                         int[] rows = ((JTree) comp).getSelectionRows();
3281                         if (rows != null && rows.length > 0) {
3282                             ii = rows[0];
3283                         } else {
3284                             return false;
3285                         }
3286                     }
3287                     TreePath path = ((JTree) comp).getPathForRow(ii);
3288                     if (path != null) {
3289                         return (comparator.equals(path.getPathComponent(path.getPathCount() - 1).toString(),
3290                                 label));
3291                     }
3292                 }
3293             }
3294             return false;
3295         }
3296 
3297         @Override
3298         public String getDescription() {
3299             return ("JTree with text \"" + label + "\" in "
3300                     + rowIndex + "'th row");
3301         }
3302 
3303         @Override
3304         public String toString() {
3305             return "JTreeByItemFinder{" + "label=" + label + ", rowIndex=" + rowIndex + ", comparator=" + comparator + '}';
3306         }
3307     }
3308 }
3309