modules/graphics/src/test/java/test/javafx/scene/FocusTest.java

Print this page
rev 9250 : 8134762: Refactor Javafx graphics module tests for clear separation of tests
Reviewed-by:


   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();