Index: javax/swing/JScrollPane.java =================================================================== RCS file: /cvsroot/classpath/classpath/javax/swing/JScrollPane.java,v retrieving revision 1.27 diff -u -r1.27 JScrollPane.java --- javax/swing/JScrollPane.java 12 Sep 2005 20:59:15 -0000 1.27 +++ javax/swing/JScrollPane.java 23 Sep 2005 20:23:59 -0000 @@ -40,16 +40,12 @@ import java.awt.Component; import java.awt.ComponentOrientation; -import java.awt.Dimension; import java.awt.Insets; import java.awt.LayoutManager; -import java.awt.Point; import java.awt.Rectangle; import javax.accessibility.Accessible; import javax.swing.border.Border; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; import javax.swing.plaf.ScrollPaneUI; import javax.swing.plaf.UIResource; @@ -100,7 +96,6 @@ Border viewportBorder; boolean wheelScrollingEnabled; - ChangeListener scrollListener; public JViewport getColumnHeader() { @@ -331,18 +326,6 @@ firePropertyChange("horizontalScrollBar", old, h); sync(); - if (old != null) - { - BoundedRangeModel model = old.getModel(); - if (model != null) - model.removeChangeListener(scrollListener); - } - if (h != null) - { - BoundedRangeModel model = h.getModel(); - if (model != null) - model.addChangeListener(scrollListener); - } } public void setHorizontalScrollBarPolicy(int h) @@ -359,6 +342,7 @@ horizontalScrollBarPolicy = h; firePropertyChange("horizontalScrollBarPolicy", old, h); sync(); + revalidate(); } public void setLayout(LayoutManager l) @@ -403,19 +387,6 @@ addNonNull(v, JScrollPane.VERTICAL_SCROLLBAR); firePropertyChange("verticalScrollBar", old, v); sync(); - - if (old != null) - { - BoundedRangeModel model = old.getModel(); - if (model != null) - model.removeChangeListener(scrollListener); - } - if (v != null) - { - BoundedRangeModel model = v.getModel(); - if (model != null) - model.addChangeListener(scrollListener); - } } public void setVerticalScrollBarPolicy(int v) @@ -432,6 +403,7 @@ verticalScrollBarPolicy = v; firePropertyChange("verticalScrollBarPolicy", old, v); sync(); + revalidate(); } public void setWheelScrollingEnabled(boolean b) @@ -452,11 +424,7 @@ JViewport old = viewport; removeNonNull(old); - if (old != null) - old.removeChangeListener(scrollListener); viewport = v; - if (v != null) - v.addChangeListener(scrollListener); addNonNull(v, JScrollPane.VIEWPORT); revalidate(); repaint(); @@ -494,79 +462,6 @@ return true; } - ChangeListener createScrollListener() - { - return new ChangeListener() - { - - public void stateChanged(ChangeEvent event) - { - JScrollBar vsb = JScrollPane.this.getVerticalScrollBar(); - JScrollBar hsb = JScrollPane.this.getHorizontalScrollBar(); - JViewport vp = JScrollPane.this.getViewport(); - - if (vp != null && event.getSource() == vp) - { - // if the viewport changed, we should update the VSB / HSB - // models according to the new vertical and horizontal sizes - - Rectangle vr = vp.getViewRect(); - Dimension vs = vp.getViewSize(); - if (vsb != null - && (vsb.getMinimum() != 0 - || vsb.getMaximum() != vs.height - || vsb.getValue() != vr.y - || vsb.getVisibleAmount() != vr.height)) - vsb.setValues(vr.y, vr.height, 0, vs.height); - - if (hsb != null - && (hsb.getMinimum() != 0 - || hsb.getMaximum() != vs.width - || hsb.getValue() != vr.width - || hsb.getVisibleAmount() != vr.height)) - hsb.setValues(vr.x, vr.width, 0, vs.width); - } - else - { - // otherwise we got a change update from either the VSB or - // HSB model, and we need to update the viewport positions of - // both the main viewport and any row or column headers to - // match. - - int xpos = 0; - int ypos = 0; - - if (vsb != null) - ypos = vsb.getValue(); - - if (hsb != null) - xpos = hsb.getValue(); - - Point pt = new Point(xpos, ypos); - - if (vp != null - && vp.getViewPosition() != pt) - vp.setViewPosition(pt); - - pt.x = 0; - - if (rowHeader != null - && rowHeader.getViewPosition() != pt) - rowHeader.setViewPosition(pt); - - pt.x = xpos; - pt.y = 0; - - if (columnHeader != null - && columnHeader.getViewPosition() != pt) - columnHeader.setViewPosition(pt); - - } - } - }; - } - - /** * Creates a new JScrollPane without a view. The scrollbar * policy is set to address@hidden #VERTICAL_SCROLLBAR_AS_NEEDED} and @@ -627,7 +522,6 @@ */ public JScrollPane(Component view, int vsbPolicy, int hsbPolicy) { - scrollListener = createScrollListener(); setVerticalScrollBarPolicy(vsbPolicy); setVerticalScrollBar(createVerticalScrollBar()); setHorizontalScrollBarPolicy(hsbPolicy); @@ -635,7 +529,6 @@ viewport = createViewport(); if (view != null) getViewport().setView(view); - viewport.addChangeListener(scrollListener); add(viewport,0); setLayout(new ScrollPaneLayout()); setOpaque(false); Index: javax/swing/plaf/basic/BasicScrollPaneUI.java =================================================================== RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java,v retrieving revision 1.12 diff -u -r1.12 BasicScrollPaneUI.java --- javax/swing/plaf/basic/BasicScrollPaneUI.java 26 Jul 2005 14:16:43 -0000 1.12 +++ javax/swing/plaf/basic/BasicScrollPaneUI.java 23 Sep 2005 20:23:59 -0000 @@ -40,13 +40,22 @@ import java.awt.Dimension; import java.awt.Graphics; +import java.awt.Point; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import javax.swing.JComponent; +import javax.swing.JScrollBar; import javax.swing.JScrollPane; +import javax.swing.JViewport; import javax.swing.ScrollPaneConstants; import javax.swing.ScrollPaneLayout; import javax.swing.UIDefaults; import javax.swing.UIManager; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ScrollPaneUI; @@ -54,9 +63,195 @@ implements ScrollPaneConstants { + /** + * Listens for changes in the state of the horizontal scrollbar's model and + * updates the scrollpane accordingly. + * + * @author Roman Kennke (address@hidden) + */ + public class HSBChangeListener implements ChangeListener + { + + /** + * Receives notification when the state of the horizontal scrollbar + * model has changed. + * + * @param event the change event + */ + public void stateChanged(ChangeEvent event) + { + JScrollBar hsb = scrollpane.getHorizontalScrollBar(); + JViewport vp = scrollpane.getViewport(); + Point viewPosition = vp.getViewPosition(); + int xpos = hsb.getValue(); + + if (xpos != viewPosition.x) + { + viewPosition.x = xpos; + vp.setViewPosition(viewPosition); + } + + viewPosition.y = 0; + JViewport columnHeader = scrollpane.getColumnHeader(); + if (columnHeader != null + && !columnHeader.getViewPosition().equals(viewPosition)) + columnHeader.setViewPosition(viewPosition); + } + + } + + /** + * Listens for changes in the state of the vertical scrollbar's model and + * updates the scrollpane accordingly. + * + * @author Roman Kennke (address@hidden) + */ + public class VSBChangeListener implements ChangeListener + { + + /** + * Receives notification when the state of the vertical scrollbar + * model has changed. + * + * @param event the change event + */ + public void stateChanged(ChangeEvent event) + { + JScrollBar vsb = scrollpane.getVerticalScrollBar(); + JViewport vp = scrollpane.getViewport(); + Point viewPosition = vp.getViewPosition(); + int ypos = vsb.getValue(); + + if (ypos != viewPosition.x) + { + viewPosition.y = ypos; + vp.setViewPosition(viewPosition); + } + + viewPosition.x = 0; + JViewport rowHeader = scrollpane.getRowHeader(); + if (rowHeader != null + && !rowHeader.getViewPosition().equals(viewPosition)) + rowHeader.setViewPosition(viewPosition); + } + + } + + /** + * Listens for changes of the viewport's extent size and updates the + * scrollpane accordingly. + * + * @author Roman Kennke (address@hidden) + */ + public class ViewportChangeHandler implements ChangeListener + { + + /** + * Receives notification when the view's size, position or extent size + * changes. When the extents size has changed, this method calls + * address@hidden BasicScrollPaneUI#syncScrollPaneWithViewport()} to adjust the + * scrollbars extents as well. + * + * @param event the change event + */ + public void stateChanged(ChangeEvent event) + { + JViewport vp = scrollpane.getViewport(); + JScrollBar hsb = scrollpane.getHorizontalScrollBar(); + JScrollBar vsb = scrollpane.getVerticalScrollBar(); + Dimension extents = vp.getExtentSize(); + if (extents.width != hsb.getModel().getExtent() + || extents.height != vsb.getModel().getExtent()) + syncScrollPaneWithViewport(); + } + + } + + /** + * Listens for property changes on the scrollpane and update the view + * accordingly. + * + * @author Roman Kennke (address@hidden) + */ + public class PropertyChangeHandler implements PropertyChangeListener + { + + /** + * Receives notification when any of the scrollpane's bound property + * changes. This method calls the appropriate update method on the + * ScrollBarUI. + * + * @param e the property change event + * + * @see BasicScrollPaneUI#updateColumnHeader(PropertyChangeEvent) + * @see BasicScrollPaneUI#updateRowHeader(PropertyChangeEvent) + * @see BasicScrollPaneUI#updateScrollBarDisplayPolicy(PropertyChangeEvent) + * @see BasicScrollPaneUI#updateViewport(PropertyChangeEvent) + */ + public void propertyChange(PropertyChangeEvent e) + { + if (e.getPropertyName().equals("viewport")) + updateViewport(e); + else if (e.getPropertyName().equals("rowHeader")) + updateRowHeader(e); + else if (e.getPropertyName().equals("columnHeader")) + updateColumnHeader(e); + else if (e.getPropertyName().equals("horizontalScrollBarPolicy") + || e.getPropertyName().equals("verticalScrollBarPolicy")) + updateScrollBarDisplayPolicy(e); + } + + } + + /** + * Listens for mouse wheel events and update the scrollpane accordingly. + * + * @author Roman Kennke (address@hidden) + * + * @since 1.4 + */ + protected class MouseWheelHandler implements MouseWheelListener + { + + /** + * Receives notification whenever the mouse wheel is moved. + * + * @param event the mouse wheel event + */ + public void mouseWheelMoved(MouseWheelEvent event) + { + } + + } + /** The Scrollpane for which the UI is provided by this class. */ protected JScrollPane scrollpane; + /** + * The horizontal scrollbar listener. + */ + protected ChangeListener hsbChangeListener; + + /** + * The vertical scrollbar listener. + */ + protected ChangeListener vsbChangeListener; + + /** + * The viewport listener. + */ + protected ChangeListener viewportChangeListener; + + /** + * The scrollpane property change listener. + */ + protected PropertyChangeListener spPropertyChangeListener; + + /** + * The mousewheel listener for the scrollpane. + */ + MouseWheelListener mouseWheelListener; + public static ComponentUI createUI(final JComponent c) { return new BasicScrollPaneUI(); @@ -85,16 +280,103 @@ public void installUI(final JComponent c) { super.installUI(c); - this.installDefaults((JScrollPane)c); + installDefaults((JScrollPane) c); + installListeners((JScrollPane) c); + } + + /** + * Installs the listeners on the scrollbars, the viewport and the scrollpane. + * + * @param sp the scrollpane on which to install the listeners + */ + protected void installListeners(JScrollPane sp) + { + if (spPropertyChangeListener == null) + spPropertyChangeListener = createPropertyChangeListener(); + sp.addPropertyChangeListener(spPropertyChangeListener); + + if (hsbChangeListener == null) + hsbChangeListener = createHSBChangeListener(); + sp.getHorizontalScrollBar().getModel().addChangeListener(hsbChangeListener); + + if (vsbChangeListener == null) + vsbChangeListener = createVSBChangeListener(); + sp.getVerticalScrollBar().getModel().addChangeListener(vsbChangeListener); + + if (viewportChangeListener == null) + viewportChangeListener = createViewportChangeListener(); + sp.getViewport().addChangeListener(viewportChangeListener); + + if (mouseWheelListener == null) + mouseWheelListener = new MouseWheelHandler(); + sp.addMouseWheelListener(mouseWheelListener); + } + + /** + * Creates and returns the change listener for the horizontal scrollbar. + * + * @return the change listener for the horizontal scrollbar + */ + protected ChangeListener createHSBChangeListener() + { + return new HSBChangeListener(); + } + + /** + * Creates and returns the change listener for the vertical scrollbar. + * + * @return the change listener for the vertical scrollbar + */ + protected ChangeListener createVSBChangeListener() + { + return new VSBChangeListener(); + } + + /** + * Creates and returns the change listener for the viewport. + * + * @return the change listener for the viewport + */ + protected ChangeListener createViewportChangeListener() + { + return new ViewportChangeHandler(); + } + + /** + * Creates and returns the property change listener for the scrollpane. + * + * @return the property change listener for the scrollpane + */ + protected PropertyChangeListener createPropertyChangeListener() + { + return new PropertyChangeHandler(); } public void uninstallUI(final JComponent c) { super.uninstallUI(c); this.uninstallDefaults((JScrollPane)c); + uninstallListeners((JScrollPane) c); + } + + /** + * Uninstalls all the listeners that have been installed in + * address@hidden #installListeners(JScrollPane)}. + * + * @param c the scrollpane from which to uninstall the listeners + */ + protected void uninstallListeners(JComponent c) + { + JScrollPane sp = (JScrollPane) c; + sp.removePropertyChangeListener(spPropertyChangeListener); + sp.getHorizontalScrollBar().getModel() + .removeChangeListener(hsbChangeListener); + sp.getVerticalScrollBar().getModel() + .removeChangeListener(vsbChangeListener); + sp.getViewport().removeChangeListener(viewportChangeListener); + sp.removeMouseWheelListener(mouseWheelListener); } - public Dimension getMinimumSize(JComponent c) { JScrollPane p = (JScrollPane ) c; @@ -106,6 +388,68 @@ { // do nothing; the normal painting-of-children algorithm, along with // ScrollPaneLayout, does all the relevant work. + } + + /** + * Synchronizes the scrollbars with the viewport's extents. + */ + protected void syncScrollPaneWithViewport() + { + JViewport vp = scrollpane.getViewport(); + JScrollBar vsb = scrollpane.getVerticalScrollBar(); + JScrollBar hsb = scrollpane.getHorizontalScrollBar(); + hsb.getModel().setExtent(vp.getExtentSize().width); + vsb.getModel().setExtent(vp.getExtentSize().height); + } + + /** + * Receives notification when the columnHeader property has + * changed on the scrollpane. + * + * @param ev the property change event + */ + protected void updateColumnHeader(PropertyChangeEvent ev) + { + // TODO: Find out what should be done here. Or is this only a hook? + } + + /** + * Receives notification when the rowHeader property has changed + * on the scrollpane. + * + * @param ev the property change event + */ + protected void updateRowHeader(PropertyChangeEvent ev) + { + // TODO: Find out what should be done here. Or is this only a hook? + } + + /** + * Receives notification when the scrollBarDisplayPolicy + * property has changed on the scrollpane. + * + * @param ev the property change event + */ + protected void updateScrollBarDisplayPolicy(PropertyChangeEvent ev) + { + // TODO: Find out what should be done here. Or is this only a hook? + } + + /** + * Receives notification when the viewport property has changed + * on the scrollpane. + * + * This method sets removes the viewportChangeListener from the old viewport + * and adds it to the new viewport. + * + * @param ev the property change event + */ + protected void updateViewport(PropertyChangeEvent ev) + { + JViewport oldViewport = (JViewport) ev.getOldValue(); + oldViewport.removeChangeListener(viewportChangeListener); + JViewport newViewport = (JViewport) ev.getNewValue(); + oldViewport.addChangeListener(viewportChangeListener); } }