6864297: Right-to-left oriented JScrollPane is aligned to the wrong direction while resizing the container
authormalenkov
Tue, 28 Jul 2009 13:10:14 +0400
changeset 3350 100ac73bfe6e
parent 3349 7927a519e42b
child 3351 478ff4c1be9b
child 3501 a3168c7b4011
6864297: Right-to-left oriented JScrollPane is aligned to the wrong direction while resizing the container Reviewed-by: peterz
jdk/src/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java
jdk/test/javax/swing/JScrollPane/Test6526631.java
jdk/test/javax/swing/SwingTest.java
--- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java	Mon Jul 27 03:42:47 2009 -0700
+++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java	Tue Jul 28 13:10:14 2009 +0400
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2005 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc.  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
@@ -37,17 +37,12 @@
 import java.beans.PropertyChangeEvent;
 
 import java.awt.Component;
-import java.awt.Container;
-import java.awt.LayoutManager;
 import java.awt.Rectangle;
 import java.awt.Dimension;
 import java.awt.Point;
 import java.awt.Insets;
 import java.awt.Graphics;
 import java.awt.event.*;
-import java.io.Serializable;
-import java.awt.Toolkit;
-import java.awt.ComponentOrientation;
 
 /**
  * A default L&F implementation of ScrollPaneUI.
@@ -63,6 +58,7 @@
     protected ChangeListener viewportChangeListener;
     protected PropertyChangeListener spPropertyChangeListener;
     private MouseWheelListener mouseScrollListener;
+    private int oldExtent = Integer.MIN_VALUE;
 
     /**
      * PropertyChangeListener installed on the vertical scrollbar.
@@ -327,9 +323,13 @@
                             * leave it until someone claims.
                             */
                             value = Math.max(0, Math.min(max - extent, max - extent - viewPosition.x));
+                            if (oldExtent > extent) {
+                                value -= oldExtent - extent;
+                            }
                         }
                     }
                 }
+                oldExtent = extent;
                 hsb.setValues(value, extent, 0, max);
             }
 
