1 /*
2  * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 /*
24    @test
25   @key headful
26    @bug 4927934
27    @summary JTree traversal is unlike Native windows tree traversal
28    @author Andrey Pikalev
29    @run main bug4927934
30 */
31 
32 import javax.swing.*;
33 import javax.swing.event.*;
34 import javax.swing.tree.*;
35 import java.awt.*;
36 import java.awt.event.*;
37 import java.lang.reflect.InvocationTargetException;
38 
39 public class bug4927934 implements TreeSelectionListener, TreeExpansionListener, FocusListener {
40 
41     final static Object listener = new bug4927934();
42 
43     static boolean focusGained = false;
44     public static boolean selectionChanged = false;
45     public static boolean treeExpanded = false;
46     public static boolean treeCollapsed = false;
47 
48     static JFrame frame;
49     static JTree tree;
50     static Robot robot;
51 
main(String args[])52     public static void main(String args[]) throws Exception {
53         UIManager.setLookAndFeel(new javax.swing.plaf.metal.MetalLookAndFeel());
54 
55         robot = new Robot();
56         robot.setAutoDelay(50);
57 
58         SwingUtilities.invokeAndWait(new Runnable() {
59             public void run() {
60                 frame = new JFrame();
61 
62                 DefaultMutableTreeNode root = new DefaultMutableTreeNode("root");
63                 createNodes(root);
64                 tree = new JTree(root);
65                 JScrollPane scrollPane = new JScrollPane(tree);
66                 frame.getContentPane().add(scrollPane);
67 
68                 tree.addFocusListener((FocusListener)listener);
69                 tree.addTreeSelectionListener((TreeSelectionListener)listener);
70                 tree.addTreeExpansionListener((TreeExpansionListener)listener);
71 
72                 frame.setSize(300, 300);
73                 frame.setVisible(true);
74             }
75         });
76 
77         robot.waitForIdle();
78         Thread.sleep(1000);
79 
80         SwingUtilities.invokeLater(new Runnable() {
81             public void run() {
82                 tree.requestFocus();
83             }
84         });
85 
86         synchronized(listener) {
87             if (!focusGained) {
88                 System.out.println("waiting focusGained...");
89                 try {
90                     listener.wait(10000);
91                 } catch (InterruptedException e) {
92                     e.printStackTrace();
93                 }
94             }
95         }
96 
97         // GO TO RIGHT
98         selectionChanged = false;
99         hitKey(KeyEvent.VK_RIGHT);
100         robot.waitForIdle();
101         if (!checkSelectionChanged(tree, 0)) {
102             throw new RuntimeException("Root should be selected");
103         }
104 
105         selectionChanged = false;
106         hitKey(KeyEvent.VK_RIGHT);
107         robot.waitForIdle();
108         if (!checkSelectionChanged(tree, 1)) {
109             throw new RuntimeException("Node should be selected");
110         }
111 
112         treeExpanded = false;
113         hitKey(KeyEvent.VK_RIGHT);
114         robot.waitForIdle();
115         if (!isTreeExpanded()) {
116             throw new RuntimeException("Node should be expanded");
117         }
118 
119         selectionChanged = false;
120         hitKey(KeyEvent.VK_RIGHT);
121         robot.waitForIdle();
122         if (!checkSelectionChanged(tree, 2)) {
123             throw new RuntimeException("Leaf1 should be selected");
124         }
125 
126         selectionChanged = false;
127         hitKey(KeyEvent.VK_RIGHT);
128         robot.waitForIdle();
129         if (!checkSelectionChanged(tree, 2)) {
130             throw new RuntimeException("Leaf1 should be selected");
131         }
132 
133         // GO TO LEFT
134         selectionChanged = false;
135         hitKey(KeyEvent.VK_LEFT);
136         robot.waitForIdle();
137         if (!checkSelectionChanged(tree, 1)) {
138             throw new RuntimeException("Node should be selected");
139         }
140 
141         treeCollapsed = false;
142         hitKey(KeyEvent.VK_LEFT);
143         if (!isTreeCollapsed()) {
144             throw new RuntimeException("Node should be collapsed");
145         }
146 
147         selectionChanged = false;
148         hitKey(KeyEvent.VK_LEFT);
149         robot.waitForIdle();
150         if (!checkSelectionChanged(tree, 0)) {
151             throw new RuntimeException("Root should be selected");
152         }
153 
154         treeCollapsed = false;
155         hitKey(KeyEvent.VK_LEFT);
156         robot.waitForIdle();
157         if (!isTreeCollapsed()) {
158             throw new RuntimeException("Root should be collapsed");
159         }
160     }
161 
162 
focusLost(FocusEvent e)163     synchronized public void focusLost(FocusEvent e) {
164     }
165 
focusGained(FocusEvent e)166     synchronized public void focusGained(FocusEvent e) {
167         focusGained = true;
168         System.out.println("focusGained");
169         listener.notifyAll();
170     }
171 
createNodes(DefaultMutableTreeNode root)172     private static void createNodes(DefaultMutableTreeNode root) {
173         DefaultMutableTreeNode node = new DefaultMutableTreeNode("Node");
174         node.add(new DefaultMutableTreeNode("Leaf1"));
175         node.add(new DefaultMutableTreeNode("Leaf2"));
176         root.add(node);
177         root.add(new DefaultMutableTreeNode("Leaf3"));
178     }
179 
valueChanged(TreeSelectionEvent e)180     synchronized public void valueChanged(TreeSelectionEvent e) {
181         selectionChanged = true;
182         System.out.println("selectionChanged");
183         notifyAll();
184     }
185 
treeCollapsed(TreeExpansionEvent e)186     synchronized public void treeCollapsed(TreeExpansionEvent e) {
187         System.out.println("treeCollapsed");
188         treeCollapsed = true;
189         notifyAll();
190     }
191 
treeExpanded(TreeExpansionEvent e)192     synchronized public void treeExpanded(TreeExpansionEvent e) {
193         System.out.println("treeExpanded");
194         treeExpanded = true;
195         notifyAll();
196     }
197 
hitKey(int key)198     private static void hitKey(int key) {
199         System.out.println("key " + key + " pressed");
200         robot.keyPress(key);
201         robot.keyRelease(key);
202     }
203 
checkSelectionChanged(JTree tree, int shouldBeSel)204     private static boolean checkSelectionChanged(JTree tree, int shouldBeSel) {
205         synchronized(listener) {
206             if (!selectionChanged) {
207                 System.out.println("waiting for selectionChanged...");
208                 try {
209                     listener.wait(5000);
210                 } catch (InterruptedException e) {
211                     e.printStackTrace();
212                 }
213             }
214         }
215         int selRow = tree.getLeadSelectionRow();
216         System.out.println("Selected row: " + selRow);
217         return selRow == shouldBeSel;
218     }
219 
isTreeExpanded()220     private static boolean isTreeExpanded() {
221         synchronized(listener) {
222             if (!treeExpanded) {
223                 System.out.println("waiting for treeExpanded...");
224                 try {
225                     listener.wait(5000);
226                 } catch (InterruptedException e) {
227                     e.printStackTrace();
228                 }
229             }
230         }
231         return treeExpanded;
232     }
233 
isTreeCollapsed()234     private static boolean isTreeCollapsed() {
235         synchronized(listener) {
236             if (!treeCollapsed) {
237                 System.out.println("waiting for treeCollapsed...");
238                 try {
239                     listener.wait(5000);
240                 } catch (InterruptedException e) {
241                     e.printStackTrace();
242                 }
243             }
244         }
245         return treeCollapsed;
246     }
247 }
248