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