@@ -1020,7 +1020,7 @@
 
             if (viewport != null) {
                 if (e.getSource() == viewport) {
-                    viewportStateChanged(e);
+                    syncScrollPaneWithViewport();
                 }
                 else {
                     JScrollBar hsb = scrollpane.getHorizontalScrollBar();
@@ -1077,11 +1077,6 @@
             viewport.setViewPosition(p);
         }
 
-        private void viewportStateChanged(ChangeEvent e) {
-            syncScrollPaneWithViewport();
-        }
-
-
         //
         // PropertyChangeListener: This is installed on both the JScrollPane
         // and the horizontal/vertical scrollbars.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JScrollPane/Test6526631.java	Tue Jul 28 13:10:14 2009 +0400
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6526631
+ * @summary Resizes right-oriented scroll pane
+ * @author Sergey Malenkov
+ * @library ..
+ * @build SwingTest
+ * @run main Test6526631
+ */
+
+import java.awt.Dimension;
+import javax.swing.JFrame;
+import javax.swing.JScrollBar;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JViewport;
+
+import static java.awt.ComponentOrientation.RIGHT_TO_LEFT;
+
+public class Test6526631 {
+
+    private static final int COLS = 90;
+    private static final int ROWS = 50;
+    private static final int OFFSET = 10;
+
+    public static void main(String[] args) {
+        SwingTest.start(Test6526631.class);
+    }
+
+    private final JScrollPane pane;
+    private final JFrame frame;
+
+    public Test6526631(JFrame frame) {
+        this.pane = new JScrollPane(new JTextArea(ROWS, COLS));
+        this.pane.setComponentOrientation(RIGHT_TO_LEFT);
+        this.frame = frame;
+        this.frame.add(this.pane);
+    }
+
+    private void update(int offset) {
+        Dimension size = this.frame.getSize();
+        size.width += offset;
+        this.frame.setSize(size);
+    }
+
+    public void validateFirst() {
+        validateThird();
+        update(OFFSET);
+    }
+
+    public void validateSecond() {
+        validateThird();
+        update(-OFFSET);
+    }
+
+    public void validateThird() {
+        JViewport viewport = this.pane.getViewport();
+        JScrollBar scroller = this.pane.getHorizontalScrollBar();
+        if (!scroller.getComponentOrientation().equals(RIGHT_TO_LEFT)) {
+            throw new IllegalStateException("unexpected component orientation");
+        }
+        int value = scroller.getValue();
+        if (value != 0) {
+            throw new IllegalStateException("unexpected scroll value");
+        }
+        int extent = viewport.getExtentSize().width;
+        if (extent != scroller.getVisibleAmount()) {
+            throw new IllegalStateException("unexpected visible amount");
+        }
+        int size = viewport.getViewSize().width;
+        if (size != scroller.getMaximum()) {
+            throw new IllegalStateException("unexpected maximum");
+        }
+        int pos = size - extent - value;
+        if (pos != viewport.getViewPosition().x) {
+            throw new IllegalStateException("unexpected position");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/SwingTest.java	Tue Jul 28 13:10:14 2009 +0400
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.io.PrintWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.swing.JFrame;
+
+import static javax.swing.SwingUtilities.invokeLater;
+
+/**
+ * SwingTestHelper is a utility class for writing regression tests
+ * that require interacting with the UI.
+ *
+ * @author Sergey A. Malenkov
+ */
+final class SwingTest implements Runnable {
+
+    private static final int WIDTH = 640;
+    private static final int HEIGHT = 480;
+
+    public static void start(Class<?> type) {
+        new SwingTest(type).start();
+    }
+
+    private final PrintWriter writer = new PrintWriter(System.out, true);
+
+    private Class<?> type;
+    private JFrame frame;
+    private Iterator<Method> methods;
+    private Object object;
+    private Method method;
+    private Throwable error;
+
+    private SwingTest(Class<?> type) {
+        this.type = type;
+    }
+
+    public void run() {
+        synchronized (this.writer) {
+            if (this.error != null) {
+                this.frame.dispose();
+                this.frame = null;
+            }
+            else if (this.object == null) {
+                invoke();
+                Set<Method> methods = new TreeSet<Method>(new Comparator<Method>() {
+                    public int compare(Method first, Method second) {
+                        return first.getName().compareTo(second.getName());
+                    }
+                });
+                for (Method method : this.type.getMethods()) {
+                    if (method.getDeclaringClass().equals(this.type)) {
+                        if (method.getReturnType().equals(void.class)) {
+                            if (0 == method.getParameterTypes().length) {
+                                methods.add(method);
+                            }
+                        }
+                    }
+                }
+                this.methods = methods.iterator();
+            }
+            else if (this.method != null) {
+                invoke();
+            }
+            else if (this.methods.hasNext()) {
+                this.method = this.methods.next();
+            }
+            else {
+                this.frame.dispose();
+                this.frame = null;
+                this.type = null;
+            }
+            this.writer.notifyAll();
+        }
+    }
+
+    private void start() {
+        synchronized (this.writer) {
+            while (this.type != null) {
+                if ((this.method != null) && Modifier.isStatic(this.method.getModifiers())) {
+                    invoke();
+                }
+                else {
+                    invokeLater(this);
+                    try {
+                        this.writer.wait();
+                    }
+                    catch (InterruptedException exception) {
+                        exception.printStackTrace(this.writer);
+                    }
+                }
+                if ((this.frame == null) && (this.error != null)) {
+                    throw new Error("unexpected error", this.error);
+                }
+            }
+        }
+    }
+
+    private void invoke() {
+        try {
+            if (this.method != null) {
+                this.writer.println(this.method);
+                this.method.invoke(this.object);
+                this.method = null;
+            }
+            else {
+                this.writer.println(this.type);
+                this.frame = new JFrame(this.type.getSimpleName());
+                this.frame.setSize(WIDTH, HEIGHT);
+                this.frame.setLocationRelativeTo(null);
+                this.object = this.type.getConstructor(JFrame.class).newInstance(this.frame);
+                this.frame.setVisible(true);
+            }
+        }
+        catch (NoSuchMethodException exception) {
+            this.error = exception;
+        }
+        catch (SecurityException exception) {
+            this.error = exception;
+        }
+        catch (IllegalAccessException exception) {
+            this.error = exception;
+        }
+        catch (IllegalArgumentException exception) {
+            this.error = exception;
+        }
+        catch (InstantiationException exception) {
+            this.error = exception;
+        }
+        catch (InvocationTargetException exception) {
+            this.error = exception.getTargetException();
+        }
+    }
+}