| /* BasicScrollBarUI.java -- |
| Copyright (C) 2004, 2005, 2006, Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| 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.Color; |
| import java.awt.Component; |
| import java.awt.Container; |
| import java.awt.Dimension; |
| import java.awt.Graphics; |
| import java.awt.Insets; |
| import java.awt.LayoutManager; |
| import java.awt.Rectangle; |
| import java.awt.event.ActionEvent; |
| import java.awt.event.ActionListener; |
| import java.awt.event.MouseAdapter; |
| import java.awt.event.MouseEvent; |
| import java.awt.event.MouseMotionListener; |
| import java.beans.PropertyChangeEvent; |
| import java.beans.PropertyChangeListener; |
| |
| import javax.swing.AbstractAction; |
| import javax.swing.ActionMap; |
| import javax.swing.BoundedRangeModel; |
| import javax.swing.InputMap; |
| import javax.swing.JButton; |
| import javax.swing.JComponent; |
| import javax.swing.JScrollBar; |
| import javax.swing.JSlider; |
| import javax.swing.LookAndFeel; |
| import javax.swing.SwingConstants; |
| import javax.swing.SwingUtilities; |
| import javax.swing.Timer; |
| import javax.swing.UIManager; |
| import javax.swing.event.ChangeEvent; |
| import javax.swing.event.ChangeListener; |
| import javax.swing.plaf.ActionMapUIResource; |
| import javax.swing.plaf.ComponentUI; |
| import javax.swing.plaf.ScrollBarUI; |
| |
| /** |
| * The Basic Look and Feel UI delegate for JScrollBar. |
| */ |
| public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager, |
| SwingConstants |
| { |
| /** |
| * A helper class that listens to the two JButtons on each end of the |
| * JScrollBar. |
| */ |
| protected class ArrowButtonListener extends MouseAdapter |
| { |
| |
| /** |
| * Move the thumb in the direction specified by the button's arrow. If |
| * this button is held down, then it should keep moving the thumb. |
| * |
| * @param e The MouseEvent fired by the JButton. |
| */ |
| public void mousePressed(MouseEvent e) |
| { |
| scrollTimer.stop(); |
| scrollListener.setScrollByBlock(false); |
| if (e.getSource() == incrButton) |
| scrollListener.setDirection(POSITIVE_SCROLL); |
| else if (e.getSource() == decrButton) |
| scrollListener.setDirection(NEGATIVE_SCROLL); |
| scrollTimer.setDelay(100); |
| scrollTimer.start(); |
| } |
| |
| /** |
| * Stops the thumb when the JButton is released. |
| * |
| * @param e The MouseEvent fired by the JButton. |
| */ |
| public void mouseReleased(MouseEvent e) |
| { |
| scrollTimer.stop(); |
| scrollTimer.setDelay(300); |
| if (e.getSource() == incrButton) |
| scrollByUnit(POSITIVE_SCROLL); |
| else if (e.getSource() == decrButton) |
| scrollByUnit(NEGATIVE_SCROLL); |
| } |
| } |
| |
| /** |
| * A helper class that listens to the ScrollBar's model for ChangeEvents. |
| */ |
| protected class ModelListener implements ChangeListener |
| { |
| /** |
| * Called when the model changes. |
| * |
| * @param e The ChangeEvent fired by the model. |
| */ |
| public void stateChanged(ChangeEvent e) |
| { |
| calculatePreferredSize(); |
| updateThumbRect(); |
| scrollbar.repaint(); |
| } |
| } |
| |
| /** |
| * A helper class that listens to the ScrollBar's properties. |
| */ |
| public class PropertyChangeHandler implements PropertyChangeListener |
| { |
| /** |
| * Called when one of the ScrollBar's properties change. |
| * |
| * @param e The PropertyChangeEvent fired by the ScrollBar. |
| */ |
| public void propertyChange(PropertyChangeEvent e) |
| { |
| if (e.getPropertyName().equals("model")) |
| { |
| ((BoundedRangeModel) e.getOldValue()).removeChangeListener(modelListener); |
| scrollbar.getModel().addChangeListener(modelListener); |
| updateThumbRect(); |
| } |
| else if (e.getPropertyName().equals("orientation")) |
| { |
| uninstallListeners(); |
| uninstallComponents(); |
| uninstallDefaults(); |
| installDefaults(); |
| installComponents(); |
| installListeners(); |
| } |
| else if (e.getPropertyName().equals("enabled")) |
| { |
| Boolean b = (Boolean) e.getNewValue(); |
| if (incrButton != null) |
| incrButton.setEnabled(b.booleanValue()); |
| if (decrButton != null) |
| decrButton.setEnabled(b.booleanValue()); |
| } |
| } |
| } |
| |
| /** |
| * A helper class that listens for events from the timer that is used to |
| * move the thumb. |
| */ |
| protected class ScrollListener implements ActionListener |
| { |
| /** The direction the thumb moves in. */ |
| private transient int direction; |
| |
| /** Whether movement will be in blocks. */ |
| private transient boolean block; |
| |
| /** |
| * Creates a new ScrollListener object. The default is scrolling |
| * positively with block movement. |
| */ |
| public ScrollListener() |
| { |
| direction = POSITIVE_SCROLL; |
| block = true; |
| } |
| |
| /** |
| * Creates a new ScrollListener object using the given direction and |
| * block. |
| * |
| * @param dir The direction to move in. |
| * @param block Whether movement will be in blocks. |
| */ |
| public ScrollListener(int dir, boolean block) |
| { |
| direction = dir; |
| this.block = block; |
| } |
| |
| /** |
| * Sets the direction to scroll in. |
| * |
| * @param direction The direction to scroll in. |
| */ |
| public void setDirection(int direction) |
| { |
| this.direction = direction; |
| } |
| |
| /** |
| * Sets whether scrolling will be done in blocks. |
| * |
| * @param block Whether scrolling will be in blocks. |
| */ |
| public void setScrollByBlock(boolean block) |
| { |
| this.block = block; |
| } |
| |
| /** |
| * Called every time the timer reaches its interval. |
| * |
| * @param e The ActionEvent fired by the timer. |
| */ |
| public void actionPerformed(ActionEvent e) |
| { |
| if (block) |
| { |
| // Only need to check it if it's block scrolling |
| // We only block scroll if the click occurs |
| // in the track. |
| if (!trackListener.shouldScroll(direction)) |
| { |
| trackHighlight = NO_HIGHLIGHT; |
| scrollbar.repaint(); |
| return; |
| } |
| scrollByBlock(direction); |
| } |
| else |
| scrollByUnit(direction); |
| } |
| } |
| |
| /** |
| * Helper class that listens for movement on the track. |
| */ |
| protected class TrackListener extends MouseAdapter |
| implements MouseMotionListener |
| { |
| /** The current X coordinate of the mouse. */ |
| protected int currentMouseX; |
| |
| /** The current Y coordinate of the mouse. */ |
| protected int currentMouseY; |
| |
| /** |
| * The offset between the current mouse cursor and the current value of |
| * the scrollbar. |
| */ |
| protected int offset; |
| |
| /** |
| * This method is called when the mouse is being dragged. |
| * |
| * @param e The MouseEvent given. |
| */ |
| public void mouseDragged(MouseEvent e) |
| { |
| currentMouseX = e.getX(); |
| currentMouseY = e.getY(); |
| if (scrollbar.getValueIsAdjusting()) |
| { |
| int value; |
| if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL) |
| value = valueForXPosition(currentMouseX) - offset; |
| else |
| value = valueForYPosition(currentMouseY) - offset; |
| |
| scrollbar.setValue(value); |
| } |
| } |
| |
| /** |
| * This method is called when the mouse is moved. |
| * |
| * @param e The MouseEvent given. |
| */ |
| public void mouseMoved(MouseEvent e) |
| { |
| if (thumbRect.contains(e.getPoint())) |
| thumbRollover = true; |
| else |
| thumbRollover = false; |
| } |
| |
| /** |
| * This method is called when the mouse is pressed. When it is pressed, |
| * the thumb should move in blocks towards the cursor. |
| * |
| * @param e The MouseEvent given. |
| */ |
| public void mousePressed(MouseEvent e) |
| { |
| currentMouseX = e.getX(); |
| currentMouseY = e.getY(); |
| |
| int value; |
| if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL) |
| value = valueForXPosition(currentMouseX); |
| else |
| value = valueForYPosition(currentMouseY); |
| |
| if (! thumbRect.contains(e.getPoint())) |
| { |
| scrollTimer.stop(); |
| scrollListener.setScrollByBlock(true); |
| if (value > scrollbar.getValue()) |
| { |
| trackHighlight = INCREASE_HIGHLIGHT; |
| scrollListener.setDirection(POSITIVE_SCROLL); |
| } |
| else |
| { |
| trackHighlight = DECREASE_HIGHLIGHT; |
| scrollListener.setDirection(NEGATIVE_SCROLL); |
| } |
| scrollTimer.setDelay(100); |
| scrollTimer.start(); |
| } |
| else |
| { |
| // We'd like to keep track of where the cursor |
| // is inside the thumb. |
| // This works because the scrollbar's value represents |
| // "lower" edge of the thumb. The value at which |
| // the cursor is at must be greater or equal |
| // to that value. |
| |
| scrollListener.setScrollByBlock(false); |
| scrollbar.setValueIsAdjusting(true); |
| offset = value - scrollbar.getValue(); |
| } |
| scrollbar.repaint(); |
| } |
| |
| /** |
| * This method is called when the mouse is released. It should stop |
| * movement on the thumb |
| * |
| * @param e The MouseEvent given. |
| */ |
| public void mouseReleased(MouseEvent e) |
| { |
| scrollTimer.stop(); |
| scrollTimer.setDelay(300); |
| currentMouseX = e.getX(); |
| currentMouseY = e.getY(); |
| |
| if (shouldScroll(POSITIVE_SCROLL)) |
| scrollByBlock(POSITIVE_SCROLL); |
| else if (shouldScroll(NEGATIVE_SCROLL)) |
| scrollByBlock(NEGATIVE_SCROLL); |
| |
| trackHighlight = NO_HIGHLIGHT; |
| scrollListener.setScrollByBlock(false); |
| scrollbar.setValueIsAdjusting(true); |
| scrollbar.repaint(); |
| } |
| |
| /** |
| * A helper method that decides whether we should keep scrolling in the |
| * given direction. |
| * |
| * @param direction The direction to check for. |
| * |
| * @return Whether the thumb should keep scrolling. |
| */ |
| boolean shouldScroll(int direction) |
| { |
| int value; |
| if (scrollbar.getOrientation() == HORIZONTAL) |
| value = valueForXPosition(currentMouseX); |
| else |
| value = valueForYPosition(currentMouseY); |
| |
| if (thumbRect.contains(currentMouseX, currentMouseY)) |
| return false; |
| |
| if (direction == POSITIVE_SCROLL) |
| return value > scrollbar.getValue(); |
| else |
| return value < scrollbar.getValue(); |
| } |
| } |
| |
| /** The listener that listens to the JButtons. */ |
| protected ArrowButtonListener buttonListener; |
| |
| /** The listener that listens to the model. */ |
| protected ModelListener modelListener; |
| |
| /** The listener that listens to the scrollbar for property changes. */ |
| protected PropertyChangeListener propertyChangeListener; |
| |
| /** The listener that listens to the timer. */ |
| protected ScrollListener scrollListener; |
| |
| /** The listener that listens for MouseEvents on the track. */ |
| protected TrackListener trackListener; |
| |
| /** The JButton that decrements the scrollbar's value. */ |
| protected JButton decrButton; |
| |
| /** The JButton that increments the scrollbar's value. */ |
| protected JButton incrButton; |
| |
| /** The dimensions of the maximum thumb size. */ |
| protected Dimension maximumThumbSize; |
| |
| /** The dimensions of the minimum thumb size. */ |
| protected Dimension minimumThumbSize; |
| |
| /** The color of the thumb. */ |
| protected Color thumbColor; |
| |
| /** The outer shadow of the thumb. */ |
| protected Color thumbDarkShadowColor; |
| |
| /** The top and left edge color for the thumb. */ |
| protected Color thumbHighlightColor; |
| |
| /** The outer light shadow for the thumb. */ |
| protected Color thumbLightShadowColor; |
| |
| /** The color that is used when the mouse press occurs in the track. */ |
| protected Color trackHighlightColor; |
| |
| /** The color of the track. */ |
| protected Color trackColor; |
| |
| /** The size and position of the track. */ |
| protected Rectangle trackRect; |
| |
| /** The size and position of the thumb. */ |
| protected Rectangle thumbRect; |
| |
| /** Indicates that the decrease highlight should be painted. */ |
| protected static final int DECREASE_HIGHLIGHT = 1; |
| |
| /** Indicates that the increase highlight should be painted. */ |
| protected static final int INCREASE_HIGHLIGHT = 2; |
| |
| /** Indicates that no highlight should be painted. */ |
| protected static final int NO_HIGHLIGHT = 0; |
| |
| /** Indicates that the scrolling direction is positive. */ |
| private static final int POSITIVE_SCROLL = 1; |
| |
| /** Indicates that the scrolling direction is negative. */ |
| private static final int NEGATIVE_SCROLL = -1; |
| |
| /** The cached preferred size for the scrollbar. */ |
| private transient Dimension preferredSize; |
| |
| /** The current highlight status. */ |
| protected int trackHighlight; |
| |
| /** FIXME: Use this for something (presumably mouseDragged) */ |
| protected boolean isDragging; |
| |
| /** The timer used to move the thumb when the mouse is held. */ |
| protected Timer scrollTimer; |
| |
| /** The scrollbar this UI is acting for. */ |
| protected JScrollBar scrollbar; |
| |
| /** True if the mouse is over the thumb. */ |
| boolean thumbRollover; |
| |
| /** |
| * This method adds a component to the layout. |
| * |
| * @param name The name to associate with the component that is added. |
| * @param child The Component to add. |
| */ |
| public void addLayoutComponent(String name, Component child) |
| { |
| // You should not be adding stuff to this component. |
| // The contents are fixed. |
| } |
| |
| /** |
| * This method configures the scrollbar's colors. This can be done by |
| * looking up the standard colors from the Look and Feel defaults. |
| */ |
| protected void configureScrollBarColors() |
| { |
| trackColor = UIManager.getColor("ScrollBar.track"); |
| trackHighlightColor = UIManager.getColor("ScrollBar.trackHighlight"); |
| thumbColor = UIManager.getColor("ScrollBar.thumb"); |
| thumbHighlightColor = UIManager.getColor("ScrollBar.thumbHighlight"); |
| thumbDarkShadowColor = UIManager.getColor("ScrollBar.thumbDarkShadow"); |
| thumbLightShadowColor = UIManager.getColor("ScrollBar.thumbShadow"); |
| } |
| |
| /** |
| * This method creates an ArrowButtonListener. |
| * |
| * @return A new ArrowButtonListener. |
| */ |
| protected ArrowButtonListener createArrowButtonListener() |
| { |
| return new ArrowButtonListener(); |
| } |
| |
| /** |
| * This method creates a new JButton with the appropriate icon for the |
| * orientation. |
| * |
| * @param orientation The orientation this JButton uses. |
| * |
| * @return The increase JButton. |
| */ |
| protected JButton createIncreaseButton(int orientation) |
| { |
| return new BasicArrowButton(orientation); |
| } |
| |
| /** |
| * This method creates a new JButton with the appropriate icon for the |
| * orientation. |
| * |
| * @param orientation The orientation this JButton uses. |
| * |
| * @return The decrease JButton. |
| */ |
| protected JButton createDecreaseButton(int orientation) |
| { |
| return new BasicArrowButton(orientation); |
| } |
| |
| /** |
| * This method creates a new ModelListener. |
| * |
| * @return A new ModelListener. |
| */ |
| protected ModelListener createModelListener() |
| { |
| return new ModelListener(); |
| } |
| |
| /** |
| * This method creates a new PropertyChangeListener. |
| * |
| * @return A new PropertyChangeListener. |
| */ |
| protected PropertyChangeListener createPropertyChangeListener() |
| { |
| return new PropertyChangeHandler(); |
| } |
| |
| /** |
| * This method creates a new ScrollListener. |
| * |
| * @return A new ScrollListener. |
| */ |
| protected ScrollListener createScrollListener() |
| { |
| return new ScrollListener(); |
| } |
| |
| /** |
| * This method creates a new TrackListener. |
| * |
| * @return A new TrackListener. |
| */ |
| protected TrackListener createTrackListener() |
| { |
| return new TrackListener(); |
| } |
| |
| /** |
| * This method returns a new BasicScrollBarUI. |
| * |
| * @param c The JComponent to create a UI for. |
| * |
| * @return A new BasicScrollBarUI. |
| */ |
| public static ComponentUI createUI(JComponent c) |
| { |
| return new BasicScrollBarUI(); |
| } |
| |
| /** |
| * This method returns the maximum size for this JComponent. |
| * |
| * @param c The JComponent to measure the maximum size for. |
| * |
| * @return The maximum size for the component. |
| */ |
| public Dimension getMaximumSize(JComponent c) |
| { |
| return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); |
| } |
| |
| /** |
| * This method returns the maximum thumb size. |
| * |
| * @return The maximum thumb size. |
| */ |
| protected Dimension getMaximumThumbSize() |
| { |
| return maximumThumbSize; |
| } |
| |
| /** |
| * This method returns the minimum size for this JComponent. |
| * |
| * @param c The JComponent to measure the minimum size for. |
| * |
| * @return The minimum size for the component. |
| */ |
| public Dimension getMinimumSize(JComponent c) |
| { |
| return getPreferredSize(c); |
| } |
| |
| /** |
| * This method returns the minimum thumb size. |
| * |
| * @return The minimum thumb size. |
| */ |
| protected Dimension getMinimumThumbSize() |
| { |
| return minimumThumbSize; |
| } |
| |
| /** |
| * This method calculates the preferred size since calling |
| * getPreferredSize() returns a cached value. |
| * This is package-private to avoid an accessor method. |
| */ |
| void calculatePreferredSize() |
| { |
| int height; |
| int width; |
| height = width = 0; |
| |
| if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL) |
| { |
| width += incrButton.getPreferredSize().getWidth(); |
| width += decrButton.getPreferredSize().getWidth(); |
| width += 16; |
| height = UIManager.getInt("ScrollBar.width"); |
| } |
| else |
| { |
| height += incrButton.getPreferredSize().getHeight(); |
| height += decrButton.getPreferredSize().getHeight(); |
| height += 16; |
| width = UIManager.getInt("ScrollBar.width"); |
| } |
| |
| Insets insets = scrollbar.getInsets(); |
| |
| height += insets.top + insets.bottom; |
| width += insets.left + insets.right; |
| |
| preferredSize = new Dimension(width, height); |
| } |
| |
| /** |
| * This method returns a cached value of the preferredSize. The only |
| * restrictions are: If the scrollbar is horizontal, the height should be |
| * the maximum of the height of the JButtons and the minimum width of the |
| * thumb. For vertical scrollbars, the calculation is similar (swap width |
| * for height and vice versa). |
| * |
| * @param c The JComponent to measure. |
| * |
| * @return The preferredSize. |
| */ |
| public Dimension getPreferredSize(JComponent c) |
| { |
| calculatePreferredSize(); |
| return preferredSize; |
| } |
| |
| /** |
| * This method returns the thumb's bounds based on the current value of the |
| * scrollbar. This method updates the cached value and returns that. |
| * |
| * @return The thumb bounds. |
| */ |
| protected Rectangle getThumbBounds() |
| { |
| return thumbRect; |
| } |
| |
| /** |
| * This method calculates the bounds of the track. This method updates the |
| * cached value and returns it. |
| * |
| * @return The track's bounds. |
| */ |
| protected Rectangle getTrackBounds() |
| { |
| return trackRect; |
| } |
| |
| /** |
| * This method installs any addition Components that are a part of or |
| * related to this scrollbar. |
| */ |
| protected void installComponents() |
| { |
| int orientation = scrollbar.getOrientation(); |
| switch (orientation) |
| { |
| case JScrollBar.HORIZONTAL: |
| incrButton = createIncreaseButton(EAST); |
| decrButton = createDecreaseButton(WEST); |
| break; |
| default: |
| incrButton = createIncreaseButton(SOUTH); |
| decrButton = createDecreaseButton(NORTH); |
| break; |
| } |
| |
| if (incrButton != null) |
| scrollbar.add(incrButton); |
| if (decrButton != null) |
| scrollbar.add(decrButton); |
| } |
| |
| /** |
| * This method installs the defaults for the scrollbar specified by the |
| * Basic Look and Feel. |
| */ |
| protected void installDefaults() |
| { |
| LookAndFeel.installColors(scrollbar, "ScrollBar.background", |
| "ScrollBar.foreground"); |
| LookAndFeel.installBorder(scrollbar, "ScrollBar.border"); |
| scrollbar.setOpaque(true); |
| scrollbar.setLayout(this); |
| |
| thumbColor = UIManager.getColor("ScrollBar.thumb"); |
| thumbDarkShadowColor = UIManager.getColor("ScrollBar.thumbDarkShadow"); |
| thumbHighlightColor = UIManager.getColor("ScrollBar.thumbHighlight"); |
| thumbLightShadowColor = UIManager.getColor("ScrollBar.thumbShadow"); |
| |
| maximumThumbSize = UIManager.getDimension("ScrollBar.maximumThumbSize"); |
| minimumThumbSize = UIManager.getDimension("ScrollBar.minimumThumbSize"); |
| } |
| |
| /** |
| * Installs the input map from the look and feel defaults, and a |
| * corresponding action map. Note the the keyboard bindings will only |
| * work when the {@link JScrollBar} component has the focus, which is rare. |
| */ |
| protected void installKeyboardActions() |
| { |
| InputMap keyMap = getInputMap( |
| JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); |
| SwingUtilities.replaceUIInputMap(scrollbar, |
| JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, keyMap); |
| ActionMap map = getActionMap(); |
| SwingUtilities.replaceUIActionMap(scrollbar, map); |
| } |
| |
| /** |
| * Uninstalls the input map and action map installed by |
| * {@link #installKeyboardActions()}. |
| */ |
| protected void uninstallKeyboardActions() |
| { |
| SwingUtilities.replaceUIActionMap(scrollbar, null); |
| SwingUtilities.replaceUIInputMap(scrollbar, |
| JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null); |
| } |
| |
| InputMap getInputMap(int condition) |
| { |
| if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) |
| return (InputMap) UIManager.get("ScrollBar.focusInputMap"); |
| return null; |
| } |
| |
| /** |
| * Returns the action map for the {@link JScrollBar}. All scroll bars |
| * share a single action map which is created the first time this method is |
| * called, then stored in the UIDefaults table for subsequent access. |
| * |
| * @return The shared action map. |
| */ |
| ActionMap getActionMap() |
| { |
| ActionMap map = (ActionMap) UIManager.get("ScrollBar.actionMap"); |
| |
| if (map == null) // first time here |
| { |
| map = createActionMap(); |
| if (map != null) |
| UIManager.put("ScrollBar.actionMap", map); |
| } |
| return map; |
| } |
| |
| /** |
| * Creates the action map shared by all {@link JSlider} instances. |
| * This method is called once by {@link #getActionMap()} when it |
| * finds no action map in the UIDefaults table...after the map is |
| * created, it gets added to the defaults table so that subsequent |
| * calls to {@link #getActionMap()} will return the same shared |
| * instance. |
| * |
| * @return The action map. |
| */ |
| ActionMap createActionMap() |
| { |
| ActionMap map = new ActionMapUIResource(); |
| map.put("positiveUnitIncrement", |
| new AbstractAction("positiveUnitIncrement") { |
| public void actionPerformed(ActionEvent event) |
| { |
| JScrollBar sb = (JScrollBar) event.getSource(); |
| if (sb.isVisible()) |
| { |
| int delta = sb.getUnitIncrement(1); |
| sb.setValue(sb.getValue() + delta); |
| } |
| } |
| } |
| ); |
| map.put("positiveBlockIncrement", |
| new AbstractAction("positiveBlockIncrement") { |
| public void actionPerformed(ActionEvent event) |
| { |
| JScrollBar sb = (JScrollBar) event.getSource(); |
| if (sb.isVisible()) |
| { |
| int delta = sb.getBlockIncrement(1); |
| sb.setValue(sb.getValue() + delta); |
| } |
| } |
| } |
| ); |
| map.put("negativeUnitIncrement", |
| new AbstractAction("negativeUnitIncrement") { |
| public void actionPerformed(ActionEvent event) |
| { |
| JScrollBar sb = (JScrollBar) event.getSource(); |
| if (sb.isVisible()) |
| { |
| int delta = sb.getUnitIncrement(-1); |
| sb.setValue(sb.getValue() + delta); |
| } |
| } |
| } |
| ); |
| map.put("negativeBlockIncrement", |
| new AbstractAction("negativeBlockIncrement") { |
| public void actionPerformed(ActionEvent event) |
| { |
| JScrollBar sb = (JScrollBar) event.getSource(); |
| if (sb.isVisible()) |
| { |
| int delta = sb.getBlockIncrement(-1); |
| sb.setValue(sb.getValue() + delta); |
| } |
| } |
| } |
| ); |
| map.put("minScroll", |
| new AbstractAction("minScroll") { |
| public void actionPerformed(ActionEvent event) |
| { |
| JScrollBar sb = (JScrollBar) event.getSource(); |
| if (sb.isVisible()) |
| { |
| sb.setValue(sb.getMinimum()); |
| } |
| } |
| } |
| ); |
| map.put("maxScroll", |
| new AbstractAction("maxScroll") { |
| public void actionPerformed(ActionEvent event) |
| { |
| JScrollBar sb = (JScrollBar) event.getSource(); |
| if (sb.isVisible()) |
| { |
| sb.setValue(sb.getMaximum()); |
| } |
| } |
| } |
| ); |
| return map; |
| } |
| |
| /** |
| * This method installs any listeners for the scrollbar. This method also |
| * installs listeners for things such as the JButtons and the timer. |
| */ |
| protected void installListeners() |
| { |
| scrollListener = createScrollListener(); |
| trackListener = createTrackListener(); |
| buttonListener = createArrowButtonListener(); |
| modelListener = createModelListener(); |
| propertyChangeListener = createPropertyChangeListener(); |
| |
| scrollbar.addMouseMotionListener(trackListener); |
| scrollbar.addMouseListener(trackListener); |
| |
| incrButton.addMouseListener(buttonListener); |
| decrButton.addMouseListener(buttonListener); |
| |
| scrollbar.addPropertyChangeListener(propertyChangeListener); |
| scrollbar.getModel().addChangeListener(modelListener); |
| |
| scrollTimer.addActionListener(scrollListener); |
| } |
| |
| /** |
| * This method installs the UI for the component. This can include setting |
| * up listeners, defaults, and components. This also includes initializing |
| * any data objects. |
| * |
| * @param c The JComponent to install. |
| */ |
| public void installUI(JComponent c) |
| { |
| super.installUI(c); |
| if (c instanceof JScrollBar) |
| { |
| scrollbar = (JScrollBar) c; |
| |
| trackRect = new Rectangle(); |
| thumbRect = new Rectangle(); |
| |
| scrollTimer = new Timer(300, null); |
| |
| installDefaults(); |
| installComponents(); |
| configureScrollBarColors(); |
| installListeners(); |
| installKeyboardActions(); |
| |
| calculatePreferredSize(); |
| } |
| } |
| |
| /** |
| * This method lays out the scrollbar. |
| * |
| * @param scrollbarContainer The Container to layout. |
| */ |
| public void layoutContainer(Container scrollbarContainer) |
| { |
| if (scrollbarContainer instanceof JScrollBar) |
| { |
| if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL) |
| layoutHScrollbar((JScrollBar) scrollbarContainer); |
| else |
| layoutVScrollbar((JScrollBar) scrollbarContainer); |
| } |
| } |
| |
| /** |
| * This method lays out the scrollbar horizontally. |
| * |
| * @param sb The JScrollBar to layout. |
| */ |
| protected void layoutHScrollbar(JScrollBar sb) |
| { |
| Rectangle vr = new Rectangle(); |
| SwingUtilities.calculateInnerArea(scrollbar, vr); |
| |
| Dimension incrDims = incrButton.getPreferredSize(); |
| Dimension decrDims = decrButton.getPreferredSize(); |
| |
| // calculate and update the track bounds |
| SwingUtilities.calculateInnerArea(scrollbar, trackRect); |
| trackRect.width -= incrDims.getWidth(); |
| trackRect.width -= decrDims.getWidth(); |
| trackRect.x += decrDims.getWidth(); |
| |
| updateThumbRect(); |
| |
| decrButton.setBounds(vr.x, vr.y, decrDims.width, trackRect.height); |
| incrButton.setBounds(trackRect.x + trackRect.width, vr.y, incrDims.width, |
| trackRect.height); |
| } |
| |
| /** |
| * This method lays out the scrollbar vertically. |
| * |
| * @param sb The JScrollBar to layout. |
| */ |
| protected void layoutVScrollbar(JScrollBar sb) |
| { |
| Rectangle vr = new Rectangle(); |
| SwingUtilities.calculateInnerArea(scrollbar, vr); |
| |
| Dimension incrDims = incrButton.getPreferredSize(); |
| Dimension decrDims = decrButton.getPreferredSize(); |
| |
| // Update rectangles |
| SwingUtilities.calculateInnerArea(scrollbar, trackRect); |
| trackRect.height -= incrDims.getHeight(); |
| trackRect.height -= decrDims.getHeight(); |
| trackRect.y += decrDims.getHeight(); |
| |
| updateThumbRect(); |
| |
| decrButton.setBounds(vr.x, vr.y, trackRect.width, decrDims.height); |
| incrButton.setBounds(vr.x, trackRect.y + trackRect.height, |
| trackRect.width, incrDims.height); |
| } |
| |
| /** |
| * Updates the thumb rect. |
| */ |
| void updateThumbRect() |
| { |
| int max = scrollbar.getMaximum(); |
| int min = scrollbar.getMinimum(); |
| int value = scrollbar.getValue(); |
| int extent = scrollbar.getVisibleAmount(); |
| if (max - extent <= min) |
| { |
| if (scrollbar.getOrientation() == JScrollBar.HORIZONTAL) |
| { |
| thumbRect.x = trackRect.x; |
| thumbRect.y = trackRect.y; |
| thumbRect.width = getMinimumThumbSize().width; |
| thumbRect.height = trackRect.height; |
| } |
| else |
| { |
| thumbRect.x = trackRect.x; |
| thumbRect.y = trackRect.y; |
| thumbRect.width = trackRect.width; |
| thumbRect.height = getMinimumThumbSize().height; |
| } |
| } |
| else |
| { |
| if (scrollbar.getOrientation() == JScrollBar.HORIZONTAL) |
| { |
| thumbRect.x = trackRect.x; |
| thumbRect.width = Math.max(extent * trackRect.width / (max - min), |
| getMinimumThumbSize().width); |
| int availableWidth = trackRect.width - thumbRect.width; |
| thumbRect.x += (value - min) * availableWidth / (max - min - extent); |
| thumbRect.y = trackRect.y; |
| thumbRect.height = trackRect.height; |
| } |
| else |
| { |
| thumbRect.x = trackRect.x; |
| thumbRect.height = Math.max(extent * trackRect.height / (max - min), |
| getMinimumThumbSize().height); |
| int availableHeight = trackRect.height - thumbRect.height; |
| thumbRect.y = trackRect.y |
| + (value - min) * availableHeight / (max - min - extent); |
| thumbRect.width = trackRect.width; |
| } |
| } |
| |
| } |
| |
| /** |
| * This method returns the minimum size required for the layout. |
| * |
| * @param scrollbarContainer The Container that is laid out. |
| * |
| * @return The minimum size. |
| */ |
| public Dimension minimumLayoutSize(Container scrollbarContainer) |
| { |
| return preferredLayoutSize(scrollbarContainer); |
| } |
| |
| /** |
| * This method is called when the component is painted. |
| * |
| * @param g The Graphics object to paint with. |
| * @param c The JComponent to paint. |
| */ |
| public void paint(Graphics g, JComponent c) |
| { |
| paintTrack(g, c, getTrackBounds()); |
| paintThumb(g, c, getThumbBounds()); |
| |
| if (trackHighlight == INCREASE_HIGHLIGHT) |
| paintIncreaseHighlight(g); |
| else if (trackHighlight == DECREASE_HIGHLIGHT) |
| paintDecreaseHighlight(g); |
| } |
| |
| /** |
| * This method is called when repainting and the mouse is pressed in the |
| * track. It paints the track below the thumb with the trackHighlight |
| * color. |
| * |
| * @param g The Graphics object to paint with. |
| */ |
| protected void paintDecreaseHighlight(Graphics g) |
| { |
| Color saved = g.getColor(); |
| |
| g.setColor(trackHighlightColor); |
| if (scrollbar.getOrientation() == HORIZONTAL) |
| g.fillRect(trackRect.x, trackRect.y, thumbRect.x - trackRect.x, |
| trackRect.height); |
| else |
| g.fillRect(trackRect.x, trackRect.y, trackRect.width, |
| thumbRect.y - trackRect.y); |
| g.setColor(saved); |
| } |
| |
| /** |
| * This method is called when repainting and the mouse is pressed in the |
| * track. It paints the track above the thumb with the trackHighlight |
| * color. |
| * |
| * @param g The Graphics objet to paint with. |
| */ |
| protected void paintIncreaseHighlight(Graphics g) |
| { |
| Color saved = g.getColor(); |
| |
| g.setColor(trackHighlightColor); |
| if (scrollbar.getOrientation() == HORIZONTAL) |
| g.fillRect(thumbRect.x + thumbRect.width, trackRect.y, |
| trackRect.x + trackRect.width - thumbRect.x - thumbRect.width, |
| trackRect.height); |
| else |
| g.fillRect(trackRect.x, thumbRect.y + thumbRect.height, trackRect.width, |
| trackRect.y + trackRect.height - thumbRect.y |
| - thumbRect.height); |
| g.setColor(saved); |
| } |
| |
| /** |
| * This method paints the thumb. |
| * |
| * @param g The Graphics object to paint with. |
| * @param c The Component that is being painted. |
| * @param thumbBounds The thumb bounds. |
| */ |
| protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) |
| { |
| g.setColor(thumbColor); |
| g.fillRect(thumbBounds.x, thumbBounds.y, thumbBounds.width, |
| thumbBounds.height); |
| |
| BasicGraphicsUtils.drawBezel(g, thumbBounds.x, thumbBounds.y, |
| thumbBounds.width, thumbBounds.height, |
| false, false, thumbDarkShadowColor, |
| thumbDarkShadowColor, thumbHighlightColor, |
| thumbHighlightColor); |
| } |
| |
| /** |
| * This method paints the track. |
| * |
| * @param g The Graphics object to paint with. |
| * @param c The JComponent being painted. |
| * @param trackBounds The track's bounds. |
| */ |
| protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds) |
| { |
| Color saved = g.getColor(); |
| g.setColor(trackColor); |
| g.fill3DRect(trackBounds.x, trackBounds.y, trackBounds.width, |
| trackBounds.height, false); |
| g.setColor(saved); |
| } |
| |
| /** |
| * This method returns the preferred size for the layout. |
| * |
| * @param scrollbarContainer The Container to find a size for. |
| * |
| * @return The preferred size for the layout. |
| */ |
| public Dimension preferredLayoutSize(Container scrollbarContainer) |
| { |
| if (scrollbarContainer instanceof JComponent) |
| return getPreferredSize((JComponent) scrollbarContainer); |
| else |
| return null; |
| } |
| |
| /** |
| * This method removes a child component from the layout. |
| * |
| * @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) |
| { |
| scrollbar.setValue(scrollbar.getValue() |
| + scrollbar.getBlockIncrement(direction)); |
| } |
| |
| /** |
| * The method scrolls the thumb by a unit in the direction specified. |
| * |
| * @param direction The direction to scroll. |
| */ |
| protected void scrollByUnit(int direction) |
| { |
| scrollbar.setValue(scrollbar.getValue() |
| + scrollbar.getUnitIncrement(direction)); |
| } |
| |
| /** |
| * 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; |
| thumbRect.height = height; |
| } |
| |
| /** |
| * This method uninstalls any components that are a part of or related to |
| * this scrollbar. |
| */ |
| protected void uninstallComponents() |
| { |
| if (incrButton != null) |
| scrollbar.remove(incrButton); |
| if (decrButton != null) |
| scrollbar.remove(decrButton); |
| } |
| |
| /** |
| * This method uninstalls any defaults that this scrollbar acquired from the |
| * Basic Look and Feel defaults. |
| */ |
| protected void uninstallDefaults() |
| { |
| scrollbar.setForeground(null); |
| scrollbar.setBackground(null); |
| LookAndFeel.uninstallBorder(scrollbar); |
| incrButton = null; |
| decrButton = null; |
| } |
| |
| /** |
| * This method uninstalls any listeners that were registered during install. |
| */ |
| protected void uninstallListeners() |
| { |
| if (scrollTimer != null) |
| scrollTimer.removeActionListener(scrollListener); |
| |
| if (scrollbar != null) |
| { |
| scrollbar.getModel().removeChangeListener(modelListener); |
| scrollbar.removePropertyChangeListener(propertyChangeListener); |
| scrollbar.removeMouseListener(trackListener); |
| scrollbar.removeMouseMotionListener(trackListener); |
| } |
| |
| if (decrButton != null) |
| decrButton.removeMouseListener(buttonListener); |
| if (incrButton != null) |
| incrButton.removeMouseListener(buttonListener); |
| |
| propertyChangeListener = null; |
| modelListener = null; |
| buttonListener = null; |
| trackListener = null; |
| scrollListener = null; |
| } |
| |
| /** |
| * This method uninstalls the UI. This includes removing any defaults, |
| * listeners, and components that this UI may have initialized. It also |
| * nulls any instance data. |
| * |
| * @param c The Component to uninstall for. |
| */ |
| public void uninstallUI(JComponent c) |
| { |
| uninstallKeyboardActions(); |
| uninstallListeners(); |
| uninstallDefaults(); |
| uninstallComponents(); |
| |
| scrollTimer = null; |
| |
| thumbRect = null; |
| trackRect = null; |
| |
| trackColor = null; |
| trackHighlightColor = null; |
| thumbColor = null; |
| thumbHighlightColor = null; |
| thumbDarkShadowColor = null; |
| thumbLightShadowColor = null; |
| |
| scrollbar = null; |
| } |
| |
| /** |
| * This method returns the value in the scrollbar's range given the y |
| * coordinate. If the value is out of range, it will return the closest |
| * legal value. |
| * This is package-private to avoid an accessor method. |
| * |
| * @param yPos The y coordinate to calculate a value for. |
| * |
| * @return The value for the y coordinate. |
| */ |
| int valueForYPosition(int yPos) |
| { |
| int min = scrollbar.getMinimum(); |
| int max = scrollbar.getMaximum(); |
| int len = trackRect.height; |
| |
| int value; |
| |
| // If the length is 0, you shouldn't be able to even see where the thumb is. |
| // This really shouldn't ever happen, but just in case, we'll return the middle. |
| if (len == 0) |
| return (max - min) / 2; |
| |
| value = (yPos - trackRect.y) * (max - min) / len + min; |
| |
| // If this isn't a legal value, then we'll have to move to one now. |
| if (value > max) |
| value = max; |
| else if (value < min) |
| value = min; |
| return value; |
| } |
| |
| /** |
| * This method returns the value in the scrollbar's range given the x |
| * coordinate. If the value is out of range, it will return the closest |
| * legal value. |
| * This is package-private to avoid an accessor method. |
| * |
| * @param xPos The x coordinate to calculate a value for. |
| * |
| * @return The value for the x coordinate. |
| */ |
| int valueForXPosition(int xPos) |
| { |
| int min = scrollbar.getMinimum(); |
| int max = scrollbar.getMaximum(); |
| int len = trackRect.width; |
| |
| int value; |
| |
| // If the length is 0, you shouldn't be able to even see where the slider is. |
| // This really shouldn't ever happen, but just in case, we'll return the middle. |
| if (len == 0) |
| return (max - min) / 2; |
| |
| value = (xPos - trackRect.x) * (max - min) / len + min; |
| |
| // If this isn't a legal value, then we'll have to move to one now. |
| if (value > max) |
| value = max; |
| else if (value < min) |
| value = min; |
| return value; |
| } |
| |
| /** |
| * Returns true if the mouse is over the thumb. |
| * |
| * @return true if the mouse is over the thumb. |
| * |
| * @since 1.5 |
| */ |
| public boolean isThumbRollover() |
| { |
| return thumbRollover; |
| } |
| |
| /** |
| * Set thumbRollover to active. This indicates |
| * whether or not the mouse is over the thumb. |
| * |
| * @param active - true if the mouse is over the thumb. |
| * |
| * @since 1.5 |
| */ |
| protected void setThumbRollover(boolean active) |
| { |
| thumbRollover = active; |
| } |
| |
| /** |
| * Indicates whether the user can position the thumb with |
| * a mouse click (i.e. middle button). |
| * |
| * @return true if the user can position the thumb with a mouse |
| * click. |
| * |
| * @since 1.5 |
| */ |
| public boolean getSupportsAbsolutePositioning() |
| { |
| // The positioning feature has not been implemented. |
| // So, false is always returned. |
| return false; |
| } |
| } |