1 /*
   2  * Copyright (c) 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 import java.awt.*;
  25 import java.awt.event.*;
  26 import javax.swing.*;
  27 import javax.swing.event.*;
  28 
  29 /**
  30  * @test
  31  * @bug 4245587 4474813 4425878 4767478 8015599
  32  * @key headful
  33  * @author Mark Davidson
  34  * @summary Tests the location of the heavy weight popup portion of JComboBox,
  35  * JMenu and JPopupMenu.
  36  * @library ../regtesthelpers
  37  * @build Util
  38  * @run main TaskbarPositionTest
  39  */
  40 public class TaskbarPositionTest extends JFrame implements ActionListener {
  41 
  42     private boolean done;
  43     private Throwable error;
  44     private static TaskbarPositionTest test;
  45     private static JPopupMenu popupMenu;
  46     private static JPanel panel;
  47     private static JComboBox<String> combo1;
  48     private static JComboBox<String> combo2;
  49     private static JMenuBar menubar;
  50     private static JMenu menu1;
  51     private static JMenu menu2;
  52     private static Rectangle fullScreenBounds;
  53     // The usable desktop space: screen size - screen insets.
  54     private static Rectangle screenBounds;
  55     private static String[] numData = {
  56         "One", "Two", "Three", "Four", "Five", "Six", "Seven"
  57     };
  58     private static String[] dayData = {
  59         "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"
  60     };
  61     private static char[] mnDayData = {
  62         'M', 'T', 'W', 'R', 'F', 'S', 'U'
  63     };
  64 
  65     public TaskbarPositionTest() {
  66         super("Use CTRL-down to show a JPopupMenu");
  67         setContentPane(panel = createContentPane());
  68         setJMenuBar(createMenuBar("1 - First Menu", true));
  69         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  70 
  71         // CTRL-down will show the popup.
  72         panel.getInputMap().put(KeyStroke.getKeyStroke(
  73                 KeyEvent.VK_DOWN, InputEvent.CTRL_MASK), "OPEN_POPUP");
  74         panel.getActionMap().put("OPEN_POPUP", new PopupHandler());
  75 
  76         pack();
  77 
  78         Toolkit toolkit = Toolkit.getDefaultToolkit();
  79         fullScreenBounds = new Rectangle(new Point(), toolkit.getScreenSize());
  80         screenBounds = new Rectangle(new Point(), toolkit.getScreenSize());
  81 
  82         // Place the frame near the bottom. This is a pretty wild guess.
  83         this.setLocation(0, (int) screenBounds.getHeight() - 2 * this.getHeight());
  84 
  85         // Reduce the screen bounds by the insets.
  86         GraphicsConfiguration gc = this.getGraphicsConfiguration();
  87         if (gc != null) {
  88             Insets screenInsets = toolkit.getScreenInsets(gc);
  89             screenBounds = gc.getBounds();
  90             screenBounds.width -= (screenInsets.left + screenInsets.right);
  91             screenBounds.height -= (screenInsets.top + screenInsets.bottom);
  92             screenBounds.x += screenInsets.left;
  93             screenBounds.y += screenInsets.top;
  94         }
  95 
  96         setVisible(true);
  97     }
  98 
  99     public static class ComboPopupCheckListener implements PopupMenuListener {
 100 
 101         public void popupMenuCanceled(PopupMenuEvent ev) {
 102         }
 103 
 104         public void popupMenuWillBecomeVisible(PopupMenuEvent ev) {
 105         }
 106 
 107         public void popupMenuWillBecomeInvisible(PopupMenuEvent ev) {
 108             Point cpos = combo1.getLocation();
 109             SwingUtilities.convertPointToScreen(cpos, panel);
 110 
 111             JPopupMenu pm = (JPopupMenu) combo1.getUI().getAccessibleChild(combo1, 0);
 112 
 113             if (pm != null) {
 114                 Point p = pm.getLocation();
 115                 SwingUtilities.convertPointToScreen(p, pm);
 116                 if (p.y < cpos.y) {
 117                     throw new RuntimeException("ComboBox popup is wrongly aligned");
 118                 }  // check that popup was opened down
 119             }
 120         }
 121     }
 122 
 123     private class PopupHandler extends AbstractAction {
 124 
 125         public void actionPerformed(ActionEvent e) {
 126             if (!popupMenu.isVisible()) {
 127                 popupMenu.show((Component) e.getSource(), 40, 40);
 128             }
 129             isPopupOnScreen(popupMenu, fullScreenBounds);
 130         }
 131     }
 132 
 133     class PopupListener extends MouseAdapter {
 134 
 135         private JPopupMenu popup;
 136 
 137         public PopupListener(JPopupMenu popup) {
 138             this.popup = popup;
 139         }
 140 
 141         public void mousePressed(MouseEvent e) {
 142             maybeShowPopup(e);
 143         }
 144 
 145         public void mouseReleased(MouseEvent e) {
 146             maybeShowPopup(e);
 147         }
 148 
 149         private void maybeShowPopup(MouseEvent e) {
 150             if (e.isPopupTrigger()) {
 151                 popup.show(e.getComponent(), e.getX(), e.getY());
 152                 isPopupOnScreen(popup, fullScreenBounds);
 153             }
 154         }
 155     }
 156 
 157     /**
 158      * Tests if the popup is on the screen.
 159      */
 160     public static void isPopupOnScreen(JPopupMenu popup, Rectangle checkBounds) {
 161         Dimension dim = popup.getSize();
 162         Point pt = new Point();
 163         SwingUtilities.convertPointToScreen(pt, popup);
 164         Rectangle bounds = new Rectangle(pt, dim);
 165 
 166         if (!SwingUtilities.isRectangleContainingRectangle(checkBounds, bounds)) {
 167             throw new RuntimeException("We do not match! " + checkBounds + " / " + bounds);
 168         }
 169 
 170     }
 171 
 172     private JPanel createContentPane() {
 173         JPanel panel = new JPanel();
 174 
 175         combo1 = new JComboBox<>(numData);
 176         panel.add(combo1);
 177         combo2 = new JComboBox<>(dayData);
 178         combo2.setEditable(true);
 179         panel.add(combo2);
 180         panel.setSize(300, 200);
 181 
 182         popupMenu = new JPopupMenu();
 183         JMenuItem item;
 184         for (int i = 0; i < dayData.length; i++) {
 185             item = popupMenu.add(new JMenuItem(dayData[i], mnDayData[i]));
 186             item.addActionListener(this);
 187         }
 188         panel.addMouseListener(new PopupListener(popupMenu));
 189 
 190         JTextField field = new JTextField("CTRL+down for Popup");
 191         // CTRL-down will show the popup.
 192         field.getInputMap().put(KeyStroke.getKeyStroke(
 193                 KeyEvent.VK_DOWN, InputEvent.CTRL_MASK), "OPEN_POPUP");
 194         field.getActionMap().put("OPEN_POPUP", new PopupHandler());
 195 
 196         panel.add(field);
 197 
 198         return panel;
 199     }
 200 
 201     /**
 202      * @param str name of Menu
 203      * @param bFlag set mnemonics on menu items
 204      */
 205     private JMenuBar createMenuBar(String str, boolean bFlag) {
 206         menubar = new JMenuBar();
 207 
 208         menu1 = new JMenu(str);
 209         menu1.setMnemonic(str.charAt(0));
 210         menu1.addActionListener(this);
 211 
 212         menubar.add(menu1);
 213         for (int i = 0; i < 8; i++) {
 214             JMenuItem menuitem = new JMenuItem("1 JMenuItem" + i);
 215             menuitem.addActionListener(this);
 216             if (bFlag) {
 217                 menuitem.setMnemonic('0' + i);
 218             }
 219             menu1.add(menuitem);
 220         }
 221 
 222         // second menu
 223         menu2 = new JMenu("2 - Second Menu");
 224         menu2.addActionListener(this);
 225         menu2.setMnemonic('2');
 226 
 227         menubar.add(menu2);
 228         for (int i = 0; i < 5; i++) {
 229             JMenuItem menuitem = new JMenuItem("2 JMenuItem" + i);
 230             menuitem.addActionListener(this);
 231 
 232             if (bFlag) {
 233                 menuitem.setMnemonic('0' + i);
 234             }
 235             menu2.add(menuitem);
 236         }
 237         JMenu submenu = new JMenu("Sub Menu");
 238         submenu.setMnemonic('S');
 239         submenu.addActionListener(this);
 240         for (int i = 0; i < 5; i++) {
 241             JMenuItem menuitem = new JMenuItem("S JMenuItem" + i);
 242             menuitem.addActionListener(this);
 243             if (bFlag) {
 244                 menuitem.setMnemonic('0' + i);
 245             }
 246             submenu.add(menuitem);
 247         }
 248         menu2.add(new JSeparator());
 249         menu2.add(submenu);
 250 
 251         return menubar;
 252     }
 253 
 254     public void actionPerformed(ActionEvent evt) {
 255         Object obj = evt.getSource();
 256         if (obj instanceof JMenuItem) {
 257             // put the focus on the noneditable combo.
 258             combo1.requestFocus();
 259         }
 260     }
 261 
 262     public static void main(String[] args) throws Throwable {
 263 
 264 
 265         SwingUtilities.invokeAndWait(new Runnable() {
 266             public void run() {
 267                 test = new TaskbarPositionTest();
 268             }
 269         });
 270 
 271         // Use Robot to automate the test
 272         Robot robot;
 273         robot = new Robot();
 274         robot.setAutoDelay(125);
 275 
 276         // 1 - menu
 277         Util.hitMnemonics(robot, KeyEvent.VK_1);
 278 
 279         robot.waitForIdle();
 280         isPopupOnScreen(menu1.getPopupMenu(), screenBounds);
 281 
 282         // 2 menu with sub menu
 283         robot.keyPress(KeyEvent.VK_RIGHT);
 284         robot.keyRelease(KeyEvent.VK_RIGHT);
 285         Util.hitMnemonics(robot, KeyEvent.VK_S);
 286 
 287         robot.waitForIdle();
 288         isPopupOnScreen(menu2.getPopupMenu(), screenBounds);
 289 
 290         robot.keyPress(KeyEvent.VK_ENTER);
 291         robot.keyRelease(KeyEvent.VK_ENTER);
 292 
 293         // Focus should go to non editable combo box
 294         robot.waitForIdle();
 295         Thread.sleep(500);
 296 
 297         robot.keyPress(KeyEvent.VK_DOWN);
 298 
 299         // How do we check combo boxes?
 300 
 301         // Editable combo box
 302         robot.keyPress(KeyEvent.VK_TAB);
 303         robot.keyRelease(KeyEvent.VK_TAB);
 304         robot.keyPress(KeyEvent.VK_DOWN);
 305         robot.keyRelease(KeyEvent.VK_DOWN);
 306 
 307         // combo1.getUI();
 308 
 309         // Popup from Text field
 310         robot.keyPress(KeyEvent.VK_TAB);
 311         robot.keyRelease(KeyEvent.VK_TAB);
 312         robot.keyPress(KeyEvent.VK_CONTROL);
 313         robot.keyPress(KeyEvent.VK_DOWN);
 314         robot.keyRelease(KeyEvent.VK_DOWN);
 315         robot.keyRelease(KeyEvent.VK_CONTROL);
 316 
 317         // Popup from a mouse click.
 318         Point pt = new Point(2, 2);
 319         SwingUtilities.convertPointToScreen(pt, panel);
 320         robot.mouseMove((int) pt.getX(), (int) pt.getY());
 321         robot.mousePress(InputEvent.BUTTON3_MASK);
 322         robot.mouseRelease(InputEvent.BUTTON3_MASK);
 323 
 324         robot.waitForIdle();
 325         SwingUtilities.invokeAndWait(new Runnable() {
 326             public void run() {
 327                 test.setLocation(-30, 100);
 328                 combo1.addPopupMenuListener(new ComboPopupCheckListener());
 329                 combo1.requestFocus();
 330             }
 331         });
 332 
 333         robot.keyPress(KeyEvent.VK_DOWN);
 334         robot.keyRelease(KeyEvent.VK_DOWN);
 335         robot.keyPress(KeyEvent.VK_ESCAPE);
 336         robot.keyRelease(KeyEvent.VK_ESCAPE);
 337 
 338         robot.waitForIdle();
 339         Thread.sleep(500);
 340     }
 341 }