FileDocCategorySizeDatePackage
BasicScrollBarUI.javaAPI DocJava SE 6 API49550Tue Jun 10 00:26:48 BST 2008javax.swing.plaf.basic

BasicScrollBarUI

public class BasicScrollBarUI extends ScrollBarUI implements SwingConstants, LayoutManager
Implementation of ScrollBarUI for the Basic Look and Feel
version
1.87 11/17/05
author
Rich Schiavi
author
David Kloba
author
Hans Muller

Fields Summary
private static final int
POSITIVE_SCROLL
private static final int
NEGATIVE_SCROLL
private static final int
MIN_SCROLL
private static final int
MAX_SCROLL
protected Dimension
minimumThumbSize
protected Dimension
maximumThumbSize
protected Color
thumbHighlightColor
protected Color
thumbLightShadowColor
protected Color
thumbDarkShadowColor
protected Color
thumbColor
protected Color
trackColor
protected Color
trackHighlightColor
protected JScrollBar
scrollbar
protected JButton
incrButton
protected JButton
decrButton
protected boolean
isDragging
protected TrackListener
trackListener
protected ArrowButtonListener
buttonListener
protected ModelListener
modelListener
protected Rectangle
thumbRect
protected Rectangle
trackRect
protected int
trackHighlight
protected static final int
NO_HIGHLIGHT
protected static final int
DECREASE_HIGHLIGHT
protected static final int
INCREASE_HIGHLIGHT
protected ScrollListener
scrollListener
protected PropertyChangeListener
propertyChangeListener
protected Timer
scrollTimer
private static final int
scrollSpeedThrottle
private boolean
supportsAbsolutePositioning
True indicates a middle click will absolutely position the scrollbar.
private int
scrollBarWidth
Hint as to what width (when vertical) or height (when horizontal) should be.
private Handler
handler
private boolean
thumbActive
private boolean
useCachedValue
Determine whether scrollbar layout should use cached value or adjusted value returned by scrollbar's getValue.
private int
scrollBarValue
The scrollbar value is cached to save real value if the view is adjusted.
Constructors Summary
Methods Summary
public voidaddLayoutComponent(java.lang.String name, java.awt.Component child)

protected voidconfigureScrollBarColors()

        LookAndFeel.installColors(scrollbar, "ScrollBar.background",
                                  "ScrollBar.foreground");
	thumbHighlightColor = UIManager.getColor("ScrollBar.thumbHighlight");
	thumbLightShadowColor = UIManager.getColor("ScrollBar.thumbShadow");
	thumbDarkShadowColor = UIManager.getColor("ScrollBar.thumbDarkShadow");
	thumbColor = UIManager.getColor("ScrollBar.thumb");
	trackColor = UIManager.getColor("ScrollBar.track");
	trackHighlightColor = UIManager.getColor("ScrollBar.trackHighlight");
    
protected javax.swing.plaf.basic.BasicScrollBarUI$ArrowButtonListenercreateArrowButtonListener()

	return new ArrowButtonListener();
    
protected javax.swing.JButtoncreateDecreaseButton(int orientation)

        return new BasicArrowButton(orientation, 
				    UIManager.getColor("ScrollBar.thumb"),
				    UIManager.getColor("ScrollBar.thumbShadow"),
				    UIManager.getColor("ScrollBar.thumbDarkShadow"),
				    UIManager.getColor("ScrollBar.thumbHighlight"));
    
protected javax.swing.JButtoncreateIncreaseButton(int orientation)

        return new BasicArrowButton(orientation,
				    UIManager.getColor("ScrollBar.thumb"),
				    UIManager.getColor("ScrollBar.thumbShadow"),
				    UIManager.getColor("ScrollBar.thumbDarkShadow"),
				    UIManager.getColor("ScrollBar.thumbHighlight"));
    
protected javax.swing.plaf.basic.BasicScrollBarUI$ModelListenercreateModelListener()

	return new ModelListener();
    
protected java.beans.PropertyChangeListenercreatePropertyChangeListener()

	return getHandler();
    
