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 java.awt.Robot; 33 import java.awt.event.FocusEvent; 34 import java.awt.event.FocusListener; 35 import java.awt.event.KeyEvent; 36 37 import javax.swing.JFrame; 38 import javax.swing.JTree; 39 import javax.swing.SwingUtilities; 40 import javax.swing.UIManager; 41 import javax.swing.JScrollPane; 42 import javax.swing.event.TreeSelectionListener; 43 import javax.swing.event.TreeExpansionListener; 44 import javax.swing.event.TreeSelectionEvent; 45 import javax.swing.event.TreeExpansionEvent; 46 import javax.swing.tree.DefaultMutableTreeNode; 47 48 public class bug4927934 implements TreeSelectionListener, TreeExpansionListener, FocusListener { 49 50 final static Object listener = new bug4927934(); 51 52 static boolean focusGained = false; 53 public static boolean selectionChanged = false; 54 public static boolean treeExpanded = false; 55 public static boolean treeCollapsed = false; 56 57 static JFrame frame; 58 static JTree tree; 59 static Robot robot; 60 main(String args[])61 public static void main(String args[]) throws Exception { 62 UIManager.setLookAndFeel(new javax.swing.plaf.metal.MetalLookAndFeel()); 63 64 robot = new Robot(); 65 robot.setAutoDelay(50); 66 67 try { 68 SwingUtilities.invokeAndWait(new Runnable() { 69 public void run() { 70 frame = new JFrame(); 71 72 DefaultMutableTreeNode root = new DefaultMutableTreeNode("root"); 73 createNodes(root); 74 tree = new JTree(root); 75 JScrollPane scrollPane = new JScrollPane(tree); 76 frame.getContentPane().add(scrollPane); 77 78 tree.addFocusListener((FocusListener) listener); 79 tree.addTreeSelectionListener((TreeSelectionListener) listener); 80 tree.addTreeExpansionListener((TreeExpansionListener) listener); 81 82 frame.setSize(300, 300); 83 frame.setVisible(true); 84 } 85 }); 86 87 robot.waitForIdle(); 88 Thread.sleep(1000); 89 90 SwingUtilities.invokeLater(new Runnable() { 91 public void run() { 92 tree.requestFocus(); 93 } 94 }); 95 96 synchronized (listener) { 97 if (!focusGained) { 98 System.out.println("waiting focusGained..."); 99 try { 100 listener.wait(10000); 101 } catch (InterruptedException e) { 102 e.printStackTrace(); 103 } 104 } 105 } 106 107 // GO TO RIGHT 108 selectionChanged = false; 109 hitKey(KeyEvent.VK_RIGHT); 110 robot.waitForIdle(); 111 if (!checkSelectionChanged(tree, 0)) { 112 throw new RuntimeException("Root should be selected"); 113 } 114 115 selectionChanged = false; 116 hitKey(KeyEvent.VK_RIGHT); 117 robot.waitForIdle(); 118 if (!checkSelectionChanged(tree, 1)) { 119 throw new RuntimeException("Node should be selected"); 120 } 121 122 treeExpanded = false; 123 hitKey(KeyEvent.VK_RIGHT); 124 robot.waitForIdle(); 125 if (!isTreeExpanded()) { 126 throw new RuntimeException("Node should be expanded"); 127 } 128 129 selectionChanged = false; 130 hitKey(KeyEvent.VK_RIGHT); 131 robot.waitForIdle(); 132 if (!checkSelectionChanged(tree, 2)) { 133 throw new RuntimeException("Leaf1 should be selected"); 134 } 135 136 selectionChanged = false; 137 hitKey(KeyEvent.VK_RIGHT); 138 robot.waitForIdle(); 139 if (!checkSelectionChanged(tree, 2)) { 140 throw new RuntimeException("Leaf1 should be selected"); 141 } 142 143 // GO TO LEFT 144 selectionChanged = false; 145 hitKey(KeyEvent.VK_LEFT); 146 robot.waitForIdle(); 147 if (!checkSelectionChanged(tree, 1)) { 148 throw new RuntimeException("Node should be selected"); 149 } 150 151 treeCollapsed = false; 152 hitKey(KeyEvent.VK_LEFT); 153 if (!isTreeCollapsed()) { 154 throw new RuntimeException("Node should be collapsed"); 155 } 156 157 selectionChanged = false; 158 hitKey(KeyEvent.VK_LEFT); 159 robot.waitForIdle(); 160 if (!checkSelectionChanged(tree, 0)) { 161 throw new RuntimeException("Root should be selected"); 162 } 163 164 treeCollapsed = false; 165 hitKey(KeyEvent.VK_LEFT); 166 robot.waitForIdle(); 167 if (!isTreeCollapsed()) { 168 throw new RuntimeException("Root should be collapsed"); 169 } 170 } finally { 171 if (frame != null) { 172 SwingUtilities.invokeAndWait(frame::dispose); 173 } 174 } 175 } 176 177 focusLost(FocusEvent e)178 synchronized public void focusLost(FocusEvent e) { 179 } 180 focusGained(FocusEvent e)181 synchronized public void focusGained(FocusEvent e) { 182 focusGained = true; 183 System.out.println("focusGained"); 184 listener.notifyAll(); 185 } 186 createNodes(DefaultMutableTreeNode root)187 private static void createNodes(DefaultMutableTreeNode root) { 188 DefaultMutableTreeNode node = new DefaultMutableTreeNode("Node"); 189 node.add(new DefaultMutableTreeNode("Leaf1")); 190 node.add(new DefaultMutableTreeNode("Leaf2")); 191 root.add(node); 192 root.add(new DefaultMutableTreeNode("Leaf3")); 193 } 194 valueChanged(TreeSelectionEvent e)195 synchronized public void valueChanged(TreeSelectionEvent e) { 196 selectionChanged = true; 197 System.out.println("selectionChanged"); 198 notifyAll(); 199 } 200 treeCollapsed(TreeExpansionEvent e)201 synchronized public void treeCollapsed(TreeExpansionEvent e) { 202 System.out.println("treeCollapsed"); 203 treeCollapsed = true; 204 notifyAll(); 205 } 206 treeExpanded(TreeExpansionEvent e)207 synchronized public void treeExpanded(TreeExpansionEvent e) { 208 System.out.println("treeExpanded"); 209 treeExpanded = true; 210 notifyAll(); 211 } 212 hitKey(int key)213 private static void hitKey(int key) { 214 System.out.println("key " + key + " pressed"); 215 robot.keyPress(key); 216 robot.keyRelease(key); 217 } 218 checkSelectionChanged(JTree tree, int shouldBeSel)219 private static boolean checkSelectionChanged(JTree tree, int shouldBeSel) { 220 synchronized(listener) { 221 if (!selectionChanged) { 222 System.out.println("waiting for selectionChanged..."); 223 try { 224 listener.wait(5000); 225 } catch (InterruptedException e) { 226 e.printStackTrace(); 227 } 228 } 229 } 230 int selRow = tree.getLeadSelectionRow(); 231 System.out.println("Selected row: " + selRow); 232 return selRow == shouldBeSel; 233 } 234 isTreeExpanded()235 private static boolean isTreeExpanded() { 236 synchronized(listener) { 237 if (!treeExpanded) { 238 System.out.println("waiting for treeExpanded..."); 239 try { 240 listener.wait(5000); 241 } catch (InterruptedException e) { 242 e.printStackTrace(); 243 } 244 } 245 } 246 return treeExpanded; 247 } 248 isTreeCollapsed()249 private static boolean isTreeCollapsed() { 250 synchronized(listener) { 251 if (!treeCollapsed) { 252 System.out.println("waiting for treeCollapsed..."); 253 try { 254 listener.wait(5000); 255 } catch (InterruptedException e) { 256 e.printStackTrace(); 257 } 258 } 259 } 260 return treeCollapsed; 261 } 262 } 263