6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package javafx.scene;
27
28
29 import com.sun.javafx.pgstub.StubScene;
30 import com.sun.javafx.pgstub.StubToolkit;
31 import com.sun.javafx.tk.Toolkit;
32 import static org.junit.Assert.assertEquals;
33 import static org.junit.Assert.assertFalse;
34 import static org.junit.Assert.assertNull;
35 import static org.junit.Assert.assertSame;
36 import static org.junit.Assert.assertTrue;
37 import static org.junit.Assert.fail;
38
39 import java.util.ArrayList;
40 import java.util.List;
41 import javafx.beans.InvalidationListener;
42 import javafx.beans.Observable;
43 import javafx.beans.value.ChangeListener;
44 import javafx.beans.value.ObservableValue;
45
46 import javafx.scene.shape.Rectangle;
47 import javafx.stage.Stage;
48
49 import org.junit.After;
50 import org.junit.Before;
51 import org.junit.Test;
52
53 public class FocusTest {
54
55 private Stage stage;
56 private Scene scene;
57 private List<Node> nodes;
58 private int nodeIndex;
59 private StubToolkit toolkit;
60 private boolean actionTaken;
61
62 @Before
63 public void setUp() {
64 stage = new Stage();
65 scene = new Scene(new Group(), 500, 500);
66 stage.setScene(scene);
67 stage.show();
68 stage.requestFocus();
69 nodes = new ArrayList();
70 nodeIndex = 0;
71
72 toolkit = (StubToolkit) Toolkit.getToolkit();
73 }
74
75 @After
76 public void tearDown() {
77 stage.hide();
78 stage = null;
79 scene = null;
80 }
81
82 void fireTestPulse() {
83 // TODO: an actual pulse doesn't work in the stub environment.
84 // Just clean up focus instead.
85 scene.focusCleanup();
86 }
87
88 boolean T = true;
89 boolean F = false;
90
91 Node n(boolean trav, boolean vis, boolean enable) {
92 Rectangle node = new Rectangle();
93 node.setId("Rect-" + nodeIndex);
94 node.setFocusTraversable(trav);
95 node.setVisible(vis);
96 node.setDisable(!enable);
97 nodes.add(node);
98 nodeIndex++;
99
100 return node;
101 }
102
103 Node n() {
104 return n(T, T, T);
105 }
108 assertEquals(n, s.getFocusOwner());
109 assertTrue(n.isFocused());
110 }
111
112 private void assertNotFocused(Scene s, Node n) {
113 assertTrue(n != s.getFocusOwner());
114 assertFalse(n.isFocused());
115 }
116
117 private void assertNullFocus(Scene s) {
118 assertNull(s.getFocusOwner());
119 }
120
121 /**
122 * Test setting of initial focus.
123 */
124 @Test
125 public void testInitial() {
126 assertNullFocus(scene);
127 scene.setRoot(new Group());
128 scene.getRoot().getChildren().add(n());
129 fireTestPulse();
130 assertIsFocused(scene, nodes.get(0));
131 }
132
133 /**
134 * Test requestFocus() on eligible and ineligible nodes.
135 */
136 @Test
137 public void testRequest() {
138 scene.setRoot(new Group());
139 scene.getRoot().getChildren().addAll(
140 n(T, T, T), // 0 - focusable
141 n(F, T, T), // 1 - focusable
142 n(T, T, F), // 2 - not focusable
143 n(F, T, F), // 3 - not focusable
144 n(T, F, T), // 4 - not focusable
145 n(F, F, T), // 5 - not focusable
146 n(T, F, F), // 6 - not focusable
147 n(F, F, F) // 7 - not focusable
148 );
149 n(); // 8 - not focusable, because not in scene
150
151 nodes.get(0).requestFocus();
152 assertIsFocused(scene, nodes.get(0));
153 nodes.get(1).requestFocus();
154 assertIsFocused(scene, nodes.get(1));
155 nodes.get(2).requestFocus();
156 assertNotFocused(scene, nodes.get(2));
157 nodes.get(3).requestFocus();
158 assertNotFocused(scene, nodes.get(3));
159 nodes.get(4).requestFocus();
160 assertNotFocused(scene, nodes.get(4));
161 nodes.get(5).requestFocus();
162 assertNotFocused(scene, nodes.get(5));
163 nodes.get(6).requestFocus();
164 assertNotFocused(scene, nodes.get(6));
165 nodes.get(7).requestFocus();
166 assertNotFocused(scene, nodes.get(7));
167 nodes.get(8).requestFocus();
168 assertNotFocused(scene, nodes.get(8));
169 }
170
171 /**
172 * Test removing the focus owner without another eligible node in the scene.
173 */
174 @Test
175 public void testRemove1() {
176 scene.setRoot(new Group());
177 scene.getRoot().getChildren().add(n());
178 nodes.get(0).requestFocus();
179 scene.getRoot().getChildren().remove(nodes.get(0));
180 fireTestPulse();
181 assertNotFocused(scene, nodes.get(0));
182 assertNullFocus(scene);
183 }
184
185 /**
186 * Test removing the focus owner with another eligible node in the scene.
187 */
188 @Test
189 public void testRemove2() {
190 scene.setRoot(new Group());
191 scene.getRoot().getChildren().addAll(n(), n());
192 nodes.get(0).requestFocus();
193 scene.getRoot().getChildren().remove(nodes.get(0));
194 fireTestPulse();
195 assertNotFocused(scene, nodes.get(0));
196 assertIsFocused(scene, nodes.get(1));
197 }
198
199 /**
200 * Test removing the focus owner without another eligible node in the scene.
201 */
202 @Test
203 public void testRemove_ClearsFocusOnRemovedNode1() {
204 Node n = n();
205 scene.setRoot(new Group());
206 scene.getRoot().getChildren().add(n);
207 n.requestFocus();
208 scene.getRoot().getChildren().remove(n);
209 fireTestPulse();
210 assertNotFocused(scene, n);
211 }
212
213 /**
214 * Test removing the focus owner with another eligible node in the scene.
215 */
216 @Test
217 public void testRemove_ClearsFocusOnRemovedNode2() {
218 Node n = n();
219 scene.setRoot(new Group());
220 scene.getRoot().getChildren().addAll(n, n());
221 n.requestFocus();
222 scene.getRoot().getChildren().remove(n);
223 fireTestPulse();
224 assertNotFocused(scene, n);
225 assertIsFocused(scene, scene.getRoot().getChildren().get(0));
226 }
227
228 /**
229 * Test removing the focus owner without another eligible node in the scene.
230 */
231 @Test
232 public void testRemoveChildOfGroup_ClearsFocusOnRemovedNode1() {
233 Node n = n();
234 Group g = new Group(n);
235 scene.setRoot(new Group());
236 scene.getRoot().getChildren().add(g);
237 n.requestFocus();
238 g.getChildren().remove(n);
239 fireTestPulse();
240 assertNotFocused(scene, n);
241 }
242
243 /**
244 * Test making the focus owner invisible without another eligible
245 * node in the scene.
246 */
247 @Test
248 public void testInvisible1() {
249 scene.setRoot(new Group());
250 scene.getRoot().getChildren().add(n());
251 nodes.get(0).requestFocus();
252 assertIsFocused(scene, nodes.get(0));
253 nodes.get(0).setVisible(false);
254 fireTestPulse();
255 assertNotFocused(scene, nodes.get(0));
256 assertNullFocus(scene);
257 }
258
259 /**
260 * Test making the focus owner invisible with another eligible
261 * node in the scene.
262 */
263 @Test
264 public void testInvisible2() {
265 scene.setRoot(new Group());
266 scene.getRoot().getChildren().addAll(n(), n());
267 nodes.get(0).requestFocus();
268 assertIsFocused(scene, nodes.get(0));
269 nodes.get(0).setVisible(false);
270 fireTestPulse();
271 assertNotFocused(scene, nodes.get(0));
272 assertIsFocused(scene, nodes.get(1));
273 }
274
275 /**
276 * Test making the focus owner disabled without another eligible
277 * node in the scene.
278 */
279 @Test
280 public void testDisable1() {
281 scene.setRoot(new Group());
282 scene.getRoot().getChildren().add(n());
283 nodes.get(0).requestFocus();
284 nodes.get(0).setDisable(true);
285 fireTestPulse();
286 assertNotFocused(scene, nodes.get(0));
287 assertNullFocus(scene);
288 }
289
290 /**
291 * Test making the focus owner disabled with another eligible
292 * node in the scene.
293 */
294 @Test
295 public void testDisable2() {
296 scene.setRoot(new Group());
297 scene.getRoot().getChildren().addAll(n(), n());
298 nodes.get(0).requestFocus();
299 nodes.get(0).setDisable(true);
300 fireTestPulse();
301 assertNotFocused(scene, nodes.get(0));
302 assertIsFocused(scene, nodes.get(1));
303 }
304
305 /**
306 * When focus null, test adding an eligible, traversable node.
307 */
308 @Test
309 public void testAddEligible() {
310 fireTestPulse(); // make sure focus is clean
311 assertNullFocus(scene);
312 scene.setRoot(new Group());
313 scene.getRoot().getChildren().add(n());
314 fireTestPulse();
315 assertIsFocused(scene, nodes.get(0));
316 }
317
318 /**
319 * When focus null, test making a node traversable.
320 */
321 @Test
322 public void testBecomeTraversable() {
323 scene.setRoot(new Group());
324 scene.getRoot().getChildren().addAll(n(F, T, T), n(F, T, T));
325 fireTestPulse();
326 assertNullFocus(scene);
327 toolkit.clearPulseRequested();
328 assertFalse(toolkit.isPulseRequested());
329 nodes.get(0).setFocusTraversable(true);
330 assertTrue(toolkit.isPulseRequested());
331 fireTestPulse();
332 assertIsFocused(scene, nodes.get(0));
333 }
334
335 /**
336 * When focus null, test making a node visible.
337 */
338 @Test
339 public void testBecomeVisible() {
340 scene.setRoot(new Group());
341 scene.getRoot().getChildren().add(n(T, F, T));
342 fireTestPulse();
343 assertNullFocus(scene);
344 nodes.get(0).setVisible(true);
345 fireTestPulse();
346 assertIsFocused(scene, nodes.get(0));
347 }
348
349 /**
350 * When focus null, test making a node enabled.
351 */
352 @Test
353 public void testBecomeEnabled() {
354 scene.setRoot(new Group());
355 scene.getRoot().getChildren().add(n(T, T, F));
356 fireTestPulse();
357 assertNullFocus(scene);
358 nodes.get(0).setDisable(false);
359 fireTestPulse();
360 assertIsFocused(scene, nodes.get(0));
361 }
362
363 /**
364 * When focus exists, test adding an eligible, traversable node.
365 */
366 @Test
367 public void testAddEligible2() {
368 scene.setRoot(new Group());
369 scene.getRoot().getChildren().add(n());
370 fireTestPulse();
371 assertIsFocused(scene, nodes.get(0));
372 scene.getRoot().getChildren().add(n());
373 fireTestPulse();
374 assertIsFocused(scene, nodes.get(0));
375 }
376
377 /**
378 * When focus exists, test making a node traversable.
379 */
380 @Test
381 public void testBecomeTraversable2() {
382 scene.setRoot(new Group());
383 scene.getRoot().getChildren().addAll(n(), n(F, T, T));
384 fireTestPulse();
385 assertIsFocused(scene, nodes.get(0));
386 nodes.get(1).setFocusTraversable(true);
387 fireTestPulse();
388 assertIsFocused(scene, nodes.get(0));
389 }
390
391 /**
392 * When focus exists, test making a node visible.
393 */
394 @Test
395 public void testBecomeVisible2() {
396 scene.setRoot(new Group());
397 scene.getRoot().getChildren().addAll(n(), n(T, F, T));
398 fireTestPulse();
399 assertIsFocused(scene, nodes.get(0));
400 nodes.get(1).setVisible(true);
401 fireTestPulse();
402 assertIsFocused(scene, nodes.get(0));
403 }
404
405 /**
406 * When focus exists, test making a node enabled.
407 */
408 @Test
409 public void testBecomeEnabled2() {
410 scene.setRoot(new Group());
411 scene.getRoot().getChildren().addAll(n(), n(T, T, F));
412 fireTestPulse();
413 assertIsFocused(scene, nodes.get(0));
414 nodes.get(1).setDisable(false);
415 fireTestPulse();
416 assertIsFocused(scene, nodes.get(0));
417 }
418
419 /**
420 * Test moving the focus within a scene.
421 */
422 @Test
423 public void testMoveWithinScene() {
424 Group g1 = new Group(n());
425 Group g2 = new Group();
426 scene.setRoot(new Group());
427 scene.getRoot().getChildren().addAll(g1, g2);
428 fireTestPulse();
429 assertIsFocused(scene, nodes.get(0));
430 g2.getChildren().add(nodes.get(0));
431 fireTestPulse();
432 assertIsFocused(scene, nodes.get(0));
433 }
434
435 /**
436 * Test moving the focus into an invisible group, with no other
437 * eligible nodes in the scene.
438 */
439 @Test
440 public void testMoveIntoInvisible() {
441 Group g1 = new Group(n());
442 Group g2 = new Group();
443 g2.setVisible(false);
444 scene.setRoot(new Group());
445 scene.getRoot().getChildren().addAll(g1, g2);
446 fireTestPulse();
447 assertIsFocused(scene, nodes.get(0));
448 g2.getChildren().add(nodes.get(0));
449 fireTestPulse();
450 assertNullFocus(scene);
451 }
452
453 /**
454 * Test moving the focus into an invisible group, with another
455 * eligible node in the scene.
456 */
457 @Test
458 public void testMoveIntoInvisible2() {
459 Group g1 = new Group(n());
460 Group g2 = new Group();
461 g2.setVisible(false);
462 scene.setRoot(new Group());
463 scene.getRoot().getChildren().addAll(g1, g2, n());
464 nodes.get(0).requestFocus();
465 fireTestPulse();
466 assertIsFocused(scene, nodes.get(0));
467 g2.getChildren().add(nodes.get(0));
468 fireTestPulse();
469 assertIsFocused(scene, nodes.get(1));
470 }
471
472 /**
473 * Test moving the focus into a disabled group, with no other
474 * eligible nodes in the scene.
475 */
476 @Test
477 public void testMoveIntoDisabled() {
478 Group g1 = new Group(n());
479 Group g2 = new Group();
480 g2.setDisable(true);
481 scene.setRoot(new Group());
482 scene.getRoot().getChildren().addAll(g1, g2);
483 fireTestPulse();
484 assertIsFocused(scene, nodes.get(0));
485 g2.getChildren().add(nodes.get(0));
486 fireTestPulse();
487 assertNullFocus(scene);
488 }
489
490 /**
491 * Test moving the focus into a disabled group, with another
492 * eligible nodes in the scene.
493 */
494 @Test
495 public void testMoveIntoDisabled2() {
496 Group g1 = new Group(n());
497 Group g2 = new Group();
498 g2.setDisable(true);
499 scene.setRoot(new Group());
500 scene.getRoot().getChildren().addAll(g1, g2, n());
501 nodes.get(0).requestFocus();
502 fireTestPulse();
503 assertIsFocused(scene, nodes.get(0));
504 g2.getChildren().add(nodes.get(0));
505 fireTestPulse();
506 assertIsFocused(scene, nodes.get(1));
507 }
508
509 /**
510 * Test making the parent of focused node disabled, with no other
511 * eligible nodes in the scene.
512 */
513 @Test
514 public void testMakeParentDisabled() {
515 Group g1 = new Group(n());
516 Group g2 = new Group();
517 g2.setVisible(false);
518 scene.setRoot(new Group());
519 scene.getRoot().getChildren().addAll(g1, g2);
520 fireTestPulse();
521 assertIsFocused(scene, nodes.get(0));
522 g1.setDisable(true);
523 fireTestPulse();
524 assertNotFocused(scene, nodes.get(0));
525 assertNullFocus(scene);
526 }
527
528 /**
529 * Test making the parent of focused node disabled, with another
530 * eligible nodes in the scene.
531 */
532 @Test
533 public void testMakeParentDisabled2() {
534 Group g1 = new Group(n());
535 Group g2 = new Group();
536 g2.setVisible(false);
537 scene.setRoot(new Group());
538 scene.getRoot().getChildren().addAll(g1, g2, n());
539 nodes.get(0).requestFocus();
540 fireTestPulse();
541 assertIsFocused(scene, nodes.get(0));
542 g1.setDisable(true);
543 fireTestPulse();
544 assertNotFocused(scene, nodes.get(0));
545 assertIsFocused(scene, nodes.get(1));
546 }
547
548 /**
549 * Test making the parent of focused node invisible, with no other
550 * eligible nodes in the scene.
551 */
552 @Test
553 public void testMakeParentInvisible() {
554 Group g1 = new Group(n());
555 Group g2 = new Group();
556 g2.setVisible(false);
557 scene.setRoot(new Group());
558 scene.getRoot().getChildren().addAll(g1, g2);
559 fireTestPulse();
560 assertIsFocused(scene, nodes.get(0));
561 g1.setVisible(false);
562 fireTestPulse();
563 assertNotFocused(scene, nodes.get(0));
564 assertNullFocus(scene);
565 }
566
567 /**
568 * Test making the parent of focused node invisible, with another
569 * eligible nodes in the scene.
570 */
571 @Test
572 public void testMakeParentInvisible2() {
573 Group g1 = new Group(n());
574 Group g2 = new Group();
575 g2.setVisible(false);
576 scene.setRoot(new Group());
577 scene.getRoot().getChildren().addAll(g1, g2, n());
578 nodes.get(0).requestFocus();
579 fireTestPulse();
580 assertIsFocused(scene, nodes.get(0));
581 g1.setVisible(false);
582 fireTestPulse();
583 assertNotFocused(scene, nodes.get(0));
584 assertIsFocused(scene, nodes.get(1));
585 }
586
587 /**
588 * Focus should not move if stacking order changes.
589 */
590 @Test
591 public void testToFront() {
592 scene.setRoot(new Group());
593 scene.getRoot().getChildren().addAll(n(), n());
594 nodes.get(0).requestFocus();
595 assertIsFocused(scene, nodes.get(0));
596 assertNotFocused(scene, nodes.get(1));
597 nodes.get(0).toFront();
598 assertIsFocused(scene, nodes.get(0));
599 assertNotFocused(scene, nodes.get(1));
600 nodes.get(0).toBack();
601 assertIsFocused(scene, nodes.get(0));
602 assertNotFocused(scene, nodes.get(1));
603 }
604
605 /**
606 * Test moving focused node into scene which is not in active stage.
607 */
608 @Test
609 public void testMoveIntoInactiveScene() {
610 scene.setRoot(new Group());
611 scene.getRoot().getChildren().add(n());
612 nodes.get(0).requestFocus();
613 assertIsFocused(scene, nodes.get(0));
614 Scene scene2 = new Scene(new Group());
615 scene2.getRoot().getChildren().add(nodes.get(0));
616 fireTestPulse();
617 assertNullFocus(scene);
618 assertNullFocus(scene2);
619 nodes.get(0).requestFocus();
620 fireTestPulse();
621 assertNullFocus(scene);
622 assertEquals(nodes.get(0), scene2.getFocusOwner());
623 assertFalse(nodes.get(0).isFocused());
624 stage.setScene(scene2);
625 fireTestPulse();
626 assertNullFocus(scene);
627 assertIsFocused(scene2, nodes.get(0));
628 }
629
630 /**
631 * Test making stage invisible.
632 */
633 @Test
634 public void testInvisibleStage() {
635 scene.setRoot(new Group());
636 scene.getRoot().getChildren().add(n());
637 nodes.get(0).requestFocus();
638 stage.show();
639 fireTestPulse();
640 assertIsFocused(scene, nodes.get(0));
641 stage.hide();
642 nodes.get(0).requestFocus();
643 fireTestPulse();
644 assertEquals(nodes.get(0), scene.getFocusOwner());
645 assertFalse(nodes.get(0).isFocused());
646 }
647
648 /**
649 * Test switching two scenes in one stage. Focus owner in scenes should
650 * remain the same while focused node should change.
651 */
652 @Test
653 public void testSwitchScenes(){
654 scene.setRoot(new Group());
655 scene.getRoot().getChildren().add(n());
656 nodes.get(0).requestFocus();
657 Scene scene2 = new Scene(new Group());
658 scene2.getRoot().getChildren().add(n());
659 nodes.get(1).requestFocus();
660 fireTestPulse();
661 assertIsFocused(scene, nodes.get(0));
662 assertFalse(nodes.get(1).isFocused());
663 assertEquals(nodes.get(1), scene2.getFocusOwner());
664 stage.setScene(scene2);
665 fireTestPulse();
666 assertFalse(nodes.get(0).isFocused());
667 assertEquals(nodes.get(0), scene.getFocusOwner());
668 assertIsFocused(scene2, nodes.get(1));
669 }
670
671 @Test public void nestedFocusRequestsShouldResultInOneFocusedNode() {
672 final Node n1 = n();
673 final Node n2 = n();
674 scene.setRoot(new Group(n1, n2));
675
676 n1.focusedProperty().addListener((ov, lostFocus, getFocus) -> {
677 if (lostFocus) {
678 n1.requestFocus();
|
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package test.javafx.scene;
27
28
29 import test.com.sun.javafx.pgstub.StubScene;
30 import test.com.sun.javafx.pgstub.StubToolkit;
31 import com.sun.javafx.tk.Toolkit;
32 import static org.junit.Assert.assertEquals;
33 import static org.junit.Assert.assertFalse;
34 import static org.junit.Assert.assertNull;
35 import static org.junit.Assert.assertSame;
36 import static org.junit.Assert.assertTrue;
37 import static org.junit.Assert.fail;
38
39 import java.util.ArrayList;
40 import java.util.List;
41 import javafx.beans.InvalidationListener;
42 import javafx.beans.Observable;
43 import javafx.beans.value.ChangeListener;
44 import javafx.beans.value.ObservableValue;
45 import javafx.scene.Group;
46 import javafx.scene.Node;
47 import javafx.scene.ParentShim;
48 import javafx.scene.Scene;
49 import javafx.scene.SceneShim;
50
51 import javafx.scene.shape.Rectangle;
52 import javafx.stage.Stage;
53
54 import org.junit.After;
55 import org.junit.Before;
56 import org.junit.Test;
57
58 public class FocusTest {
59
60 private Stage stage;
61 private Scene scene;
62 private List<Node> nodes;
63 private int nodeIndex;
64 private StubToolkit toolkit;
65 private boolean actionTaken;
66
67 @Before
68 public void setUp() {
69 stage = new Stage();
70 scene = new Scene(new Group(), 500, 500);
71 stage.setScene(scene);
72 stage.show();
73 stage.requestFocus();
74 nodes = new ArrayList();
75 nodeIndex = 0;
76
77 toolkit = (StubToolkit) Toolkit.getToolkit();
78 }
79
80 @After
81 public void tearDown() {
82 stage.hide();
83 stage = null;
84 scene = null;
85 }
86
87 void fireTestPulse() {
88 // TODO: an actual pulse doesn't work in the stub environment.
89 // Just clean up focus instead.
90 SceneShim.focusCleanup(scene);
91 }
92
93 boolean T = true;
94 boolean F = false;
95
96 Node n(boolean trav, boolean vis, boolean enable) {
97 Rectangle node = new Rectangle();
98 node.setId("Rect-" + nodeIndex);
99 node.setFocusTraversable(trav);
100 node.setVisible(vis);
101 node.setDisable(!enable);
102 nodes.add(node);
103 nodeIndex++;
104
105 return node;
106 }
107
108 Node n() {
109 return n(T, T, T);
110 }
113 assertEquals(n, s.getFocusOwner());
114 assertTrue(n.isFocused());
115 }
116
117 private void assertNotFocused(Scene s, Node n) {
118 assertTrue(n != s.getFocusOwner());
119 assertFalse(n.isFocused());
120 }
121
122 private void assertNullFocus(Scene s) {
123 assertNull(s.getFocusOwner());
124 }
125
126 /**
127 * Test setting of initial focus.
128 */
129 @Test
130 public void testInitial() {
131 assertNullFocus(scene);
132 scene.setRoot(new Group());
133 ParentShim.getChildren(scene.getRoot()).add(n());
134 fireTestPulse();
135 assertIsFocused(scene, nodes.get(0));
136 }
137
138 /**
139 * Test requestFocus() on eligible and ineligible nodes.
140 */
141 @Test
142 public void testRequest() {
143 scene.setRoot(new Group());
144 ParentShim.getChildren(scene.getRoot()).addAll(
145 n(T, T, T), // 0 - focusable
146 n(F, T, T), // 1 - focusable
147 n(T, T, F), // 2 - not focusable
148 n(F, T, F), // 3 - not focusable
149 n(T, F, T), // 4 - not focusable
150 n(F, F, T), // 5 - not focusable
151 n(T, F, F), // 6 - not focusable
152 n(F, F, F) // 7 - not focusable
153 );
154 n(); // 8 - not focusable, because not in scene
155
156 nodes.get(0).requestFocus();
157 assertIsFocused(scene, nodes.get(0));
158 nodes.get(1).requestFocus();
159 assertIsFocused(scene, nodes.get(1));
160 nodes.get(2).requestFocus();
161 assertNotFocused(scene, nodes.get(2));
162 nodes.get(3).requestFocus();
163 assertNotFocused(scene, nodes.get(3));
164 nodes.get(4).requestFocus();
165 assertNotFocused(scene, nodes.get(4));
166 nodes.get(5).requestFocus();
167 assertNotFocused(scene, nodes.get(5));
168 nodes.get(6).requestFocus();
169 assertNotFocused(scene, nodes.get(6));
170 nodes.get(7).requestFocus();
171 assertNotFocused(scene, nodes.get(7));
172 nodes.get(8).requestFocus();
173 assertNotFocused(scene, nodes.get(8));
174 }
175
176 /**
177 * Test removing the focus owner without another eligible node in the scene.
178 */
179 @Test
180 public void testRemove1() {
181 scene.setRoot(new Group());
182 ParentShim.getChildren(scene.getRoot()).add(n());
183 nodes.get(0).requestFocus();
184 ParentShim.getChildren(scene.getRoot()).remove(nodes.get(0));
185 fireTestPulse();
186 assertNotFocused(scene, nodes.get(0));
187 assertNullFocus(scene);
188 }
189
190 /**
191 * Test removing the focus owner with another eligible node in the scene.
192 */
193 @Test
194 public void testRemove2() {
195 scene.setRoot(new Group());
196 ParentShim.getChildren(scene.getRoot()).addAll(n(), n());
197 nodes.get(0).requestFocus();
198 ParentShim.getChildren(scene.getRoot()).remove(nodes.get(0));
199 fireTestPulse();
200 assertNotFocused(scene, nodes.get(0));
201 assertIsFocused(scene, nodes.get(1));
202 }
203
204 /**
205 * Test removing the focus owner without another eligible node in the scene.
206 */
207 @Test
208 public void testRemove_ClearsFocusOnRemovedNode1() {
209 Node n = n();
210 scene.setRoot(new Group());
211 ParentShim.getChildren(scene.getRoot()).add(n);
212 n.requestFocus();
213 ParentShim.getChildren(scene.getRoot()).remove(n);
214 fireTestPulse();
215 assertNotFocused(scene, n);
216 }
217
218 /**
219 * Test removing the focus owner with another eligible node in the scene.
220 */
221 @Test
222 public void testRemove_ClearsFocusOnRemovedNode2() {
223 Node n = n();
224 scene.setRoot(new Group());
225 ParentShim.getChildren(scene.getRoot()).addAll(n, n());
226 n.requestFocus();
227 ParentShim.getChildren(scene.getRoot()).remove(n);
228 fireTestPulse();
229 assertNotFocused(scene, n);
230 assertIsFocused(scene, ParentShim.getChildren(scene.getRoot()).get(0));
231 }
232
233 /**
234 * Test removing the focus owner without another eligible node in the scene.
235 */
236 @Test
237 public void testRemoveChildOfGroup_ClearsFocusOnRemovedNode1() {
238 Node n = n();
239 Group g = new Group(n);
240 scene.setRoot(new Group());
241 ParentShim.getChildren(scene.getRoot()).add(g);
242 n.requestFocus();
243 ParentShim.getChildren(g).remove(n);
244 fireTestPulse();
245 assertNotFocused(scene, n);
246 }
247
248 /**
249 * Test making the focus owner invisible without another eligible
250 * node in the scene.
251 */
252 @Test
253 public void testInvisible1() {
254 scene.setRoot(new Group());
255 ParentShim.getChildren(scene.getRoot()).add(n());
256 nodes.get(0).requestFocus();
257 assertIsFocused(scene, nodes.get(0));
258 nodes.get(0).setVisible(false);
259 fireTestPulse();
260 assertNotFocused(scene, nodes.get(0));
261 assertNullFocus(scene);
262 }
263
264 /**
265 * Test making the focus owner invisible with another eligible
266 * node in the scene.
267 */
268 @Test
269 public void testInvisible2() {
270 scene.setRoot(new Group());
271 ParentShim.getChildren(scene.getRoot()).addAll(n(), n());
272 nodes.get(0).requestFocus();
273 assertIsFocused(scene, nodes.get(0));
274 nodes.get(0).setVisible(false);
275 fireTestPulse();
276 assertNotFocused(scene, nodes.get(0));
277 assertIsFocused(scene, nodes.get(1));
278 }
279
280 /**
281 * Test making the focus owner disabled without another eligible
282 * node in the scene.
283 */
284 @Test
285 public void testDisable1() {
286 scene.setRoot(new Group());
287 ParentShim.getChildren(scene.getRoot()).add(n());
288 nodes.get(0).requestFocus();
289 nodes.get(0).setDisable(true);
290 fireTestPulse();
291 assertNotFocused(scene, nodes.get(0));
292 assertNullFocus(scene);
293 }
294
295 /**
296 * Test making the focus owner disabled with another eligible
297 * node in the scene.
298 */
299 @Test
300 public void testDisable2() {
301 scene.setRoot(new Group());
302 ParentShim.getChildren(scene.getRoot()).addAll(n(), n());
303 nodes.get(0).requestFocus();
304 nodes.get(0).setDisable(true);
305 fireTestPulse();
306 assertNotFocused(scene, nodes.get(0));
307 assertIsFocused(scene, nodes.get(1));
308 }
309
310 /**
311 * When focus null, test adding an eligible, traversable node.
312 */
313 @Test
314 public void testAddEligible() {
315 fireTestPulse(); // make sure focus is clean
316 assertNullFocus(scene);
317 scene.setRoot(new Group());
318 ParentShim.getChildren(scene.getRoot()).add(n());
319 fireTestPulse();
320 assertIsFocused(scene, nodes.get(0));
321 }
322
323 /**
324 * When focus null, test making a node traversable.
325 */
326 @Test
327 public void testBecomeTraversable() {
328 scene.setRoot(new Group());
329 ParentShim.getChildren(scene.getRoot()).addAll(n(F, T, T), n(F, T, T));
330 fireTestPulse();
331 assertNullFocus(scene);
332 toolkit.clearPulseRequested();
333 assertFalse(toolkit.isPulseRequested());
334 nodes.get(0).setFocusTraversable(true);
335 assertTrue(toolkit.isPulseRequested());
336 fireTestPulse();
337 assertIsFocused(scene, nodes.get(0));
338 }
339
340 /**
341 * When focus null, test making a node visible.
342 */
343 @Test
344 public void testBecomeVisible() {
345 scene.setRoot(new Group());
346 ParentShim.getChildren(scene.getRoot()).add(n(T, F, T));
347 fireTestPulse();
348 assertNullFocus(scene);
349 nodes.get(0).setVisible(true);
350 fireTestPulse();
351 assertIsFocused(scene, nodes.get(0));
352 }
353
354 /**
355 * When focus null, test making a node enabled.
356 */
357 @Test
358 public void testBecomeEnabled() {
359 scene.setRoot(new Group());
360 ParentShim.getChildren(scene.getRoot()).add(n(T, T, F));
361 fireTestPulse();
362 assertNullFocus(scene);
363 nodes.get(0).setDisable(false);
364 fireTestPulse();
365 assertIsFocused(scene, nodes.get(0));
366 }
367
368 /**
369 * When focus exists, test adding an eligible, traversable node.
370 */
371 @Test
372 public void testAddEligible2() {
373 scene.setRoot(new Group());
374 ParentShim.getChildren(scene.getRoot()).add(n());
375 fireTestPulse();
376 assertIsFocused(scene, nodes.get(0));
377 ParentShim.getChildren(scene.getRoot()).add(n());
378 fireTestPulse();
379 assertIsFocused(scene, nodes.get(0));
380 }
381
382 /**
383 * When focus exists, test making a node traversable.
384 */
385 @Test
386 public void testBecomeTraversable2() {
387 scene.setRoot(new Group());
388 ParentShim.getChildren(scene.getRoot()).addAll(n(), n(F, T, T));
389 fireTestPulse();
390 assertIsFocused(scene, nodes.get(0));
391 nodes.get(1).setFocusTraversable(true);
392 fireTestPulse();
393 assertIsFocused(scene, nodes.get(0));
394 }
395
396 /**
397 * When focus exists, test making a node visible.
398 */
399 @Test
400 public void testBecomeVisible2() {
401 scene.setRoot(new Group());
402 ParentShim.getChildren(scene.getRoot()).addAll(n(), n(T, F, T));
403 fireTestPulse();
404 assertIsFocused(scene, nodes.get(0));
405 nodes.get(1).setVisible(true);
406 fireTestPulse();
407 assertIsFocused(scene, nodes.get(0));
408 }
409
410 /**
411 * When focus exists, test making a node enabled.
412 */
413 @Test
414 public void testBecomeEnabled2() {
415 scene.setRoot(new Group());
416 ParentShim.getChildren(scene.getRoot()).addAll(n(), n(T, T, F));
417 fireTestPulse();
418 assertIsFocused(scene, nodes.get(0));
419 nodes.get(1).setDisable(false);
420 fireTestPulse();
421 assertIsFocused(scene, nodes.get(0));
422 }
423
424 /**
425 * Test moving the focus within a scene.
426 */
427 @Test
428 public void testMoveWithinScene() {
429 Group g1 = new Group(n());
430 Group g2 = new Group();
431 scene.setRoot(new Group());
432 ParentShim.getChildren(scene.getRoot()).addAll(g1, g2);
433 fireTestPulse();
434 assertIsFocused(scene, nodes.get(0));
435 ParentShim.getChildren(g2).add(nodes.get(0));
436 fireTestPulse();
437 assertIsFocused(scene, nodes.get(0));
438 }
439
440 /**
441 * Test moving the focus into an invisible group, with no other
442 * eligible nodes in the scene.
443 */
444 @Test
445 public void testMoveIntoInvisible() {
446 Group g1 = new Group(n());
447 Group g2 = new Group();
448 g2.setVisible(false);
449 scene.setRoot(new Group());
450 ParentShim.getChildren(scene.getRoot()).addAll(g1, g2);
451 fireTestPulse();
452 assertIsFocused(scene, nodes.get(0));
453 ParentShim.getChildren(g2).add(nodes.get(0));
454 fireTestPulse();
455 assertNullFocus(scene);
456 }
457
458 /**
459 * Test moving the focus into an invisible group, with another
460 * eligible node in the scene.
461 */
462 @Test
463 public void testMoveIntoInvisible2() {
464 Group g1 = new Group(n());
465 Group g2 = new Group();
466 g2.setVisible(false);
467 scene.setRoot(new Group());
468 ParentShim.getChildren(scene.getRoot()).addAll(g1, g2, n());
469 nodes.get(0).requestFocus();
470 fireTestPulse();
471 assertIsFocused(scene, nodes.get(0));
472 ParentShim.getChildren(g2).add(nodes.get(0));
473 fireTestPulse();
474 assertIsFocused(scene, nodes.get(1));
475 }
476
477 /**
478 * Test moving the focus into a disabled group, with no other
479 * eligible nodes in the scene.
480 */
481 @Test
482 public void testMoveIntoDisabled() {
483 Group g1 = new Group(n());
484 Group g2 = new Group();
485 g2.setDisable(true);
486 scene.setRoot(new Group());
487 ParentShim.getChildren(scene.getRoot()).addAll(g1, g2);
488 fireTestPulse();
489 assertIsFocused(scene, nodes.get(0));
490 ParentShim.getChildren(g2).add(nodes.get(0));
491 fireTestPulse();
492 assertNullFocus(scene);
493 }
494
495 /**
496 * Test moving the focus into a disabled group, with another
497 * eligible nodes in the scene.
498 */
499 @Test
500 public void testMoveIntoDisabled2() {
501 Group g1 = new Group(n());
502 Group g2 = new Group();
503 g2.setDisable(true);
504 scene.setRoot(new Group());
505 ParentShim.getChildren(scene.getRoot()).addAll(g1, g2, n());
506 nodes.get(0).requestFocus();
507 fireTestPulse();
508 assertIsFocused(scene, nodes.get(0));
509 ParentShim.getChildren(g2).add(nodes.get(0));
510 fireTestPulse();
511 assertIsFocused(scene, nodes.get(1));
512 }
513
514 /**
515 * Test making the parent of focused node disabled, with no other
516 * eligible nodes in the scene.
517 */
518 @Test
519 public void testMakeParentDisabled() {
520 Group g1 = new Group(n());
521 Group g2 = new Group();
522 g2.setVisible(false);
523 scene.setRoot(new Group());
524 ParentShim.getChildren(scene.getRoot()).addAll(g1, g2);
525 fireTestPulse();
526 assertIsFocused(scene, nodes.get(0));
527 g1.setDisable(true);
528 fireTestPulse();
529 assertNotFocused(scene, nodes.get(0));
530 assertNullFocus(scene);
531 }
532
533 /**
534 * Test making the parent of focused node disabled, with another
535 * eligible nodes in the scene.
536 */
537 @Test
538 public void testMakeParentDisabled2() {
539 Group g1 = new Group(n());
540 Group g2 = new Group();
541 g2.setVisible(false);
542 scene.setRoot(new Group());
543 ParentShim.getChildren(scene.getRoot()).addAll(g1, g2, n());
544 nodes.get(0).requestFocus();
545 fireTestPulse();
546 assertIsFocused(scene, nodes.get(0));
547 g1.setDisable(true);
548 fireTestPulse();
549 assertNotFocused(scene, nodes.get(0));
550 assertIsFocused(scene, nodes.get(1));
551 }
552
553 /**
554 * Test making the parent of focused node invisible, with no other
555 * eligible nodes in the scene.
556 */
557 @Test
558 public void testMakeParentInvisible() {
559 Group g1 = new Group(n());
560 Group g2 = new Group();
561 g2.setVisible(false);
562 scene.setRoot(new Group());
563 ParentShim.getChildren(scene.getRoot()).addAll(g1, g2);
564 fireTestPulse();
565 assertIsFocused(scene, nodes.get(0));
566 g1.setVisible(false);
567 fireTestPulse();
568 assertNotFocused(scene, nodes.get(0));
569 assertNullFocus(scene);
570 }
571
572 /**
573 * Test making the parent of focused node invisible, with another
574 * eligible nodes in the scene.
575 */
576 @Test
577 public void testMakeParentInvisible2() {
578 Group g1 = new Group(n());
579 Group g2 = new Group();
580 g2.setVisible(false);
581 scene.setRoot(new Group());
582 ParentShim.getChildren(scene.getRoot()).addAll(g1, g2, n());
583 nodes.get(0).requestFocus();
584 fireTestPulse();
585 assertIsFocused(scene, nodes.get(0));
586 g1.setVisible(false);
587 fireTestPulse();
588 assertNotFocused(scene, nodes.get(0));
589 assertIsFocused(scene, nodes.get(1));
590 }
591
592 /**
593 * Focus should not move if stacking order changes.
594 */
595 @Test
596 public void testToFront() {
597 scene.setRoot(new Group());
598 ParentShim.getChildren(scene.getRoot()).addAll(n(), n());
599 nodes.get(0).requestFocus();
600 assertIsFocused(scene, nodes.get(0));
601 assertNotFocused(scene, nodes.get(1));
602 nodes.get(0).toFront();
603 assertIsFocused(scene, nodes.get(0));
604 assertNotFocused(scene, nodes.get(1));
605 nodes.get(0).toBack();
606 assertIsFocused(scene, nodes.get(0));
607 assertNotFocused(scene, nodes.get(1));
608 }
609
610 /**
611 * Test moving focused node into scene which is not in active stage.
612 */
613 @Test
614 public void testMoveIntoInactiveScene() {
615 scene.setRoot(new Group());
616 ParentShim.getChildren(scene.getRoot()).add(n());
617 nodes.get(0).requestFocus();
618 assertIsFocused(scene, nodes.get(0));
619 Scene scene2 = new Scene(new Group());
620 ParentShim.getChildren(scene2.getRoot()).add(nodes.get(0));
621 fireTestPulse();
622 assertNullFocus(scene);
623 assertNullFocus(scene2);
624 nodes.get(0).requestFocus();
625 fireTestPulse();
626 assertNullFocus(scene);
627 assertEquals(nodes.get(0), scene2.getFocusOwner());
628 assertFalse(nodes.get(0).isFocused());
629 stage.setScene(scene2);
630 fireTestPulse();
631 assertNullFocus(scene);
632 assertIsFocused(scene2, nodes.get(0));
633 }
634
635 /**
636 * Test making stage invisible.
637 */
638 @Test
639 public void testInvisibleStage() {
640 scene.setRoot(new Group());
641 ParentShim.getChildren(scene.getRoot()).add(n());
642 nodes.get(0).requestFocus();
643 stage.show();
644 fireTestPulse();
645 assertIsFocused(scene, nodes.get(0));
646 stage.hide();
647 nodes.get(0).requestFocus();
648 fireTestPulse();
649 assertEquals(nodes.get(0), scene.getFocusOwner());
650 assertFalse(nodes.get(0).isFocused());
651 }
652
653 /**
654 * Test switching two scenes in one stage. Focus owner in scenes should
655 * remain the same while focused node should change.
656 */
657 @Test
658 public void testSwitchScenes(){
659 scene.setRoot(new Group());
660 ParentShim.getChildren(scene.getRoot()).add(n());
661 nodes.get(0).requestFocus();
662 Scene scene2 = new Scene(new Group());
663 ParentShim.getChildren(scene2.getRoot()).add(n());
664 nodes.get(1).requestFocus();
665 fireTestPulse();
666 assertIsFocused(scene, nodes.get(0));
667 assertFalse(nodes.get(1).isFocused());
668 assertEquals(nodes.get(1), scene2.getFocusOwner());
669 stage.setScene(scene2);
670 fireTestPulse();
671 assertFalse(nodes.get(0).isFocused());
672 assertEquals(nodes.get(0), scene.getFocusOwner());
673 assertIsFocused(scene2, nodes.get(1));
674 }
675
676 @Test public void nestedFocusRequestsShouldResultInOneFocusedNode() {
677 final Node n1 = n();
678 final Node n2 = n();
679 scene.setRoot(new Group(n1, n2));
680
681 n1.focusedProperty().addListener((ov, lostFocus, getFocus) -> {
682 if (lostFocus) {
683 n1.requestFocus();
|