protected javax.swing.plaf.basic.BasicScrollBarUI$ScrollListenercreateScrollListener()

	return new ScrollListener();
    
protected javax.swing.plaf.basic.BasicScrollBarUI$TrackListenercreateTrackListener()

	return new TrackListener();
    
public static javax.swing.plaf.ComponentUIcreateUI(javax.swing.JComponent c)

        return new BasicScrollBarUI();
    
private javax.swing.plaf.basic.BasicScrollBarUI$HandlergetHandler()

        if (handler == null) {
            handler = new Handler();
        }
        return handler;
    
private javax.swing.InputMapgetInputMap(int condition)

	if (condition == JComponent.WHEN_FOCUSED) {
            InputMap keyMap = (InputMap)DefaultLookup.get(
                        scrollbar, this, "ScrollBar.focusInputMap");
            InputMap rtlKeyMap;

            if (scrollbar.getComponentOrientation().isLeftToRight() ||
                ((rtlKeyMap = (InputMap)DefaultLookup.get(scrollbar, this, "ScrollBar.focusInputMap.RightToLeft")) == null)) {
                return keyMap;
            } else {
                rtlKeyMap.setParent(keyMap);
                return rtlKeyMap;
            }
	}
	else if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
            InputMap keyMap = (InputMap)DefaultLookup.get(
                        scrollbar, this, "ScrollBar.ancestorInputMap");
            InputMap rtlKeyMap;

            if (scrollbar.getComponentOrientation().isLeftToRight() ||
                ((rtlKeyMap = (InputMap)DefaultLookup.get(scrollbar, this, "ScrollBar.ancestorInputMap.RightToLeft")) == null)) {
                return keyMap;
            } else {
                rtlKeyMap.setParent(keyMap);
                return rtlKeyMap;
            }
	}
	return null;
    
public java.awt.DimensiongetMaximumSize(javax.swing.JComponent c)

param
c The JScrollBar that's delegating this method to us.
return
new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
see
#getMinimumSize
see
#getPreferredSize

        return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
    
protected java.awt.DimensiongetMaximumThumbSize()
Return the largest acceptable size for the thumb. To create a fixed size thumb one make this method and getMinimumThumbSize return the same value.

Warning : the value returned by this method should not be be modified, it's a shared static constant.

return
The largest acceptable size for the thumb.
see
#getMinimumThumbSize

 
	return maximumThumbSize;
    
protected java.awt.DimensiongetMinimumThumbSize()
Return the smallest acceptable size for the thumb. If the scrollbar becomes so small that this size isn't available, the thumb will be hidden.

Warning : the value returned by this method should not be be modified, it's a shared static constant.

return
The smallest acceptable size for the thumb.
see
#getMaximumThumbSize

 
	return minimumThumbSize;
    
public java.awt.DimensiongetPreferredSize(javax.swing.JComponent c)
A vertical scrollbar's preferred width is the maximum of preferred widths of the (non null) increment/decrement buttons, and the minimum width of the thumb. The preferred height is the sum of the preferred heights of the same parts. The basis for the preferred size of a horizontal scrollbar is similar.

The preferredSize is only computed once, subsequent calls to this method just return a cached size.

param
c the JScrollBar that's delegating this method to us
return
the preferred size of a Basic JScrollBar
see
#getMaximumSize
see
#getMinimumSize

	return (scrollbar.getOrientation() == JScrollBar.VERTICAL)
	    ? new Dimension(scrollBarWidth, 48)
	    : new Dimension(48, scrollBarWidth);
    
public booleangetSupportsAbsolutePositioning()
Indicates whether the user can absolutely position the thumb with a mouse gesture (usually the middle mouse button).

return
true if a mouse gesture can absolutely position the thumb
since
1.5

	return supportsAbsolutePositioning;
    
protected java.awt.RectanglegetThumbBounds()
Return the current size/location of the thumb.

Warning : the value returned by this method should not be be modified, it's a reference to the actual rectangle, not a copy.

return
The current size/location of the thumb.
see
#setThumbBounds

	return thumbRect;
    
