1 /*
   2  * Copyright (c) 2015, 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  * @key headful
  27  * @bug 7072653 8144161
  28  * @summary JComboBox popup mispositioned if its height exceeds the screen height
  29  * @run main bug7072653
  30  */
  31 import java.awt.FlowLayout;
  32 import java.awt.GraphicsConfiguration;
  33 import java.awt.Insets;
  34 import java.awt.Robot;
  35 import javax.swing.event.PopupMenuEvent;
  36 import javax.swing.event.PopupMenuListener;
  37 import java.awt.Toolkit;
  38 import java.awt.Window;
  39 import java.util.Arrays;
  40 import javax.swing.DefaultComboBoxModel;
  41 import javax.swing.JComboBox;
  42 import javax.swing.JFrame;
  43 import javax.swing.SwingUtilities;
  44 import javax.swing.UIManager;
  45 import javax.swing.UnsupportedLookAndFeelException;
  46 
  47 public class bug7072653 {
  48 
  49     private static JComboBox combobox;
  50     private static JFrame frame;
  51     private static Robot robot;
  52     private static volatile String errorString = "";
  53 
  54     public static void main(String[] args) throws Exception {
  55         robot = new Robot();
  56         robot.delay(100);
  57         UIManager.LookAndFeelInfo[] lookAndFeelArray
  58                 = UIManager.getInstalledLookAndFeels();
  59         for (UIManager.LookAndFeelInfo lookAndFeelItem : lookAndFeelArray) {
  60             executeCase(lookAndFeelItem.getClassName());
  61             robot.delay(1000);
  62         }
  63         if (!"".equals(errorString)) {
  64 
  65             throw new RuntimeException("Error Log:\n" + errorString);
  66         }
  67     }
  68 
  69     private static void executeCase(String lookAndFeelString) throws Exception {
  70         if (tryLookAndFeel(lookAndFeelString)) {
  71             SwingUtilities.invokeAndWait(new Runnable() {
  72                 @Override
  73                 public void run() {
  74                     try {
  75                         setup(lookAndFeelString);
  76                         test();
  77                     } catch (Exception ex) {
  78                         errorString += "\n";
  79                         errorString += Arrays.toString(ex.getStackTrace());
  80                     }
  81                     finally {
  82                         frame.dispose();
  83                     }
  84                 }
  85             });
  86         }
  87 
  88     }
  89 
  90     private static void setup(String lookAndFeelString)
  91             throws Exception {
  92 
  93         frame = new JFrame("JComboBox Test " + lookAndFeelString);
  94         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  95         frame.setSize(320, 200);
  96         frame.getContentPane().setLayout(new FlowLayout());
  97         frame.setLocationRelativeTo(null);
  98         combobox = new JComboBox(new DefaultComboBoxModel() {
  99             @Override
 100             public Object getElementAt(int index) {
 101                 return "Element " + index;
 102             }
 103 
 104             @Override
 105             public int getSize() {
 106                 return 100;
 107             }
 108         });
 109 
 110         combobox.setMaximumRowCount(100);
 111         frame.getContentPane().add(combobox);
 112         frame.setVisible(true);
 113         combobox.addPopupMenuListener(new PopupMenuListener() {
 114             @Override
 115             public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
 116             }
 117 
 118             @Override
 119             public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
 120                 int height = 0;
 121                 for (Window window : JFrame.getWindows()) {
 122                     if (Window.Type.POPUP == window.getType()) {
 123                         height = window.getSize().height;
 124                         break;
 125                     }
 126                 }
 127                 GraphicsConfiguration gc
 128                         = combobox.getGraphicsConfiguration();
 129                 Insets screenInsets = Toolkit.getDefaultToolkit()
 130                         .getScreenInsets(gc);
 131                 int gcHeight = gc.getBounds().height;
 132                 if (lookAndFeelString.contains("aqua")) {
 133                     gcHeight = gcHeight - screenInsets.top;
 134                     //For Aqua LAF
 135                 } else {
 136                     gcHeight = gcHeight - screenInsets.top
 137                             - screenInsets.bottom;
 138                 }
 139                 if (height == gcHeight) {
 140                     return;
 141                 }
 142 
 143                 String exception = "Popup window height "
 144                         + "For LookAndFeel" + lookAndFeelString + " is wrong"
 145                         + "\nShould be " + height + "Actually " + gcHeight;
 146                 errorString += exception;
 147             }
 148 
 149             @Override
 150             public void popupMenuCanceled(PopupMenuEvent e) {
 151             }
 152 
 153         });
 154 
 155     }
 156 
 157     private static void test() throws Exception {
 158         combobox.setPopupVisible(true);
 159         combobox.setPopupVisible(false);
 160     }
 161 
 162     private static boolean tryLookAndFeel(String lookAndFeelString)
 163             throws Exception {
 164         try {
 165             UIManager.setLookAndFeel(
 166                     lookAndFeelString);
 167 
 168         } catch (UnsupportedLookAndFeelException
 169                 | ClassNotFoundException
 170                 | InstantiationException
 171                 | IllegalAccessException e) {
 172             return false;
 173         }
 174         return true;
 175     }
 176 }