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