protected java.awt.RectanglegetTrackBounds()
Returns the current bounds of the track, i.e. the space in between the increment and decrement buttons, less the insets. The value returned by this method is updated each time the scrollbar is laid out (validated).

Warning : the value returned by this method should not be be modified, it's a reference to the actual rectangle, not a copy.

return
the current bounds of the scrollbar track
see
#layoutContainer

	return trackRect;
    
private intgetValue(javax.swing.JScrollBar sb)

	return (useCachedValue) ? scrollBarValue : sb.getValue();
    
protected voidinstallComponents()

        switch (scrollbar.getOrientation()) {
        case JScrollBar.VERTICAL:
            incrButton = createIncreaseButton(SOUTH);
            decrButton = createDecreaseButton(NORTH);
            break;
            
        case JScrollBar.HORIZONTAL:
            if (scrollbar.getComponentOrientation().isLeftToRight()) {    
                incrButton = createIncreaseButton(EAST);
                decrButton = createDecreaseButton(WEST);
            } else {
                incrButton = createIncreaseButton(WEST);
                decrButton = createDecreaseButton(EAST);
            }
            break;
        }
        scrollbar.add(incrButton);
        scrollbar.add(decrButton);
        // Force the children's enabled state to be updated.
	scrollbar.setEnabled(scrollbar.isEnabled());
    
protected voidinstallDefaults()

	scrollBarWidth = UIManager.getInt("ScrollBar.width");
        if (scrollBarWidth <= 0) {
            scrollBarWidth = 16;
        }
	minimumThumbSize = (Dimension)UIManager.get("ScrollBar.minimumThumbSize");
	maximumThumbSize = (Dimension)UIManager.get("ScrollBar.maximumThumbSize");

	Boolean absB = (Boolean)UIManager.get("ScrollBar.allowsAbsolutePositioning");
	supportsAbsolutePositioning = (absB != null) ? absB.booleanValue() :
	                              false;

	trackHighlight = NO_HIGHLIGHT;
        if (scrollbar.getLayout() == null ||
                     (scrollbar.getLayout() instanceof UIResource)) {
            scrollbar.setLayout(this);
        }
	configureScrollBarColors();
        LookAndFeel.installBorder(scrollbar, "ScrollBar.border");
	LookAndFeel.installProperty(scrollbar, "opaque", Boolean.TRUE);

	scrollBarValue = scrollbar.getValue();
    
protected voidinstallKeyboardActions()

        LazyActionMap.installLazyActionMap(scrollbar, BasicScrollBarUI.class,
                                           "ScrollBar.actionMap");

	InputMap inputMap = getInputMap(JComponent.WHEN_FOCUSED);
	SwingUtilities.replaceUIInputMap(scrollbar, JComponent.WHEN_FOCUSED,
					 inputMap);
	inputMap = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
	SwingUtilities.replaceUIInputMap(scrollbar,
                   JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap);
    
protected voidinstallListeners()

	trackListener = createTrackListener();
    	buttonListener = createArrowButtonListener();
    	modelListener = createModelListener();
	propertyChangeListener = createPropertyChangeListener();

	scrollbar.addMouseListener(trackListener);
	scrollbar.addMouseMotionListener(trackListener);
        scrollbar.getModel().addChangeListener(modelListener);
	scrollbar.addPropertyChangeListener(propertyChangeListener);
        scrollbar.addFocusListener(getHandler());

        if (incrButton != null) {
            incrButton.addMouseListener(buttonListener);
	}
        if (decrButton != null)	{
            decrButton.addMouseListener(buttonListener);
	}

	scrollListener = createScrollListener();
	scrollTimer = new Timer(scrollSpeedThrottle, scrollListener);
	scrollTimer.setInitialDelay(300);  // default InitialDelay?
    
public voidinstallUI(javax.swing.JComponent c)

	scrollbar = (JScrollBar)c;
        thumbRect = new Rectangle(0, 0, 0, 0);
        trackRect = new Rectangle(0, 0, 0, 0);
	installDefaults();
	installComponents();
	installListeners();
	installKeyboardActions();
    
private booleanisMouseAfterThumb()

        return scrollbar.getComponentOrientation().isLeftToRight()
            ? isMouseRightOfThumb()
            : isMouseLeftOfThumb();
    
