7072653: JComboBox popup mispositioned if its height exceeds the screen height
authorssadetsky
Fri, 08 May 2015 16:46:24 +0300
changeset 30917 511aae7fee1a
parent 30916 8d4095a7bf7a
child 30918 ee2374d4aae3
7072653: JComboBox popup mispositioned if its height exceeds the screen height Reviewed-by: alexsch, azvegint
jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaComboBoxPopup.java
jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicComboPopup.java
jdk/test/javax/swing/plaf/basic/BasicComboPopup/7072653/bug7072653.java
--- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaComboBoxPopup.java	Fri May 08 15:37:38 2015 +0300
+++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaComboBoxPopup.java	Fri May 08 16:46:24 2015 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -204,7 +204,8 @@
             if ((p.x + comboBoxBounds.width < 0) || (p.y + comboBoxBounds.height < 0) || (p.x > scrSize.width) || (p.y > scrSize.height)) {
                 return null;
             }
-            return new Rectangle(0, 22, scrSize.width, scrSize.height - 22);
+            Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(comboBox.getGraphicsConfiguration());
+            return new Rectangle(0, insets.top, scrSize.width, scrSize.height - insets.top - insets.bottom);
         }
 
         for (final GraphicsDevice gd : gs) {
@@ -314,10 +315,17 @@
         }
 
         final Rectangle r = new Rectangle(px, py, pw, ph);
-        // Check whether it goes below the bottom of the screen, if so flip it
-        if (r.y + r.height < top.y + scrBounds.y + scrBounds.height) return r;
-
-        return new Rectangle(px, -r.height + comboBoxInsets.top, r.width, r.height);
+        if (py + ph > scrBounds.y + scrBounds.height) {
+            if (ph <= -scrBounds.y ) {
+                // popup goes above
+                r.y = -ph ;
+            } else {
+                // a full screen height popup
+                r.y = scrBounds.y + Math.max(0, (scrBounds.height - ph) / 2 );
+                r.height = Math.min(scrBounds.height, ph);
+            }
+        }
+        return r;
     }
 
     // The one to use when itemCount <= maxRowCount.  Size never adjusts for arrows
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicComboPopup.java	Fri May 08 15:37:38 2015 +0300
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicComboPopup.java	Fri May 08 16:46:24 2015 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1287,11 +1287,24 @@
         else {
             screenBounds = new Rectangle(p, toolkit.getScreenSize());
         }
-
-        Rectangle rect = new Rectangle(px,py,pw,ph);
-        if (py+ph > screenBounds.y+screenBounds.height
-            && ph < screenBounds.height) {
-            rect.y = -rect.height;
+        int borderHeight = 0;
+        Border popupBorder = getBorder();
+        if (popupBorder != null) {
+            Insets borderInsets = popupBorder.getBorderInsets(this);
+            borderHeight = borderInsets.top + borderInsets.bottom;
+            screenBounds.width -= (borderInsets.left + borderInsets.right);
+            screenBounds.height -= borderHeight;
+        }
+        Rectangle rect = new Rectangle(px, py, pw, ph);
+        if (py + ph > screenBounds.y + screenBounds.height) {
+            if (ph <= -screenBounds.y - borderHeight) {
+                // popup goes above
+                rect.y = -ph - borderHeight;
+            } else {
+                // a full screen height popup
+                rect.y = screenBounds.y + Math.max(0, (screenBounds.height - ph) / 2 );
+                rect.height = Math.min(screenBounds.height, ph);
+            }
         }
         return rect;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/plaf/basic/BasicComboPopup/7072653/bug7072653.java	Fri May 08 16:46:24 2015 +0300
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+   @bug 7072653
+   @summary JComboBox popup mispositioned if its height exceeds the screen height
+   @author Semyon Sadetsky
+  */
+
+
+import javax.swing.*;
+import javax.swing.event.PopupMenuEvent;
+import javax.swing.event.PopupMenuListener;
+import java.awt.*;
+import java.awt.Toolkit;
+
+public class bug7072653 {
+
+    private static JComboBox combobox;
+    private static JFrame frame;
+
+    public static void main(String[] args) throws Exception {
+        try {
+            SwingUtilities.invokeAndWait(new Runnable() {
+                @Override
+                public void run() {
+                    frame = new JFrame("JComboBox Test");
+                    setup(frame);
+                }
+            });
+            test();
+        }
+        finally {
+            frame.dispose();
+        }
+
+    }
+
+    static void setup(JFrame frame)  {
+
+
+        frame.setUndecorated(true);
+        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+        frame.setSize(320, 200);
+
+        frame.getContentPane().setLayout(new FlowLayout());
+
+        combobox = new JComboBox(new DefaultComboBoxModel() {
+            public Object getElementAt(int index) { return "Element " + index; }
+            public int getSize() {
+                return 1000;
+            }
+        });
+
+
+        combobox.setMaximumRowCount(100);
+        frame.getContentPane().add(combobox);
+
+        frame.setVisible(true);
+
+    }
+
+    static void test() throws Exception{
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                combobox.addPopupMenuListener(new PopupMenuListener() {
+                    @Override
+                    public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
+                    }
+
+                    @Override
+                    public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
+                        int height = 0;
+                        for (Window window : JFrame.getWindows()) {
+                            if (Window.Type.POPUP == window.getType()) {
+                                height = window.getSize().height;
+                                break;
+                            }
+                        }
+                        GraphicsConfiguration gc =
+                                combobox.getGraphicsConfiguration();
+                        Insets screenInsets = Toolkit.getDefaultToolkit()
+                                .getScreenInsets(gc);
+
+                        if (height == gc.getBounds().height - screenInsets.top -
+                                screenInsets.bottom ) {
+                            System.out.println("ok");
+                            return;
+                        }
+                        throw new RuntimeException(
+                                "Popup window height is wrong " + height);
+                    }
+
+                    @Override
+                    public void popupMenuCanceled(PopupMenuEvent e) {
+                    }
+                });
+                combobox.setPopupVisible(true);
+                combobox.setPopupVisible(false);
+            }
+        });
+    }
+
+
+}