This fixes a couple more issues with scrolling:
- In JTree I found a thinko in the Scrollable implementation, sometimes
causing a 'round-trip' scrolling when scrolling down.
- Sometimes the JTree cause an NPE in JComponent.repaint() when it
passed a null Rectangle in there. However, the
JTree.TreeSelectionRedirector class shouldn't paint at all, it only
redirects selection events. JTrees are still painted correctly.

- I moved some code around in BasicScrollBarUI and BasicScrollPaneUI to
avoid duplication of scrolling code in the wheel scroller.
- Also I added a check to only allow wheel scrolling when the
appropriate property in JScrollPane is set.

/Roman

2006-10-18  Roman Kennke  <[EMAIL PROTECTED]>

        PR 28769
        * javax/swing/JScrollPane.java
        (viewportBorder): Made field private.
        (wheelScrollingEnabled): Made field private.
        (JScrollPane): Enabled wheel scrolling by default.
        * javax/swing/JTree.java
        (TreeSelectionRedirector.valueChanged): Don't repaint anything
        here.
        (getScrollableUnitIncrement): Fixed thinko.
        * javax/swing/plaf/basic/BasicScrollBarUI.java
        (static scrollByBlock): New static method to avoid code duplication
        for the BasicScrollPane wheel scrolling.
        (static scrollByUnits): New static method to avoid code duplication
        for the BasicScrollPane wheel scrolling.
        (scrollByBlock): Delegate to static helper method.
        (scrollByUnit): Delegate to static helper method.
        * javax/swing/plaf/basic/BasicScrollPaneUI.java
        (MouseWheelHandler.mouseWheelMoved): Delegate to BasicScrollBarUI
        static helper methods to avoid code duplication.
        (MouseWheelHandler.bounds): Removed.
        (MouseWheelHandler.getValue): Removed.
        (MouseWheelHandler.scroll): Removed.

Index: javax/swing/JScrollPane.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/JScrollPane.java,v
retrieving revision 1.32
diff -u -1 -5 -r1.32 JScrollPane.java
--- javax/swing/JScrollPane.java	1 Jun 2006 04:38:49 -0000	1.32
+++ javax/swing/JScrollPane.java	18 Oct 2006 18:45:23 -0000
@@ -149,33 +149,34 @@
   
   protected JViewport columnHeader;
   protected JViewport rowHeader;
 
   protected Component lowerLeft;
   protected Component lowerRight;
   protected Component upperLeft;
   protected Component upperRight;
 
   protected JScrollBar horizontalScrollBar;
   protected int horizontalScrollBarPolicy;
   protected JScrollBar verticalScrollBar;
   protected int verticalScrollBarPolicy;
 
   protected JViewport viewport;