private booleanisMouseBeforeThumb()

        return scrollbar.getComponentOrientation().isLeftToRight()
            ? isMouseLeftOfThumb()
            : isMouseRightOfThumb();
    
private booleanisMouseLeftOfThumb()

        return trackListener.currentMouseX < getThumbBounds().x;
    
private booleanisMouseRightOfThumb()

        Rectangle tb = getThumbBounds();
        return trackListener.currentMouseX > tb.x + tb.width;
    
public booleanisThumbRollover()
Returns true if the mouse is currently over the thumb.

return
true if the thumb is currently active
since
1.5

        return thumbActive;
    
public voidlayoutContainer(java.awt.Container scrollbarContainer)

	/* If the user is dragging the value, we'll assume that the 
	 * scrollbars layout is OK modulo the thumb which is being 
	 * handled by the dragging code.
	 */
	if (isDragging) {
	    return;
	}

        JScrollBar scrollbar = (JScrollBar)scrollbarContainer;
        switch (scrollbar.getOrientation()) {
        case JScrollBar.VERTICAL:
            layoutVScrollbar(scrollbar);
            break;
            
        case JScrollBar.HORIZONTAL:
            layoutHScrollbar(scrollbar);
            break;
        }
    
protected voidlayoutHScrollbar(javax.swing.JScrollBar sb)

        Dimension sbSize = sb.getSize();
        Insets sbInsets = sb.getInsets();
        
	/* Height and top edge of the buttons and thumb.
	 */
	int itemH = sbSize.height - (sbInsets.top + sbInsets.bottom);
	int itemY = sbInsets.top;

        boolean ltr = sb.getComponentOrientation().isLeftToRight();

        /* Nominal locations of the buttons, assuming their preferred
	 * size will fit.
	 */
        boolean squareButtons = DefaultLookup.getBoolean(
            scrollbar, this, "ScrollBar.squareButtons", false);
        int leftButtonW = squareButtons ? itemH :
                          decrButton.getPreferredSize().width;
        int rightButtonW = squareButtons ? itemH :
                          incrButton.getPreferredSize().width;
        if (!ltr) {
            int temp = leftButtonW;
            leftButtonW = rightButtonW;
            rightButtonW = temp;
        }
        int leftButtonX = sbInsets.left;        
        int rightButtonX = sbSize.width - (sbInsets.right + rightButtonW);

        /* The thumb must fit within the width left over after we
	 * subtract the preferredSize of the buttons and the insets.
	 */
        int sbInsetsW = sbInsets.left + sbInsets.right;
        int sbButtonsW = leftButtonW + rightButtonW;
        float trackW = sbSize.width - (sbInsetsW + sbButtonsW);
        
        /* Compute the width and origin of the thumb.  Enforce
	 * the thumbs min/max dimensions.  The case where the thumb 
	 * is at the right edge is handled specially to avoid numerical 
	 * problems in computing thumbX.  If the thumb doesn't
	 * fit in the track (trackH) we'll hide it later.
	 */
        float min = sb.getMinimum();
        float max = sb.getMaximum();
        float extent = sb.getVisibleAmount();
        float range = max - min;
        float value = getValue(sb);

        int thumbW = (range <= 0) 
	    ? getMaximumThumbSize().width : (int)(trackW * (extent / range));
        thumbW = Math.max(thumbW, getMinimumThumbSize().width);
        thumbW = Math.min(thumbW, getMaximumThumbSize().width);
        
	int thumbX = ltr ? rightButtonX - thumbW : leftButtonX + leftButtonW;
	if (value < (max - sb.getVisibleAmount())) {
	    float thumbRange = trackW - thumbW;
            if( ltr ) {
                thumbX = (int)(0.5f + (thumbRange * ((value - min) / (range - extent))));
            } else {
                thumbX = (int)(0.5f + (thumbRange * ((max - extent - value) / (range - extent))));
            }
	    thumbX +=  leftButtonX + leftButtonW;
	}

        /* If the buttons don't fit, allocate half of the available 
         * space to each and move the right one over.
         */
        int sbAvailButtonW = (sbSize.width - sbInsetsW);
        if (sbAvailButtonW < sbButtonsW) {
            rightButtonW = leftButtonW = sbAvailButtonW / 2;
            rightButtonX = sbSize.width - (sbInsets.right + rightButtonW);
        }
        
        (ltr ? decrButton : incrButton).setBounds(leftButtonX, itemY, leftButtonW, itemH);
        (ltr ? incrButton : decrButton).setBounds(rightButtonX, itemY, rightButtonW, itemH);

	/* Update the trackRect field.
	 */	
	int itrackX = leftButtonX + leftButtonW;
	int itrackW = rightButtonX - itrackX;
	trackRect.setBounds(itrackX, itemY, itrackW, itemH);

	/* Make sure the thumb fits between the buttons.  Note 
	 * that setting the thumbs bounds causes a repaint.
	 */
	if (thumbW >= (int)trackW) {
	    setThumbBounds(0, 0, 0, 0);
	}
	else {
	    if (thumbX + thumbW > rightButtonX) {
		thumbX = rightButtonX - thumbW;
	    }
	    if (thumbX  < leftButtonX + leftButtonW) {
		thumbX = leftButtonX + leftButtonW + 1;
	    }
	    setThumbBounds(thumbX, itemY, thumbW, itemH);
	}
    
