0N/A/*
3261N/A * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage javax.swing.plaf.basic;
0N/A
0N/Aimport sun.swing.DefaultLookup;
0N/Aimport sun.swing.UIAction;
0N/A
0N/Aimport javax.swing.*;
0N/Aimport javax.swing.event.*;
0N/Aimport javax.swing.border.*;
0N/Aimport javax.swing.plaf.*;
0N/A
0N/Aimport java.beans.PropertyChangeListener;
0N/Aimport java.beans.PropertyChangeEvent;
0N/A
0N/Aimport java.awt.Component;
0N/Aimport java.awt.Rectangle;
0N/Aimport java.awt.Dimension;
0N/Aimport java.awt.Point;
0N/Aimport java.awt.Insets;
0N/Aimport java.awt.Graphics;
0N/Aimport java.awt.event.*;
0N/A
0N/A/**
0N/A * A default L&F implementation of ScrollPaneUI.
0N/A *
0N/A * @author Hans Muller
0N/A */
0N/Apublic class BasicScrollPaneUI
0N/A extends ScrollPaneUI implements ScrollPaneConstants
0N/A{
0N/A protected JScrollPane scrollpane;
0N/A protected ChangeListener vsbChangeListener;
0N/A protected ChangeListener hsbChangeListener;
0N/A protected ChangeListener viewportChangeListener;
0N/A protected PropertyChangeListener spPropertyChangeListener;
0N/A private MouseWheelListener mouseScrollListener;
1457N/A private int oldExtent = Integer.MIN_VALUE;
0N/A
0N/A /**
0N/A * PropertyChangeListener installed on the vertical scrollbar.
0N/A */
0N/A private PropertyChangeListener vsbPropertyChangeListener;
0N/A
0N/A /**
0N/A * PropertyChangeListener installed on the horizontal scrollbar.
0N/A */
0N/A private PropertyChangeListener hsbPropertyChangeListener;
0N/A
0N/A private Handler handler;
0N/A
0N/A /**
0N/A * State flag that shows whether setValue() was called from a user program
0N/A * before the value of "extent" was set in right-to-left component
0N/A * orientation.
0N/A */
0N/A private boolean setValueCalled = false;
0N/A
0N/A
0N/A public static ComponentUI createUI(JComponent x) {
0N/A return new BasicScrollPaneUI();
0N/A }
0N/A
0N/A static void loadActionMap(LazyActionMap map) {
0N/A map.put(new Actions(Actions.SCROLL_UP));
0N/A map.put(new Actions(Actions.SCROLL_DOWN));
0N/A map.put(new Actions(Actions.SCROLL_HOME));
0N/A map.put(new Actions(Actions.SCROLL_END));
0N/A map.put(new Actions(Actions.UNIT_SCROLL_UP));
0N/A map.put(new Actions(Actions.UNIT_SCROLL_DOWN));
0N/A map.put(new Actions(Actions.SCROLL_LEFT));
0N/A map.put(new Actions(Actions.SCROLL_RIGHT));
0N/A map.put(new Actions(Actions.UNIT_SCROLL_RIGHT));
0N/A map.put(new Actions(Actions.UNIT_SCROLL_LEFT));
0N/A }
0N/A
0N/A
0N/A
0N/A public void paint(Graphics g, JComponent c) {
0N/A Border vpBorder = scrollpane.getViewportBorder();
0N/A if (vpBorder != null) {
0N/A Rectangle r = scrollpane.getViewportBorderBounds();
0N/A vpBorder.paintBorder(scrollpane, g, r.x, r.y, r.width, r.height);
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * @return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE)
0N/A */
0N/A public Dimension getMaximumSize(JComponent c) {
0N/A return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
0N/A }
0N/A
0N/A
0N/A protected void installDefaults(JScrollPane scrollpane)
0N/A {
0N/A LookAndFeel.installBorder(scrollpane, "ScrollPane.border");
0N/A LookAndFeel.installColorsAndFont(scrollpane,
0N/A "ScrollPane.background",
0N/A "ScrollPane.foreground",
0N/A "ScrollPane.font");
0N/A
0N/A Border vpBorder = scrollpane.getViewportBorder();
0N/A if ((vpBorder == null) ||( vpBorder instanceof UIResource)) {
0N/A vpBorder = UIManager.getBorder("ScrollPane.viewportBorder");
0N/A scrollpane.setViewportBorder(vpBorder);
0N/A }
0N/A LookAndFeel.installProperty(scrollpane, "opaque", Boolean.TRUE);
0N/A }
0N/A
0N/A
0N/A protected void installListeners(JScrollPane c)
0N/A {
0N/A vsbChangeListener = createVSBChangeListener();
0N/A vsbPropertyChangeListener = createVSBPropertyChangeListener();
0N/A hsbChangeListener = createHSBChangeListener();
0N/A hsbPropertyChangeListener = createHSBPropertyChangeListener();
0N/A viewportChangeListener = createViewportChangeListener();
0N/A spPropertyChangeListener = createPropertyChangeListener();
0N/A
0N/A JViewport viewport = scrollpane.getViewport();
0N/A JScrollBar vsb = scrollpane.getVerticalScrollBar();
0N/A JScrollBar hsb = scrollpane.getHorizontalScrollBar();
0N/A
0N/A if (viewport != null) {
0N/A viewport.addChangeListener(viewportChangeListener);
0N/A }
0N/A if (vsb != null) {
0N/A vsb.getModel().addChangeListener(vsbChangeListener);
0N/A vsb.addPropertyChangeListener(vsbPropertyChangeListener);
0N/A }
0N/A if (hsb != null) {
0N/A hsb.getModel().addChangeListener(hsbChangeListener);
0N/A hsb.addPropertyChangeListener(hsbPropertyChangeListener);
0N/A }
0N/A
0N/A scrollpane.addPropertyChangeListener(spPropertyChangeListener);
0N/A
0N/A mouseScrollListener = createMouseWheelListener();
0N/A scrollpane.addMouseWheelListener(mouseScrollListener);
0N/A
0N/A }
0N/A
0N/A protected void installKeyboardActions(JScrollPane c) {
0N/A InputMap inputMap = getInputMap(JComponent.
0N/A WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
0N/A
0N/A SwingUtilities.replaceUIInputMap(c, JComponent.
0N/A WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap);
0N/A
0N/A LazyActionMap.installLazyActionMap(c, BasicScrollPaneUI.class,
0N/A "ScrollPane.actionMap");
0N/A }
0N/A
0N/A InputMap getInputMap(int condition) {
0N/A if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
0N/A InputMap keyMap = (InputMap)DefaultLookup.get(scrollpane, this,
0N/A "ScrollPane.ancestorInputMap");
0N/A InputMap rtlKeyMap;
0N/A
0N/A if (scrollpane.getComponentOrientation().isLeftToRight() ||
0N/A ((rtlKeyMap = (InputMap)DefaultLookup.get(scrollpane, this,
0N/A "ScrollPane.ancestorInputMap.RightToLeft")) == null)) {
0N/A return keyMap;
0N/A } else {
0N/A rtlKeyMap.setParent(keyMap);
0N/A return rtlKeyMap;
0N/A }
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A public void installUI(JComponent x) {
0N/A scrollpane = (JScrollPane)x;
0N/A installDefaults(scrollpane);
0N/A installListeners(scrollpane);
0N/A installKeyboardActions(scrollpane);
0N/A }
0N/A
0N/A
0N/A protected void uninstallDefaults(JScrollPane c) {
0N/A LookAndFeel.uninstallBorder(scrollpane);
0N/A
0N/A if (scrollpane.getViewportBorder() instanceof UIResource) {
0N/A scrollpane.setViewportBorder(null);
0N/A }
0N/A }
0N/A
0N/A
0N/A protected void uninstallListeners(JComponent c) {
0N/A JViewport viewport = scrollpane.getViewport();
0N/A JScrollBar vsb = scrollpane.getVerticalScrollBar();
0N/A JScrollBar hsb = scrollpane.getHorizontalScrollBar();
0N/A
0N/A if (viewport != null) {
0N/A viewport.removeChangeListener(viewportChangeListener);
0N/A }
0N/A if (vsb != null) {
0N/A vsb.getModel().removeChangeListener(vsbChangeListener);
0N/A vsb.removePropertyChangeListener(vsbPropertyChangeListener);
0N/A }
0N/A if (hsb != null) {
0N/A hsb.getModel().removeChangeListener(hsbChangeListener);
0N/A hsb.removePropertyChangeListener(hsbPropertyChangeListener);
0N/A }
0N/A
0N/A scrollpane.removePropertyChangeListener(spPropertyChangeListener);
0N/A
0N/A if (mouseScrollListener != null) {
0N/A scrollpane.removeMouseWheelListener(mouseScrollListener);
0N/A }
0N/A
0N/A vsbChangeListener = null;
0N/A hsbChangeListener = null;
0N/A viewportChangeListener = null;
0N/A spPropertyChangeListener = null;
0N/A mouseScrollListener = null;
0N/A handler = null;
0N/A }
0N/A
0N/A
0N/A protected void uninstallKeyboardActions(JScrollPane c) {
0N/A SwingUtilities.replaceUIActionMap(c, null);
0N/A SwingUtilities.replaceUIInputMap(c, JComponent.
0N/A WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
0N/A }
0N/A
0N/A
0N/A public void uninstallUI(JComponent c) {
0N/A uninstallDefaults(scrollpane);
0N/A uninstallListeners(scrollpane);
0N/A uninstallKeyboardActions(scrollpane);
0N/A scrollpane = null;
0N/A }
0N/A
0N/A private Handler getHandler() {
0N/A if (handler == null) {
0N/A handler = new Handler();
0N/A }
0N/A return handler;
0N/A }
0N/A
0N/A protected void syncScrollPaneWithViewport()
0N/A {
0N/A JViewport viewport = scrollpane.getViewport();
0N/A JScrollBar vsb = scrollpane.getVerticalScrollBar();
0N/A JScrollBar hsb = scrollpane.getHorizontalScrollBar();
0N/A JViewport rowHead = scrollpane.getRowHeader();
0N/A JViewport colHead = scrollpane.getColumnHeader();
0N/A boolean ltr = scrollpane.getComponentOrientation().isLeftToRight();
0N/A
0N/A if (viewport != null) {
0N/A Dimension extentSize = viewport.getExtentSize();
0N/A Dimension viewSize = viewport.getViewSize();
0N/A Point viewPosition = viewport.getViewPosition();
0N/A
0N/A if (vsb != null) {
0N/A int extent = extentSize.height;
0N/A int max = viewSize.height;
0N/A int value = Math.max(0, Math.min(viewPosition.y, max - extent));
0N/A vsb.setValues(value, extent, 0, max);
0N/A }
0N/A
0N/A if (hsb != null) {
0N/A int extent = extentSize.width;
0N/A int max = viewSize.width;
0N/A int value;
0N/A
0N/A if (ltr) {
0N/A value = Math.max(0, Math.min(viewPosition.x, max - extent));
0N/A } else {
0N/A int currentValue = hsb.getValue();
0N/A
0N/A /* Use a particular formula to calculate "value"
0N/A * until effective x coordinate is calculated.
0N/A */
0N/A if (setValueCalled && ((max - currentValue) == viewPosition.x)) {
0N/A value = Math.max(0, Math.min(max - extent, currentValue));
0N/A /* After "extent" is set, turn setValueCalled flag off.
0N/A */
0N/A if (extent != 0) {
0N/A setValueCalled = false;
0N/A }
0N/A } else {
0N/A if (extent > max) {
0N/A viewPosition.x = max - extent;
0N/A viewport.setViewPosition(viewPosition);
0N/A value = 0;
0N/A } else {
0N/A /* The following line can't handle a small value of
0N/A * viewPosition.x like Integer.MIN_VALUE correctly
0N/A * because (max - extent - viewPositoiin.x) causes
0N/A * an overflow. As a result, value becomes zero.
0N/A * (e.g. setViewPosition(Integer.MAX_VALUE, ...)
0N/A * in a user program causes a overflow.
0N/A * Its expected value is (max - extent).)
0N/A * However, this seems a trivial bug and adding a
0N/A * fix makes this often-called method slow, so I'll
0N/A * leave it until someone claims.
0N/A */
0N/A value = Math.max(0, Math.min(max - extent, max - extent - viewPosition.x));
1457N/A if (oldExtent > extent) {
1457N/A value -= oldExtent - extent;
1457N/A }
0N/A }
0N/A }
0N/A }
1457N/A oldExtent = extent;
0N/A hsb.setValues(value, extent, 0, max);
0N/A }
0N/A
0N/A if (rowHead != null) {
0N/A Point p = rowHead.getViewPosition();
0N/A p.y = viewport.getViewPosition().y;
0N/A p.x = 0;
0N/A rowHead.setViewPosition(p);
0N/A }
0N/A
0N/A if (colHead != null) {
0N/A Point p = colHead.getViewPosition();
0N/A if (ltr) {
0N/A p.x = viewport.getViewPosition().x;
0N/A } else {
0N/A p.x = Math.max(0, viewport.getViewPosition().x);
0N/A }
0N/A p.y = 0;
0N/A colHead.setViewPosition(p);
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns the baseline.
0N/A *
0N/A * @throws NullPointerException {@inheritDoc}
0N/A * @throws IllegalArgumentException {@inheritDoc}
0N/A * @see javax.swing.JComponent#getBaseline(int, int)
0N/A * @since 1.6
0N/A */
0N/A public int getBaseline(JComponent c, int width, int height) {
2969N/A if (c == null) {
2969N/A throw new NullPointerException("Component must be non-null");
2969N/A }
2969N/A
2969N/A if (width < 0 || height < 0) {
2969N/A throw new IllegalArgumentException("Width and height must be >= 0");
2969N/A }
2969N/A
0N/A JViewport viewport = scrollpane.getViewport();
0N/A Insets spInsets = scrollpane.getInsets();
0N/A int y = spInsets.top;
0N/A height = height - spInsets.top - spInsets.bottom;
0N/A width = width - spInsets.left - spInsets.right;
0N/A JViewport columnHeader = scrollpane.getColumnHeader();
0N/A if (columnHeader != null && columnHeader.isVisible()) {
0N/A Component header = columnHeader.getView();
0N/A if (header != null && header.isVisible()) {
0N/A // Header is always given it's preferred size.
0N/A Dimension headerPref = header.getPreferredSize();
0N/A int baseline = header.getBaseline(headerPref.width,
0N/A headerPref.height);
0N/A if (baseline >= 0) {
0N/A return y + baseline;
0N/A }
0N/A }
0N/A Dimension columnPref = columnHeader.getPreferredSize();
0N/A height -= columnPref.height;
0N/A y += columnPref.height;
0N/A }
0N/A Component view = (viewport == null) ? null : viewport.getView();
0N/A if (view != null && view.isVisible() &&
0N/A view.getBaselineResizeBehavior() ==
0N/A Component.BaselineResizeBehavior.CONSTANT_ASCENT) {
0N/A Border viewportBorder = scrollpane.getViewportBorder();
0N/A if (viewportBorder != null) {
0N/A Insets vpbInsets = viewportBorder.getBorderInsets(scrollpane);
0N/A y += vpbInsets.top;
0N/A height = height - vpbInsets.top - vpbInsets.bottom;
0N/A width = width - vpbInsets.left - vpbInsets.right;
0N/A }
0N/A if (view.getWidth() > 0 && view.getHeight() > 0) {
0N/A Dimension min = view.getMinimumSize();
0N/A width = Math.max(min.width, view.getWidth());
0N/A height = Math.max(min.height, view.getHeight());
0N/A }
0N/A if (width > 0 && height > 0) {
0N/A int baseline = view.getBaseline(width, height);
0N/A if (baseline > 0) {
0N/A return y + baseline;
0N/A }
0N/A }
0N/A }
0N/A return -1;
0N/A }
0N/A
0N/A /**
0N/A * Returns an enum indicating how the baseline of the component
0N/A * changes as the size changes.
0N/A *
0N/A * @throws NullPointerException {@inheritDoc}
0N/A * @see javax.swing.JComponent#getBaseline(int, int)
0N/A * @since 1.6
0N/A */
0N/A public Component.BaselineResizeBehavior getBaselineResizeBehavior(
0N/A JComponent c) {
0N/A super.getBaselineResizeBehavior(c);
0N/A // Baseline is either from the header, in which case it's always
0N/A // the same size and therefor can be created as CONSTANT_ASCENT.
0N/A // If the header doesn't have a baseline than the baseline will only
0N/A // be valid if it's BaselineResizeBehavior is
0N/A // CONSTANT_ASCENT, so, return CONSTANT_ASCENT.
0N/A return Component.BaselineResizeBehavior.CONSTANT_ASCENT;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Listener for viewport events.
0N/A */
0N/A public class ViewportChangeHandler implements ChangeListener
0N/A {
0N/A
0N/A // NOTE: This class exists only for backward compatability. All
0N/A // its functionality has been moved into Handler. If you need to add
0N/A // new functionality add it to the Handler, but make sure this
0N/A // class calls into the Handler.
0N/A
0N/A public void stateChanged(ChangeEvent e) {
0N/A getHandler().stateChanged(e);
0N/A }
0N/A }
0N/A
0N/A protected ChangeListener createViewportChangeListener() {
0N/A return getHandler();
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Horizontal scrollbar listener.
0N/A */
0N/A public class HSBChangeListener implements ChangeListener
0N/A {
0N/A
0N/A // NOTE: This class exists only for backward compatability. All
0N/A // its functionality has been moved into Handler. If you need to add
0N/A // new functionality add it to the Handler, but make sure this
0N/A // class calls into the Handler.
0N/A
0N/A public void stateChanged(ChangeEvent e)
0N/A {
0N/A getHandler().stateChanged(e);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns a <code>PropertyChangeListener</code> that will be installed
0N/A * on the horizontal <code>JScrollBar</code>.
0N/A */
0N/A private PropertyChangeListener createHSBPropertyChangeListener() {
0N/A return getHandler();
0N/A }
0N/A
0N/A protected ChangeListener createHSBChangeListener() {
0N/A return getHandler();
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Vertical scrollbar listener.
0N/A */
0N/A public class VSBChangeListener implements ChangeListener
0N/A {
0N/A
0N/A // NOTE: This class exists only for backward compatability. All
0N/A // its functionality has been moved into Handler. If you need to add
0N/A // new functionality add it to the Handler, but make sure this
0N/A // class calls into the Handler.
0N/A
0N/A public void stateChanged(ChangeEvent e)
0N/A {
0N/A getHandler().stateChanged(e);
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Returns a <code>PropertyChangeListener</code> that will be installed
0N/A * on the vertical <code>JScrollBar</code>.
0N/A */
0N/A private PropertyChangeListener createVSBPropertyChangeListener() {
0N/A return getHandler();
0N/A }
0N/A
0N/A protected ChangeListener createVSBChangeListener() {
0N/A return getHandler();
0N/A }
0N/A
0N/A /**
0N/A * MouseWheelHandler is an inner class which implements the
0N/A * MouseWheelListener interface. MouseWheelHandler responds to
0N/A * MouseWheelEvents by scrolling the JScrollPane appropriately.
0N/A * If the scroll pane's
0N/A * <code>isWheelScrollingEnabled</code>
0N/A * method returns false, no scrolling occurs.
0N/A *
0N/A * @see javax.swing.JScrollPane#isWheelScrollingEnabled
0N/A * @see #createMouseWheelListener
0N/A * @see java.awt.event.MouseWheelListener
0N/A * @see java.awt.event.MouseWheelEvent
0N/A * @since 1.4
0N/A */
0N/A protected class MouseWheelHandler implements MouseWheelListener {
0N/A
0N/A // NOTE: This class exists only for backward compatability. All
0N/A // its functionality has been moved into Handler. If you need to add
0N/A // new functionality add it to the Handler, but make sure this
0N/A // class calls into the Handler.
0N/A
0N/A /**
0N/A * Called when the mouse wheel is rotated while over a
0N/A * JScrollPane.
0N/A *
0N/A * @param e MouseWheelEvent to be handled
0N/A * @since 1.4
0N/A */
0N/A public void mouseWheelMoved(MouseWheelEvent e) {
0N/A getHandler().mouseWheelMoved(e);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Creates an instance of MouseWheelListener, which is added to the
0N/A * JScrollPane by installUI(). The returned MouseWheelListener is used
0N/A * to handle mouse wheel-driven scrolling.
0N/A *
0N/A * @return MouseWheelListener which implements wheel-driven scrolling
0N/A * @see #installUI
0N/A * @see MouseWheelHandler
0N/A * @since 1.4
0N/A */
0N/A protected MouseWheelListener createMouseWheelListener() {
0N/A return getHandler();
0N/A }
0N/A
0N/A protected void updateScrollBarDisplayPolicy(PropertyChangeEvent e) {
0N/A scrollpane.revalidate();
0N/A scrollpane.repaint();
0N/A }
0N/A
0N/A
0N/A protected void updateViewport(PropertyChangeEvent e)
0N/A {
0N/A JViewport oldViewport = (JViewport)(e.getOldValue());
0N/A JViewport newViewport = (JViewport)(e.getNewValue());
0N/A
0N/A if (oldViewport != null) {
0N/A oldViewport.removeChangeListener(viewportChangeListener);
0N/A }
0N/A
0N/A if (newViewport != null) {
0N/A Point p = newViewport.getViewPosition();
0N/A if (scrollpane.getComponentOrientation().isLeftToRight()) {
0N/A p.x = Math.max(p.x, 0);
0N/A } else {
0N/A int max = newViewport.getViewSize().width;
0N/A int extent = newViewport.getExtentSize().width;
0N/A if (extent > max) {
0N/A p.x = max - extent;
0N/A } else {
0N/A p.x = Math.max(0, Math.min(max - extent, p.x));
0N/A }
0N/A }
0N/A p.y = Math.max(p.y, 0);
0N/A newViewport.setViewPosition(p);
0N/A newViewport.addChangeListener(viewportChangeListener);
0N/A }
0N/A }
0N/A
0N/A
0N/A protected void updateRowHeader(PropertyChangeEvent e)
0N/A {
0N/A JViewport newRowHead = (JViewport)(e.getNewValue());
0N/A if (newRowHead != null) {
0N/A JViewport viewport = scrollpane.getViewport();
0N/A Point p = newRowHead.getViewPosition();
0N/A p.y = (viewport != null) ? viewport.getViewPosition().y : 0;
0N/A newRowHead.setViewPosition(p);
0N/A }
0N/A }
0N/A
0N/A
0N/A protected void updateColumnHeader(PropertyChangeEvent e)
0N/A {
0N/A JViewport newColHead = (JViewport)(e.getNewValue());
0N/A if (newColHead != null) {
0N/A JViewport viewport = scrollpane.getViewport();
0N/A Point p = newColHead.getViewPosition();
0N/A if (viewport == null) {
0N/A p.x = 0;
0N/A } else {
0N/A if (scrollpane.getComponentOrientation().isLeftToRight()) {
0N/A p.x = viewport.getViewPosition().x;
0N/A } else {
0N/A p.x = Math.max(0, viewport.getViewPosition().x);
0N/A }
0N/A }
0N/A newColHead.setViewPosition(p);
0N/A scrollpane.add(newColHead, COLUMN_HEADER);
0N/A }
0N/A }
0N/A
0N/A private void updateHorizontalScrollBar(PropertyChangeEvent pce) {
0N/A updateScrollBar(pce, hsbChangeListener, hsbPropertyChangeListener);
0N/A }
0N/A
0N/A private void updateVerticalScrollBar(PropertyChangeEvent pce) {
0N/A updateScrollBar(pce, vsbChangeListener, vsbPropertyChangeListener);
0N/A }
0N/A
0N/A private void updateScrollBar(PropertyChangeEvent pce, ChangeListener cl,
0N/A PropertyChangeListener pcl) {
0N/A JScrollBar sb = (JScrollBar)pce.getOldValue();
0N/A if (sb != null) {
0N/A if (cl != null) {
0N/A sb.getModel().removeChangeListener(cl);
0N/A }
0N/A if (pcl != null) {
0N/A sb.removePropertyChangeListener(pcl);
0N/A }
0N/A }
0N/A sb = (JScrollBar)pce.getNewValue();
0N/A if (sb != null) {
0N/A if (cl != null) {
0N/A sb.getModel().addChangeListener(cl);
0N/A }
0N/A if (pcl != null) {
0N/A sb.addPropertyChangeListener(pcl);
0N/A }
0N/A }
0N/A }
0N/A
0N/A public class PropertyChangeHandler implements PropertyChangeListener
0N/A {
0N/A
0N/A // NOTE: This class exists only for backward compatability. All
0N/A // its functionality has been moved into Handler. If you need to add
0N/A // new functionality add it to the Handler, but make sure this
0N/A // class calls into the Handler.
0N/A
0N/A public void propertyChange(PropertyChangeEvent e)
0N/A {
0N/A getHandler().propertyChange(e);
0N/A }
0N/A }
0N/A
0N/A
0N/A
0N/A /**
0N/A * Creates an instance of PropertyChangeListener that's added to
0N/A * the JScrollPane by installUI(). Subclasses can override this method
0N/A * to return a custom PropertyChangeListener, e.g.
0N/A * <pre>
0N/A * class MyScrollPaneUI extends BasicScrollPaneUI {
0N/A * protected PropertyChangeListener <b>createPropertyChangeListener</b>() {
0N/A * return new MyPropertyChangeListener();
0N/A * }
0N/A * public class MyPropertyChangeListener extends PropertyChangeListener {
0N/A * public void propertyChange(PropertyChangeEvent e) {
0N/A * if (e.getPropertyName().equals("viewport")) {
0N/A * // do some extra work when the viewport changes
0N/A * }
0N/A * super.propertyChange(e);
0N/A * }
0N/A * }
0N/A * }
0N/A * </pre>
0N/A *
0N/A * @see java.beans.PropertyChangeListener
0N/A * @see #installUI
0N/A */
0N/A protected PropertyChangeListener createPropertyChangeListener() {
0N/A return getHandler();
0N/A }
0N/A
0N/A
0N/A private static class Actions extends UIAction {
0N/A private static final String SCROLL_UP = "scrollUp";
0N/A private static final String SCROLL_DOWN = "scrollDown";
0N/A private static final String SCROLL_HOME = "scrollHome";
0N/A private static final String SCROLL_END = "scrollEnd";
0N/A private static final String UNIT_SCROLL_UP = "unitScrollUp";
0N/A private static final String UNIT_SCROLL_DOWN = "unitScrollDown";
0N/A private static final String SCROLL_LEFT = "scrollLeft";
0N/A private static final String SCROLL_RIGHT = "scrollRight";
0N/A private static final String UNIT_SCROLL_LEFT = "unitScrollLeft";
0N/A private static final String UNIT_SCROLL_RIGHT = "unitScrollRight";
0N/A
0N/A
0N/A Actions(String key) {
0N/A super(key);
0N/A }
0N/A
0N/A public void actionPerformed(ActionEvent e) {
0N/A JScrollPane scrollPane = (JScrollPane)e.getSource();
0N/A boolean ltr = scrollPane.getComponentOrientation().isLeftToRight();
0N/A String key = getName();
0N/A
0N/A if (key == SCROLL_UP) {
0N/A scroll(scrollPane, SwingConstants.VERTICAL, -1, true);
0N/A }
0N/A else if (key == SCROLL_DOWN) {
0N/A scroll(scrollPane, SwingConstants.VERTICAL, 1, true);
0N/A }
0N/A else if (key == SCROLL_HOME) {
0N/A scrollHome(scrollPane);
0N/A }
0N/A else if (key == SCROLL_END) {
0N/A scrollEnd(scrollPane);
0N/A }
0N/A else if (key == UNIT_SCROLL_UP) {
0N/A scroll(scrollPane, SwingConstants.VERTICAL, -1, false);
0N/A }
0N/A else if (key == UNIT_SCROLL_DOWN) {
0N/A scroll(scrollPane, SwingConstants.VERTICAL, 1, false);
0N/A }
0N/A else if (key == SCROLL_LEFT) {
0N/A scroll(scrollPane, SwingConstants.HORIZONTAL, ltr ? -1 : 1,
0N/A true);
0N/A }
0N/A else if (key == SCROLL_RIGHT) {
0N/A scroll(scrollPane, SwingConstants.HORIZONTAL, ltr ? 1 : -1,
0N/A true);
0N/A }
0N/A else if (key == UNIT_SCROLL_LEFT) {
0N/A scroll(scrollPane, SwingConstants.HORIZONTAL, ltr ? -1 : 1,
0N/A false);
0N/A }
0N/A else if (key == UNIT_SCROLL_RIGHT) {
0N/A scroll(scrollPane, SwingConstants.HORIZONTAL, ltr ? 1 : -1,
0N/A false);
0N/A }
0N/A }
0N/A
0N/A private void scrollEnd(JScrollPane scrollpane) {
0N/A JViewport vp = scrollpane.getViewport();
0N/A Component view;
0N/A if (vp != null && (view = vp.getView()) != null) {
0N/A Rectangle visRect = vp.getViewRect();
0N/A Rectangle bounds = view.getBounds();
0N/A if (scrollpane.getComponentOrientation().isLeftToRight()) {
0N/A vp.setViewPosition(new Point(bounds.width - visRect.width,
0N/A bounds.height - visRect.height));
0N/A } else {
0N/A vp.setViewPosition(new Point(0,
0N/A bounds.height - visRect.height));
0N/A }
0N/A }
0N/A }
0N/A
0N/A private void scrollHome(JScrollPane scrollpane) {
0N/A JViewport vp = scrollpane.getViewport();
0N/A Component view;
0N/A if (vp != null && (view = vp.getView()) != null) {
0N/A if (scrollpane.getComponentOrientation().isLeftToRight()) {
0N/A vp.setViewPosition(new Point(0, 0));
0N/A } else {
0N/A Rectangle visRect = vp.getViewRect();
0N/A Rectangle bounds = view.getBounds();
0N/A vp.setViewPosition(new Point(bounds.width - visRect.width, 0));
0N/A }
0N/A }
0N/A }
0N/A
0N/A private void scroll(JScrollPane scrollpane, int orientation,
0N/A int direction, boolean block) {
0N/A JViewport vp = scrollpane.getViewport();
0N/A Component view;
0N/A if (vp != null && (view = vp.getView()) != null) {
0N/A Rectangle visRect = vp.getViewRect();
0N/A Dimension vSize = view.getSize();
0N/A int amount;
0N/A
0N/A if (view instanceof Scrollable) {
0N/A if (block) {
0N/A amount = ((Scrollable)view).getScrollableBlockIncrement
0N/A (visRect, orientation, direction);
0N/A }
0N/A else {
0N/A amount = ((Scrollable)view).getScrollableUnitIncrement
0N/A (visRect, orientation, direction);
0N/A }
0N/A }
0N/A else {
0N/A if (block) {
0N/A if (orientation == SwingConstants.VERTICAL) {
0N/A amount = visRect.height;
0N/A }
0N/A else {
0N/A amount = visRect.width;
0N/A }
0N/A }
0N/A else {
0N/A amount = 10;
0N/A }
0N/A }
0N/A if (orientation == SwingConstants.VERTICAL) {
0N/A visRect.y += (amount * direction);
0N/A if ((visRect.y + visRect.height) > vSize.height) {
0N/A visRect.y = Math.max(0, vSize.height - visRect.height);
0N/A }
0N/A else if (visRect.y < 0) {
0N/A visRect.y = 0;
0N/A }
0N/A }
0N/A else {
0N/A if (scrollpane.getComponentOrientation().isLeftToRight()) {
0N/A visRect.x += (amount * direction);
0N/A if ((visRect.x + visRect.width) > vSize.width) {
0N/A visRect.x = Math.max(0, vSize.width - visRect.width);
0N/A } else if (visRect.x < 0) {
0N/A visRect.x = 0;
0N/A }
0N/A } else {
0N/A visRect.x -= (amount * direction);
0N/A if (visRect.width > vSize.width) {
0N/A visRect.x = vSize.width - visRect.width;
0N/A } else {
0N/A visRect.x = Math.max(0, Math.min(vSize.width - visRect.width, visRect.x));
0N/A }
0N/A }
0N/A }
0N/A vp.setViewPosition(visRect.getLocation());
0N/A }
0N/A }
0N/A }
0N/A
0N/A
0N/A class Handler implements ChangeListener, PropertyChangeListener, MouseWheelListener {
0N/A //
0N/A // MouseWheelListener
0N/A //
0N/A public void mouseWheelMoved(MouseWheelEvent e) {
0N/A if (scrollpane.isWheelScrollingEnabled() &&
0N/A e.getWheelRotation() != 0) {
0N/A JScrollBar toScroll = scrollpane.getVerticalScrollBar();
0N/A int direction = e.getWheelRotation() < 0 ? -1 : 1;
0N/A int orientation = SwingConstants.VERTICAL;
0N/A
0N/A // find which scrollbar to scroll, or return if none
0N/A if (toScroll == null || !toScroll.isVisible()) {
0N/A toScroll = scrollpane.getHorizontalScrollBar();
0N/A if (toScroll == null || !toScroll.isVisible()) {
0N/A return;
0N/A }
0N/A orientation = SwingConstants.HORIZONTAL;
0N/A }
0N/A
2287N/A e.consume();
2287N/A
0N/A if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
0N/A JViewport vp = scrollpane.getViewport();
0N/A if (vp == null) { return; }
0N/A Component comp = vp.getView();
0N/A int units = Math.abs(e.getUnitsToScroll());
0N/A
0N/A // When the scrolling speed is set to maximum, it's possible
0N/A // for a single wheel click to scroll by more units than
0N/A // will fit in the visible area. This makes it
0N/A // hard/impossible to get to certain parts of the scrolling
0N/A // Component with the wheel. To make for more accurate
0N/A // low-speed scrolling, we limit scrolling to the block
0N/A // increment if the wheel was only rotated one click.
0N/A boolean limitScroll = Math.abs(e.getWheelRotation()) == 1;
0N/A
0N/A // Check if we should use the visibleRect trick
0N/A Object fastWheelScroll = toScroll.getClientProperty(
0N/A "JScrollBar.fastWheelScrolling");
0N/A if (Boolean.TRUE == fastWheelScroll &&
0N/A comp instanceof Scrollable) {
0N/A // 5078454: Under maximum acceleration, we may scroll
0N/A // by many 100s of units in ~1 second.
0N/A //
0N/A // BasicScrollBarUI.scrollByUnits() can bog down the EDT
0N/A // with repaints in this situation. However, the
0N/A // Scrollable interface allows us to pass in an
0N/A // arbitrary visibleRect. This allows us to accurately
0N/A // calculate the total scroll amount, and then update
0N/A // the GUI once. This technique provides much faster
0N/A // accelerated wheel scrolling.
0N/A Scrollable scrollComp = (Scrollable) comp;
0N/A Rectangle viewRect = vp.getViewRect();
0N/A int startingX = viewRect.x;
0N/A boolean leftToRight =
0N/A comp.getComponentOrientation().isLeftToRight();
0N/A int scrollMin = toScroll.getMinimum();
0N/A int scrollMax = toScroll.getMaximum() -
0N/A toScroll.getModel().getExtent();
0N/A
0N/A if (limitScroll) {
0N/A int blockIncr =
0N/A scrollComp.getScrollableBlockIncrement(viewRect,
0N/A orientation,
0N/A direction);
0N/A if (direction < 0) {
0N/A scrollMin = Math.max(scrollMin,
0N/A toScroll.getValue() - blockIncr);
0N/A }
0N/A else {
0N/A scrollMax = Math.min(scrollMax,
0N/A toScroll.getValue() + blockIncr);
0N/A }
0N/A }
0N/A
0N/A for (int i = 0; i < units; i++) {
0N/A int unitIncr =
0N/A scrollComp.getScrollableUnitIncrement(viewRect,
0N/A orientation, direction);
0N/A // Modify the visible rect for the next unit, and
0N/A // check to see if we're at the end already.
0N/A if (orientation == SwingConstants.VERTICAL) {
0N/A if (direction < 0) {
0N/A viewRect.y -= unitIncr;
0N/A if (viewRect.y <= scrollMin) {
0N/A viewRect.y = scrollMin;
0N/A break;
0N/A }
0N/A }
0N/A else { // (direction > 0
0N/A viewRect.y += unitIncr;
0N/A if (viewRect.y >= scrollMax) {
0N/A viewRect.y = scrollMax;
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A else {
0N/A // Scroll left
0N/A if ((leftToRight && direction < 0) ||
0N/A (!leftToRight && direction > 0)) {
0N/A viewRect.x -= unitIncr;
0N/A if (leftToRight) {
0N/A if (viewRect.x < scrollMin) {
0N/A viewRect.x = scrollMin;
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A // Scroll right
0N/A else if ((leftToRight && direction > 0) ||
0N/A (!leftToRight && direction < 0)) {
0N/A viewRect.x += unitIncr;
0N/A if (leftToRight) {
0N/A if (viewRect.x > scrollMax) {
0N/A viewRect.x = scrollMax;
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A else {
0N/A assert false : "Non-sensical ComponentOrientation / scroll direction";
0N/A }
0N/A }
0N/A }
0N/A // Set the final view position on the ScrollBar
0N/A if (orientation == SwingConstants.VERTICAL) {
0N/A toScroll.setValue(viewRect.y);
0N/A }
0N/A else {
0N/A if (leftToRight) {
0N/A toScroll.setValue(viewRect.x);
0N/A }
0N/A else {
0N/A // rightToLeft scrollbars are oriented with
0N/A // minValue on the right and maxValue on the
0N/A // left.
0N/A int newPos = toScroll.getValue() -
0N/A (viewRect.x - startingX);
0N/A if (newPos < scrollMin) {
0N/A newPos = scrollMin;
0N/A }
0N/A else if (newPos > scrollMax) {
0N/A newPos = scrollMax;
0N/A }
0N/A toScroll.setValue(newPos);
0N/A }
0N/A }
0N/A }
0N/A else {
0N/A // Viewport's view is not a Scrollable, or fast wheel
0N/A // scrolling is not enabled.
0N/A BasicScrollBarUI.scrollByUnits(toScroll, direction,
0N/A units, limitScroll);
0N/A }
0N/A }
0N/A else if (e.getScrollType() ==
0N/A MouseWheelEvent.WHEEL_BLOCK_SCROLL) {
0N/A BasicScrollBarUI.scrollByBlock(toScroll, direction);
0N/A }
0N/A }
0N/A }
0N/A
0N/A //
0N/A // ChangeListener: This is added to the vieport, and hsb/vsb models.
0N/A //
0N/A public void stateChanged(ChangeEvent e) {
0N/A JViewport viewport = scrollpane.getViewport();
0N/A
0N/A if (viewport != null) {
0N/A if (e.getSource() == viewport) {
1457N/A syncScrollPaneWithViewport();
0N/A }
0N/A else {
0N/A JScrollBar hsb = scrollpane.getHorizontalScrollBar();
0N/A if (hsb != null && e.getSource() == hsb.getModel()) {
0N/A hsbStateChanged(viewport, e);
0N/A }
0N/A else {
0N/A JScrollBar vsb = scrollpane.getVerticalScrollBar();
0N/A if (vsb != null && e.getSource() == vsb.getModel()) {
0N/A vsbStateChanged(viewport, e);
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A private void vsbStateChanged(JViewport viewport, ChangeEvent e) {
0N/A BoundedRangeModel model = (BoundedRangeModel)(e.getSource());
0N/A Point p = viewport.getViewPosition();
0N/A p.y = model.getValue();
0N/A viewport.setViewPosition(p);
0N/A }
0N/A
0N/A private void hsbStateChanged(JViewport viewport, ChangeEvent e) {
0N/A BoundedRangeModel model = (BoundedRangeModel)(e.getSource());
0N/A Point p = viewport.getViewPosition();
0N/A int value = model.getValue();
0N/A if (scrollpane.getComponentOrientation().isLeftToRight()) {
0N/A p.x = value;
0N/A } else {
0N/A int max = viewport.getViewSize().width;
0N/A int extent = viewport.getExtentSize().width;
0N/A int oldX = p.x;
0N/A
0N/A /* Set new X coordinate based on "value".
0N/A */
0N/A p.x = max - extent - value;
0N/A
0N/A /* If setValue() was called before "extent" was fixed,
0N/A * turn setValueCalled flag on.
0N/A */
0N/A if ((extent == 0) && (value != 0) && (oldX == max)) {
0N/A setValueCalled = true;
0N/A } else {
0N/A /* When a pane without a horizontal scroll bar was
0N/A * reduced and the bar appeared, the viewport should
0N/A * show the right side of the view.
0N/A */
0N/A if ((extent != 0) && (oldX < 0) && (p.x == 0)) {
0N/A p.x += value;
0N/A }
0N/A }
0N/A }
0N/A viewport.setViewPosition(p);
0N/A }
0N/A
0N/A //
0N/A // PropertyChangeListener: This is installed on both the JScrollPane
0N/A // and the horizontal/vertical scrollbars.
0N/A //
0N/A
0N/A // Listens for changes in the model property and reinstalls the
0N/A // horizontal/vertical PropertyChangeListeners.
0N/A public void propertyChange(PropertyChangeEvent e) {
0N/A if (e.getSource() == scrollpane) {
0N/A scrollPanePropertyChange(e);
0N/A }
0N/A else {
0N/A sbPropertyChange(e);
0N/A }
0N/A }
0N/A
0N/A private void scrollPanePropertyChange(PropertyChangeEvent e) {
0N/A String propertyName = e.getPropertyName();
0N/A
0N/A if (propertyName == "verticalScrollBarDisplayPolicy") {
0N/A updateScrollBarDisplayPolicy(e);
0N/A }
0N/A else if (propertyName == "horizontalScrollBarDisplayPolicy") {
0N/A updateScrollBarDisplayPolicy(e);
0N/A }
0N/A else if (propertyName == "viewport") {
0N/A updateViewport(e);
0N/A }
0N/A else if (propertyName == "rowHeader") {
0N/A updateRowHeader(e);
0N/A }
0N/A else if (propertyName == "columnHeader") {
0N/A updateColumnHeader(e);
0N/A }
0N/A else if (propertyName == "verticalScrollBar") {
0N/A updateVerticalScrollBar(e);
0N/A }
0N/A else if (propertyName == "horizontalScrollBar") {
0N/A updateHorizontalScrollBar(e);
0N/A }
0N/A else if (propertyName == "componentOrientation") {
0N/A scrollpane.revalidate();
0N/A scrollpane.repaint();
0N/A }
0N/A }
0N/A
0N/A // PropertyChangeListener for the horizontal and vertical scrollbars.
0N/A private void sbPropertyChange(PropertyChangeEvent e) {
0N/A String propertyName = e.getPropertyName();
0N/A Object source = e.getSource();
0N/A
0N/A if ("model" == propertyName) {
0N/A JScrollBar sb = scrollpane.getVerticalScrollBar();
0N/A BoundedRangeModel oldModel = (BoundedRangeModel)e.
0N/A getOldValue();
0N/A ChangeListener cl = null;
0N/A
0N/A if (source == sb) {
0N/A cl = vsbChangeListener;
0N/A }
0N/A else if (source == scrollpane.getHorizontalScrollBar()) {
0N/A sb = scrollpane.getHorizontalScrollBar();
0N/A cl = hsbChangeListener;
0N/A }
0N/A if (cl != null) {
0N/A if (oldModel != null) {
0N/A oldModel.removeChangeListener(cl);
0N/A }
0N/A if (sb.getModel() != null) {
0N/A sb.getModel().addChangeListener(cl);
0N/A }
0N/A }
0N/A }
0N/A else if ("componentOrientation" == propertyName) {
0N/A if (source == scrollpane.getHorizontalScrollBar()) {
0N/A JScrollBar hsb = scrollpane.getHorizontalScrollBar();
0N/A JViewport viewport = scrollpane.getViewport();
0N/A Point p = viewport.getViewPosition();
0N/A if (scrollpane.getComponentOrientation().isLeftToRight()) {
0N/A p.x = hsb.getValue();
0N/A } else {
0N/A p.x = viewport.getViewSize().width - viewport.getExtentSize().width - hsb.getValue();
0N/A }
0N/A viewport.setViewPosition(p);
0N/A }
0N/A }
0N/A }
0N/A }
0N/A}