1 /*
   2  * Copyright (c) 2011, 2012, 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 /*
  25  * @test
  26  * @bug 6263446
  27  * @summary Tests that double-clicking to edit a cell doesn't select the content.
  28  * @author Shannon Hickey
  29  * @run main bug6263446
  30  */
  31 import java.awt.*;
  32 import java.awt.event.InputEvent;
  33 import java.lang.reflect.Field;
  34 import javax.swing.*;
  35 import javax.swing.tree.*;
  36 import sun.awt.SunToolkit;
  37 
  38 public class bug6263446 {
  39 
  40     private static final String FIRST = "AAAAAAAAAAA";
  41     private static final String SECOND = "BB";
  42     private static final String ALL = FIRST + " " + SECOND;
  43     private static JTree tree;
  44     private static Robot robot;
  45     private static SunToolkit toolkit;
  46 
  47     public static void main(String[] args) throws Exception {
  48         toolkit = (SunToolkit) Toolkit.getDefaultToolkit();
  49         robot = new Robot();
  50         robot.setAutoDelay(50);
  51 
  52         SwingUtilities.invokeAndWait(new Runnable() {
  53 
  54             public void run() {
  55                 createAndShowGUI();
  56             }
  57         });
  58 
  59         toolkit.realSync();
  60 
  61         Point point = getClickPoint();
  62         robot.mouseMove(point.x, point.y);
  63 
  64         // click count 3
  65         click(1);
  66         assertNotEditing();
  67 
  68         click(2);
  69         assertNotEditing();
  70 
  71         click(3);
  72         assertEditing();
  73         cancelCellEditing();
  74         assertNotEditing();
  75 
  76         click(4);
  77         checkSelectedText(FIRST);
  78 
  79         click(5);
  80         checkSelectedText(ALL);
  81 
  82         // click count 4
  83         setClickCountToStart(4);
  84 
  85         click(1);
  86         assertNotEditing();
  87 
  88         click(2);
  89         assertNotEditing();
  90 
  91         click(3);
  92         assertNotEditing();
  93 
  94         click(4);
  95         assertEditing();
  96         cancelCellEditing();
  97         assertNotEditing();
  98 
  99         click(5);
 100         checkSelectedText(FIRST);
 101 
 102         click(6);
 103         checkSelectedText(ALL);
 104 
 105         // start path editing
 106         startPathEditing();
 107         assertEditing();
 108 
 109         click(1);
 110         checkSelection(null);
 111 
 112         click(2);
 113         checkSelection(FIRST);
 114 
 115         click(3);
 116         checkSelection(ALL);
 117     }
 118 
 119     private static void click(int times) {
 120         robot.delay(500);
 121         for (int i = 0; i < times; i++) {
 122             robot.mousePress(InputEvent.BUTTON1_MASK);
 123             robot.mouseRelease(InputEvent.BUTTON1_MASK);
 124         }
 125     }
 126 
 127     private static Point getClickPoint() throws Exception {
 128         final Point[] result = new Point[1];
 129 
 130         SwingUtilities.invokeAndWait(new Runnable() {
 131 
 132             @Override
 133             public void run() {
 134                 Rectangle rect = tree.getRowBounds(0);
 135                 // UPDATE !!!
 136                 Point p = new Point(rect.x + rect.width / 2, rect.y + 2);
 137                 SwingUtilities.convertPointToScreen(p, tree);
 138                 result[0] = p;
 139 
 140             }
 141         });
 142 
 143         return result[0];
 144     }
 145 
 146     private static TreeModel createTreeModel() {
 147         return new DefaultTreeModel(new DefaultMutableTreeNode(ALL));
 148     }
 149 
 150     private static void createAndShowGUI() {
 151 
 152         JFrame frame = new JFrame();
 153         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 154 
 155         tree = new JTree(createTreeModel());
 156         tree.setRootVisible(true);
 157         tree.setEditable(true);
 158 
 159 
 160         frame.getContentPane().add(tree);
 161         frame.pack();
 162         frame.setVisible(true);
 163     }
 164 
 165     private static void setClickCountToStart(final int clicks) throws Exception {
 166         SwingUtilities.invokeAndWait(new Runnable() {
 167 
 168             @Override
 169             public void run() {
 170                 try {
 171                     DefaultTreeCellEditor editor =
 172                             (DefaultTreeCellEditor) tree.getCellEditor();
 173                     Field field = DefaultTreeCellEditor.class.getDeclaredField("realEditor");
 174                     field.setAccessible(true);
 175                     DefaultCellEditor ce = (DefaultCellEditor) field.get(editor);
 176                     ce.setClickCountToStart(clicks);
 177                 } catch (IllegalAccessException e) {
 178                     throw new RuntimeException(e);
 179                 } catch (NoSuchFieldException e) {
 180                     throw new RuntimeException(e);
 181                 }
 182             }
 183         });
 184 
 185         toolkit.realSync();
 186 
 187     }
 188 
 189     private static void startPathEditing() throws Exception {
 190         SwingUtilities.invokeAndWait(new Runnable() {
 191 
 192             @Override
 193             public void run() {
 194                 tree.startEditingAtPath(tree.getPathForRow(0));
 195             }
 196         });
 197     }
 198 
 199     private static void cancelCellEditing() throws Exception {
 200         SwingUtilities.invokeAndWait(new Runnable() {
 201 
 202             @Override
 203             public void run() {
 204                 tree.getCellEditor().cancelCellEditing();
 205             }
 206         });
 207     }
 208 
 209     private static void checkSelection(final String sel) throws Exception {
 210         SwingUtilities.invokeAndWait(new Runnable() {
 211 
 212             @Override
 213             public void run() {
 214                 try {
 215                     DefaultTreeCellEditor editor =
 216                             (DefaultTreeCellEditor) tree.getCellEditor();
 217                     Field field = DefaultTreeCellEditor.class.getDeclaredField("realEditor");
 218                     field.setAccessible(true);
 219                     DefaultCellEditor ce = (DefaultCellEditor) field.get(editor);
 220                     JTextField tf = (JTextField) ce.getComponent();
 221                     String text = tf.getSelectedText();
 222 
 223                     if (sel == null) {
 224                         if (text != null && text.length() != 0) {
 225                             throw new RuntimeException("Nothing should be selected, but \"" + text + "\" is selected.");
 226                         }
 227                     } else if (!sel.equals(text)) {
 228                         throw new RuntimeException("\"" + sel + "\" should be selected, but \"" + text + "\" is selected.");
 229                     }
 230                 } catch (IllegalAccessException e) {
 231                     throw new RuntimeException(e);
 232                 } catch (NoSuchFieldException e) {
 233                     throw new RuntimeException(e);
 234                 }
 235             }
 236         });
 237     }
 238 
 239     private static void checkSelectedText(String sel) throws Exception {
 240         assertEditing();
 241         checkSelection(sel);
 242         cancelCellEditing();
 243         assertNotEditing();
 244     }
 245 
 246     private static void assertEditing() throws Exception {
 247         assertEditingNoTreeLock(true);
 248     }
 249 
 250     private static void assertNotEditing() throws Exception {
 251         assertEditingNoTreeLock(false);
 252     }
 253 
 254     private static void assertEditingNoTreeLock(final boolean editing) throws Exception {
 255         toolkit.realSync();
 256 
 257         SwingUtilities.invokeAndWait(new Runnable() {
 258 
 259             @Override
 260             public void run() {
 261                 if (editing && !tree.isEditing()) {
 262                     throw new RuntimeException("Tree should be editing");
 263                 }
 264                 if (!editing && tree.isEditing()) {
 265                     throw new RuntimeException("Tree should not be editing");
 266                 }
 267             }
 268         });
 269 
 270     }
 271 
 272 }