protected voidlayoutVScrollbar(javax.swing.JScrollBar sb)

        Dimension sbSize = sb.getSize();
        Insets sbInsets = sb.getInsets();

	/*
	 * Width and left edge of the buttons and thumb.
	 */
	int itemW = sbSize.width - (sbInsets.left + sbInsets.right);
	int itemX = sbInsets.left;
        
        /* Nominal locations of the buttons, assuming their preferred
	 * size will fit.
	 */
        boolean squareButtons = DefaultLookup.getBoolean(
            scrollbar, this, "ScrollBar.squareButtons", false);
        int decrButtonH = squareButtons ? itemW :
                          decrButton.getPreferredSize().height;
        int decrButtonY = sbInsets.top;
        
        int incrButtonH = squareButtons ? itemW :
                          incrButton.getPreferredSize().height;
        int incrButtonY = sbSize.height - (sbInsets.bottom + incrButtonH);
        
        /* The thumb must fit within the height left over after we
	 * subtract the preferredSize of the buttons and the insets.
	 */
        int sbInsetsH = sbInsets.top + sbInsets.bottom;
        int sbButtonsH = decrButtonH + incrButtonH;
        float trackH = sbSize.height - (sbInsetsH + sbButtonsH);
        
        /* Compute the height and origin of the thumb.   The case
	 * where the thumb is at the bottom edge is handled specially 
	 * to avoid numerical problems in computing thumbY.  Enforce
	 * the thumbs min/max dimensions.  If the thumb doesn't
	 * fit in the track (trackH) we'll hide it later.
	 */
	float min = sb.getMinimum();
	float extent = sb.getVisibleAmount();
	float range = sb.getMaximum() - min;
	float value = getValue(sb);

        int thumbH = (range <= 0) 
	    ? getMaximumThumbSize().height : (int)(trackH * (extent / range));
	thumbH = Math.max(thumbH, getMinimumThumbSize().height);
	thumbH = Math.min(thumbH, getMaximumThumbSize().height);
        
	int thumbY = incrButtonY - thumbH;  
	if (value < (sb.getMaximum() - sb.getVisibleAmount())) {
	    float thumbRange = trackH - thumbH;
	    thumbY = (int)(0.5f + (thumbRange * ((value - min) / (range - extent))));
	    thumbY +=  decrButtonY + decrButtonH;
	}

        /* If the buttons don't fit, allocate half of the available 
	 * space to each and move the lower one (incrButton) down.
	 */
        int sbAvailButtonH = (sbSize.height - sbInsetsH);
        if (sbAvailButtonH < sbButtonsH) {
            incrButtonH = decrButtonH = sbAvailButtonH / 2;
            incrButtonY = sbSize.height - (sbInsets.bottom + incrButtonH);
        }
        decrButton.setBounds(itemX, decrButtonY, itemW, decrButtonH);
        incrButton.setBounds(itemX, incrButtonY, itemW, incrButtonH);

	/* Update the trackRect field.
	 */	
	int itrackY = decrButtonY + decrButtonH;
	int itrackH = incrButtonY - itrackY;
	trackRect.setBounds(itemX, itrackY, itemW, itrackH);
	
	/* If the thumb isn't going to fit, zero it's bounds.  Otherwise
	 * make sure it fits between the buttons.  Note that setting the
	 * thumbs bounds will cause a repaint.
	 */
	if(thumbH >= (int)trackH)	{
	    setThumbBounds(0, 0, 0, 0);
	}
	else {
	    if ((thumbY + thumbH) > incrButtonY) {
		thumbY = incrButtonY - thumbH;
	    }
	    if (thumbY  < (decrButtonY + decrButtonH)) {
		thumbY = decrButtonY + decrButtonH + 1;
	    }
	    setThumbBounds(itemX, thumbY, itemW, thumbH);
	}
    
