|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package javax.swing.plaf.basic; |
|
|
|
import sun.swing.DefaultLookup; |
|
import sun.swing.UIAction; |
|
|
|
import javax.swing.*; |
|
import javax.swing.event.*; |
|
import javax.swing.border.*; |
|
import javax.swing.plaf.*; |
|
|
|
import java.beans.PropertyChangeListener; |
|
import java.beans.PropertyChangeEvent; |
|
|
|
import java.awt.Component; |
|
import java.awt.Rectangle; |
|
import java.awt.Dimension; |
|
import java.awt.Point; |
|
import java.awt.Insets; |
|
import java.awt.Graphics; |
|
import java.awt.event.*; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class BasicScrollPaneUI |
|
extends ScrollPaneUI implements ScrollPaneConstants |
|
{ |
|
protected JScrollPane scrollpane; |
|
protected ChangeListener vsbChangeListener; |
|
protected ChangeListener hsbChangeListener; |
|
protected ChangeListener viewportChangeListener; |
|
protected PropertyChangeListener spPropertyChangeListener; |
|
private MouseWheelListener mouseScrollListener; |
|
private int oldExtent = Integer.MIN_VALUE; |
|
|
|
|
|
|
|
*/ |
|
private PropertyChangeListener vsbPropertyChangeListener; |
|
|
|
|
|
|
|
*/ |
|
private PropertyChangeListener hsbPropertyChangeListener; |
|
|
|
private Handler handler; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private boolean setValueCalled = false; |
|
|
|
|
|
public static ComponentUI createUI(JComponent x) { |
|
return new BasicScrollPaneUI(); |
|
} |
|
|
|
static void loadActionMap(LazyActionMap map) { |
|
map.put(new Actions(Actions.SCROLL_UP)); |
|
map.put(new Actions(Actions.SCROLL_DOWN)); |
|
map.put(new Actions(Actions.SCROLL_HOME)); |
|
map.put(new Actions(Actions.SCROLL_END)); |
|
map.put(new Actions(Actions.UNIT_SCROLL_UP)); |
|
map.put(new Actions(Actions.UNIT_SCROLL_DOWN)); |
|
map.put(new Actions(Actions.SCROLL_LEFT)); |
|
map.put(new Actions(Actions.SCROLL_RIGHT)); |
|
map.put(new Actions(Actions.UNIT_SCROLL_RIGHT)); |
|
map.put(new Actions(Actions.UNIT_SCROLL_LEFT)); |
|
} |
|
|
|
|
|
|
|
public void paint(Graphics g, JComponent c) { |
|
Border vpBorder = scrollpane.getViewportBorder(); |
|
if (vpBorder != null) { |
|
Rectangle r = scrollpane.getViewportBorderBounds(); |
|
vpBorder.paintBorder(scrollpane, g, r.x, r.y, r.width, r.height); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public Dimension getMaximumSize(JComponent c) { |
|
return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE); |
|
} |
|
|
|
|
|
protected void installDefaults(JScrollPane scrollpane) |
|
{ |
|
LookAndFeel.installBorder(scrollpane, "ScrollPane.border"); |
|
LookAndFeel.installColorsAndFont(scrollpane, |
|
"ScrollPane.background", |
|
"ScrollPane.foreground", |
|
"ScrollPane.font"); |
|
|
|
Border vpBorder = scrollpane.getViewportBorder(); |
|
if ((vpBorder == null) ||( vpBorder instanceof UIResource)) { |
|
vpBorder = UIManager.getBorder("ScrollPane.viewportBorder"); |
|
scrollpane.setViewportBorder(vpBorder); |
|
} |
|
LookAndFeel.installProperty(scrollpane, "opaque", Boolean.TRUE); |
|
} |
|
|
|
|
|
protected void installListeners(JScrollPane c) |
|
{ |
|
vsbChangeListener = createVSBChangeListener(); |
|
vsbPropertyChangeListener = createVSBPropertyChangeListener(); |
|
hsbChangeListener = createHSBChangeListener(); |
|
hsbPropertyChangeListener = createHSBPropertyChangeListener(); |
|
viewportChangeListener = createViewportChangeListener(); |
|
spPropertyChangeListener = createPropertyChangeListener(); |
|
|
|
JViewport viewport = scrollpane.getViewport(); |
|
JScrollBar vsb = scrollpane.getVerticalScrollBar(); |
|
JScrollBar hsb = scrollpane.getHorizontalScrollBar(); |
|
|
|
if (viewport != null) { |
|
viewport.addChangeListener(viewportChangeListener); |
|
} |
|
if (vsb != null) { |
|
vsb.getModel().addChangeListener(vsbChangeListener); |
|
vsb.addPropertyChangeListener(vsbPropertyChangeListener); |
|
} |
|
if (hsb != null) { |
|
hsb.getModel().addChangeListener(hsbChangeListener); |
|
hsb.addPropertyChangeListener(hsbPropertyChangeListener); |
|
} |
|
|
|
scrollpane.addPropertyChangeListener(spPropertyChangeListener); |
|
|
|
mouseScrollListener = createMouseWheelListener(); |
|
scrollpane.addMouseWheelListener(mouseScrollListener); |
|
|
|
} |
|
|
|
protected void installKeyboardActions(JScrollPane c) { |
|
InputMap inputMap = getInputMap(JComponent. |
|
WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); |
|
|
|
SwingUtilities.replaceUIInputMap(c, JComponent. |
|
WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap); |
|
|
|
LazyActionMap.installLazyActionMap(c, BasicScrollPaneUI.class, |
|
"ScrollPane.actionMap"); |
|
} |
|
|
|
InputMap getInputMap(int condition) { |
|
if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) { |
|
InputMap keyMap = (InputMap)DefaultLookup.get(scrollpane, this, |
|
"ScrollPane.ancestorInputMap"); |
|
InputMap rtlKeyMap; |
|
|
|
if (scrollpane.getComponentOrientation().isLeftToRight() || |
|
((rtlKeyMap = (InputMap)DefaultLookup.get(scrollpane, this, |
|
"ScrollPane.ancestorInputMap.RightToLeft")) == null)) { |
|
return keyMap; |
|
} else { |
|
rtlKeyMap.setParent(keyMap); |
|
return rtlKeyMap; |
|
} |
|
} |
|
return null; |
|
} |
|
|
|
public void installUI(JComponent x) { |
|
scrollpane = (JScrollPane)x; |
|
installDefaults(scrollpane); |
|
installListeners(scrollpane); |
|
installKeyboardActions(scrollpane); |
|
} |
|
|
|
|
|
protected void uninstallDefaults(JScrollPane c) { |
|
LookAndFeel.uninstallBorder(scrollpane); |
|
|
|
if (scrollpane.getViewportBorder() instanceof UIResource) { |
|
scrollpane.setViewportBorder(null); |
|
} |
|
} |
|
|
|
|
|
protected void uninstallListeners(JComponent c) { |
|
JViewport viewport = scrollpane.getViewport(); |
|
JScrollBar vsb = scrollpane.getVerticalScrollBar(); |
|
JScrollBar hsb = scrollpane.getHorizontalScrollBar(); |
|
|
|
if (viewport != null) { |
|
viewport.removeChangeListener(viewportChangeListener); |
|
} |
|
if (vsb != null) { |
|
vsb.getModel().removeChangeListener(vsbChangeListener); |
|
vsb.removePropertyChangeListener(vsbPropertyChangeListener); |
|
} |
|
if (hsb != null) { |
|
hsb.getModel().removeChangeListener(hsbChangeListener); |
|
hsb.removePropertyChangeListener(hsbPropertyChangeListener); |
|
} |
|
|
|
scrollpane.removePropertyChangeListener(spPropertyChangeListener); |
|
|
|
if (mouseScrollListener != null) { |
|
scrollpane.removeMouseWheelListener(mouseScrollListener); |
|
} |
|
|
|
vsbChangeListener = null; |
|
hsbChangeListener = null; |
|
viewportChangeListener = null; |
|
spPropertyChangeListener = null; |
|
mouseScrollListener = null; |
|
handler = null; |
|
} |
|
|
|
|
|
protected void uninstallKeyboardActions(JScrollPane c) { |
|
SwingUtilities.replaceUIActionMap(c, null); |
|
SwingUtilities.replaceUIInputMap(c, JComponent. |
|
WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null); |
|
} |
|
|
|
|
|
public void uninstallUI(JComponent c) { |
|
uninstallDefaults(scrollpane); |
|
uninstallListeners(scrollpane); |
|
uninstallKeyboardActions(scrollpane); |
|
scrollpane = null; |
|
} |
|
|
|
private Handler getHandler() { |
|
if (handler == null) { |
|
handler = new Handler(); |
|
} |
|
return handler; |
|
} |
|
|
|
protected void syncScrollPaneWithViewport() |
|
{ |
|
JViewport viewport = scrollpane.getViewport(); |
|
JScrollBar vsb = scrollpane.getVerticalScrollBar(); |
|
JScrollBar hsb = scrollpane.getHorizontalScrollBar(); |
|
JViewport rowHead = scrollpane.getRowHeader(); |
|
JViewport colHead = scrollpane.getColumnHeader(); |
|
boolean ltr = scrollpane.getComponentOrientation().isLeftToRight(); |
|
|
|
if (viewport != null) { |
|
Dimension extentSize = viewport.getExtentSize(); |
|
Dimension viewSize = viewport.getViewSize(); |
|
Point viewPosition = viewport.getViewPosition(); |
|
|
|
if (vsb != null) { |
|
int extent = extentSize.height; |
|
int max = viewSize.height; |
|
int value = Math.max(0, Math.min(viewPosition.y, max - extent)); |
|
vsb.setValues(value, extent, 0, max); |
|
} |
|
|
|
if (hsb != null) { |
|
int extent = extentSize.width; |
|
int max = viewSize.width; |
|
int value; |
|
|
|
if (ltr) { |
|
value = Math.max(0, Math.min(viewPosition.x, max - extent)); |
|
} else { |
|
int currentValue = hsb.getValue(); |
|
|
|
|
|
|
|
*/ |
|
if (setValueCalled && ((max - currentValue) == viewPosition.x)) { |
|
value = Math.max(0, Math.min(max - extent, currentValue)); |
|
|
|
*/ |
|
if (extent != 0) { |
|
setValueCalled = false; |
|
} |
|
} else { |
|
if (extent > max) { |
|
viewPosition.x = max - extent; |
|
viewport.setViewPosition(viewPosition); |
|
value = 0; |
|
} else { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
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); |
|
} |
|
|
|
if (rowHead != null) { |
|
Point p = rowHead.getViewPosition(); |
|
p.y = viewport.getViewPosition().y; |
|
p.x = 0; |
|
rowHead.setViewPosition(p); |
|
} |
|
|
|
if (colHead != null) { |
|
Point p = colHead.getViewPosition(); |
|
if (ltr) { |
|
p.x = viewport.getViewPosition().x; |
|
} else { |
|
p.x = Math.max(0, viewport.getViewPosition().x); |
|
} |
|
p.y = 0; |
|
colHead.setViewPosition(p); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public int getBaseline(JComponent c, int width, int height) { |
|
if (c == null) { |
|
throw new NullPointerException("Component must be non-null"); |
|
} |
|
|
|
if (width < 0 || height < 0) { |
|
throw new IllegalArgumentException("Width and height must be >= 0"); |
|
} |
|
|
|
JViewport viewport = scrollpane.getViewport(); |
|
Insets spInsets = scrollpane.getInsets(); |
|
int y = spInsets.top; |
|
height = height - spInsets.top - spInsets.bottom; |
|
width = width - spInsets.left - spInsets.right; |
|
JViewport columnHeader = scrollpane.getColumnHeader(); |
|
if (columnHeader != null && columnHeader.isVisible()) { |
|
Component header = columnHeader.getView(); |
|
if (header != null && header.isVisible()) { |
|
|
|
Dimension headerPref = header.getPreferredSize(); |
|
int baseline = header.getBaseline(headerPref.width, |
|
headerPref.height); |
|
if (baseline >= 0) { |
|
return y + baseline; |
|
} |
|
} |
|
Dimension columnPref = columnHeader.getPreferredSize(); |
|
height -= columnPref.height; |
|
y += columnPref.height; |
|
} |
|
Component view = (viewport == null) ? null : viewport.getView(); |
|
if (view != null && view.isVisible() && |
|
view.getBaselineResizeBehavior() == |
|
Component.BaselineResizeBehavior.CONSTANT_ASCENT) { |
|
Border viewportBorder = scrollpane.getViewportBorder(); |
|
if (viewportBorder != null) { |
|
Insets vpbInsets = viewportBorder.getBorderInsets(scrollpane); |
|
y += vpbInsets.top; |
|
height = height - vpbInsets.top - vpbInsets.bottom; |
|
width = width - vpbInsets.left - vpbInsets.right; |
|
} |
|
if (view.getWidth() > 0 && view.getHeight() > 0) { |
|
Dimension min = view.getMinimumSize(); |
|
width = Math.max(min.width, view.getWidth()); |
|
height = Math.max(min.height, view.getHeight()); |
|
} |
|
if (width > 0 && height > 0) { |
|
int baseline = view.getBaseline(width, height); |
|
if (baseline > 0) { |
|
return y + baseline; |
|
} |
|
} |
|
} |
|
return -1; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public Component.BaselineResizeBehavior getBaselineResizeBehavior( |
|
JComponent c) { |
|
super.getBaselineResizeBehavior(c); |
|
// Baseline is either from the header, in which case it's always |
|
// the same size and therefor can be created as CONSTANT_ASCENT. |
|
// If the header doesn't have a baseline than the baseline will only |
|
// be valid if it's BaselineResizeBehavior is |
|
|
|
return Component.BaselineResizeBehavior.CONSTANT_ASCENT; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public class ViewportChangeHandler implements ChangeListener |
|
{ |
|
|
|
// NOTE: This class exists only for backward compatibility. All |
|
// its functionality has been moved into Handler. If you need to add |
|
// new functionality add it to the Handler, but make sure this |
|
// class calls into the Handler. |
|
|
|
public void stateChanged(ChangeEvent e) { |
|
getHandler().stateChanged(e); |
|
} |
|
} |
|
|
|
protected ChangeListener createViewportChangeListener() { |
|
return getHandler(); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public class HSBChangeListener implements ChangeListener |
|
{ |
|
|
|
// NOTE: This class exists only for backward compatibility. All |
|
// its functionality has been moved into Handler. If you need to add |
|
// new functionality add it to the Handler, but make sure this |
|
// class calls into the Handler. |
|
|
|
public void stateChanged(ChangeEvent e) |
|
{ |
|
getHandler().stateChanged(e); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private PropertyChangeListener createHSBPropertyChangeListener() { |
|
return getHandler(); |
|
} |
|
|
|
protected ChangeListener createHSBChangeListener() { |
|
return getHandler(); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public class VSBChangeListener implements ChangeListener |
|
{ |
|
|
|
// NOTE: This class exists only for backward compatibility. All |
|
// its functionality has been moved into Handler. If you need to add |
|
// new functionality add it to the Handler, but make sure this |
|
// class calls into the Handler. |
|
|
|
public void stateChanged(ChangeEvent e) |
|
{ |
|
getHandler().stateChanged(e); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private PropertyChangeListener createVSBPropertyChangeListener() { |
|
return getHandler(); |
|
} |
|
|
|
protected ChangeListener createVSBChangeListener() { |
|
return getHandler(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected class MouseWheelHandler implements MouseWheelListener { |
|
|
|
// NOTE: This class exists only for backward compatibility. All |
|
// its functionality has been moved into Handler. If you need to add |
|
// new functionality add it to the Handler, but make sure this |
|
// class calls into the Handler. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void mouseWheelMoved(MouseWheelEvent e) { |
|
getHandler().mouseWheelMoved(e); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected MouseWheelListener createMouseWheelListener() { |
|
return getHandler(); |
|
} |
|
|
|
protected void updateScrollBarDisplayPolicy(PropertyChangeEvent e) { |
|
scrollpane.revalidate(); |
|
scrollpane.repaint(); |
|
} |
|
|
|
|
|
protected void updateViewport(PropertyChangeEvent e) |
|
{ |
|
JViewport oldViewport = (JViewport)(e.getOldValue()); |
|
JViewport newViewport = (JViewport)(e.getNewValue()); |
|
|
|
if (oldViewport != null) { |
|
oldViewport.removeChangeListener(viewportChangeListener); |
|
} |
|
|
|
if (newViewport != null) { |
|
Point p = newViewport.getViewPosition(); |
|
if (scrollpane.getComponentOrientation().isLeftToRight()) { |
|
p.x = Math.max(p.x, 0); |
|
} else { |
|
int max = newViewport.getViewSize().width; |
|
int extent = newViewport.getExtentSize().width; |
|
if (extent > max) { |
|
p.x = max - extent; |
|
} else { |
|
p.x = Math.max(0, Math.min(max - extent, p.x)); |
|
} |
|
} |
|
p.y = Math.max(p.y, 0); |
|
newViewport.setViewPosition(p); |
|
newViewport.addChangeListener(viewportChangeListener); |
|
} |
|
} |
|
|
|
|
|
protected void updateRowHeader(PropertyChangeEvent e) |
|
{ |
|
JViewport newRowHead = (JViewport)(e.getNewValue()); |
|
if (newRowHead != null) { |
|
JViewport viewport = scrollpane.getViewport(); |
|
Point p = newRowHead.getViewPosition(); |
|
p.y = (viewport != null) ? viewport.getViewPosition().y : 0; |
|
newRowHead.setViewPosition(p); |
|
} |
|
} |
|
|
|
|
|
protected void updateColumnHeader(PropertyChangeEvent e) |
|
{ |
|
JViewport newColHead = (JViewport)(e.getNewValue()); |
|
if (newColHead != null) { |
|
JViewport viewport = scrollpane.getViewport(); |
|
Point p = newColHead.getViewPosition(); |
|
if (viewport == null) { |
|
p.x = 0; |
|
} else { |
|
if (scrollpane.getComponentOrientation().isLeftToRight()) { |
|
p.x = viewport.getViewPosition().x; |
|
} else { |
|
p.x = Math.max(0, viewport.getViewPosition().x); |
|
} |
|
} |
|
newColHead.setViewPosition(p); |
|
scrollpane.add(newColHead, COLUMN_HEADER); |
|
} |
|
} |
|
|
|
private void updateHorizontalScrollBar(PropertyChangeEvent pce) { |
|
updateScrollBar(pce, hsbChangeListener, hsbPropertyChangeListener); |
|
} |
|
|
|
private void updateVerticalScrollBar(PropertyChangeEvent pce) { |
|
updateScrollBar(pce, vsbChangeListener, vsbPropertyChangeListener); |
|
} |
|
|
|
private void updateScrollBar(PropertyChangeEvent pce, ChangeListener cl, |
|
PropertyChangeListener pcl) { |
|
JScrollBar sb = (JScrollBar)pce.getOldValue(); |
|
if (sb != null) { |
|
if (cl != null) { |
|
sb.getModel().removeChangeListener(cl); |
|
} |
|
if (pcl != null) { |
|
sb.removePropertyChangeListener(pcl); |
|
} |
|
} |
|
sb = (JScrollBar)pce.getNewValue(); |
|
if (sb != null) { |
|
if (cl != null) { |
|
sb.getModel().addChangeListener(cl); |
|
} |
|
if (pcl != null) { |
|
sb.addPropertyChangeListener(pcl); |
|
} |
|
} |
|
} |
|
|
|
public class PropertyChangeHandler implements PropertyChangeListener |
|
{ |
|
|
|
// NOTE: This class exists only for backward compatibility. All |
|
// its functionality has been moved into Handler. If you need to add |
|
// new functionality add it to the Handler, but make sure this |
|
// class calls into the Handler. |
|
|
|
public void propertyChange(PropertyChangeEvent e) |
|
{ |
|
getHandler().propertyChange(e); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected PropertyChangeListener createPropertyChangeListener() { |
|
return getHandler(); |
|
} |
|
|
|
|
|
private static class Actions extends UIAction { |
|
private static final String SCROLL_UP = "scrollUp"; |
|
private static final String SCROLL_DOWN = "scrollDown"; |
|
private static final String SCROLL_HOME = "scrollHome"; |
|
private static final String SCROLL_END = "scrollEnd"; |
|
private static final String UNIT_SCROLL_UP = "unitScrollUp"; |
|
private static final String UNIT_SCROLL_DOWN = "unitScrollDown"; |
|
private static final String SCROLL_LEFT = "scrollLeft"; |
|
private static final String SCROLL_RIGHT = "scrollRight"; |
|
private static final String UNIT_SCROLL_LEFT = "unitScrollLeft"; |
|
private static final String UNIT_SCROLL_RIGHT = "unitScrollRight"; |
|
|
|
|
|
Actions(String key) { |
|
super(key); |
|
} |
|
|
|
public void actionPerformed(ActionEvent e) { |
|
JScrollPane scrollPane = (JScrollPane)e.getSource(); |
|
boolean ltr = scrollPane.getComponentOrientation().isLeftToRight(); |
|
String key = getName(); |
|
|
|
if (key == SCROLL_UP) { |
|
scroll(scrollPane, SwingConstants.VERTICAL, -1, true); |
|
} |
|
else if (key == SCROLL_DOWN) { |
|
scroll(scrollPane, SwingConstants.VERTICAL, 1, true); |
|
} |
|
else if (key == SCROLL_HOME) { |
|
scrollHome(scrollPane); |
|
} |
|
else if (key == SCROLL_END) { |
|
scrollEnd(scrollPane); |
|
} |
|
else if (key == UNIT_SCROLL_UP) { |
|
scroll(scrollPane, SwingConstants.VERTICAL, -1, false); |
|
} |
|
else if (key == UNIT_SCROLL_DOWN) { |
|
scroll(scrollPane, SwingConstants.VERTICAL, 1, false); |
|
} |
|
else if (key == SCROLL_LEFT) { |
|
scroll(scrollPane, SwingConstants.HORIZONTAL, ltr ? -1 : 1, |
|
true); |
|
} |
|
else if (key == SCROLL_RIGHT) { |
|
scroll(scrollPane, SwingConstants.HORIZONTAL, ltr ? 1 : -1, |
|
true); |
|
} |
|
else if (key == UNIT_SCROLL_LEFT) { |
|
scroll(scrollPane, SwingConstants.HORIZONTAL, ltr ? -1 : 1, |
|
false); |
|
} |
|
else if (key == UNIT_SCROLL_RIGHT) { |
|
scroll(scrollPane, SwingConstants.HORIZONTAL, ltr ? 1 : -1, |
|
false); |
|
} |
|
} |
|
|
|
private void scrollEnd(JScrollPane scrollpane) { |
|
JViewport vp = scrollpane.getViewport(); |
|
Component view; |
|
if (vp != null && (view = vp.getView()) != null) { |
|
Rectangle visRect = vp.getViewRect(); |
|
Rectangle bounds = view.getBounds(); |
|
if (scrollpane.getComponentOrientation().isLeftToRight()) { |
|
vp.setViewPosition(new Point(bounds.width - visRect.width, |
|
bounds.height - visRect.height)); |
|
} else { |
|
vp.setViewPosition(new Point(0, |
|
bounds.height - visRect.height)); |
|
} |
|
} |
|
} |
|
|
|
private void scrollHome(JScrollPane scrollpane) { |
|
JViewport vp = scrollpane.getViewport(); |
|
Component view; |
|
if (vp != null && (view = vp.getView()) != null) { |
|
if (scrollpane.getComponentOrientation().isLeftToRight()) { |
|
vp.setViewPosition(new Point(0, 0)); |
|
} else { |
|
Rectangle visRect = vp.getViewRect(); |
|
Rectangle bounds = view.getBounds(); |
|
vp.setViewPosition(new Point(bounds.width - visRect.width, 0)); |
|
} |
|
} |
|
} |
|
|
|
private void scroll(JScrollPane scrollpane, int orientation, |
|
int direction, boolean block) { |
|
JViewport vp = scrollpane.getViewport(); |
|
Component view; |
|
if (vp != null && (view = vp.getView()) != null) { |
|
Rectangle visRect = vp.getViewRect(); |
|
Dimension vSize = view.getSize(); |
|
int amount; |
|
|
|
if (view instanceof Scrollable) { |
|
if (block) { |
|
amount = ((Scrollable)view).getScrollableBlockIncrement |
|
(visRect, orientation, direction); |
|
} |
|
else { |
|
amount = ((Scrollable)view).getScrollableUnitIncrement |
|
(visRect, orientation, direction); |
|
} |
|
} |
|
else { |
|
if (block) { |
|
if (orientation == SwingConstants.VERTICAL) { |
|
amount = visRect.height; |
|
} |
|
else { |
|
amount = visRect.width; |
|
} |
|
} |
|
else { |
|
amount = 10; |
|
} |
|
} |
|
if (orientation == SwingConstants.VERTICAL) { |
|
visRect.y += (amount * direction); |
|
if ((visRect.y + visRect.height) > vSize.height) { |
|
visRect.y = Math.max(0, vSize.height - visRect.height); |
|
} |
|
else if (visRect.y < 0) { |
|
visRect.y = 0; |
|
} |
|
} |
|
else { |
|
if (scrollpane.getComponentOrientation().isLeftToRight()) { |
|
visRect.x += (amount * direction); |
|
if ((visRect.x + visRect.width) > vSize.width) { |
|
visRect.x = Math.max(0, vSize.width - visRect.width); |
|
} else if (visRect.x < 0) { |
|
visRect.x = 0; |
|
} |
|
} else { |
|
visRect.x -= (amount * direction); |
|
if (visRect.width > vSize.width) { |
|
visRect.x = vSize.width - visRect.width; |
|
} else { |
|
visRect.x = Math.max(0, Math.min(vSize.width - visRect.width, visRect.x)); |
|
} |
|
} |
|
} |
|
vp.setViewPosition(visRect.getLocation()); |
|
} |
|
} |
|
} |
|
|
|
|
|
class Handler implements ChangeListener, PropertyChangeListener, MouseWheelListener { |
|
// |
|
// MouseWheelListener |
|
|
|
public void mouseWheelMoved(MouseWheelEvent e) { |
|
if (scrollpane.isWheelScrollingEnabled() && |
|
e.getWheelRotation() != 0) { |
|
JScrollBar toScroll = scrollpane.getVerticalScrollBar(); |
|
int direction = e.getWheelRotation() < 0 ? -1 : 1; |
|
int orientation = SwingConstants.VERTICAL; |
|
|
|
|
|
if (toScroll == null || !toScroll.isVisible() |
|
|| e.isShiftDown()) { |
|
toScroll = scrollpane.getHorizontalScrollBar(); |
|
if (toScroll == null || !toScroll.isVisible()) { |
|
return; |
|
} |
|
orientation = SwingConstants.HORIZONTAL; |
|
} |
|
|
|
e.consume(); |
|
|
|
if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) { |
|
JViewport vp = scrollpane.getViewport(); |
|
if (vp == null) { return; } |
|
Component comp = vp.getView(); |
|
int units = Math.abs(e.getUnitsToScroll()); |
|
|
|
// When the scrolling speed is set to maximum, it's possible |
|
// for a single wheel click to scroll by more units than |
|
// will fit in the visible area. This makes it |
|
// hard/impossible to get to certain parts of the scrolling |
|
// Component with the wheel. To make for more accurate |
|
// low-speed scrolling, we limit scrolling to the block |
|
|
|
boolean limitScroll = Math.abs(e.getWheelRotation()) == 1; |
|
|
|
|
|
Object fastWheelScroll = toScroll.getClientProperty( |
|
"JScrollBar.fastWheelScrolling"); |
|
if (Boolean.TRUE == fastWheelScroll && |
|
comp instanceof Scrollable) { |
|
// 5078454: Under maximum acceleration, we may scroll |
|
// by many 100s of units in ~1 second. |
|
// |
|
// BasicScrollBarUI.scrollByUnits() can bog down the EDT |
|
// with repaints in this situation. However, the |
|
// Scrollable interface allows us to pass in an |
|
// arbitrary visibleRect. This allows us to accurately |
|
// calculate the total scroll amount, and then update |
|
// the GUI once. This technique provides much faster |
|
|
|
Scrollable scrollComp = (Scrollable) comp; |
|
Rectangle viewRect = vp.getViewRect(); |
|
int startingX = viewRect.x; |
|
boolean leftToRight = |
|
comp.getComponentOrientation().isLeftToRight(); |
|
int scrollMin = toScroll.getMinimum(); |
|
int scrollMax = toScroll.getMaximum() - |
|
toScroll.getModel().getExtent(); |
|
|
|
if (limitScroll) { |
|
int blockIncr = |
|
scrollComp.getScrollableBlockIncrement(viewRect, |
|
orientation, |
|
direction); |
|
if (direction < 0) { |
|
scrollMin = Math.max(scrollMin, |
|
toScroll.getValue() - blockIncr); |
|
} |
|
else { |
|
scrollMax = Math.min(scrollMax, |
|
toScroll.getValue() + blockIncr); |
|
} |
|
} |
|
|
|
for (int i = 0; i < units; i++) { |
|
int unitIncr = |
|
scrollComp.getScrollableUnitIncrement(viewRect, |
|
orientation, direction); |
|
// Modify the visible rect for the next unit, and |
|
|
|
if (orientation == SwingConstants.VERTICAL) { |
|
if (direction < 0) { |
|
viewRect.y -= unitIncr; |
|
if (viewRect.y <= scrollMin) { |
|
viewRect.y = scrollMin; |
|
break; |
|
} |
|
} |
|
else { |
|
viewRect.y += unitIncr; |
|
if (viewRect.y >= scrollMax) { |
|
viewRect.y = scrollMax; |
|
break; |
|
} |
|
} |
|
} |
|
else { |
|
|
|
if ((leftToRight && direction < 0) || |
|
(!leftToRight && direction > 0)) { |
|
viewRect.x -= unitIncr; |
|
if (leftToRight) { |
|
if (viewRect.x < scrollMin) { |
|
viewRect.x = scrollMin; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
else if ((leftToRight && direction > 0) || |
|
(!leftToRight && direction < 0)) { |
|
viewRect.x += unitIncr; |
|
if (leftToRight) { |
|
if (viewRect.x > scrollMax) { |
|
viewRect.x = scrollMax; |
|
break; |
|
} |
|
} |
|
} |
|
else { |
|
assert false : "Non-sensical ComponentOrientation / scroll direction"; |
|
} |
|
} |
|
} |
|
|
|
if (orientation == SwingConstants.VERTICAL) { |
|
toScroll.setValue(viewRect.y); |
|
} |
|
else { |
|
if (leftToRight) { |
|
toScroll.setValue(viewRect.x); |
|
} |
|
else { |
|
// rightToLeft scrollbars are oriented with |
|
// minValue on the right and maxValue on the |
|
|
|
int newPos = toScroll.getValue() - |
|
(viewRect.x - startingX); |
|
if (newPos < scrollMin) { |
|
newPos = scrollMin; |
|
} |
|
else if (newPos > scrollMax) { |
|
newPos = scrollMax; |
|
} |
|
toScroll.setValue(newPos); |
|
} |
|
} |
|
} |
|
else { |
|
// Viewport's view is not a Scrollable, or fast wheel |
|
|
|
BasicScrollBarUI.scrollByUnits(toScroll, direction, |
|
units, limitScroll); |
|
} |
|
} |
|
else if (e.getScrollType() == |
|
MouseWheelEvent.WHEEL_BLOCK_SCROLL) { |
|
BasicScrollBarUI.scrollByBlock(toScroll, direction); |
|
} |
|
} |
|
} |
|
|
|
// |
|
// ChangeListener: This is added to the vieport, and hsb/vsb models. |
|
|
|
public void stateChanged(ChangeEvent e) { |
|
JViewport viewport = scrollpane.getViewport(); |
|
|
|
if (viewport != null) { |
|
if (e.getSource() == viewport) { |
|
syncScrollPaneWithViewport(); |
|
} |
|
else { |
|
JScrollBar hsb = scrollpane.getHorizontalScrollBar(); |
|
if (hsb != null && e.getSource() == hsb.getModel()) { |
|
hsbStateChanged(viewport, e); |
|
} |
|
else { |
|
JScrollBar vsb = scrollpane.getVerticalScrollBar(); |
|
if (vsb != null && e.getSource() == vsb.getModel()) { |
|
vsbStateChanged(viewport, e); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
private void vsbStateChanged(JViewport viewport, ChangeEvent e) { |
|
BoundedRangeModel model = (BoundedRangeModel)(e.getSource()); |
|
Point p = viewport.getViewPosition(); |
|
p.y = model.getValue(); |
|
viewport.setViewPosition(p); |
|
} |
|
|
|
private void hsbStateChanged(JViewport viewport, ChangeEvent e) { |
|
BoundedRangeModel model = (BoundedRangeModel)(e.getSource()); |
|
Point p = viewport.getViewPosition(); |
|
int value = model.getValue(); |
|
if (scrollpane.getComponentOrientation().isLeftToRight()) { |
|
p.x = value; |
|
} else { |
|
int max = viewport.getViewSize().width; |
|
int extent = viewport.getExtentSize().width; |
|
int oldX = p.x; |
|
|
|
|
|
*/ |
|
p.x = max - extent - value; |
|
|
|
|
|
|
|
*/ |
|
if ((extent == 0) && (value != 0) && (oldX == max)) { |
|
setValueCalled = true; |
|
} else { |
|
|
|
|
|
|
|
*/ |
|
if ((extent != 0) && (oldX < 0) && (p.x == 0)) { |
|
p.x += value; |
|
} |
|
} |
|
} |
|
viewport.setViewPosition(p); |
|
} |
|
|
|
// |
|
// PropertyChangeListener: This is installed on both the JScrollPane |
|
// and the horizontal/vertical scrollbars. |
|
// |
|
|
|
// Listens for changes in the model property and reinstalls the |
|
|
|
public void propertyChange(PropertyChangeEvent e) { |
|
if (e.getSource() == scrollpane) { |
|
scrollPanePropertyChange(e); |
|
} |
|
else { |
|
sbPropertyChange(e); |
|
} |
|
} |
|
|
|
private void scrollPanePropertyChange(PropertyChangeEvent e) { |
|
String propertyName = e.getPropertyName(); |
|
|
|
if (propertyName == "verticalScrollBarDisplayPolicy") { |
|
updateScrollBarDisplayPolicy(e); |
|
} |
|
else if (propertyName == "horizontalScrollBarDisplayPolicy") { |
|
updateScrollBarDisplayPolicy(e); |
|
} |
|
else if (propertyName == "viewport") { |
|
updateViewport(e); |
|
} |
|
else if (propertyName == "rowHeader") { |
|
updateRowHeader(e); |
|
} |
|
else if (propertyName == "columnHeader") { |
|
updateColumnHeader(e); |
|
} |
|
else if (propertyName == "verticalScrollBar") { |
|
updateVerticalScrollBar(e); |
|
} |
|
else if (propertyName == "horizontalScrollBar") { |
|
updateHorizontalScrollBar(e); |
|
} |
|
else if (propertyName == "componentOrientation") { |
|
scrollpane.revalidate(); |
|
scrollpane.repaint(); |
|
} |
|
} |
|
|
|
|
|
private void sbPropertyChange(PropertyChangeEvent e) { |
|
String propertyName = e.getPropertyName(); |
|
Object source = e.getSource(); |
|
|
|
if ("model" == propertyName) { |
|
JScrollBar sb = scrollpane.getVerticalScrollBar(); |
|
BoundedRangeModel oldModel = (BoundedRangeModel)e. |
|
getOldValue(); |
|
ChangeListener cl = null; |
|
|
|
if (source == sb) { |
|
cl = vsbChangeListener; |
|
} |
|
else if (source == scrollpane.getHorizontalScrollBar()) { |
|
sb = scrollpane.getHorizontalScrollBar(); |
|
cl = hsbChangeListener; |
|
} |
|
if (cl != null) { |
|
if (oldModel != null) { |
|
oldModel.removeChangeListener(cl); |
|
} |
|
if (sb.getModel() != null) { |
|
sb.getModel().addChangeListener(cl); |
|
} |
|
} |
|
} |
|
else if ("componentOrientation" == propertyName) { |
|
if (source == scrollpane.getHorizontalScrollBar()) { |
|
JScrollBar hsb = scrollpane.getHorizontalScrollBar(); |
|
JViewport viewport = scrollpane.getViewport(); |
|
Point p = viewport.getViewPosition(); |
|
if (scrollpane.getComponentOrientation().isLeftToRight()) { |
|
p.x = hsb.getValue(); |
|
} else { |
|
p.x = viewport.getViewSize().width - viewport.getExtentSize().width - hsb.getValue(); |
|
} |
|
viewport.setViewPosition(p); |
|
} |
|
} |
|
} |
|
} |
|
} |