1 /*
   2  * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  @test
  26  @summary Make sure that we can handle mouse and key events in a relatively simple component heirarchy
  27  @summary This test creates a frame with several nested panels (as well as several labels that tell where things are)
  28  @summary It then makes sure the frame is visible, requests focus in the top panel, and then either clicks or types in this panel
  29  @summary com.apple.junit.java.awt.Event;
  30  @library ../../regtesthelpers
  31  @build RobotUtilities
  32  @build VisibilityValidator
  33  @run main EventHeirachyWithListeners
  34  */
  35 
  36 import junit.framework.*;
  37 
  38 import java.awt.*;
  39 import java.awt.event.*;
  40 import java.util.*;
  41 
  42 import test.java.awt.regtesthelpers.RobotUtilities;
  43 import test.java.awt.regtesthelpers.VisibilityValidator;
  44 
  45 public class EventHeirachyWithListeners extends TestCase {
  46     static final Random rand = new Random(161566);
  47     static final boolean DEBUG = false;
  48     private static final int TIMEOUT = 5000; // Timeout for expected events
  49     protected Timer ticktock;
  50     protected TestFrame f;
  51 
  52 
  53     // Make a frame with several nested panels
  54     // These panels needs some knowledge of what focus events and click events the test will generate
  55     @SuppressWarnings("serial")
  56     class TestFrame extends Frame {
  57         static final int NUM_NESTED_PANELS = 6;
  58         static final int BOTTOM_PANEL = 0;
  59         static final int TOP_PANEL = NUM_NESTED_PANELS-1;
  60         TestPanel fPanels[] = new TestPanel[NUM_NESTED_PANELS];
  61         Label fStatusLabel = new Label("Waiting for the test to get around to putting some status into this label.");
  62         private volatile int fEventCount;
  63         private volatile boolean fFocused;
  64 
  65         // This is a sub-panel set up with listeners which watch for our test events
  66         class TestPanel extends Panel {
  67             // Panel identifier, for debug purposes
  68             int id;
  69 
  70             public TestPanel( int id)  {
  71                 this.id = id;
  72                 setMinimumSize(new Dimension(200, 100));
  73 
  74                 // Give it a vaguely interesting color
  75                 Color color = new Color( 0x80 + rand.nextInt(0x80), 0x80 + rand.nextInt(0x80), 0x80 + rand.nextInt(0x80) );
  76                 setBackground(color);
  77 
  78                 // Hack in some spacers so we can see the nesting
  79                 setLayout( new BorderLayout());
  80                 add( new Label( "-"+id+"-", Label.CENTER), BorderLayout.NORTH);
  81                 add( new Label( "-"+id+"-", Label.CENTER), BorderLayout.SOUTH);
  82                 add( new Label( "-"+id+"-", Label.CENTER), BorderLayout.EAST);
  83                 add( new Label( "-"+id+"-", Label.CENTER), BorderLayout.WEST);
  84 
  85                 // Add the listners
  86                 TestFrame.this.doListeners( this );
  87             }
  88 
  89             // Painting, mostly for debug purposes
  90             @Override
  91             public void paint(Graphics g) {
  92                 super.paint(g);
  93                 Dimension size = getSize();
  94                 g.setColor( Color.BLACK );
  95                 g.drawString (" Panel " + id , 30, size.height/2 );
  96             }
  97 
  98             // A more informative toString() for debugging
  99             @Override
 100             public String toString() {
 101                 String me = "Test Panel " + id;
 102                 if (id == BOTTOM_PANEL) {
 103                     me += " - bottom ";
 104                 }
 105                 if (id == TOP_PANEL) {
 106                     me += " - top";
 107                 }
 108                 return me;
 109             }
 110         }
 111 
 112         // Constructor to build the frame and add the sub-panels
 113         public TestFrame( int width, int height ) throws Exception {
 114             setLayout( new BorderLayout());
 115             add(fStatusLabel,BorderLayout.NORTH);
 116 
 117             for (int i = 0; i < fPanels.length; i++) {
 118                 fPanels[i] = new TestPanel(i);
 119                 if (i != BOTTOM_PANEL) {
 120                     fPanels[i-1].add(fPanels[i],BorderLayout.CENTER);
 121                 }
 122                 else {
 123                     add( fPanels[BOTTOM_PANEL],BorderLayout.CENTER);
 124                 }
 125             }
 126 
 127             // explicitly watch for a focus event on the top panel
 128             // this get us out of our loopForFocus() in the tests below
 129             fPanels[TOP_PANEL].addFocusListener(new FocusAdapter() {
 130                 @Override
 131                 public void focusGained(FocusEvent e) {
 132                     if (DEBUG) {System.out.println(e);}
 133                     handleFocusEvent();
 134                 }
 135             });
 136 
 137             setMinimumSize(new Dimension(width, height));
 138             pack();
 139         }
 140 
 141         // events will get us out of the loopForEvents below
 142         synchronized void handleRobotEvent() {
 143             fEventCount++;
 144             notify();
 145         }
 146 
 147         // events will get us out of the loopForFocus loop below
 148         synchronized void handleFocusEvent() {
 149             fFocused = true;
 150             notify();
 151         }
 152 
 153         // Accessor for the top panel
 154         public TestPanel getTopPanel() {
 155             return (fPanels[TOP_PANEL]);
 156         }
 157 
 158         // Add in the key/mouse listeners
 159         void doListeners( Component c) {
 160             c.addKeyListener( new KeyAdapter() {
 161                 @Override
 162                 public void keyPressed( KeyEvent e ) {
 163                     if (DEBUG) {System.out.println(e);}
 164                     handleRobotEvent();
 165                 }
 166             } );
 167             c.addMouseListener( new MouseAdapter() {
 168                 @Override
 169                 public void mousePressed( MouseEvent e ) {
 170                     handleRobotEvent();
 171                     if (DEBUG) {System.out.println(e);}
 172                 }
 173             } );
 174 
 175         }
 176 
 177         // smart loop waiting for focus event
 178         synchronized public boolean loopForFocus() throws Exception {
 179             long endtime = System.currentTimeMillis() + TIMEOUT;
 180             int count = 0;
 181             while (fFocused == false) {
 182                 // Debugging feedback
 183                 if (System.currentTimeMillis() < endtime) {
 184                     fStatusLabel.setText((count++) + " Waiting for the top panel to get focus.");
 185                     fStatusLabel.repaint();
 186                     wait( TIMEOUT / 100 );
 187                 }
 188                 else {
 189                     break;
 190                 }
 191             }
 192             return (fFocused);
 193         }
 194 
 195         // smart loop waiting for key/mouse events
 196         synchronized public boolean loopForEvents( int total, long timeout ) throws Exception {
 197             long endtime = System.currentTimeMillis() + timeout;
 198             int count = 0;
 199             while (fEventCount < total) {
 200                 // Debugging feedback
 201                 if (System.currentTimeMillis() < endtime) {
 202                     fStatusLabel.setText((count++) + " Waiting for the Robot to press any key or click mouse...");
 203                     fStatusLabel.repaint();
 204                     wait( timeout / 100 );
 205                 }
 206                 else {
 207                     break;
 208                 }
 209             }
 210             return (fEventCount == total);
 211         }
 212     }
 213 
 214 
 215     // setUp delivers a test frame with a focused top panel
 216     @Override
 217     protected void setUp() throws Exception {
 218         ticktock = new Timer();
 219         f = new TestFrame( 400, 500 );
 220         VisibilityValidator.setVisibleAndConfirm(f);
 221 
 222         // In a few seconds, make the top panel the fFocused
 223         TimerTask action = new TimerTask() {
 224             @Override
 225             public void run() {
 226                 Panel p = f.getTopPanel();
 227                 if (DEBUG) {System.out.println("Grabbing Focus" + p);}
 228                 p.requestFocus();
 229 
 230             }
 231         };
 232         ticktock.schedule( action, TIMEOUT/4 );
 233 
 234         // Meanwhile, wait for the event
 235         boolean focusOK = f.loopForFocus( );
 236         assertTrue( "Top panel never got a focus event", focusOK );
 237 
 238     }
 239 
 240     // tearDown destroys a test frame
 241     @Override
 242     protected void tearDown() throws Exception {
 243         // Thread.sleep(50000);
 244         f.dispose();
 245         ticktock.cancel();
 246     }
 247 
 248     // Make sure we can handle a simple mouse click
 249     public void testMouseEvent() throws Exception {
 250 
 251         // In a few more seconds, click the mouse
 252         TimerTask action = new TimerTask() {
 253             @Override
 254             public void run() {
 255                 Panel p = f.getTopPanel();
 256                 RobotUtilities.click(p);
 257             }
 258         };
 259         ticktock.schedule( action, TIMEOUT/4 );
 260 
 261         // Meanwhile, wait for the event
 262         boolean gotEvent = f.loopForEvents( 1, TIMEOUT );
 263         assertTrue( "We should have gotten a single mouse click", gotEvent );
 264     }
 265 
 266 
 267     // Make sure we can handle a simple key event
 268     public void testKeyEvent() throws Exception {
 269 
 270         // In a few more seconds, hit the space bar
 271         TimerTask action = new TimerTask() {
 272             @Override
 273             public void run() {
 274                 RobotUtilities.typeKey( KeyEvent.VK_SPACE );
 275             }
 276         };
 277         ticktock.schedule( action, TIMEOUT/4 );
 278 
 279         // Meanwhile, wait for the event
 280         boolean gotEvent = f.loopForEvents( 1, TIMEOUT );
 281         assertTrue( "We should have gotten a single keyboard space bar pressed", gotEvent );
 282     }
 283 
 284 
 285     // Make sure diableEvent works
 286     public void testKeyEventDisabled() throws Exception {
 287 
 288         // Disable the top panel
 289         Panel p = f.getTopPanel();
 290         p.setEnabled(false);
 291 
 292         // In a few more seconds, hit the space bar
 293         TimerTask action = new TimerTask() {
 294             @Override
 295             public void run() {
 296                 RobotUtilities.typeKey( KeyEvent.VK_SPACE );
 297             }
 298         };
 299         ticktock.schedule( action, TIMEOUT/4 );
 300 
 301         // We expect to hit the timeout, as we have disabled the component that gets the event
 302         // Use a shorter timeout -- 5 seconds is a long time...
 303         boolean gotEvent = f.loopForEvents( 1, TIMEOUT/3 );
 304 
 305         // We should not get events, as we are disabled
 306         assertFalse( "We should time out without ever getting any events", gotEvent );
 307     }
 308 
 309     public static Test suite() {
 310         return new TestSuite( EventHeirachyWithListeners.class);
 311     }
 312 
 313     public static void main (String[] args) throws RuntimeException {
 314         TestResult tr = junit.textui.TestRunner.run(suite());
 315         if((tr.errorCount() != 0) || (tr.failureCount() != 0)) {
 316             throw new RuntimeException("### Unexpected JUnit errors or failures.");
 317         }
 318     }
 319 }