static voidloadActionMap(javax.swing.plaf.basic.LazyActionMap map)


        
        map.put(new Actions(Actions.POSITIVE_UNIT_INCREMENT));
        map.put(new Actions(Actions.POSITIVE_BLOCK_INCREMENT));
        map.put(new Actions(Actions.NEGATIVE_UNIT_INCREMENT));
        map.put(new Actions(Actions.NEGATIVE_BLOCK_INCREMENT));
        map.put(new Actions(Actions.MIN_SCROLL));
        map.put(new Actions(Actions.MAX_SCROLL));
    
public java.awt.DimensionminimumLayoutSize(java.awt.Container scrollbarContainer)

        return getMinimumSize((JComponent)scrollbarContainer);
    
public voidpaint(java.awt.Graphics g, javax.swing.JComponent c)

	paintTrack(g, c, getTrackBounds());		
	Rectangle thumbBounds = getThumbBounds();
	if (thumbBounds.intersects(g.getClipBounds())) {
	    paintThumb(g, c, thumbBounds);
	}
    
protected voidpaintDecreaseHighlight(java.awt.Graphics g)

	Insets insets = scrollbar.getInsets();
	Rectangle thumbR = getThumbBounds();
	g.setColor(trackHighlightColor);

	if (scrollbar.getOrientation() == JScrollBar.VERTICAL) {
	    int x = insets.left;
	    int y = decrButton.getY() + decrButton.getHeight();
	    int w = scrollbar.getWidth() - (insets.left + insets.right);
	    int h = thumbR.y - y;
	    g.fillRect(x, y, w, h);
	} 
	else	{
	    int x, w;
	    if (scrollbar.getComponentOrientation().isLeftToRight()) {
		x = decrButton.getX() + decrButton.getWidth();
		w = thumbR.x - x;
	    } else {
		x = thumbR.x + thumbR.width;
		w = decrButton.getX() - x;
	    }
	    int y = insets.top;
	    int h = scrollbar.getHeight() - (insets.top + insets.bottom);
	    g.fillRect(x, y, w, h);
	}
    
protected voidpaintIncreaseHighlight(java.awt.Graphics g)

	Insets insets = scrollbar.getInsets();
	Rectangle thumbR = getThumbBounds();
	g.setColor(trackHighlightColor);

	if (scrollbar.getOrientation() == JScrollBar.VERTICAL) {
	    int x = insets.left;
	    int y = thumbR.y + thumbR.height;
	    int w = scrollbar.getWidth() - (insets.left + insets.right);
	    int h = incrButton.getY() - y;
	    g.fillRect(x, y, w, h);
	} 
	else {
	    int x, w;
	    if (scrollbar.getComponentOrientation().isLeftToRight()) {
		x = thumbR.x + thumbR.width;
		w = incrButton.getX() - x;
	    } else {
		x = incrButton.getX() + incrButton.getWidth();
		w = thumbR.x - x;
	    }
	    int y = insets.top;
	    int h = scrollbar.getHeight() - (insets.top + insets.bottom);
	    g.fillRect(x, y, w, h);
	}
    
