Source for javax.swing.plaf.basic.BasicScrollBarUI

   1: /* BasicScrollBarUI.java --
   2:    Copyright (C) 2004, 2005, 2006,  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.swing.plaf.basic;
  40: 
  41: import java.awt.Color;
  42: import java.awt.Component;
  43: import java.awt.Container;
  44: import java.awt.Dimension;
  45: import java.awt.Graphics;
  46: import java.awt.Insets;
  47: import java.awt.LayoutManager;
  48: import java.awt.Rectangle;
  49: import java.awt.event.ActionEvent;
  50: import java.awt.event.ActionListener;
  51: import java.awt.event.MouseAdapter;
  52: import java.awt.event.MouseEvent;
  53: import java.awt.event.MouseMotionListener;
  54: import java.beans.PropertyChangeEvent;
  55: import java.beans.PropertyChangeListener;
  56: 
  57: import javax.swing.AbstractAction;
  58: import javax.swing.ActionMap;
  59: import javax.swing.BoundedRangeModel;
  60: import javax.swing.InputMap;
  61: import javax.swing.JButton;
  62: import javax.swing.JComponent;
  63: import javax.swing.JScrollBar;
  64: import javax.swing.JSlider;
  65: import javax.swing.LookAndFeel;
  66: import javax.swing.SwingConstants;
  67: import javax.swing.SwingUtilities;
  68: import javax.swing.Timer;
  69: import javax.swing.UIManager;
  70: import javax.swing.event.ChangeEvent;
  71: import javax.swing.event.ChangeListener;
  72: import javax.swing.plaf.ActionMapUIResource;
  73: import javax.swing.plaf.ComponentUI;
  74: import javax.swing.plaf.ScrollBarUI;
  75: 
  76: /**
  77:  * The Basic Look and Feel UI delegate for JScrollBar.
  78:  */
  79: public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager,
  80:                                                              SwingConstants
  81: {
  82:   /**
  83:    * A helper class that listens to the two JButtons on each end of the
  84:    * JScrollBar.
  85:    */
  86:   protected class ArrowButtonListener extends MouseAdapter
  87:   {
  88: 
  89:     /**
  90:      * Move the thumb in the direction specified by the  button's arrow. If
  91:      * this button is held down, then it should keep moving the thumb.
  92:      *
  93:      * @param e The MouseEvent fired by the JButton.
  94:      */
  95:     public void mousePressed(MouseEvent e)
  96:     {
  97:       scrollTimer.stop();
  98:       scrollListener.setScrollByBlock(false);
  99:       if (e.getSource() == incrButton)
 100:           scrollListener.setDirection(POSITIVE_SCROLL);
 101:       else if (e.getSource() == decrButton)
 102:           scrollListener.setDirection(NEGATIVE_SCROLL);
 103:       scrollTimer.setDelay(100);
 104:       scrollTimer.start();
 105:     }
 106: 
 107:     /**
 108:      * Stops the thumb when the JButton is released.
 109:      *
 110:      * @param e The MouseEvent fired by the JButton.
 111:      */
 112:     public void mouseReleased(MouseEvent e)
 113:     {
 114:       scrollTimer.stop();
 115:       scrollTimer.setDelay(300);
 116:       if (e.getSource() == incrButton)
 117:           scrollByUnit(POSITIVE_SCROLL);
 118:       else if (e.getSource() == decrButton)
 119:         scrollByUnit(NEGATIVE_SCROLL);
 120:     }
 121:   }
 122: 
 123:   /**
 124:    * A helper class that listens to the ScrollBar's model for ChangeEvents.
 125:    */
 126:   protected class ModelListener implements ChangeListener
 127:   {
 128:     /**
 129:      * Called when the model changes.
 130:      *
 131:      * @param e The ChangeEvent fired by the model.
 132:      */
 133:     public void stateChanged(ChangeEvent e)
 134:     {
 135:       calculatePreferredSize();
 136:       updateThumbRect();
 137:       scrollbar.repaint();
 138:     }
 139:   }
 140: 
 141:   /**
 142:    * A helper class that listens to the ScrollBar's properties.
 143:    */
 144:   public class PropertyChangeHandler implements PropertyChangeListener
 145:   {
 146:     /**
 147:      * Called when one of the ScrollBar's properties change.
 148:      *
 149:      * @param e The PropertyChangeEvent fired by the ScrollBar.
 150:      */
 151:     public void propertyChange(PropertyChangeEvent e)
 152:     {
 153:       if (e.getPropertyName().equals("model"))
 154:         {
 155:           ((BoundedRangeModel) e.getOldValue()).removeChangeListener(modelListener);
 156:           scrollbar.getModel().addChangeListener(modelListener);
 157:           updateThumbRect();
 158:         }
 159:       else if (e.getPropertyName().equals("orientation"))
 160:         {
 161:           uninstallListeners();
 162:           uninstallComponents();
 163:           uninstallDefaults();
 164:           installDefaults();
 165:           installComponents();
 166:           installListeners();
 167:         }
 168:       else if (e.getPropertyName().equals("enabled"))
 169:         {
 170:           Boolean b = (Boolean) e.getNewValue();
 171:           if (incrButton != null)
 172:             incrButton.setEnabled(b.booleanValue());
 173:           if (decrButton != null)
 174:             decrButton.setEnabled(b.booleanValue());
 175:         }
 176:     }
 177:   }
 178: 
 179:   /**
 180:    * A helper class that listens for events from the timer that is used to
 181:    * move the thumb.
 182:    */
 183:   protected class ScrollListener implements ActionListener
 184:   {
 185:     /** The direction the thumb moves in. */
 186:     private transient int direction;
 187: 
 188:     /** Whether movement will be in blocks. */
 189:     private transient boolean block;
 190: 
 191:     /**
 192:      * Creates a new ScrollListener object. The default is scrolling
 193:      * positively with block movement.
 194:      */
 195:     public ScrollListener()
 196:     {
 197:       direction = POSITIVE_SCROLL;
 198:       block = true;
 199:     }
 200: 
 201:     /**
 202:      * Creates a new ScrollListener object using the given direction and
 203:      * block.
 204:      *
 205:      * @param dir The direction to move in.
 206:      * @param block Whether movement will be in blocks.
 207:      */
 208:     public ScrollListener(int dir, boolean block)
 209:     {
 210:       direction = dir;
 211:       this.block = block;
 212:     }
 213: 
 214:     /**
 215:      * Sets the direction to scroll in.
 216:      *
 217:      * @param direction The direction to scroll in.
 218:      */
 219:     public void setDirection(int direction)
 220:     {
 221:       this.direction = direction;
 222:     }
 223: 
 224:     /**
 225:      * Sets whether scrolling will be done in blocks.
 226:      *
 227:      * @param block Whether scrolling will be in blocks.
 228:      */
 229:     public void setScrollByBlock(boolean block)
 230:     {
 231:       this.block = block;
 232:     }
 233: 
 234:     /**
 235:      * Called every time the timer reaches its interval.
 236:      *
 237:      * @param e The ActionEvent fired by the timer.
 238:      */
 239:     public void actionPerformed(ActionEvent e)
 240:     {
 241:       if (block)
 242:         {
 243:           // Only need to check it if it's block scrolling
 244:           // We only block scroll if the click occurs
 245:           // in the track.
 246:           if (!trackListener.shouldScroll(direction))
 247:             {
 248:               trackHighlight = NO_HIGHLIGHT;
 249:               scrollbar.repaint();
 250:               return;
 251:             }
 252:             scrollByBlock(direction);
 253:         }
 254:       else
 255:         scrollByUnit(direction);
 256:     }
 257:   }
 258: 
 259:   /**
 260:    * Helper class that listens for movement on the track.
 261:    */
 262:   protected class TrackListener extends MouseAdapter
 263:     implements MouseMotionListener
 264:   {
 265:     /** The current X coordinate of the mouse. */
 266:     protected int currentMouseX;
 267: 
 268:     /** The current Y coordinate of the mouse. */
 269:     protected int currentMouseY;
 270: 
 271:     /**
 272:      * The offset between the current mouse cursor and the  current value of
 273:      * the scrollbar.
 274:      */
 275:     protected int offset;
 276: 
 277:     /**
 278:      * This method is called when the mouse is being dragged.
 279:      *
 280:      * @param e The MouseEvent given.
 281:      */
 282:     public void mouseDragged(MouseEvent e)
 283:     {
 284:       currentMouseX = e.getX();
 285:       currentMouseY = e.getY();
 286:       if (scrollbar.getValueIsAdjusting())
 287:         {
 288:           int value;
 289:           if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL)
 290:             value = valueForXPosition(currentMouseX) - offset;
 291:           else
 292:             value = valueForYPosition(currentMouseY) - offset;
 293: 
 294:           scrollbar.setValue(value);
 295:         }
 296:     }
 297: 
 298:     /**
 299:      * This method is called when the mouse is moved.
 300:      *
 301:      * @param e The MouseEvent given.
 302:      */
 303:     public void mouseMoved(MouseEvent e)
 304:     {
 305:       if (thumbRect.contains(e.getPoint()))
 306:         thumbRollover = true;
 307:       else
 308:         thumbRollover = false;
 309:     }
 310: 
 311:     /**
 312:      * This method is called when the mouse is pressed. When it is pressed,
 313:      * the thumb should move in blocks towards the cursor.
 314:      *
 315:      * @param e The MouseEvent given.
 316:      */
 317:     public void mousePressed(MouseEvent e)
 318:     {
 319:       currentMouseX = e.getX();
 320:       currentMouseY = e.getY();
 321: 
 322:       int value;
 323:       if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL)
 324:         value = valueForXPosition(currentMouseX);
 325:       else
 326:         value = valueForYPosition(currentMouseY);
 327: 
 328:       if (! thumbRect.contains(e.getPoint()))
 329:         {
 330:           scrollTimer.stop();
 331:           scrollListener.setScrollByBlock(true);
 332:           if (value > scrollbar.getValue())
 333:             {
 334:               trackHighlight = INCREASE_HIGHLIGHT;
 335:               scrollListener.setDirection(POSITIVE_SCROLL);
 336:             }
 337:           else
 338:             {
 339:               trackHighlight = DECREASE_HIGHLIGHT;
 340:               scrollListener.setDirection(NEGATIVE_SCROLL);
 341:             }
 342:       scrollTimer.setDelay(100);
 343:           scrollTimer.start();
 344:         }
 345:       else
 346:         {
 347:           // We'd like to keep track of where the cursor
 348:           // is inside the thumb.
 349:           // This works because the scrollbar's value represents
 350:           // "lower" edge of the thumb. The value at which
 351:           // the cursor is at must be greater or equal
 352:           // to that value.
 353: 
 354:       scrollListener.setScrollByBlock(false);
 355:           scrollbar.setValueIsAdjusting(true);
 356:       offset = value - scrollbar.getValue();
 357:         }
 358:       scrollbar.repaint();
 359:     }
 360: 
 361:     /**
 362:      * This method is called when the mouse is released. It should stop
 363:      * movement on the thumb
 364:      *
 365:      * @param e The MouseEvent given.
 366:      */
 367:     public void mouseReleased(MouseEvent e)
 368:     {
 369:       scrollTimer.stop();
 370:       scrollTimer.setDelay(300);
 371:       currentMouseX = e.getX();
 372:       currentMouseY = e.getY();
 373: 
 374:       if (shouldScroll(POSITIVE_SCROLL))
 375:         scrollByBlock(POSITIVE_SCROLL);
 376:       else if (shouldScroll(NEGATIVE_SCROLL))
 377:         scrollByBlock(NEGATIVE_SCROLL);
 378: 
 379:       trackHighlight = NO_HIGHLIGHT;
 380:       scrollListener.setScrollByBlock(false);
 381:       scrollbar.setValueIsAdjusting(true);
 382:       scrollbar.repaint();
 383:     }
 384: 
 385:     /**
 386:      * A helper method that decides whether we should keep scrolling in the
 387:      * given direction.
 388:      *
 389:      * @param direction The direction to check for.
 390:      *
 391:      * @return Whether the thumb should keep scrolling.
 392:      */
 393:     boolean shouldScroll(int direction)
 394:     {
 395:       int value;
 396:       if (scrollbar.getOrientation() == HORIZONTAL)
 397:         value = valueForXPosition(currentMouseX);
 398:       else
 399:         value = valueForYPosition(currentMouseY);
 400: 
 401:       if (thumbRect.contains(currentMouseX, currentMouseY))
 402:         return false;
 403: 
 404:       if (direction == POSITIVE_SCROLL)
 405:         return value > scrollbar.getValue();
 406:       else
 407:         return value < scrollbar.getValue();
 408:     }
 409:   }
 410: 
 411:   /** The listener that listens to the JButtons. */
 412:   protected ArrowButtonListener buttonListener;
 413: 
 414:   /** The listener that listens to the model. */
 415:   protected ModelListener modelListener;
 416: 
 417:   /** The listener that listens to the scrollbar for property changes. */
 418:   protected PropertyChangeListener propertyChangeListener;
 419: 
 420:   /** The listener that listens to the timer. */
 421:   protected ScrollListener scrollListener;
 422: 
 423:   /** The listener that listens for MouseEvents on the track. */
 424:   protected TrackListener trackListener;
 425: 
 426:   /** The JButton that decrements the scrollbar's value. */
 427:   protected JButton decrButton;
 428: 
 429:   /** The JButton that increments the scrollbar's value. */
 430:   protected JButton incrButton;
 431: 
 432:   /** The dimensions of the maximum thumb size. */
 433:   protected Dimension maximumThumbSize;
 434: 
 435:   /** The dimensions of the minimum thumb size. */
 436:   protected Dimension minimumThumbSize;
 437: 
 438:   /** The color of the thumb. */
 439:   protected Color thumbColor;
 440: 
 441:   /** The outer shadow of the thumb. */
 442:   protected Color thumbDarkShadowColor;
 443: 
 444:   /** The top and left edge color for the thumb. */
 445:   protected Color thumbHighlightColor;
 446: 
 447:   /** The outer light shadow for the thumb. */
 448:   protected Color thumbLightShadowColor;
 449: 
 450:   /** The color that is used when the mouse press occurs in the track. */
 451:   protected Color trackHighlightColor;
 452: 
 453:   /** The color of the track. */
 454:   protected Color trackColor;
 455: 
 456:   /** The size and position of the track. */
 457:   protected Rectangle trackRect;
 458: 
 459:   /** The size and position of the thumb. */
 460:   protected Rectangle thumbRect;
 461: 
 462:   /** Indicates that the decrease highlight should be painted. */
 463:   protected static final int DECREASE_HIGHLIGHT = 1;
 464: 
 465:   /** Indicates that the increase highlight should be painted. */
 466:   protected static final int INCREASE_HIGHLIGHT = 2;
 467: 
 468:   /** Indicates that no highlight should be painted. */
 469:   protected static final int NO_HIGHLIGHT = 0;
 470: 
 471:   /** Indicates that the scrolling direction is positive. */
 472:   private static final int POSITIVE_SCROLL = 1;
 473: 
 474:   /** Indicates that the scrolling direction is negative. */
 475:   private static final int NEGATIVE_SCROLL = -1;
 476: 
 477:   /** The cached preferred size for the scrollbar. */
 478:   private transient Dimension preferredSize;
 479: 
 480:   /** The current highlight status. */
 481:   protected int trackHighlight;
 482: 
 483:   /** FIXME: Use this for something (presumably mouseDragged) */
 484:   protected boolean isDragging;
 485: 
 486:   /** The timer used to move the thumb when the mouse is held. */
 487:   protected Timer scrollTimer;
 488: 
 489:   /** The scrollbar this UI is acting for. */
 490:   protected JScrollBar scrollbar;
 491: 
 492:   /** True if the mouse is over the thumb. */
 493:   boolean thumbRollover;
 494: 
 495:   /**
 496:    * This method adds a component to the layout.
 497:    *
 498:    * @param name The name to associate with the component that is added.
 499:    * @param child The Component to add.
 500:    */
 501:   public void addLayoutComponent(String name, Component child)
 502:   {
 503:     // You should not be adding stuff to this component.
 504:     // The contents are fixed.
 505:   }
 506: 
 507:   /**
 508:    * This method configures the scrollbar's colors. This can be  done by
 509:    * looking up the standard colors from the Look and Feel defaults.
 510:    */
 511:   protected void configureScrollBarColors()
 512:   {
 513:     trackColor = UIManager.getColor("ScrollBar.track");
 514:     trackHighlightColor = UIManager.getColor("ScrollBar.trackHighlight");
 515:     thumbColor = UIManager.getColor("ScrollBar.thumb");
 516:     thumbHighlightColor = UIManager.getColor("ScrollBar.thumbHighlight");
 517:     thumbDarkShadowColor = UIManager.getColor("ScrollBar.thumbDarkShadow");
 518:     thumbLightShadowColor = UIManager.getColor("ScrollBar.thumbShadow");
 519:   }
 520: 
 521:   /**
 522:    * This method creates an ArrowButtonListener.
 523:    *
 524:    * @return A new ArrowButtonListener.
 525:    */
 526:   protected ArrowButtonListener createArrowButtonListener()
 527:   {
 528:     return new ArrowButtonListener();
 529:   }
 530: 
 531:   /**
 532:    * This method creates a new JButton with the appropriate icon for the
 533:    * orientation.
 534:    *
 535:    * @param orientation The orientation this JButton uses.
 536:    *
 537:    * @return The increase JButton.
 538:    */
 539:   protected JButton createIncreaseButton(int orientation)
 540:   {
 541:     return new BasicArrowButton(orientation);
 542:   }
 543: 
 544:   /**
 545:    * This method creates a new JButton with the appropriate icon for the
 546:    * orientation.
 547:    *
 548:    * @param orientation The orientation this JButton uses.
 549:    *
 550:    * @return The decrease JButton.
 551:    */
 552:   protected JButton createDecreaseButton(int orientation)
 553:   {
 554:     return new BasicArrowButton(orientation);
 555:   }
 556: 
 557:   /**
 558:    * This method creates a new ModelListener.
 559:    *
 560:    * @return A new ModelListener.
 561:    */
 562:   protected ModelListener createModelListener()
 563:   {
 564:     return new ModelListener();
 565:   }
 566: 
 567:   /**
 568:    * This method creates a new PropertyChangeListener.
 569:    *
 570:    * @return A new PropertyChangeListener.
 571:    */
 572:   protected PropertyChangeListener createPropertyChangeListener()
 573:   {
 574:     return new PropertyChangeHandler();
 575:   }
 576: 
 577:   /**
 578:    * This method creates a new ScrollListener.
 579:    *
 580:    * @return A new ScrollListener.
 581:    */
 582:   protected ScrollListener createScrollListener()
 583:   {
 584:     return new ScrollListener();
 585:   }
 586: 
 587:   /**
 588:    * This method creates a new TrackListener.
 589:    *
 590:    * @return A new TrackListener.
 591:    */
 592:   protected TrackListener createTrackListener()
 593:   {
 594:     return new TrackListener();
 595:   }
 596: 
 597:   /**
 598:    * This method returns a new BasicScrollBarUI.
 599:    *
 600:    * @param c The JComponent to create a UI for.
 601:    *
 602:    * @return A new BasicScrollBarUI.
 603:    */
 604:   public static ComponentUI createUI(JComponent c)
 605:   {
 606:     return new BasicScrollBarUI();
 607:   }
 608: 
 609:   /**
 610:    * This method returns the maximum size for this JComponent.
 611:    *
 612:    * @param c The JComponent to measure the maximum size for.
 613:    *
 614:    * @return The maximum size for the component.
 615:    */
 616:   public Dimension getMaximumSize(JComponent c)
 617:   {
 618:     return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
 619:   }
 620: 
 621:   /**
 622:    * This method returns the maximum thumb size.
 623:    *
 624:    * @return The maximum thumb size.
 625:    */
 626:   protected Dimension getMaximumThumbSize()
 627:   {
 628:     return maximumThumbSize;
 629:   }
 630: 
 631:   /**
 632:    * This method returns the minimum size for this JComponent.
 633:    *
 634:    * @param c The JComponent to measure the minimum size for.
 635:    *
 636:    * @return The minimum size for the component.
 637:    */
 638:   public Dimension getMinimumSize(JComponent c)
 639:   {
 640:     return getPreferredSize(c);
 641:   }
 642: 
 643:   /**
 644:    * This method returns the minimum thumb size.
 645:    *
 646:    * @return The minimum thumb size.
 647:    */
 648:   protected Dimension getMinimumThumbSize()
 649:   {
 650:     return minimumThumbSize;
 651:   }
 652: 
 653:   /**
 654:    * This method calculates the preferred size since calling
 655:    * getPreferredSize() returns a cached value.
 656:    * This is package-private to avoid an accessor method.
 657:    */
 658:   void calculatePreferredSize()
 659:   {
 660:     int height;
 661:     int width;
 662:     height = width = 0;
 663: 
 664:     if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL)
 665:       {
 666:         width += incrButton.getPreferredSize().getWidth();
 667:         width += decrButton.getPreferredSize().getWidth();
 668:         width += 16;
 669:         height = UIManager.getInt("ScrollBar.width");
 670:       }
 671:     else
 672:       {
 673:         height += incrButton.getPreferredSize().getHeight();
 674:         height += decrButton.getPreferredSize().getHeight();
 675:         height += 16;
 676:         width = UIManager.getInt("ScrollBar.width");
 677:       }
 678: 
 679:     Insets insets = scrollbar.getInsets();
 680: 
 681:     height += insets.top + insets.bottom;
 682:     width += insets.left + insets.right;
 683: 
 684:     preferredSize = new Dimension(width, height);
 685:   }
 686: 
 687:   /**
 688:    * This method returns a cached value of the preferredSize. The only
 689:    * restrictions are: If the scrollbar is horizontal, the height should be
 690:    * the maximum of the height of the JButtons and  the minimum width of the
 691:    * thumb. For vertical scrollbars, the  calculation is similar (swap width
 692:    * for height and vice versa).
 693:    *
 694:    * @param c The JComponent to measure.
 695:    *
 696:    * @return The preferredSize.
 697:    */
 698:   public Dimension getPreferredSize(JComponent c)
 699:   {
 700:     calculatePreferredSize();
 701:     return preferredSize;
 702:   }
 703: 
 704:   /**
 705:    * This method returns the thumb's bounds based on the  current value of the
 706:    * scrollbar. This method updates the cached value and returns that.
 707:    *
 708:    * @return The thumb bounds.
 709:    */
 710:   protected Rectangle getThumbBounds()
 711:   {
 712:     return thumbRect;
 713:   }
 714: 
 715:   /**
 716:    * This method calculates the bounds of the track. This method updates the
 717:    * cached value and returns it.
 718:    *
 719:    * @return The track's bounds.
 720:    */
 721:   protected Rectangle getTrackBounds()
 722:   {
 723:     return trackRect;
 724:   }
 725: 
 726:   /**
 727:    * This method installs any addition Components that  are a part of or
 728:    * related to this scrollbar.
 729:    */
 730:   protected void installComponents()
 731:   {
 732:     int orientation = scrollbar.getOrientation();
 733:     switch (orientation)
 734:       {
 735:       case JScrollBar.HORIZONTAL:
 736:         incrButton = createIncreaseButton(EAST);
 737:         decrButton = createDecreaseButton(WEST);
 738:         break;
 739:       default:
 740:         incrButton = createIncreaseButton(SOUTH);
 741:         decrButton = createDecreaseButton(NORTH);
 742:         break;
 743:       }
 744: 
 745:     if (incrButton != null)
 746:       scrollbar.add(incrButton);
 747:     if (decrButton != null)
 748:       scrollbar.add(decrButton);
 749:   }
 750: 
 751:   /**
 752:    * This method installs the defaults for the scrollbar specified by the
 753:    * Basic Look and Feel.
 754:    */
 755:   protected void installDefaults()
 756:   {
 757:     LookAndFeel.installColors(scrollbar, "ScrollBar.background",
 758:                               "ScrollBar.foreground");
 759:     LookAndFeel.installBorder(scrollbar, "ScrollBar.border");
 760:     scrollbar.setOpaque(true);
 761:     scrollbar.setLayout(this);
 762: 
 763:     configureScrollBarColors();
 764: 
 765:     maximumThumbSize = UIManager.getDimension("ScrollBar.maximumThumbSize");
 766:     minimumThumbSize = UIManager.getDimension("ScrollBar.minimumThumbSize");
 767:   }
 768: 
 769:   /**
 770:    * Installs the input map from the look and feel defaults, and a
 771:    * corresponding action map.  Note the the keyboard bindings will only
 772:    * work when the {@link JScrollBar} component has the focus, which is rare.
 773:    */
 774:   protected void installKeyboardActions()
 775:   {
 776:     InputMap keyMap = getInputMap(
 777:         JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
 778:     SwingUtilities.replaceUIInputMap(scrollbar,
 779:         JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, keyMap);
 780:     ActionMap map = getActionMap();
 781:     SwingUtilities.replaceUIActionMap(scrollbar, map);
 782:   }
 783: 
 784:   /**
 785:    * Uninstalls the input map and action map installed by
 786:    * {@link #installKeyboardActions()}.
 787:    */
 788:   protected void uninstallKeyboardActions()
 789:   {
 790:     SwingUtilities.replaceUIActionMap(scrollbar, null);
 791:     SwingUtilities.replaceUIInputMap(scrollbar,
 792:         JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
 793:   }
 794: 
 795:   InputMap getInputMap(int condition)
 796:   {
 797:     if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
 798:       return (InputMap) UIManager.get("ScrollBar.focusInputMap");
 799:     return null;
 800:   }
 801: 
 802:   /**
 803:    * Returns the action map for the {@link JScrollBar}.  All scroll bars
 804:    * share a single action map which is created the first time this method is
 805:    * called, then stored in the UIDefaults table for subsequent access.
 806:    *
 807:    * @return The shared action map.
 808:    */
 809:   ActionMap getActionMap()
 810:   {
 811:     ActionMap map = (ActionMap) UIManager.get("ScrollBar.actionMap");
 812: 
 813:     if (map == null) // first time here
 814:       {
 815:         map = createActionMap();
 816:         if (map != null)
 817:           UIManager.put("ScrollBar.actionMap", map);
 818:       }
 819:     return map;
 820:   }
 821: 
 822:   /**
 823:    * Creates the action map shared by all {@link JSlider} instances.
 824:    * This method is called once by {@link #getActionMap()} when it
 825:    * finds no action map in the UIDefaults table...after the map is
 826:    * created, it gets added to the defaults table so that subsequent
 827:    * calls to {@link #getActionMap()} will return the same shared
 828:    * instance.
 829:    *
 830:    * @return The action map.
 831:    */
 832:   ActionMap createActionMap()
 833:   {
 834:     ActionMap map = new ActionMapUIResource();
 835:     map.put("positiveUnitIncrement",
 836:             new AbstractAction("positiveUnitIncrement") {
 837:               public void actionPerformed(ActionEvent event)
 838:               {
 839:                 JScrollBar sb = (JScrollBar) event.getSource();
 840:                 if (sb.isVisible())
 841:                   {
 842:                     int delta = sb.getUnitIncrement(1);
 843:                     sb.setValue(sb.getValue() + delta);
 844:                   }
 845:               }
 846:             }
 847:     );
 848:     map.put("positiveBlockIncrement",
 849:             new AbstractAction("positiveBlockIncrement") {
 850:               public void actionPerformed(ActionEvent event)
 851:               {
 852:                 JScrollBar sb = (JScrollBar) event.getSource();
 853:                 if (sb.isVisible())
 854:                   {
 855:                     int delta = sb.getBlockIncrement(1);
 856:                     sb.setValue(sb.getValue() + delta);
 857:                   }
 858:               }
 859:             }
 860:     );
 861:     map.put("negativeUnitIncrement",
 862:             new AbstractAction("negativeUnitIncrement") {
 863:               public void actionPerformed(ActionEvent event)
 864:               {
 865:                 JScrollBar sb = (JScrollBar) event.getSource();
 866:                 if (sb.isVisible())
 867:                   {
 868:                     int delta = sb.getUnitIncrement(-1);
 869:                     sb.setValue(sb.getValue() + delta);
 870:                   }
 871:               }
 872:             }
 873:     );
 874:     map.put("negativeBlockIncrement",
 875:             new AbstractAction("negativeBlockIncrement") {
 876:               public void actionPerformed(ActionEvent event)
 877:               {
 878:                 JScrollBar sb = (JScrollBar) event.getSource();
 879:                 if (sb.isVisible())
 880:                   {
 881:                     int delta = sb.getBlockIncrement(-1);
 882:                     sb.setValue(sb.getValue() + delta);
 883:                   }
 884:               }
 885:             }
 886:     );
 887:     map.put("minScroll",
 888:             new AbstractAction("minScroll") {
 889:               public void actionPerformed(ActionEvent event)
 890:               {
 891:                 JScrollBar sb = (JScrollBar) event.getSource();
 892:                 if (sb.isVisible())
 893:                   {
 894:                     sb.setValue(sb.getMinimum());
 895:                   }
 896:               }
 897:             }
 898:     );
 899:     map.put("maxScroll",
 900:             new AbstractAction("maxScroll") {
 901:               public void actionPerformed(ActionEvent event)
 902:               {
 903:                 JScrollBar sb = (JScrollBar) event.getSource();
 904:                 if (sb.isVisible())
 905:                   {
 906:                     sb.setValue(sb.getMaximum());
 907:                   }
 908:               }
 909:             }
 910:     );
 911:     return map;
 912:   }
 913: 
 914:   /**
 915:    * This method installs any listeners for the scrollbar. This method also
 916:    * installs listeners for things such as the JButtons and the timer.
 917:    */
 918:   protected void installListeners()
 919:   {
 920:     scrollListener = createScrollListener();
 921:     trackListener = createTrackListener();
 922:     buttonListener = createArrowButtonListener();
 923:     modelListener = createModelListener();
 924:     propertyChangeListener = createPropertyChangeListener();
 925: 
 926:     scrollbar.addMouseMotionListener(trackListener);
 927:     scrollbar.addMouseListener(trackListener);
 928: 
 929:     incrButton.addMouseListener(buttonListener);
 930:     decrButton.addMouseListener(buttonListener);
 931: 
 932:     scrollbar.addPropertyChangeListener(propertyChangeListener);
 933:     scrollbar.getModel().addChangeListener(modelListener);
 934: 
 935:     scrollTimer.addActionListener(scrollListener);
 936:   }
 937: 
 938:   /**
 939:    * This method installs the UI for the component. This can include setting
 940:    * up listeners, defaults,  and components. This also includes initializing
 941:    * any data objects.
 942:    *
 943:    * @param c The JComponent to install.
 944:    */
 945:   public void installUI(JComponent c)
 946:   {
 947:     super.installUI(c);
 948:     if (c instanceof JScrollBar)
 949:       {
 950:         scrollbar = (JScrollBar) c;
 951: 
 952:         trackRect = new Rectangle();
 953:         thumbRect = new Rectangle();
 954: 
 955:         scrollTimer = new Timer(300, null);
 956: 
 957:         installDefaults();
 958:         installComponents();
 959:         configureScrollBarColors();
 960:         installListeners();
 961:         installKeyboardActions();
 962: 
 963:         calculatePreferredSize();
 964:       }
 965:   }
 966: 
 967:   /**
 968:    * This method lays out the scrollbar.
 969:    *
 970:    * @param scrollbarContainer The Container to layout.
 971:    */
 972:   public void layoutContainer(Container scrollbarContainer)
 973:   {
 974:     if (scrollbarContainer instanceof JScrollBar)
 975:       {
 976:         if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL)
 977:           layoutHScrollbar((JScrollBar) scrollbarContainer);
 978:         else
 979:           layoutVScrollbar((JScrollBar) scrollbarContainer);
 980:       }
 981:   }
 982: 
 983:   /**
 984:    * This method lays out the scrollbar horizontally.
 985:    *
 986:    * @param sb The JScrollBar to layout.
 987:    */
 988:   protected void layoutHScrollbar(JScrollBar sb)
 989:   {
 990:     Rectangle vr = new Rectangle();
 991:     SwingUtilities.calculateInnerArea(scrollbar, vr);
 992: 
 993:     Dimension incrDims = incrButton.getPreferredSize();
 994:     Dimension decrDims = decrButton.getPreferredSize();
 995: 
 996:     // calculate and update the track bounds
 997:     SwingUtilities.calculateInnerArea(scrollbar, trackRect);
 998:     trackRect.width -= incrDims.getWidth();
 999:     trackRect.width -= decrDims.getWidth();
1000:     trackRect.x += decrDims.getWidth();
1001: 
1002:     updateThumbRect();
1003: 
1004:     decrButton.setBounds(vr.x, vr.y, decrDims.width, trackRect.height);
1005:     incrButton.setBounds(trackRect.x + trackRect.width, vr.y, incrDims.width,
1006:                          trackRect.height);
1007:   }
1008: 
1009:   /**
1010:    * This method lays out the scrollbar vertically.
1011:    *
1012:    * @param sb The JScrollBar to layout.
1013:    */
1014:   protected void layoutVScrollbar(JScrollBar sb)
1015:   {
1016:     Rectangle vr = new Rectangle();
1017:     SwingUtilities.calculateInnerArea(scrollbar, vr);
1018: 
1019:     Dimension incrDims = incrButton.getPreferredSize();
1020:     Dimension decrDims = decrButton.getPreferredSize();
1021: 
1022:     // Update rectangles
1023:     SwingUtilities.calculateInnerArea(scrollbar, trackRect);
1024:     trackRect.height -= incrDims.getHeight();
1025:     trackRect.height -= decrDims.getHeight();
1026:     trackRect.y += decrDims.getHeight();
1027: 
1028:     updateThumbRect();
1029: 
1030:     decrButton.setBounds(vr.x, vr.y, trackRect.width, decrDims.height);
1031:     incrButton.setBounds(vr.x, trackRect.y + trackRect.height,
1032:                          trackRect.width, incrDims.height);
1033:   }
1034: 
1035:   /**
1036:    * Updates the thumb rect.
1037:    */
1038:   void updateThumbRect()
1039:   {
1040:     int max = scrollbar.getMaximum();
1041:     int min = scrollbar.getMinimum();
1042:     int value = scrollbar.getValue();
1043:     int extent = scrollbar.getVisibleAmount();
1044:     if (max - extent <= min)
1045:       {
1046:         if (scrollbar.getOrientation() == JScrollBar.HORIZONTAL)
1047:           {
1048:             thumbRect.x = trackRect.x;
1049:             thumbRect.y = trackRect.y;
1050:             thumbRect.width = getMinimumThumbSize().width;
1051:             thumbRect.height = trackRect.height;
1052:           }
1053:         else
1054:           {
1055:             thumbRect.x = trackRect.x;
1056:             thumbRect.y = trackRect.y;
1057:             thumbRect.width = trackRect.width;
1058:             thumbRect.height = getMinimumThumbSize().height;
1059:           }
1060:       }
1061:     else
1062:       {
1063:         if (scrollbar.getOrientation() == JScrollBar.HORIZONTAL)
1064:           {
1065:             thumbRect.x = trackRect.x;
1066:             thumbRect.width = Math.max(extent * trackRect.width / (max - min),
1067:                 getMinimumThumbSize().width);
1068:             int availableWidth = trackRect.width - thumbRect.width;
1069:             thumbRect.x += (value - min) * availableWidth / (max - min - extent);
1070:             thumbRect.y = trackRect.y;
1071:             thumbRect.height = trackRect.height;
1072:           }
1073:         else
1074:           {
1075:             thumbRect.x = trackRect.x;
1076:             thumbRect.height = Math.max(extent * trackRect.height / (max - min),
1077:                     getMinimumThumbSize().height);
1078:             int availableHeight = trackRect.height - thumbRect.height;
1079:             thumbRect.y = trackRect.y
1080:               + (value - min) * availableHeight / (max - min - extent);
1081:             thumbRect.width = trackRect.width;
1082:           }
1083:       }
1084: 
1085:   }
1086: 
1087:   /**
1088:    * This method returns the minimum size required for the layout.
1089:    *
1090:    * @param scrollbarContainer The Container that is laid out.
1091:    *
1092:    * @return The minimum size.
1093:    */
1094:   public Dimension minimumLayoutSize(Container scrollbarContainer)
1095:   {
1096:     return preferredLayoutSize(scrollbarContainer);
1097:   }
1098: 
1099:   /**
1100:    * This method is called when the component is painted.
1101:    *
1102:    * @param g The Graphics object to paint with.
1103:    * @param c The JComponent to paint.
1104:    */
1105:   public void paint(Graphics g, JComponent c)
1106:   {
1107:     paintTrack(g, c, getTrackBounds());
1108:     paintThumb(g, c, getThumbBounds());
1109: 
1110:     if (trackHighlight == INCREASE_HIGHLIGHT)
1111:       paintIncreaseHighlight(g);
1112:     else if (trackHighlight == DECREASE_HIGHLIGHT)
1113:       paintDecreaseHighlight(g);
1114:   }
1115: 
1116:   /**
1117:    * This method is called when repainting and the mouse is  pressed in the
1118:    * track. It paints the track below the thumb with the trackHighlight
1119:    * color.
1120:    *
1121:    * @param g The Graphics object to paint with.
1122:    */
1123:   protected void paintDecreaseHighlight(Graphics g)
1124:   {
1125:     Color saved = g.getColor();
1126: 
1127:     g.setColor(trackHighlightColor);
1128:     if (scrollbar.getOrientation() == HORIZONTAL)
1129:       g.fillRect(trackRect.x, trackRect.y, thumbRect.x - trackRect.x,
1130:                  trackRect.height);
1131:     else
1132:       g.fillRect(trackRect.x, trackRect.y, trackRect.width,
1133:                  thumbRect.y - trackRect.y);
1134:     g.setColor(saved);
1135:   }
1136: 
1137:   /**
1138:    * This method is called when repainting and the mouse is  pressed in the
1139:    * track. It paints the track above the thumb with the trackHighlight
1140:    * color.
1141:    *
1142:    * @param g The Graphics objet to paint with.
1143:    */
1144:   protected void paintIncreaseHighlight(Graphics g)
1145:   {
1146:     Color saved = g.getColor();
1147: 
1148:     g.setColor(trackHighlightColor);
1149:     if (scrollbar.getOrientation() == HORIZONTAL)
1150:       g.fillRect(thumbRect.x + thumbRect.width, trackRect.y,
1151:                  trackRect.x + trackRect.width - thumbRect.x - thumbRect.width,
1152:                  trackRect.height);
1153:     else
1154:       g.fillRect(trackRect.x, thumbRect.y + thumbRect.height, trackRect.width,
1155:                  trackRect.y + trackRect.height - thumbRect.y
1156:                  - thumbRect.height);
1157:     g.setColor(saved);
1158:   }
1159: 
1160:   /**
1161:    * This method paints the thumb.
1162:    *
1163:    * @param g The Graphics object to paint with.
1164:    * @param c The Component that is being painted.
1165:    * @param thumbBounds The thumb bounds.
1166:    */
1167:   protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds)
1168:   {
1169:     g.setColor(thumbColor);
1170:     g.fillRect(thumbBounds.x, thumbBounds.y, thumbBounds.width,
1171:                thumbBounds.height);
1172: 
1173:     BasicGraphicsUtils.drawBezel(g, thumbBounds.x, thumbBounds.y,
1174:                                  thumbBounds.width, thumbBounds.height,
1175:                                  false, false, thumbDarkShadowColor,
1176:                                  thumbDarkShadowColor, thumbHighlightColor,
1177:                                  thumbHighlightColor);
1178:   }
1179: 
1180:   /**
1181:    * This method paints the track.
1182:    *
1183:    * @param g The Graphics object to paint with.
1184:    * @param c The JComponent being painted.
1185:    * @param trackBounds The track's bounds.
1186:    */
1187:   protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds)
1188:   {
1189:     Color saved = g.getColor();
1190:     g.setColor(trackColor);
1191:     g.fill3DRect(trackBounds.x, trackBounds.y, trackBounds.width,
1192:                  trackBounds.height, false);
1193:     g.setColor(saved);
1194:   }
1195: 
1196:   /**
1197:    * This method returns the preferred size for the layout.
1198:    *
1199:    * @param scrollbarContainer The Container to find a size for.
1200:    *
1201:    * @return The preferred size for the layout.
1202:    */
1203:   public Dimension preferredLayoutSize(Container scrollbarContainer)
1204:   {
1205:     if (scrollbarContainer instanceof JComponent)
1206:       return getPreferredSize((JComponent) scrollbarContainer);
1207:     else
1208:       return null;
1209:   }
1210: 
1211:   /**
1212:    * This method removes a child component from the layout.
1213:    *
1214:    * @param child The child to remove.
1215:    */
1216:   public void removeLayoutComponent(Component child)
1217:   {
1218:     // You should not be removing stuff from this component.
1219:   }
1220: 
1221:   /**
1222:    * The method scrolls the thumb by a block in the  direction specified.
1223:    *
1224:    * @param direction The direction to scroll.
1225:    */
1226:   protected void scrollByBlock(int direction)
1227:   {
1228:     scrollByBlock(scrollbar, direction);
1229:   }
1230: 
1231:   /**
1232:    * Scrolls the specified <code>scrollBar</code> by one block (according
1233:    * to the scrollable protocol) in the specified <code>direction</code>.
1234:    *
1235:    * This method is here statically to support wheel scrolling from the
1236:    * BasicScrollPaneUI without code duplication.
1237:    *
1238:    * @param scrollBar the scrollbar to scroll
1239:    * @param direction the scroll direction
1240:    */
1241:   static final void scrollByBlock(JScrollBar scrollBar, int direction)
1242:   {
1243:     int delta;
1244:     if (direction > 0)
1245:       delta = scrollBar.getBlockIncrement(direction);
1246:     else
1247:       delta = - scrollBar.getBlockIncrement(direction);
1248:     int oldValue = scrollBar.getValue();
1249:     int newValue = oldValue + delta;
1250: 
1251:     // Overflow check.
1252:     if (delta > 0 && newValue < oldValue)
1253:       newValue = scrollBar.getMaximum();
1254:     else if (delta < 0 && newValue > oldValue)
1255:       newValue = scrollBar.getMinimum();
1256: 
1257:     scrollBar.setValue(newValue);
1258:   }
1259: 
1260:   /**
1261:    * The method scrolls the thumb by a unit in the direction specified.
1262:    *
1263:    * @param direction The direction to scroll.
1264:    */
1265:   protected void scrollByUnit(int direction)
1266:   {
1267:     scrollByUnits(scrollbar, direction, 1);
1268:   }
1269: 
1270:   /**
1271:    * Scrolls the specified <code>scrollbac/code> by <code>units</code> units
1272:    * in the specified <code>direction</code>.
1273:    *
1274:    * This method is here statically to support wheel scrolling from the
1275:    * BasicScrollPaneUI without code duplication.
1276:    *
1277:    * @param scrollBar the scrollbar to scroll
1278:    * @param direction the direction
1279:    * @param units the number of units to scroll
1280:    */
1281:   static final void scrollByUnits(JScrollBar scrollBar, int direction,
1282:                                    int units)
1283:   {
1284:     // Do this inside a loop so that we don't clash with the scrollable
1285:     // interface, which can return different units at times. For instance,
1286:     // a Scrollable could return a unit of 2 pixels only to adjust the
1287:     // visibility of an item. If we would simply multiply this by units,
1288:     // then we would only get 6 pixels, which is complete crap.
1289:     for (int i = 0; i < units; i++)
1290:       {
1291:         int delta;
1292:         if (direction > 0)
1293:           delta = scrollBar.getUnitIncrement(direction);
1294:         else
1295:           delta = - scrollBar.getUnitIncrement(direction);
1296:         int oldValue = scrollBar.getValue();
1297:         int newValue = oldValue + delta;
1298: 
1299:         // Overflow check.
1300:         if (delta > 0 && newValue < oldValue)
1301:           newValue = scrollBar.getMaximum();
1302:         else if (delta < 0 && newValue > oldValue)
1303:           newValue = scrollBar.getMinimum();
1304: 
1305:         scrollBar.setValue(newValue);
1306:       }
1307:   }
1308: 
1309:   /**
1310:    * This method sets the thumb's bounds.
1311:    *
1312:    * @param x The X position of the thumb.
1313:    * @param y The Y position of the thumb.
1314:    * @param width The width of the thumb.
1315:    * @param height The height of the thumb.
1316:    */
1317:   protected void setThumbBounds(int x, int y, int width, int height)
1318:   {
1319:     thumbRect.x = x;
1320:     thumbRect.y = y;
1321:     thumbRect.width = width;
1322:     thumbRect.height = height;
1323:   }
1324: 
1325:   /**
1326:    * This method uninstalls any components that  are a part of or related to
1327:    * this scrollbar.
1328:    */
1329:   protected void uninstallComponents()
1330:   {
1331:     if (incrButton != null)
1332:       scrollbar.remove(incrButton);
1333:     if (decrButton != null)
1334:       scrollbar.remove(decrButton);
1335:   }
1336: 
1337:   /**
1338:    * This method uninstalls any defaults that this scrollbar acquired from the
1339:    * Basic Look and Feel defaults.
1340:    */
1341:   protected void uninstallDefaults()
1342:   {
1343:     scrollbar.setForeground(null);
1344:     scrollbar.setBackground(null);
1345:     LookAndFeel.uninstallBorder(scrollbar);
1346:     incrButton = null;
1347:     decrButton = null;
1348:   }
1349: 
1350:   /**
1351:    * This method uninstalls any listeners that were registered during install.
1352:    */
1353:   protected void uninstallListeners()
1354:   {
1355:     if (scrollTimer != null)
1356:       scrollTimer.removeActionListener(scrollListener);
1357: 
1358:     if (scrollbar != null)
1359:       {
1360:         scrollbar.getModel().removeChangeListener(modelListener);
1361:         scrollbar.removePropertyChangeListener(propertyChangeListener);
1362:         scrollbar.removeMouseListener(trackListener);
1363:         scrollbar.removeMouseMotionListener(trackListener);
1364:       }
1365: 
1366:     if (decrButton != null)
1367:       decrButton.removeMouseListener(buttonListener);
1368:     if (incrButton != null)
1369:       incrButton.removeMouseListener(buttonListener);
1370: 
1371:     propertyChangeListener = null;
1372:     modelListener = null;
1373:     buttonListener = null;
1374:     trackListener = null;
1375:     scrollListener = null;
1376:   }
1377: 
1378:   /**
1379:    * This method uninstalls the UI. This includes removing any defaults,
1380:    * listeners, and components that this UI may have initialized. It also
1381:    * nulls any instance data.
1382:    *
1383:    * @param c The Component to uninstall for.
1384:    */
1385:   public void uninstallUI(JComponent c)
1386:   {
1387:     uninstallKeyboardActions();
1388:     uninstallListeners();
1389:     uninstallDefaults();
1390:     uninstallComponents();
1391: 
1392:     scrollTimer = null;
1393: 
1394:     thumbRect = null;
1395:     trackRect = null;
1396: 
1397:     trackColor = null;
1398:     trackHighlightColor = null;
1399:     thumbColor = null;
1400:     thumbHighlightColor = null;
1401:     thumbDarkShadowColor = null;
1402:     thumbLightShadowColor = null;
1403: 
1404:     scrollbar = null;
1405:   }
1406: 
1407:   /**
1408:    * This method returns the value in the scrollbar's range given the y
1409:    * coordinate. If the value is out of range, it will return the closest
1410:    * legal value.
1411:    * This is package-private to avoid an accessor method.
1412:    *
1413:    * @param yPos The y coordinate to calculate a value for.
1414:    *
1415:    * @return The value for the y coordinate.
1416:    */
1417:   int valueForYPosition(int yPos)
1418:   {
1419:     int min = scrollbar.getMinimum();
1420:     int max = scrollbar.getMaximum();
1421:     int len = trackRect.height;
1422: 
1423:     int value;
1424: 
1425:     // If the length is 0, you shouldn't be able to even see where the thumb is.
1426:     // This really shouldn't ever happen, but just in case, we'll return the middle.
1427:     if (len == 0)
1428:       return (max - min) / 2;
1429: 
1430:     value = (yPos - trackRect.y) * (max - min) / len + min;
1431: 
1432:     // If this isn't a legal value, then we'll have to move to one now.
1433:     if (value > max)
1434:       value = max;
1435:     else if (value < min)
1436:       value = min;
1437:     return value;
1438:   }
1439: 
1440:   /**
1441:    * This method returns the value in the scrollbar's range given the x
1442:    * coordinate. If the value is out of range, it will return the closest
1443:    * legal value.
1444:    * This is package-private to avoid an accessor method.
1445:    *
1446:    * @param xPos The x coordinate to calculate a value for.
1447:    *
1448:    * @return The value for the x coordinate.
1449:    */
1450:   int valueForXPosition(int xPos)
1451:   {
1452:     int min = scrollbar.getMinimum();
1453:     int max = scrollbar.getMaximum();
1454:     int len = trackRect.width;
1455: 
1456:     int value;
1457: 
1458:     // If the length is 0, you shouldn't be able to even see where the slider is.
1459:     // This really shouldn't ever happen, but just in case, we'll return the middle.
1460:     if (len == 0)
1461:       return (max - min) / 2;
1462: 
1463:     value = (xPos - trackRect.x) * (max - min) / len + min;
1464: 
1465:     // If this isn't a legal value, then we'll have to move to one now.
1466:     if (value > max)
1467:       value = max;
1468:     else if (value < min)
1469:       value = min;
1470:     return value;
1471:   }
1472: 
1473:   /**
1474:    * Returns true if the mouse is over the thumb.
1475:    *
1476:    * @return true if the mouse is over the thumb.
1477:    *
1478:    * @since 1.5
1479:    */
1480:   public boolean isThumbRollover()
1481:   {
1482:    return thumbRollover;
1483:   }
1484: 
1485:   /**
1486:    * Set thumbRollover to active. This indicates
1487:    * whether or not the mouse is over the thumb.
1488:    *
1489:    * @param active - true if the mouse is over the thumb.
1490:    *
1491:    * @since 1.5
1492:    */
1493:   protected void setThumbRollover(boolean active)
1494:   {
1495:     thumbRollover = active;
1496:   }
1497: 
1498:   /**
1499:    * Indicates whether the user can position the thumb with
1500:    * a mouse click (i.e. middle button).
1501:    *
1502:    * @return true if the user can position the thumb with a mouse
1503:    * click.
1504:    *
1505:    * @since 1.5
1506:    */
1507:   public boolean getSupportsAbsolutePositioning()
1508:   {
1509:     // The positioning feature has not been implemented.
1510:     // So, false is always returned.
1511:     return false;
1512:   }
1513: }