-  
-  Border viewportBorder;
-  boolean wheelScrollingEnabled;
+
+  private Border viewportBorder;
+
+  private boolean wheelScrollingEnabled;
 
   public JViewport getColumnHeader()
   {
     return columnHeader;
   }
 
   public Component getCorner(String key) 
   {
     if (getComponentOrientation() 
         == ComponentOrientation.LEFT_TO_RIGHT)
       {
         if (key == LOWER_LEADING_CORNER)
           key = LOWER_LEFT_CORNER;
         else if (key == LOWER_TRAILING_CORNER)
           key = LOWER_RIGHT_CORNER;
@@ -583,30 +584,31 @@
    * <code>view</code> component; The scrollbar
    * policies are set to <code>vsbPolicy</code> and <code>hsbPolicy</code>.
    *
    * @param vsbPolicy the vertical scrollbar policy to set
    * @param hsbPolicy the vertical scrollbar policy to set
    *
    * @see ScrollPaneConstants#HORIZONTAL_SCROLLBAR_ALWAYS
    * @see ScrollPaneConstants#HORIZONTAL_SCROLLBAR_AS_NEEDED
    * @see ScrollPaneConstants#HORIZONTAL_SCROLLBAR_NEVER
    * @see ScrollPaneConstants#VERTICAL_SCROLLBAR_ALWAYS
    * @see ScrollPaneConstants#VERTICAL_SCROLLBAR_AS_NEEDED
    * @see ScrollPaneConstants#VERTICAL_SCROLLBAR_NEVER
    */
   public JScrollPane(Component view, int vsbPolicy, int hsbPolicy) 
   {
+    wheelScrollingEnabled = true;
     setVerticalScrollBarPolicy(vsbPolicy);
     setVerticalScrollBar(createVerticalScrollBar());
     setHorizontalScrollBarPolicy(hsbPolicy);
     setHorizontalScrollBar(createHorizontalScrollBar());
     viewport = createViewport();
     if (view != null)
       getViewport().setView(view);
     add(viewport,0);
     setLayout(new ScrollPaneLayout());
     setOpaque(false);
     updateUI();
   }
 
   
   public JScrollBar createHorizontalScrollBar()
Index: javax/swing/JTree.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/JTree.java,v
retrieving revision 1.76
diff -u -1 -5 -r1.76 JTree.java
--- javax/swing/JTree.java	8 Oct 2006 22:37:31 -0000	1.76
+++ javax/swing/JTree.java	18 Oct 2006 18:45:24 -0000
@@ -1267,37 +1267,30 @@
     protected TreeSelectionRedirector()
     {
       // Nothing to do here.
     }
 
     /**
      * Notifies when the tree selection changes.
      * 
      * @param ev the TreeSelectionEvent that describes the change
      */
     public void valueChanged(TreeSelectionEvent ev)
     {
       TreeSelectionEvent rewritten = 
         (TreeSelectionEvent) ev.cloneWithSource(JTree.this);
       fireValueChanged(rewritten);
-
-      // Only repaint the changed nodes.
-      TreePath[] changed = ev.getPaths();
-      for (int i = 0; i < changed.length; i++)
-        {
-          repaint(getPathBounds(changed[i]));
-        }
     }
   }
 
   /**
    * A TreeModel that does not allow anything to be selected.
    */
   protected static class EmptySelectionModel extends DefaultTreeSelectionModel
   {
     /** The serial version UID. */
     private static final long serialVersionUID = -5815023306225701477L;
 
     /**
      * The shared instance of this model.
      */
     protected static final EmptySelectionModel sharedInstance =
@@ -1686,31 +1679,31 @@
   {
     int delta = 0;
 
     // Round so that the top would start from the row boundary
     if (orientation == SwingConstants.VERTICAL)
       {
         int row = getClosestRowForLocation(0, visibleRect.y);
         if (row != -1)
           {
             Rectangle b = getRowBounds(row);
             if (b.y != visibleRect.y)
               {
                 if (direction < 0)
                   delta = Math.max(0, visibleRect.y - b.y);
                 else
-                  delta = b.y + b.height - visibleRect.height;
+                  delta = b.y + b.height - visibleRect.y;
               }
             else
               {
                 if (direction < 0)
                   {
                     if (row != 0)
                       {
                         b = getRowBounds(row - 1);
                         delta = b.height;
                       }
                   }
                 else
                   delta = b.height;
               }
           }
Index: javax/swing/plaf/basic/BasicScrollBarUI.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java,v
retrieving revision 1.39
diff -u -1 -5 -r1.39 BasicScrollBarUI.java
--- javax/swing/plaf/basic/BasicScrollBarUI.java	6 Sep 2006 16:37:30 -0000	1.39
+++ javax/swing/plaf/basic/BasicScrollBarUI.java	18 Oct 2006 18:45:25 -0000
@@ -1213,51 +1213,109 @@
    *
    * @param child The child to remove.
    */
   public void removeLayoutComponent(Component child)
   {
     // You should not be removing stuff from this component.
   }
 
   /**
    * The method scrolls the thumb by a block in the  direction specified.
    *
    * @param direction The direction to scroll.
    */
   protected void scrollByBlock(int direction)
   {
+    scrollByBlock(scrollbar, direction);
+  }
+
+  /**
+   * Scrolls the specified <code>scrollBar</code> by one block (according
+   * to the scrollable protocol) in the specified <code>direction</code>.
+   *
+   * This method is here statically to support wheel scrolling from the
+   * BasicScrollPaneUI without code duplication.
+   *
+   * @param scrollBar the scrollbar to scroll
+   * @param direction the scroll direction
+   */
+  static final void scrollByBlock(JScrollBar scrollBar, int direction)
+  {
+    int delta;
     if (direction > 0)
-    scrollbar.setValue(scrollbar.getValue()
-                       + scrollbar.getBlockIncrement(direction));
+      delta = scrollBar.getBlockIncrement(direction);
     else
-      scrollbar.setValue(scrollbar.getValue()
-                         - scrollbar.getBlockIncrement(direction));
+      delta = - scrollBar.getBlockIncrement(direction);
+    int oldValue = scrollBar.getValue();
+    int newValue = oldValue + delta;
+
+    // Overflow check.
+    if (delta > 0 && newValue < oldValue)
+      newValue = scrollBar.getMaximum();
+    else if (delta < 0 && newValue > oldValue)
+      newValue = scrollBar.getMinimum();
+
+    scrollBar.setValue(newValue);
   }
 
   /**
    * The method scrolls the thumb by a unit in the direction specified.
    *
    * @param direction The direction to scroll.
    */
   protected void scrollByUnit(int direction)
   {
-    if (direction > 0)
-      scrollbar.setValue(scrollbar.getValue()
-                         + scrollbar.getUnitIncrement(direction));
-    else
-      scrollbar.setValue(scrollbar.getValue()
-                         - scrollbar.getUnitIncrement(direction));
+    scrollByUnits(scrollbar, direction, 1);
+  }
+
+  /**
+   * Scrolls the specified <code>scrollbac/code> by <code>units</code> units
+   * in the specified <code>direction</code>.
+   *
+   * This method is here statically to support wheel scrolling from the
+   * BasicScrollPaneUI without code duplication.
+   *
+   * @param scrollBar the scrollbar to scroll
+   * @param direction the direction
+   * @param units the number of units to scroll
+   */
+  static final void scrollByUnits(JScrollBar scrollBar, int direction,
+                                   int units)
+  {
+    // Do this inside a loop so that we don't clash with the scrollable
+    // interface, which can return different units at times. For instance,
+    // a Scrollable could return a unit of 2 pixels only to adjust the
+    // visibility of an item. If we would simply multiply this by units,
+    // then we would only get 6 pixels, which is complete crap.
+    for (int i = 0; i < units; i++)
+      {
+        int delta;
+        if (direction > 0)
+          delta = scrollBar.getUnitIncrement(direction);
+        else
+          delta = - scrollBar.getUnitIncrement(direction);
+        int oldValue = scrollBar.getValue();
+        int newValue = oldValue + delta;
+
+        // Overflow check.
+        if (delta > 0 && newValue < oldValue)
+          newValue = scrollBar.getMaximum();
+        else if (delta < 0 && newValue > oldValue)
+          newValue = scrollBar.getMinimum();
+
+        scrollBar.setValue(newValue);
+      }
   }
 
   /**
    * This method sets the thumb's bounds.
    *
    * @param x The X position of the thumb.
    * @param y The Y position of the thumb.
    * @param width The width of the thumb.
    * @param height The height of the thumb.
    */
   protected void setThumbBounds(int x, int y, int width, int height)
   {
     thumbRect.x = x;
     thumbRect.y = y;
     thumbRect.width = width;
Index: javax/swing/plaf/basic/BasicScrollPaneUI.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java,v
retrieving revision 1.32
diff -u -1 -5 -r1.32 BasicScrollPaneUI.java
--- javax/swing/plaf/basic/BasicScrollPaneUI.java	21 Sep 2006 10:04:27 -0000	1.32
+++ javax/swing/plaf/basic/BasicScrollPaneUI.java	18 Oct 2006 18:45:25 -0000
@@ -26,56 +26,53 @@
 As a special exception, the copyright holders of this library give you
 permission to link this library with independent modules to produce an
 executable, regardless of the license terms of these independent
 modules, and to copy and distribute the resulting executable under
 terms of your choice, provided that you also meet, for each linked
 independent module, the terms and conditions of the license of that
 module.  An independent module is a module which is not derived from
 or based on this library.  If you modify this library, you may extend
 this exception to your version of the library, but you are not
 obligated to do so.  If you do not wish to do so, delete this
 exception statement from your version. */
 
 
 package javax.swing.plaf.basic;
 
-import java.awt.Component;
 import java.awt.Dimension;
 import java.awt.Graphics;
 import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.event.ActionEvent;
 import java.awt.event.ContainerEvent;
 import java.awt.event.ContainerListener;
 import java.awt.event.MouseWheelEvent;
 import java.awt.event.MouseWheelListener;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 
 import javax.swing.AbstractAction;
 import javax.swing.ActionMap;
 import javax.swing.InputMap;
 import javax.swing.JComponent;
 import javax.swing.JScrollBar;
 import javax.swing.JScrollPane;
 import javax.swing.JSlider;
 import javax.swing.JViewport;
 import javax.swing.LookAndFeel;
 import javax.swing.ScrollPaneConstants;
 import javax.swing.ScrollPaneLayout;
-import javax.swing.Scrollable;
-import javax.swing.SwingConstants;
 import javax.swing.SwingUtilities;
 import javax.swing.UIManager;
 import javax.swing.border.Border;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 import javax.swing.plaf.ActionMapUIResource;
 import javax.swing.plaf.ComponentUI;
 import javax.swing.plaf.ScrollPaneUI;
 import javax.swing.plaf.UIResource;
 
 /**
  * A UI delegate for the [EMAIL PROTECTED] JScrollPane} component.
  */
 public class BasicScrollPaneUI extends ScrollPaneUI
   implements ScrollPaneConstants
@@ -217,126 +214,47 @@
    */
   protected class MouseWheelHandler implements MouseWheelListener
   {
     /**
      * Use to compute the visible rectangle.
      */
     final Rectangle rect = new Rectangle();
 
     /**
      * Scroll with the mouse wheel.
      * 
      * @author Audrius Meskauskas ([EMAIL PROTECTED])
      */
     public void mouseWheelMoved(MouseWheelEvent e)
     {
-      if (scrollpane.getViewport().getComponentCount() == 0)
-        return;
-
-      Component target = scrollpane.getViewport().getComponent(0);
-      JScrollBar bar = scrollpane.getVerticalScrollBar();
-      Scrollable scrollable = (target instanceof Scrollable) ? (Scrollable) target
-                                                            : null;
-
-      boolean tracksHeight = scrollable != null
-                             && scrollable.getScrollableTracksViewportHeight();
-      int wheel = e.getWheelRotation() * ROWS_PER_WHEEL_CLICK;
-      int delta;
-
-      // If possible, scroll vertically.
-      if (bar != null && ! tracksHeight)
+      if (scrollpane.isWheelScrollingEnabled() && e.getScrollAmount() != 0)
         {
-          if (scrollable != null)
-            {
-              bounds(target);
-              delta = scrollable.getScrollableUnitIncrement(
-                rect, SwingConstants.VERTICAL, wheel);
-            }
-          else
+          // Try to scroll vertically first.
+          JScrollBar scrollBar = scrollpane.getVerticalScrollBar();
+          if (scrollBar == null || ! scrollBar.isVisible())
+            scrollBar = scrollpane.getHorizontalScrollBar();
+          if (scrollBar != null && scrollBar.isVisible())
             {
-              // Scroll non scrollables.
-              delta = wheel * SCROLL_NON_SCROLLABLES;
+              int direction = e.getWheelRotation() < 0 ? -1 : 1;
+              int scrollType = e.getScrollType();
+              if (scrollType == MouseWheelEvent.WHEEL_UNIT_SCROLL)
+                BasicScrollBarUI.scrollByUnits(scrollBar, direction,
+                                               e.getScrollAmount());
+              else if (scrollType == MouseWheelEvent.WHEEL_BLOCK_SCROLL)
+                BasicScrollBarUI.scrollByBlock(scrollBar, direction);
             }
-          scroll(bar, wheel > 0 ? delta : -delta);
         }
-      // If not, try to scroll horizontally
-      else
-        {
-          bar = scrollpane.getHorizontalScrollBar();
-          boolean tracksWidth = scrollable != null
-                                && scrollable.getScrollableTracksViewportWidth();
-
-          if (bar != null && ! tracksWidth)
-            {
-              if (scrollable != null)
-                {
-                  bounds(target);
-                  delta = scrollable.getScrollableUnitIncrement(
-                     rect, SwingConstants.HORIZONTAL, wheel);
-                }
-              else
-                {
-                  // Scroll non scrollables.
-                  delta = wheel * SCROLL_NON_SCROLLABLES;
-                }
-              scroll(bar, delta);
-            }
-        }
-    }
-    
-    /**
-     * Place the component bounds into rect. The x and y values 
-     * need to be reversed.
-     * 
-     * @param target the target being scrolled
-     */
-    final void bounds(Component target)
-    {
-      // Viewport bounds, translated by the scroll bar positions.
-      target.getParent().getBounds(rect);
-      rect.x = getValue(scrollpane.getHorizontalScrollBar());
-      rect.y = getValue(scrollpane.getVerticalScrollBar());
-    }
-    
-    /**
-     * Get the scroll bar value or 0 if there is no such scroll bar.
-     * 
-     * @param bar  the scroll bar (<code>null</code> permitted).
-     * 
-     * @return The scroll bar value, or 0.
-     */
-    final int getValue(JScrollBar bar)
-    {
-      return bar != null ? bar.getValue() : 0;
-    }
-    
-    /**
-     * Scroll the given distance.
-     * 
-     * @param bar the scrollbar to scroll
-     * @param delta the distance
-     */
-    final void scroll(JScrollBar bar, int delta)
-    {
-      int y = bar.getValue() + delta;
-
-      if (y < bar.getMinimum())
-        y = bar.getMinimum();
-      if (y > bar.getMaximum())
-        y = bar.getMaximum();
-
-      bar.setValue(y);
     }
   }
   
   /**
    * Adds/removes the mouse wheel listener when the component is added/removed
    * to/from the scroll pane view port.
    * 
    * @author Audrius Meskauskas ([EMAIL PROTECTED])
    */
   class ViewportContainerListener implements ContainerListener
   {
     /**
      * Add the mouse wheel listener, allowing to scroll with the mouse.
      */
     public void componentAdded(ContainerEvent e)

Reply via email to