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