protected voidpaintThumb(java.awt.Graphics g, javax.swing.JComponent c, java.awt.Rectangle thumbBounds)

	if(thumbBounds.isEmpty() || !scrollbar.isEnabled())	{
	    return;
	}

        int w = thumbBounds.width;
        int h = thumbBounds.height;		

	g.translate(thumbBounds.x, thumbBounds.y);

	g.setColor(thumbDarkShadowColor);
	g.drawRect(0, 0, w-1, h-1);    
	g.setColor(thumbColor);
	g.fillRect(0, 0, w-1, h-1);
        
        g.setColor(thumbHighlightColor);
        g.drawLine(1, 1, 1, h-2);
        g.drawLine(2, 1, w-3, 1);
        
        g.setColor(thumbLightShadowColor);
        g.drawLine(2, h-2, w-2, h-2);
        g.drawLine(w-2, 1, w-2, h-3);

	g.translate(-thumbBounds.x, -thumbBounds.y);
    
protected voidpaintTrack(java.awt.Graphics g, javax.swing.JComponent c, java.awt.Rectangle trackBounds)

        g.setColor(trackColor);
        g.fillRect(trackBounds.x, trackBounds.y, trackBounds.width, trackBounds.height);	

	if(trackHighlight == DECREASE_HIGHLIGHT)	{
	    paintDecreaseHighlight(g);
	} 
	else if(trackHighlight == INCREASE_HIGHLIGHT)		{
	    paintIncreaseHighlight(g);
	}
    
public java.awt.DimensionpreferredLayoutSize(java.awt.Container scrollbarContainer)

        return getPreferredSize((JComponent)scrollbarContainer);
    
public voidremoveLayoutComponent(java.awt.Component child)

static voidscrollByBlock(javax.swing.JScrollBar scrollbar, int direction)

        // This method is called from BasicScrollPaneUI to implement wheel
        // scrolling, and also from scrollByBlock().
	    int oldValue = scrollbar.getValue();
	    int blockIncrement = scrollbar.getBlockIncrement(direction);
	    int delta = blockIncrement * ((direction > 0) ? +1 : -1);
	    int newValue = oldValue + delta;
	    
	    // Check for overflow.
	    if (delta > 0 && newValue < oldValue) {
		newValue = scrollbar.getMaximum();
	    }
	    else if (delta < 0 && newValue > oldValue) {
		newValue = scrollbar.getMinimum();
	    }

	    scrollbar.setValue(newValue);			
    
