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