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