protected voidscrollByBlock(int direction)

        scrollByBlock(scrollbar, direction);
	    trackHighlight = direction > 0 ? INCREASE_HIGHLIGHT : DECREASE_HIGHLIGHT;
	    Rectangle dirtyRect = getTrackBounds();
	    scrollbar.repaint(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
    
protected voidscrollByUnit(int direction)

        scrollByUnits(scrollbar, direction, 1, false);
    
static voidscrollByUnits(javax.swing.JScrollBar scrollbar, int direction, int units, boolean limitToBlock)

        // This method is called from BasicScrollPaneUI to implement wheel
        // scrolling, as well as from scrollByUnit().
        int delta;
        int limit = -1;

        if (limitToBlock) {
            if (direction < 0) {
                limit = scrollbar.getValue() -
                                         scrollbar.getBlockIncrement(direction);
            }
            else {
                limit = scrollbar.getValue() +
                                         scrollbar.getBlockIncrement(direction);
            }
        }

        for (int i=0; i<units; i++) {
            if (direction > 0) {
                delta = scrollbar.getUnitIncrement(direction);
            }
            else {
                delta = -scrollbar.getUnitIncrement(direction);
            }

            int oldValue = scrollbar.getValue();
            int newValue = oldValue + delta;

            // Check for overflow.
            if (delta > 0 && newValue < oldValue) {
                newValue = scrollbar.getMaximum();
            }
            else if (delta < 0 && newValue > oldValue) {
                newValue = scrollbar.getMinimum();
            }
            if (oldValue == newValue) {
                break;
            }

            if (limitToBlock && i > 0) {
                assert limit != -1;
                if ((direction < 0 && newValue < limit) ||
                    (direction > 0 && newValue > limit)) {
                    break;
                }
            }
            scrollbar.setValue(newValue);
        }
    
protected voidsetThumbBounds(int x, int y, int width, int height)
Set the bounds of the thumb and force a repaint that includes the old thumbBounds and the new one.

see
#getThumbBounds

	/* If the thumbs bounds haven't changed, we're done.
	 */
	if ((thumbRect.x == x) && 
	    (thumbRect.y == y) && 
	    (thumbRect.width == width) && 
	    (thumbRect.height == height)) {
	    return;
	}

	/* Update thumbRect, and repaint the union of x,y,w,h and 
	 * the old thumbRect.
	 */
	int minX = Math.min(x, thumbRect.x);
	int minY = Math.min(y, thumbRect.y);
	int maxX = Math.max(x + width, thumbRect.x + thumbRect.width);
	int maxY = Math.max(y + height, thumbRect.y + thumbRect.height);

	thumbRect.setBounds(x, y, width, height);
	scrollbar.repaint(minX, minY, maxX - minX, maxY - minY);

        // Once there is API to determine the mouse location this will need
        // to be changed.
        setThumbRollover(false);
    
protected voidsetThumbRollover(boolean active)
Sets whether or not the mouse is currently over the thumb.

param
active True indicates the thumb is currently active.
since
1.5

        if (thumbActive != active) {
            thumbActive = active;
            scrollbar.repaint(getThumbBounds());
        }
    
protected voiduninstallComponents()

	scrollbar.remove(incrButton);
	scrollbar.remove(decrButton);
    
protected voiduninstallDefaults()

        LookAndFeel.uninstallBorder(scrollbar);
        if (scrollbar.getLayout() == this) {
            scrollbar.setLayout(null);
        }
    
protected voiduninstallKeyboardActions()

	SwingUtilities.replaceUIInputMap(scrollbar, JComponent.WHEN_FOCUSED,
					 null);
	SwingUtilities.replaceUIActionMap(scrollbar, null);
    
protected voiduninstallListeners()

	scrollTimer.stop();
	scrollTimer = null;

	if (decrButton != null){
	    decrButton.removeMouseListener(buttonListener);
	}
	if (incrButton != null){
	    incrButton.removeMouseListener(buttonListener);
	}
    
	scrollbar.getModel().removeChangeListener(modelListener);
	scrollbar.removeMouseListener(trackListener);
	scrollbar.removeMouseMotionListener(trackListener);
	scrollbar.removePropertyChangeListener(propertyChangeListener);
        scrollbar.removeFocusListener(getHandler());
        handler = null;
    
public voiduninstallUI(javax.swing.JComponent c)

	scrollbar = (JScrollBar)c;
	uninstallListeners();
	uninstallDefaults();
	uninstallComponents();
	uninstallKeyboardActions();
	thumbRect = null;
	scrollbar = null;
	incrButton = null;
	decrButton = null;
    
private voidupdateButtonDirections()

        int orient = scrollbar.getOrientation();
        if (scrollbar.getComponentOrientation().isLeftToRight()) { 
            if (incrButton instanceof BasicArrowButton) {
                ((BasicArrowButton)incrButton).setDirection(
                        orient == HORIZONTAL? EAST : SOUTH);
            }
            if (decrButton instanceof BasicArrowButton) {
                ((BasicArrowButton)decrButton).setDirection(
                        orient == HORIZONTAL? WEST : NORTH);
            }
        }
        else {
            if (incrButton instanceof BasicArrowButton) {
                ((BasicArrowButton)incrButton).setDirection(
                        orient == HORIZONTAL? WEST : SOUTH);
            }
            if (decrButton instanceof BasicArrowButton) {
                ((BasicArrowButton)decrButton).setDirection(
                        orient == HORIZONTAL ? EAST : NORTH);
            }
        }
    
private voidupdateThumbState(int x, int y)

        Rectangle rect = getThumbBounds();

        setThumbRollover(rect.contains(x, y));