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 
  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 
 163     synchronized public void focusLost(FocusEvent e) {
 164     }
 165 
 166     synchronized public void focusGained(FocusEvent e) {
 167         focusGained = true;
 168         System.out.println("focusGained");
 169         listener.notifyAll();
 170     }
 171 
 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 
 180     synchronized public void valueChanged(TreeSelectionEvent e) {
 181         selectionChanged = true;
 182         System.out.println("selectionChanged");
 183         notifyAll();
 184     }
 185 
 186     synchronized public void treeCollapsed(TreeExpansionEvent e) {
 187         System.out.println("treeCollapsed");
 188         treeCollapsed = true;
 189         notifyAll();
 190     }
 191 
 192     synchronized public void treeExpanded(TreeExpansionEvent e) {
 193         System.out.println("treeExpanded");
 194         treeExpanded = true;
 195         notifyAll();
 196     }
 197 
 198     private static void hitKey(int key) {
 199         System.out.println("key " + key + " pressed");
 200         robot.keyPress(key);
 201         robot.keyRelease(key);
 202     }
 203 
 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 
 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 
 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 }