1 /*
   2  * Copyright (c) 2010, 2016, 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.  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.stage;
  27 
  28 import com.sun.javafx.scene.NodeHelper;
  29 import com.sun.javafx.scene.SceneHelper;
  30 import com.sun.javafx.stage.WindowHelper;
  31 import test.com.sun.javafx.pgstub.StubPopupStage;
  32 import test.com.sun.javafx.pgstub.StubStage;
  33 import test.com.sun.javafx.pgstub.StubToolkit;
  34 import test.com.sun.javafx.pgstub.StubToolkit.ScreenConfiguration;
  35 import test.com.sun.javafx.test.MouseEventGenerator;
  36 import com.sun.javafx.tk.Toolkit;
  37 import javafx.concurrent.Task;
  38 import javafx.event.Event;
  39 import javafx.event.EventHandler;
  40 import javafx.geometry.BoundingBox;
  41 import javafx.geometry.Bounds;
  42 import javafx.geometry.Rectangle2D;
  43 import javafx.scene.Cursor;
  44 import javafx.scene.Group;
  45 import javafx.scene.Parent;
  46 import javafx.scene.Scene;
  47 import javafx.scene.input.KeyCode;
  48 import javafx.scene.input.KeyEvent;
  49 import javafx.scene.input.MouseEvent;
  50 import javafx.scene.shape.Rectangle;
  51 import junit.framework.Assert;
  52 import org.junit.After;
  53 import org.junit.Before;
  54 import org.junit.Ignore;
  55 import org.junit.Test;
  56 
  57 import java.util.concurrent.ExecutionException;
  58 import java.util.concurrent.atomic.AtomicBoolean;
  59 import javafx.scene.Node;
  60 import javafx.scene.ParentShim;
  61 import javafx.stage.Popup;
  62 import javafx.stage.PopupWindow;
  63 import javafx.stage.Screen;
  64 import javafx.stage.Stage;
  65 import javafx.stage.Window;
  66 
  67 import static org.junit.Assert.*;
  68 import test.com.sun.javafx.stage.PopupRootHelper;
  69 
  70 public class PopupTest {
  71 
  72     private StubToolkit toolkit;
  73     private Stage stage;
  74     private Scene scene;
  75     private boolean done = false;
  76 
  77     @Before
  78     public void setUp() {
  79         stage = new Stage();
  80         scene = new Scene(new Group(), 500, 500);
  81         stage.setScene(scene);
  82         stage.show();
  83         done = false;
  84         toolkit = (StubToolkit) Toolkit.getToolkit();
  85     }
  86 
  87     @After
  88     public void tearDown() {
  89         stage.hide();
  90         toolkit.resetScreens();
  91     }
  92 
  93     private void pulse() {
  94         toolkit.fireTestPulse();
  95     }
  96 
  97     @Test
  98     public void testShow() {
  99         // test showing popup with visible parent
 100         Popup p1 = new Popup();
 101         p1.show(stage);
 102         assertTrue(p1.isShowing());
 103 
 104         // test showing popup with invisible parent
 105         stage.hide();
 106         Popup p2 = new Popup();
 107         p2.show(stage);
 108         assertFalse(p2.isShowing());
 109 
 110         // test showing popup without parent
 111         // TODO should result in an exception
 112 //        Popup p3 = new Popup();
 113 //        p3.show(null);
 114 //        assertFalse(p3.isVisible());
 115     }
 116 
 117     @Test
 118     public void testShowNoAutofix() {
 119         Popup p1 = new Popup();
 120         p1.setAutoFix(false);
 121         p1.show(stage);
 122         assertTrue(p1.isShowing());
 123     }
 124 
 125     @Test
 126     public void testShowLocation() {
 127         Popup p1 = new Popup();
 128         p1.show(stage, 10, 20);
 129         assertTrue(p1.isShowing());
 130         assertEquals(10, p1.getX(), 1e-100);
 131         assertEquals(20, p1.getY(), 1e-100);
 132         pulse();
 133         StubPopupStage peer = (StubPopupStage) WindowHelper.getPeer(p1);
 134         assertEquals(10, peer.x, 1e-100);
 135         assertEquals(20, peer.y, 1e-100);
 136     }
 137 
 138     public static final class PopupRoot extends Parent {
 139         static {
 140             PopupRootHelper.setPopupRootAccessor(
 141                     new PopupRootHelper.PopupRootAccessor() {
 142                 @Override
 143                 public Bounds doComputeLayoutBounds(Node node) {
 144                     return ((PopupRoot) node).doComputeLayoutBounds();
 145                 }
 146             });
 147         }
 148 
 149         private final Rectangle geomBoundsRect;
 150 
 151         private double layoutBoundsX;
 152         private double layoutBoundsY;
 153         private double layoutBoundsWidth;
 154         private double layoutBoundsHeight;
 155 
 156         {
 157             // To initialize the class helper at the begining each constructor of this class
 158             PopupRootHelper.initHelper(this);
 159         }
 160         public PopupRoot() {
 161             geomBoundsRect = new Rectangle(0, 0, 100, 100);
 162             layoutBoundsWidth = 100;
 163             layoutBoundsHeight = 100;
 164 
 165             ParentShim.getChildren(this).add(geomBoundsRect);
 166         }
 167 
 168         public void setGeomBounds(final double x, final double y,
 169                                   final double width,
 170                                   final double height) {
 171             geomBoundsRect.setX(x);
 172             geomBoundsRect.setY(y);
 173             geomBoundsRect.setWidth(width);
 174             geomBoundsRect.setHeight(height);
 175         }
 176 
 177         public void setLayoutBounds(final double x, final double y,
 178                                     final double width,
 179                                     final double height) {
 180             layoutBoundsX = x;
 181             layoutBoundsY = y;
 182             layoutBoundsWidth = width;
 183             layoutBoundsHeight = height;
 184 
 185             NodeHelper.layoutBoundsChanged(this);
 186         }
 187 
 188         private Bounds doComputeLayoutBounds() {
 189             return new BoundingBox(layoutBoundsX, layoutBoundsY,
 190                                    layoutBoundsWidth, layoutBoundsHeight);
 191         }
 192     }
 193 
 194     @Test
 195     public void testAnchorPositioning() {
 196         final Popup popup = new Popup();
 197         final PopupRoot root = new PopupRoot();
 198 
 199         root.setGeomBounds(-10, 20, 120, 100);
 200         root.setLayoutBounds(0, 0, 100, 140);
 201 
 202         popup.getScene().setRoot(root);
 203 
 204         popup.setAnchorLocation(PopupWindow.AnchorLocation.WINDOW_BOTTOM_RIGHT);
 205         popup.show(stage, 400, 400);
 206 
 207         final StubPopupStage peer = (StubPopupStage) WindowHelper.getPeer(popup);
 208 
 209         pulse();
 210         assertEquals(280.0, peer.x, 1e-100);
 211         assertEquals(260.0, peer.y, 1e-100);
 212 
 213         popup.setAnchorLocation(PopupWindow.AnchorLocation.CONTENT_TOP_LEFT);
 214         assertEquals(290.0, popup.getAnchorX(), 1e-100);
 215         assertEquals(260.0, popup.getAnchorY(), 1e-100);
 216 
 217         pulse();
 218         assertEquals(280.0, peer.x, 1e-100);
 219         assertEquals(260.0, peer.y, 1e-100);
 220 
 221         popup.setAnchorX(200);
 222         popup.setAnchorY(100);
 223 
 224         pulse();
 225         assertEquals(190.0, peer.x, 1e-100);
 226         assertEquals(100.0, peer.y, 1e-100);
 227     }
 228 
 229     @Test
 230     public void testAnchorKeepsPositionOnContentChange() {
 231         final Popup popup = new Popup();
 232         final PopupRoot root = new PopupRoot();
 233 
 234         root.setGeomBounds(0, 0, 100, 140);
 235         root.setLayoutBounds(-10, 20, 120, 100);
 236 
 237         popup.getScene().setRoot(root);
 238 
 239         popup.setAnchorLocation(
 240                 PopupWindow.AnchorLocation.CONTENT_BOTTOM_RIGHT);
 241         popup.show(stage, 400, 300);
 242 
 243         final StubPopupStage peer = (StubPopupStage) WindowHelper.getPeer(popup);
 244 
 245         assertEquals(280.0, peer.x, 1e-100);
 246         assertEquals(180.0, peer.y, 1e-100);
 247 
 248         root.setLayoutBounds(10, -10, 80, 160);
 249 
 250         pulse();
 251 
 252         assertEquals(400.0, popup.getAnchorX(), 1e-100);
 253         assertEquals(300.0, popup.getAnchorY(), 1e-100);
 254         assertEquals(310.0, peer.x, 1e-100);
 255         assertEquals(140.0, peer.y, 1e-100);
 256     }
 257 
 258     @Test
 259     public void testPopupWithoutAnchorStayInTheCenter() {
 260         final Popup popup = new Popup();
 261         popup.setWidth(100);
 262         popup.setHeight(100);
 263         popup.show(stage);
 264         Rectangle2D bounds = Screen.getPrimary().getVisualBounds();
 265 
 266         double centerX = Math.ceil((bounds.getMinX() + (bounds.getWidth() - 100))/2);
 267         double centerY = Math.ceil((bounds.getMinY() + (bounds.getHeight() - 100))/3);
 268 
 269         StubPopupStage peer = (StubPopupStage) WindowHelper.getPeer(popup);
 270 
 271         assertEquals(centerX, Math.ceil(peer.x), 1e-100);
 272         assertEquals(centerY, Math.ceil(peer.y), 1e-100);
 273 
 274         popup.hide();
 275         popup.show(stage);
 276 
 277         peer = (StubPopupStage) WindowHelper.getPeer(popup);
 278 
 279         assertEquals(centerX, Math.ceil(peer.x), 1e-100);
 280         assertEquals(centerY, Math.ceil(peer.y), 1e-100);
 281     }
 282 
 283     @Test
 284     public void testHide() {
 285         Popup p1 = new Popup();
 286         p1.show(stage);
 287         assertTrue(p1.isShowing());
 288         p1.hide();
 289         assertFalse(p1.isShowing());
 290     }
 291 
 292     @Test
 293     public void testHideAll() {
 294         Popup p1 = new Popup();
 295         p1.show(stage);
 296         Popup p2 = new Popup();
 297         p2.show(p1);
 298         assertTrue(p1.isShowing());
 299         assertTrue(p2.isShowing());
 300         p1.hide();
 301         assertFalse(p1.isShowing());
 302         assertFalse(p2.isShowing());
 303         p1.show(stage);
 304         assertTrue(p1.isShowing());
 305         assertFalse(p2.isShowing());
 306         p1.hide();
 307         assertFalse(p1.isShowing());
 308         assertFalse(p2.isShowing());
 309     }
 310 
 311     @Test
 312     public void testAutoHiding() {
 313         Popup p1 = new Popup();
 314         p1.setAutoHide(true);
 315         p1.show(stage);
 316 
 317         Rectangle rect = new Rectangle();
 318         p1.getContent().add(rect);
 319         rect.requestFocus();
 320         assertTrue(p1.isShowing());
 321 
 322         // hiding popup stage removes the focus (in stubbed environment)
 323         p1.hide();
 324         assertFalse(p1.isShowing());
 325     }
 326 
 327     @Test
 328     public void testAutoHidingWithFocusedChild() {
 329         Popup p1 = new Popup();
 330         p1.setAutoHide(true);
 331         p1.show(stage);
 332         // setting initial focus
 333         Rectangle rect = new Rectangle();
 334         p1.getContent().add(rect);
 335         rect.requestFocus();
 336         assertTrue(p1.isShowing());
 337 
 338         Popup p2 = new Popup();
 339         p2.setAutoHide(true);
 340         p2.show(p1);
 341         Rectangle rect2 = new Rectangle();
 342         p2.getContent().add(rect2);
 343         rect2.requestFocus();
 344         assertTrue(p1.isShowing());
 345         assertTrue(p2.isShowing());
 346 
 347         p1.hide();
 348         // child has focus, popup should stay visible
 349         // Again this should be handled by PopupEventRedirector
 350         // all the AutoHide features are not implemented yet.
 351         //assertTrue(p1.isVisible());
 352     }
 353 
 354     @Test
 355     public void testAutoHidingTree() {
 356         Popup p0 = new Popup();
 357         p0.setAutoHide(true);
 358         p0.show(stage);
 359         // setting initial focus
 360         Rectangle rect = new Rectangle();
 361         p0.getContent().add(rect);
 362         rect.requestFocus();
 363 
 364         Popup p1 = new Popup();
 365         p1.setAutoHide(true);
 366         p1.show(p0);
 367 
 368         Popup p2 = new Popup();
 369         p2.setAutoHide(true);
 370         p2.show(p1);
 371         Rectangle rect2 = new Rectangle();
 372         p2.getContent().add(rect2);
 373         rect2.requestFocus();
 374 
 375         assertTrue(p1.isShowing());
 376         assertTrue(p2.isShowing());
 377         assertTrue(p0.isShowing());
 378 
 379         // after autohide the whole popup tree should be hidden
 380         // up to the parent popup with focus
 381         p2.hide();
 382         // Commenting this assersion for now : need to decide if
 383         // doAutoHide on popup should hide just itself or its parent popup as well.
 384         // PopupEventRedirector should probably take care of it.
 385         //assertFalse(p1.isVisible());
 386         assertFalse(p2.isShowing());
 387         assertTrue(p0.isShowing());
 388     }
 389 
 390     @Test
 391     public void testOnAutohide() {
 392         Popup p1 = new Popup();
 393         p1.setAutoHide(true);
 394         p1.show(stage);
 395         p1.setOnAutoHide(e -> {
 396             done = true;
 397         });
 398         Rectangle rect = new Rectangle(20, 20, 50, 50);
 399         p1.getContent().add(rect);
 400         assertFalse(done);
 401 
 402         final MouseEventGenerator generator = new MouseEventGenerator();
 403         SceneHelper.processMouseEvent(scene,
 404                 generator.generateMouseEvent(
 405                         MouseEvent.MOUSE_PRESSED, 0, 0));
 406 
 407         // test whether runnable ran
 408         assertTrue(done);
 409     }
 410 
 411 
 412     @Ignore ("Not sure how this ever worked, or what the point is")
 413     @Test
 414     public void testPeerListener() {
 415         Popup p = new Popup();
 416         p.setAutoHide(true);
 417         p.show(stage);
 418 
 419         StubPopupStage peer = (StubPopupStage) WindowHelper.getPeer(p);
 420         p.sizeToScene();
 421 
 422         double width = p.getWidth();
 423         double height = p.getHeight();
 424 
 425         // test changing dimensions to same values
 426         p.sizeToScene();
 427         assertEquals(width, p.getWidth(), 1e-100);
 428         assertEquals(height, p.getHeight(), 1e-100);
 429 
 430         // these methods shouldn't do anything for popups,
 431         // width and height should stay the same
 432         peer.close();
 433         assertEquals(width, p.getWidth(), 1e-100);
 434         assertEquals(height, p.getHeight(), 1e-100);
 435 
 436         peer.setFullScreen(true);
 437         assertEquals(width, p.getWidth(), 1e-100);
 438         assertEquals(height, p.getHeight(), 1e-100);
 439 
 440         peer.setIconified(true);
 441         assertEquals(width, p.getWidth(), 1e-100);
 442         assertEquals(height, p.getHeight(), 1e-100);
 443 
 444         peer.setResizable(true);
 445         assertEquals(width, p.getWidth(), 1e-100);
 446         assertEquals(height, p.getHeight(), 1e-100);
 447 
 448         peer.setLocation(0, 0);
 449         assertEquals(0, p.getX(), 1e-100);
 450         assertEquals(0, p.getY(), 1e-100);
 451         peer.setSize(100, 100);
 452         assertEquals(100, p.getWidth(), 1e-100);
 453         assertEquals(100, p.getHeight(), 1e-100);
 454     }
 455 
 456     @Test
 457     public void testDefautValueOfAutofix() {
 458         Popup p = new Popup();
 459         assertTrue(p.isAutoFix());
 460         assertTrue(p.autoFixProperty().get());
 461     }
 462 
 463     @Test
 464     public void testBasicAutofix() {
 465         toolkit.setScreens(
 466                 new ScreenConfiguration(0, 0, 1920, 1200,
 467                                         0, 200, 1920, 1000,
 468                                         96));
 469 
 470         final Popup popup = new Popup();
 471         popup.getContent().add(new Rectangle(0, 0, 50, 50));
 472         popup.show(stage, 1900, 100);
 473         assertEquals(1920, popup.getX() + popup.getWidth(), 1e-100);
 474         assertEquals(200, popup.getY(), 1e-100);
 475     }
 476 
 477     @Test
 478     public void testDoubleShowAutofix() {
 479         toolkit.setScreens(
 480                 new ScreenConfiguration(0, 0, 1920, 1200,
 481                                         0, 200, 1920, 1000,
 482                                         96));
 483 
 484         final Popup popup = new Popup();
 485         popup.getContent().add(new Rectangle(0, 0, 50, 50));
 486 
 487         popup.show(stage, 1900, 100);
 488         assertEquals(1920, popup.getX() + popup.getWidth(), 1e-100);
 489         assertEquals(200, popup.getY(), 1e-100);
 490 
 491         popup.show(stage, 1900, 100);
 492         assertEquals(1920, popup.getX() + popup.getWidth(), 1e-100);
 493         assertEquals(200, popup.getY(), 1e-100);
 494     }
 495 
 496     @Test
 497     public void testAutofixActivationAfterShow() {
 498         toolkit.setScreens(
 499                 new ScreenConfiguration(0, 0, 1920, 1200,
 500                                         0, 200, 1920, 1000,
 501                                         96));
 502 
 503         final Popup popup = new Popup();
 504         popup.setAutoFix(false);
 505         popup.getContent().add(new Rectangle(0, 0, 50, 50));
 506         popup.show(stage, 1900, 100);
 507 
 508         assertEquals(1900, popup.getX(), 1e-100);
 509         assertEquals(100, popup.getY(), 1e-100);
 510 
 511         popup.setAutoFix(true);
 512         assertEquals(1920, popup.getX() + popup.getWidth(), 1e-100);
 513         assertEquals(200, popup.getY(), 1e-100);
 514     }
 515 
 516     @Test
 517     public void testAutofixOnContentChange() {
 518         toolkit.setScreens(
 519                 new ScreenConfiguration(0, 0, 1920, 1200,
 520                                         0, 0, 1920, 1172,
 521                                         96));
 522 
 523         final Popup popup = new Popup();
 524         popup.getContent().add(new Rectangle(0, 0, 50, 50));
 525         popup.show(stage, 100, 1120);
 526         assertEquals(100, popup.getX(), 1e-100);
 527         assertEquals(1120, popup.getY(), 1e-100);
 528 
 529         popup.getContent().add(new Rectangle(0, 0, 50, 100));
 530         assertEquals(100, popup.getX(), 1e-100);
 531         assertEquals(1172, popup.getY() + popup.getHeight(), 1e-100);
 532     }
 533 
 534     @Test
 535     public void testAutofixOnScreenChange() {
 536         toolkit.setScreens(
 537                 new ScreenConfiguration(0, 0, 1920, 1200,
 538                                         0, 0, 1920, 1172,
 539                                         96));
 540 
 541         final Popup popup = new Popup();
 542         popup.getContent().add(new Rectangle(0, 0, 50, 50));
 543         popup.show(stage, 100, 1120);
 544         assertEquals(100, popup.getX(), 1e-100);
 545         assertEquals(1120, popup.getY(), 1e-100);
 546 
 547         toolkit.setScreens(
 548                 new ScreenConfiguration(0, 0, 1920, 1200,
 549                                         120, 0, 1800, 1172,
 550                                         96));
 551 
 552         assertEquals(120, popup.getX(), 1e-100);
 553         assertEquals(1120, popup.getY(), 1e-100);
 554     }
 555 
 556     @Test
 557     public void testAutofixWithFullScreen() {
 558         toolkit.setScreens(
 559                 new ScreenConfiguration(0, 0, 1920, 1200,
 560                                         0, 0, 1920, 1172,
 561                                         96));
 562 
 563         final Popup popup = new Popup();
 564         popup.getContent().add(new Rectangle(0, 0, 50, 50));
 565 
 566         stage.setFullScreen(true);
 567         popup.show(stage, 100, 1160);
 568 
 569         assertEquals(100, popup.getX(), 1e-100);
 570         assertEquals(1150, popup.getY(), 1e-100);
 571     }
 572 
 573     @Test
 574     public void testSetPopupContentByChangingRootNode() {
 575         final Popup popup = new Popup();
 576 
 577         popup.getScene().setRoot(new Group(new Rectangle(0, 0, 300, 200)));
 578         assertEquals(300, popup.getWidth(), 1e-100);
 579         assertEquals(200, popup.getHeight(), 1e-100);
 580 
 581         popup.getScene().setRoot(new Group(new Rectangle(0, 0, 200, 300)));
 582         assertEquals(200, popup.getWidth(), 1e-100);
 583         assertEquals(300, popup.getHeight(), 1e-100);
 584     }
 585 
 586     @Test
 587     public void testKeyEventTranslation() {
 588         Popup popup = new Popup();
 589         AtomicBoolean res = new AtomicBoolean(false);
 590         Rectangle rectangle = new Rectangle(0, 0, 300, 200);
 591         popup.getScene().setRoot(new Group(rectangle));
 592         popup.show(stage);
 593         rectangle.requestFocus();
 594         rectangle.setOnKeyPressed((KeyEvent e) -> {
 595             assertEquals(rectangle, e.getTarget());
 596             res.set(true);
 597         });
 598 
 599         Event.fireEvent(stage, new KeyEvent(null, stage, KeyEvent.KEY_PRESSED, "c", "c", KeyCode.C, false, false, false, false));
 600         assertTrue(res.get());
 601     }
 602 
 603     @Test
 604     public void testConsumeAutoHidingEventsProperty() {
 605         final EventCounter mouseEventCounter = new EventCounter();
 606         final EventCounter keyEventCounter = new EventCounter();
 607 
 608         stage.addEventHandler(MouseEvent.MOUSE_PRESSED, mouseEventCounter);
 609         stage.addEventHandler(KeyEvent.KEY_PRESSED, keyEventCounter);
 610         try {
 611             final MouseEventGenerator mouseEventGenerator =
 612                     new MouseEventGenerator();
 613 
 614             final Popup popup = new Popup();
 615             popup.setAutoHide(true);
 616 
 617             assertTrue(popup.getConsumeAutoHidingEvents());
 618 
 619             popup.show(stage);
 620             Event.fireEvent(stage,
 621                             mouseEventGenerator.generateMouseEvent(
 622                                 MouseEvent.MOUSE_PRESSED, 0, 0));
 623             assertEquals(0, mouseEventCounter.getValue());
 624 
 625             popup.show(stage);
 626             Event.fireEvent(stage,
 627                             new KeyEvent(null, stage,
 628                                 KeyEvent.KEY_PRESSED, KeyEvent.CHAR_UNDEFINED,
 629                                 KeyCode.ESCAPE.getName(),
 630                                 KeyCode.ESCAPE,
 631                                 false, false, false, false));
 632             assertEquals(0, keyEventCounter.getValue());
 633 
 634             popup.setConsumeAutoHidingEvents(false);
 635 
 636             popup.show(stage);
 637             Event.fireEvent(stage,
 638                             mouseEventGenerator.generateMouseEvent(
 639                                 MouseEvent.MOUSE_PRESSED, 0, 0));
 640             assertEquals(1, mouseEventCounter.getValue());
 641 
 642             popup.show(stage);
 643             Event.fireEvent(stage,
 644                             new KeyEvent(null, stage,
 645                                 KeyEvent.KEY_PRESSED,
 646                                 KeyEvent.CHAR_UNDEFINED,
 647                                 KeyCode.ESCAPE.getName(),
 648                                 KeyCode.ESCAPE,
 649                                 false, false, false, false));
 650             assertEquals(1, keyEventCounter.getValue());
 651 
 652         } finally {
 653             stage.removeEventHandler(MouseEvent.MOUSE_PRESSED,
 654                                      mouseEventCounter);
 655             stage.removeEventHandler(KeyEvent.KEY_PRESSED, keyEventCounter);
 656         }
 657     }
 658 
 659     @Test(expected=NullPointerException.class)
 660     public void testShowWithNullOwner() {
 661         final Popup popup = new Popup();
 662         popup.show(null);
 663     }
 664 
 665     @Test(expected=NullPointerException.class)
 666     public void testShowXYWithNullOwner() {
 667         final Popup popup = new Popup();
 668         popup.show((Window) null, 10, 10);
 669     }
 670 
 671     @Test(expected=IllegalArgumentException.class)
 672     public void testShowWithOwnerThatWouldCreateCycle1() {
 673         final Popup popup = new Popup();
 674         popup.show(popup);
 675     }
 676 
 677     @Test(expected=IllegalArgumentException.class)
 678     public void testShowWithOwnerThatWouldCreateCycle2() {
 679         final Popup popup1 = new Popup();
 680         final Popup popup2 = new Popup();
 681 
 682         popup1.show(stage);
 683         popup2.show(popup1);
 684         popup1.hide();
 685         popup1.show(popup2);
 686     }
 687 
 688     @Test(expected=IllegalArgumentException.class)
 689     public void testShowXYWithOwnerThatWouldCreateCycle1() {
 690         final Popup popup = new Popup();
 691         popup.show(popup, 10, 20);
 692     }
 693 
 694     @Test(expected=IllegalArgumentException.class)
 695     public void testShowXYWithOwnerThatWouldCreateCycle2() {
 696         final Popup popup1 = new Popup();
 697         final Popup popup2 = new Popup();
 698 
 699         popup1.show(stage);
 700         popup2.show(popup1);
 701         popup1.hide();
 702         popup1.show(popup2, 10, 20);
 703     }
 704 
 705     @Test
 706     public void testFocusGrabbedWhenNecessary() {
 707         final Popup popup = new Popup();
 708 
 709         popup.show(stage);
 710         stage.requestFocus();
 711 
 712         final StubStage peer = (StubStage) WindowHelper.getPeer(stage);
 713         assertFalse(peer.isFocusGrabbed());
 714 
 715         popup.setAutoHide(true);
 716         assertTrue(peer.isFocusGrabbed());
 717 
 718         popup.hide();
 719         assertFalse(peer.isFocusGrabbed());
 720     }
 721 
 722     @Test
 723     public void testPopupRootStyle() {
 724         final Popup popup = new Popup();
 725 
 726         final Parent oldRoot = popup.getScene().getRoot();
 727         Assert.assertTrue(oldRoot.getStyleClass().contains("popup"));
 728 
 729         final Group newRoot = new Group(new Rectangle(0, 0, 200, 300));
 730         popup.getScene().setRoot(newRoot);
 731 
 732         Assert.assertTrue(newRoot.getStyleClass().contains("popup"));
 733         Assert.assertFalse(oldRoot.getStyleClass().contains("popup"));
 734 
 735         System.out.println(javafx.scene.shape.Sphere.class.getResource("Sphere.class"));
 736     }
 737 
 738     @Test
 739     public void testCursorInheritance() {
 740         stage.getScene().setCursor(Cursor.CLOSED_HAND);
 741 
 742         final Popup popup = new Popup();
 743 
 744         popup.show(stage);
 745         assertEquals(Cursor.CLOSED_HAND, popup.getScene().getCursor());
 746 
 747     }
 748 
 749     private static final class EventCounter implements EventHandler<Event> {
 750         private int counter;
 751 
 752         public int getValue() {
 753             return counter;
 754         }
 755 
 756         public void handle(final Event event) {
 757             ++counter;
 758         }
 759     }
 760 }