Save This Page
Home » openjdk-7 » javax » swing » plaf » basic » [javadoc | source]
    1   /*
    2    * Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   package javax.swing.plaf.basic;
   26   
   27   
   28   import sun.swing.DefaultLookup;
   29   import sun.swing.UIAction;
   30   
   31   import java.awt;
   32   import java.awt.event;
   33   
   34   import java.beans;
   35   
   36   import javax.swing;
   37   import javax.swing.event;
   38   import javax.swing.plaf;
   39   
   40   
   41   /**
   42    * Implementation of ScrollBarUI for the Basic Look and Feel
   43    *
   44    * @author Rich Schiavi
   45    * @author David Kloba
   46    * @author Hans Muller
   47    */
   48   public class BasicScrollBarUI
   49       extends ScrollBarUI implements LayoutManager, SwingConstants
   50   {
   51       private static final int POSITIVE_SCROLL = 1;
   52       private static final int NEGATIVE_SCROLL = -1;
   53   
   54       private static final int MIN_SCROLL = 2;
   55       private static final int MAX_SCROLL = 3;
   56   
   57       // NOTE: DO NOT use this field directly, SynthScrollBarUI assumes you'll
   58       // call getMinimumThumbSize to access it.
   59       protected Dimension minimumThumbSize;
   60       protected Dimension maximumThumbSize;
   61   
   62       protected Color thumbHighlightColor;
   63       protected Color thumbLightShadowColor;
   64       protected Color thumbDarkShadowColor;
   65       protected Color thumbColor;
   66       protected Color trackColor;
   67       protected Color trackHighlightColor;
   68   
   69       protected JScrollBar scrollbar;
   70       protected JButton incrButton;
   71       protected JButton decrButton;
   72       protected boolean isDragging;
   73       protected TrackListener trackListener;
   74       protected ArrowButtonListener buttonListener;
   75       protected ModelListener modelListener;
   76   
   77       protected Rectangle thumbRect;
   78       protected Rectangle trackRect;
   79   
   80       protected int trackHighlight;
   81   
   82       protected static final int NO_HIGHLIGHT = 0;
   83       protected static final int DECREASE_HIGHLIGHT = 1;
   84       protected static final int INCREASE_HIGHLIGHT = 2;
   85   
   86       protected ScrollListener scrollListener;
   87       protected PropertyChangeListener propertyChangeListener;
   88       protected Timer scrollTimer;
   89   
   90       private final static int scrollSpeedThrottle = 60; // delay in milli seconds
   91   
   92       /** True indicates a middle click will absolutely position the
   93        * scrollbar. */
   94       private boolean supportsAbsolutePositioning;
   95   
   96       /** Hint as to what width (when vertical) or height (when horizontal)
   97        * should be.
   98        */
   99       private int scrollBarWidth;
  100   
  101       private Handler handler;
  102   
  103       private boolean thumbActive;
  104   
  105       /**
  106        * Determine whether scrollbar layout should use cached value or adjusted
  107        * value returned by scrollbar's <code>getValue</code>.
  108        */
  109       private boolean useCachedValue = false;
  110       /**
  111        * The scrollbar value is cached to save real value if the view is adjusted.
  112        */
  113       private int scrollBarValue;
  114   
  115       static void loadActionMap(LazyActionMap map) {
  116           map.put(new Actions(Actions.POSITIVE_UNIT_INCREMENT));
  117           map.put(new Actions(Actions.POSITIVE_BLOCK_INCREMENT));
  118           map.put(new Actions(Actions.NEGATIVE_UNIT_INCREMENT));
  119           map.put(new Actions(Actions.NEGATIVE_BLOCK_INCREMENT));
  120           map.put(new Actions(Actions.MIN_SCROLL));
  121           map.put(new Actions(Actions.MAX_SCROLL));
  122       }
  123   
  124   
  125       public static ComponentUI createUI(JComponent c)    {
  126           return new BasicScrollBarUI();
  127       }
  128   
  129   
  130       protected void configureScrollBarColors()
  131       {
  132           LookAndFeel.installColors(scrollbar, "ScrollBar.background",
  133                                     "ScrollBar.foreground");
  134           thumbHighlightColor = UIManager.getColor("ScrollBar.thumbHighlight");
  135           thumbLightShadowColor = UIManager.getColor("ScrollBar.thumbShadow");
  136           thumbDarkShadowColor = UIManager.getColor("ScrollBar.thumbDarkShadow");
  137           thumbColor = UIManager.getColor("ScrollBar.thumb");
  138           trackColor = UIManager.getColor("ScrollBar.track");
  139           trackHighlightColor = UIManager.getColor("ScrollBar.trackHighlight");
  140       }
  141   
  142   
  143       public void installUI(JComponent c)   {
  144           scrollbar = (JScrollBar)c;
  145           thumbRect = new Rectangle(0, 0, 0, 0);
  146           trackRect = new Rectangle(0, 0, 0, 0);
  147           installDefaults();
  148           installComponents();
  149           installListeners();
  150           installKeyboardActions();
  151       }
  152   
  153       public void uninstallUI(JComponent c) {
  154           scrollbar = (JScrollBar)c;
  155           uninstallListeners();
  156           uninstallDefaults();
  157           uninstallComponents();
  158           uninstallKeyboardActions();
  159           thumbRect = null;
  160           scrollbar = null;
  161           incrButton = null;
  162           decrButton = null;
  163       }
  164   
  165   
  166       protected void installDefaults()
  167       {
  168           scrollBarWidth = UIManager.getInt("ScrollBar.width");
  169           if (scrollBarWidth <= 0) {
  170               scrollBarWidth = 16;
  171           }
  172           minimumThumbSize = (Dimension)UIManager.get("ScrollBar.minimumThumbSize");
  173           maximumThumbSize = (Dimension)UIManager.get("ScrollBar.maximumThumbSize");
  174   
  175           Boolean absB = (Boolean)UIManager.get("ScrollBar.allowsAbsolutePositioning");
  176           supportsAbsolutePositioning = (absB != null) ? absB.booleanValue() :
  177                                         false;
  178   
  179           trackHighlight = NO_HIGHLIGHT;
  180           if (scrollbar.getLayout() == null ||
  181                        (scrollbar.getLayout() instanceof UIResource)) {
  182               scrollbar.setLayout(this);
  183           }
  184           configureScrollBarColors();
  185           LookAndFeel.installBorder(scrollbar, "ScrollBar.border");
  186           LookAndFeel.installProperty(scrollbar, "opaque", Boolean.TRUE);
  187   
  188           scrollBarValue = scrollbar.getValue();
  189       }
  190   
  191   
  192       protected void installComponents(){
  193           switch (scrollbar.getOrientation()) {
  194           case JScrollBar.VERTICAL:
  195               incrButton = createIncreaseButton(SOUTH);
  196               decrButton = createDecreaseButton(NORTH);
  197               break;
  198   
  199           case JScrollBar.HORIZONTAL:
  200               if (scrollbar.getComponentOrientation().isLeftToRight()) {
  201                   incrButton = createIncreaseButton(EAST);
  202                   decrButton = createDecreaseButton(WEST);
  203               } else {
  204                   incrButton = createIncreaseButton(WEST);
  205                   decrButton = createDecreaseButton(EAST);
  206               }
  207               break;
  208           }
  209           scrollbar.add(incrButton);
  210           scrollbar.add(decrButton);
  211           // Force the children's enabled state to be updated.
  212           scrollbar.setEnabled(scrollbar.isEnabled());
  213       }
  214   
  215       protected void uninstallComponents(){
  216           scrollbar.remove(incrButton);
  217           scrollbar.remove(decrButton);
  218       }
  219   
  220   
  221       protected void installListeners(){
  222           trackListener = createTrackListener();
  223           buttonListener = createArrowButtonListener();
  224           modelListener = createModelListener();
  225           propertyChangeListener = createPropertyChangeListener();
  226   
  227           scrollbar.addMouseListener(trackListener);
  228           scrollbar.addMouseMotionListener(trackListener);
  229           scrollbar.getModel().addChangeListener(modelListener);
  230           scrollbar.addPropertyChangeListener(propertyChangeListener);
  231           scrollbar.addFocusListener(getHandler());
  232   
  233           if (incrButton != null) {
  234               incrButton.addMouseListener(buttonListener);
  235           }
  236           if (decrButton != null) {
  237               decrButton.addMouseListener(buttonListener);
  238           }
  239   
  240           scrollListener = createScrollListener();
  241           scrollTimer = new Timer(scrollSpeedThrottle, scrollListener);
  242           scrollTimer.setInitialDelay(300);  // default InitialDelay?
  243       }
  244   
  245   
  246       protected void installKeyboardActions(){
  247           LazyActionMap.installLazyActionMap(scrollbar, BasicScrollBarUI.class,
  248                                              "ScrollBar.actionMap");
  249   
  250           InputMap inputMap = getInputMap(JComponent.WHEN_FOCUSED);
  251           SwingUtilities.replaceUIInputMap(scrollbar, JComponent.WHEN_FOCUSED,
  252                                            inputMap);
  253           inputMap = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  254           SwingUtilities.replaceUIInputMap(scrollbar,
  255                      JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap);
  256       }
  257   
  258       protected void uninstallKeyboardActions(){
  259           SwingUtilities.replaceUIInputMap(scrollbar, JComponent.WHEN_FOCUSED,
  260                                            null);
  261           SwingUtilities.replaceUIActionMap(scrollbar, null);
  262       }
  263   
  264       private InputMap getInputMap(int condition) {
  265           if (condition == JComponent.WHEN_FOCUSED) {
  266               InputMap keyMap = (InputMap)DefaultLookup.get(
  267                           scrollbar, this, "ScrollBar.focusInputMap");
  268               InputMap rtlKeyMap;
  269   
  270               if (scrollbar.getComponentOrientation().isLeftToRight() ||
  271                   ((rtlKeyMap = (InputMap)DefaultLookup.get(scrollbar, this, "ScrollBar.focusInputMap.RightToLeft")) == null)) {
  272                   return keyMap;
  273               } else {
  274                   rtlKeyMap.setParent(keyMap);
  275                   return rtlKeyMap;
  276               }
  277           }
  278           else if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
  279               InputMap keyMap = (InputMap)DefaultLookup.get(
  280                           scrollbar, this, "ScrollBar.ancestorInputMap");
  281               InputMap rtlKeyMap;
  282   
  283               if (scrollbar.getComponentOrientation().isLeftToRight() ||
  284                   ((rtlKeyMap = (InputMap)DefaultLookup.get(scrollbar, this, "ScrollBar.ancestorInputMap.RightToLeft")) == null)) {
  285                   return keyMap;
  286               } else {
  287                   rtlKeyMap.setParent(keyMap);
  288                   return rtlKeyMap;
  289               }
  290           }
  291           return null;
  292       }
  293   
  294   
  295       protected void uninstallListeners() {
  296           scrollTimer.stop();
  297           scrollTimer = null;
  298   
  299           if (decrButton != null){
  300               decrButton.removeMouseListener(buttonListener);
  301           }
  302           if (incrButton != null){
  303               incrButton.removeMouseListener(buttonListener);
  304           }
  305   
  306           scrollbar.getModel().removeChangeListener(modelListener);
  307           scrollbar.removeMouseListener(trackListener);
  308           scrollbar.removeMouseMotionListener(trackListener);
  309           scrollbar.removePropertyChangeListener(propertyChangeListener);
  310           scrollbar.removeFocusListener(getHandler());
  311           handler = null;
  312       }
  313   
  314   
  315       protected void uninstallDefaults(){
  316           LookAndFeel.uninstallBorder(scrollbar);
  317           if (scrollbar.getLayout() == this) {
  318               scrollbar.setLayout(null);
  319           }
  320       }
  321   
  322   
  323       private Handler getHandler() {
  324           if (handler == null) {
  325               handler = new Handler();
  326           }
  327           return handler;
  328       }
  329   
  330       protected TrackListener createTrackListener(){
  331           return new TrackListener();
  332       }
  333   
  334       protected ArrowButtonListener createArrowButtonListener(){
  335           return new ArrowButtonListener();
  336       }
  337   
  338       protected ModelListener createModelListener(){
  339           return new ModelListener();
  340       }
  341   
  342       protected ScrollListener createScrollListener(){
  343           return new ScrollListener();
  344       }
  345   
  346       protected PropertyChangeListener createPropertyChangeListener() {
  347           return getHandler();
  348       }
  349   
  350       private void updateThumbState(int x, int y) {
  351           Rectangle rect = getThumbBounds();
  352   
  353           setThumbRollover(rect.contains(x, y));
  354       }
  355   
  356       /**
  357        * Sets whether or not the mouse is currently over the thumb.
  358        *
  359        * @param active True indicates the thumb is currently active.
  360        * @since 1.5
  361        */
  362       protected void setThumbRollover(boolean active) {
  363           if (thumbActive != active) {
  364               thumbActive = active;
  365               scrollbar.repaint(getThumbBounds());
  366           }
  367       }
  368   
  369       /**
  370        * Returns true if the mouse is currently over the thumb.
  371        *
  372        * @return true if the thumb is currently active
  373        * @since 1.5
  374        */
  375       public boolean isThumbRollover() {
  376           return thumbActive;
  377       }
  378   
  379       public void paint(Graphics g, JComponent c) {
  380           paintTrack(g, c, getTrackBounds());
  381           Rectangle thumbBounds = getThumbBounds();
  382           if (thumbBounds.intersects(g.getClipBounds())) {
  383               paintThumb(g, c, thumbBounds);
  384           }
  385       }
  386   
  387   
  388       /**
  389        * A vertical scrollbar's preferred width is the maximum of
  390        * preferred widths of the (non <code>null</code>)
  391        * increment/decrement buttons,
  392        * and the minimum width of the thumb. The preferred height is the
  393        * sum of the preferred heights of the same parts.  The basis for
  394        * the preferred size of a horizontal scrollbar is similar.
  395        * <p>
  396        * The <code>preferredSize</code> is only computed once, subsequent
  397        * calls to this method just return a cached size.
  398        *
  399        * @param c the <code>JScrollBar</code> that's delegating this method to us
  400        * @return the preferred size of a Basic JScrollBar
  401        * @see #getMaximumSize
  402        * @see #getMinimumSize
  403        */
  404       public Dimension getPreferredSize(JComponent c) {
  405           return (scrollbar.getOrientation() == JScrollBar.VERTICAL)
  406               ? new Dimension(scrollBarWidth, 48)
  407               : new Dimension(48, scrollBarWidth);
  408       }
  409   
  410   
  411       /**
  412        * @param c The JScrollBar that's delegating this method to us.
  413        * @return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
  414        * @see #getMinimumSize
  415        * @see #getPreferredSize
  416        */
  417       public Dimension getMaximumSize(JComponent c) {
  418           return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
  419       }
  420   
  421       protected JButton createDecreaseButton(int orientation)  {
  422           return new BasicArrowButton(orientation,
  423                                       UIManager.getColor("ScrollBar.thumb"),
  424                                       UIManager.getColor("ScrollBar.thumbShadow"),
  425                                       UIManager.getColor("ScrollBar.thumbDarkShadow"),
  426                                       UIManager.getColor("ScrollBar.thumbHighlight"));
  427       }
  428   
  429       protected JButton createIncreaseButton(int orientation)  {
  430           return new BasicArrowButton(orientation,
  431                                       UIManager.getColor("ScrollBar.thumb"),
  432                                       UIManager.getColor("ScrollBar.thumbShadow"),
  433                                       UIManager.getColor("ScrollBar.thumbDarkShadow"),
  434                                       UIManager.getColor("ScrollBar.thumbHighlight"));
  435       }
  436   
  437   
  438       protected void paintDecreaseHighlight(Graphics g)
  439       {
  440           Insets insets = scrollbar.getInsets();
  441           Rectangle thumbR = getThumbBounds();
  442           g.setColor(trackHighlightColor);
  443   
  444           if (scrollbar.getOrientation() == JScrollBar.VERTICAL) {
  445               int x = insets.left;
  446               int y = decrButton.getY() + decrButton.getHeight();
  447               int w = scrollbar.getWidth() - (insets.left + insets.right);
  448               int h = thumbR.y - y;
  449               g.fillRect(x, y, w, h);
  450           }
  451           else    {
  452               int x, w;
  453               if (scrollbar.getComponentOrientation().isLeftToRight()) {
  454                   x = decrButton.getX() + decrButton.getWidth();
  455                   w = thumbR.x - x;
  456               } else {
  457                   x = thumbR.x + thumbR.width;
  458                   w = decrButton.getX() - x;
  459               }
  460               int y = insets.top;
  461               int h = scrollbar.getHeight() - (insets.top + insets.bottom);
  462               g.fillRect(x, y, w, h);
  463           }
  464       }
  465   
  466   
  467       protected void paintIncreaseHighlight(Graphics g)
  468       {
  469           Insets insets = scrollbar.getInsets();
  470           Rectangle thumbR = getThumbBounds();
  471           g.setColor(trackHighlightColor);
  472   
  473           if (scrollbar.getOrientation() == JScrollBar.VERTICAL) {
  474               int x = insets.left;
  475               int y = thumbR.y + thumbR.height;
  476               int w = scrollbar.getWidth() - (insets.left + insets.right);
  477               int h = incrButton.getY() - y;
  478               g.fillRect(x, y, w, h);
  479           }
  480           else {
  481               int x, w;
  482               if (scrollbar.getComponentOrientation().isLeftToRight()) {
  483                   x = thumbR.x + thumbR.width;
  484                   w = incrButton.getX() - x;
  485               } else {
  486                   x = incrButton.getX() + incrButton.getWidth();
  487                   w = thumbR.x - x;
  488               }
  489               int y = insets.top;
  490               int h = scrollbar.getHeight() - (insets.top + insets.bottom);
  491               g.fillRect(x, y, w, h);
  492           }
  493       }
  494   
  495   
  496       protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds)
  497       {
  498           g.setColor(trackColor);
  499           g.fillRect(trackBounds.x, trackBounds.y, trackBounds.width, trackBounds.height);
  500   
  501           if(trackHighlight == DECREASE_HIGHLIGHT)        {
  502               paintDecreaseHighlight(g);
  503           }
  504           else if(trackHighlight == INCREASE_HIGHLIGHT)           {
  505               paintIncreaseHighlight(g);
  506           }
  507       }
  508   
  509   
  510       protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds)
  511       {
  512           if(thumbBounds.isEmpty() || !scrollbar.isEnabled())     {
  513               return;
  514           }
  515   
  516           int w = thumbBounds.width;
  517           int h = thumbBounds.height;
  518   
  519           g.translate(thumbBounds.x, thumbBounds.y);
  520   
  521           g.setColor(thumbDarkShadowColor);
  522           g.drawRect(0, 0, w-1, h-1);
  523           g.setColor(thumbColor);
  524           g.fillRect(0, 0, w-1, h-1);
  525   
  526           g.setColor(thumbHighlightColor);
  527           g.drawLine(1, 1, 1, h-2);
  528           g.drawLine(2, 1, w-3, 1);
  529   
  530           g.setColor(thumbLightShadowColor);
  531           g.drawLine(2, h-2, w-2, h-2);
  532           g.drawLine(w-2, 1, w-2, h-3);
  533   
  534           g.translate(-thumbBounds.x, -thumbBounds.y);
  535       }
  536   
  537   
  538       /**
  539        * Return the smallest acceptable size for the thumb.  If the scrollbar
  540        * becomes so small that this size isn't available, the thumb will be
  541        * hidden.
  542        * <p>
  543        * <b>Warning </b>: the value returned by this method should not be
  544        * be modified, it's a shared static constant.
  545        *
  546        * @return The smallest acceptable size for the thumb.
  547        * @see #getMaximumThumbSize
  548        */
  549       protected Dimension getMinimumThumbSize() {
  550           return minimumThumbSize;
  551       }
  552   
  553       /**
  554        * Return the largest acceptable size for the thumb.  To create a fixed
  555        * size thumb one make this method and <code>getMinimumThumbSize</code>
  556        * return the same value.
  557        * <p>
  558        * <b>Warning </b>: the value returned by this method should not be
  559        * be modified, it's a shared static constant.
  560        *
  561        * @return The largest acceptable size for the thumb.
  562        * @see #getMinimumThumbSize
  563        */
  564       protected Dimension getMaximumThumbSize()   {
  565           return maximumThumbSize;
  566       }
  567   
  568   
  569       /*
  570        * LayoutManager Implementation
  571        */
  572   
  573       public void addLayoutComponent(String name, Component child) {}
  574       public void removeLayoutComponent(Component child) {}
  575   
  576       public Dimension preferredLayoutSize(Container scrollbarContainer)  {
  577           return getPreferredSize((JComponent)scrollbarContainer);
  578       }
  579   
  580       public Dimension minimumLayoutSize(Container scrollbarContainer) {
  581           return getMinimumSize((JComponent)scrollbarContainer);
  582       }
  583   
  584       private int getValue(JScrollBar sb) {
  585           return (useCachedValue) ? scrollBarValue : sb.getValue();
  586       }
  587   
  588       protected void layoutVScrollbar(JScrollBar sb)
  589       {
  590           Dimension sbSize = sb.getSize();
  591           Insets sbInsets = sb.getInsets();
  592   
  593           /*
  594            * Width and left edge of the buttons and thumb.
  595            */
  596           int itemW = sbSize.width - (sbInsets.left + sbInsets.right);
  597           int itemX = sbInsets.left;
  598   
  599           /* Nominal locations of the buttons, assuming their preferred
  600            * size will fit.
  601            */
  602           boolean squareButtons = DefaultLookup.getBoolean(
  603               scrollbar, this, "ScrollBar.squareButtons", false);
  604           int decrButtonH = squareButtons ? itemW :
  605                             decrButton.getPreferredSize().height;
  606           int decrButtonY = sbInsets.top;
  607   
  608           int incrButtonH = squareButtons ? itemW :
  609                             incrButton.getPreferredSize().height;
  610           int incrButtonY = sbSize.height - (sbInsets.bottom + incrButtonH);
  611   
  612           /* The thumb must fit within the height left over after we
  613            * subtract the preferredSize of the buttons and the insets.
  614            */
  615           int sbInsetsH = sbInsets.top + sbInsets.bottom;
  616           int sbButtonsH = decrButtonH + incrButtonH;
  617           float trackH = sbSize.height - (sbInsetsH + sbButtonsH);
  618   
  619           /* Compute the height and origin of the thumb.   The case
  620            * where the thumb is at the bottom edge is handled specially
  621            * to avoid numerical problems in computing thumbY.  Enforce
  622            * the thumbs min/max dimensions.  If the thumb doesn't
  623            * fit in the track (trackH) we'll hide it later.
  624            */
  625           float min = sb.getMinimum();
  626           float extent = sb.getVisibleAmount();
  627           float range = sb.getMaximum() - min;
  628           float value = getValue(sb);
  629   
  630           int thumbH = (range <= 0)
  631               ? getMaximumThumbSize().height : (int)(trackH * (extent / range));
  632           thumbH = Math.max(thumbH, getMinimumThumbSize().height);
  633           thumbH = Math.min(thumbH, getMaximumThumbSize().height);
  634   
  635           int thumbY = incrButtonY - thumbH;
  636           if (value < (sb.getMaximum() - sb.getVisibleAmount())) {
  637               float thumbRange = trackH - thumbH;
  638               thumbY = (int)(0.5f + (thumbRange * ((value - min) / (range - extent))));
  639               thumbY +=  decrButtonY + decrButtonH;
  640           }
  641   
  642           /* If the buttons don't fit, allocate half of the available
  643            * space to each and move the lower one (incrButton) down.
  644            */
  645           int sbAvailButtonH = (sbSize.height - sbInsetsH);
  646           if (sbAvailButtonH < sbButtonsH) {
  647               incrButtonH = decrButtonH = sbAvailButtonH / 2;
  648               incrButtonY = sbSize.height - (sbInsets.bottom + incrButtonH);
  649           }
  650           decrButton.setBounds(itemX, decrButtonY, itemW, decrButtonH);
  651           incrButton.setBounds(itemX, incrButtonY, itemW, incrButtonH);
  652   
  653           /* Update the trackRect field.
  654            */
  655           int itrackY = decrButtonY + decrButtonH;
  656           int itrackH = incrButtonY - itrackY;
  657           trackRect.setBounds(itemX, itrackY, itemW, itrackH);
  658   
  659           /* If the thumb isn't going to fit, zero it's bounds.  Otherwise
  660            * make sure it fits between the buttons.  Note that setting the
  661            * thumbs bounds will cause a repaint.
  662            */
  663           if(thumbH >= (int)trackH)       {
  664               if (UIManager.getBoolean("ScrollBar.alwaysShowThumb")) {
  665                   // This is used primarily for GTK L&F, which expands the
  666                   // thumb to fit the track when it would otherwise be hidden.
  667                   setThumbBounds(itemX, itrackY, itemW, itrackH);
  668               } else {
  669                   // Other L&F's simply hide the thumb in this case.
  670                   setThumbBounds(0, 0, 0, 0);
  671               }
  672           }
  673           else {
  674               if ((thumbY + thumbH) > incrButtonY) {
  675                   thumbY = incrButtonY - thumbH;
  676               }
  677               if (thumbY  < (decrButtonY + decrButtonH)) {
  678                   thumbY = decrButtonY + decrButtonH + 1;
  679               }
  680               setThumbBounds(itemX, thumbY, itemW, thumbH);
  681           }
  682       }
  683   
  684   
  685       protected void layoutHScrollbar(JScrollBar sb)
  686       {
  687           Dimension sbSize = sb.getSize();
  688           Insets sbInsets = sb.getInsets();
  689   
  690           /* Height and top edge of the buttons and thumb.
  691            */
  692           int itemH = sbSize.height - (sbInsets.top + sbInsets.bottom);
  693           int itemY = sbInsets.top;
  694   
  695           boolean ltr = sb.getComponentOrientation().isLeftToRight();
  696   
  697           /* Nominal locations of the buttons, assuming their preferred
  698            * size will fit.
  699            */
  700           boolean squareButtons = DefaultLookup.getBoolean(
  701               scrollbar, this, "ScrollBar.squareButtons", false);
  702           int leftButtonW = squareButtons ? itemH :
  703                             decrButton.getPreferredSize().width;
  704           int rightButtonW = squareButtons ? itemH :
  705                             incrButton.getPreferredSize().width;
  706           if (!ltr) {
  707               int temp = leftButtonW;
  708               leftButtonW = rightButtonW;
  709               rightButtonW = temp;
  710           }
  711           int leftButtonX = sbInsets.left;
  712           int rightButtonX = sbSize.width - (sbInsets.right + rightButtonW);
  713   
  714           /* The thumb must fit within the width left over after we
  715            * subtract the preferredSize of the buttons and the insets.
  716            */
  717           int sbInsetsW = sbInsets.left + sbInsets.right;
  718           int sbButtonsW = leftButtonW + rightButtonW;
  719           float trackW = sbSize.width - (sbInsetsW + sbButtonsW);
  720   
  721           /* Compute the width and origin of the thumb.  Enforce
  722            * the thumbs min/max dimensions.  The case where the thumb
  723            * is at the right edge is handled specially to avoid numerical
  724            * problems in computing thumbX.  If the thumb doesn't
  725            * fit in the track (trackH) we'll hide it later.
  726            */
  727           float min = sb.getMinimum();
  728           float max = sb.getMaximum();
  729           float extent = sb.getVisibleAmount();
  730           float range = max - min;
  731           float value = getValue(sb);
  732   
  733           int thumbW = (range <= 0)
  734               ? getMaximumThumbSize().width : (int)(trackW * (extent / range));
  735           thumbW = Math.max(thumbW, getMinimumThumbSize().width);
  736           thumbW = Math.min(thumbW, getMaximumThumbSize().width);
  737   
  738           int thumbX = ltr ? rightButtonX - thumbW : leftButtonX + leftButtonW;
  739           if (value < (max - sb.getVisibleAmount())) {
  740               float thumbRange = trackW - thumbW;
  741               if( ltr ) {
  742                   thumbX = (int)(0.5f + (thumbRange * ((value - min) / (range - extent))));
  743               } else {
  744                   thumbX = (int)(0.5f + (thumbRange * ((max - extent - value) / (range - extent))));
  745               }
  746               thumbX +=  leftButtonX + leftButtonW;
  747           }
  748   
  749           /* If the buttons don't fit, allocate half of the available
  750            * space to each and move the right one over.
  751            */
  752           int sbAvailButtonW = (sbSize.width - sbInsetsW);
  753           if (sbAvailButtonW < sbButtonsW) {
  754               rightButtonW = leftButtonW = sbAvailButtonW / 2;
  755               rightButtonX = sbSize.width - (sbInsets.right + rightButtonW);
  756           }
  757   
  758           (ltr ? decrButton : incrButton).setBounds(leftButtonX, itemY, leftButtonW, itemH);
  759           (ltr ? incrButton : decrButton).setBounds(rightButtonX, itemY, rightButtonW, itemH);
  760   
  761           /* Update the trackRect field.
  762            */
  763           int itrackX = leftButtonX + leftButtonW;
  764           int itrackW = rightButtonX - itrackX;
  765           trackRect.setBounds(itrackX, itemY, itrackW, itemH);
  766   
  767           /* Make sure the thumb fits between the buttons.  Note
  768            * that setting the thumbs bounds causes a repaint.
  769            */
  770           if (thumbW >= (int)trackW) {
  771               if (UIManager.getBoolean("ScrollBar.alwaysShowThumb")) {
  772                   // This is used primarily for GTK L&F, which expands the
  773                   // thumb to fit the track when it would otherwise be hidden.
  774                   setThumbBounds(itrackX, itemY, itrackW, itemH);
  775               } else {
  776                   // Other L&F's simply hide the thumb in this case.
  777                   setThumbBounds(0, 0, 0, 0);
  778               }
  779           }
  780           else {
  781               if (thumbX + thumbW > rightButtonX) {
  782                   thumbX = rightButtonX - thumbW;
  783               }
  784               if (thumbX  < leftButtonX + leftButtonW) {
  785                   thumbX = leftButtonX + leftButtonW + 1;
  786               }
  787               setThumbBounds(thumbX, itemY, thumbW, itemH);
  788           }
  789       }
  790   
  791       public void layoutContainer(Container scrollbarContainer)
  792       {
  793           /* If the user is dragging the value, we'll assume that the
  794            * scrollbars layout is OK modulo the thumb which is being
  795            * handled by the dragging code.
  796            */
  797           if (isDragging) {
  798               return;
  799           }
  800   
  801           JScrollBar scrollbar = (JScrollBar)scrollbarContainer;
  802           switch (scrollbar.getOrientation()) {
  803           case JScrollBar.VERTICAL:
  804               layoutVScrollbar(scrollbar);
  805               break;
  806   
  807           case JScrollBar.HORIZONTAL:
  808               layoutHScrollbar(scrollbar);
  809               break;
  810           }
  811       }
  812   
  813   
  814       /**
  815        * Set the bounds of the thumb and force a repaint that includes
  816        * the old thumbBounds and the new one.
  817        *
  818        * @see #getThumbBounds
  819        */
  820       protected void setThumbBounds(int x, int y, int width, int height)
  821       {
  822           /* If the thumbs bounds haven't changed, we're done.
  823            */
  824           if ((thumbRect.x == x) &&
  825               (thumbRect.y == y) &&
  826               (thumbRect.width == width) &&
  827               (thumbRect.height == height)) {
  828               return;
  829           }
  830   
  831           /* Update thumbRect, and repaint the union of x,y,w,h and
  832            * the old thumbRect.
  833            */
  834           int minX = Math.min(x, thumbRect.x);
  835           int minY = Math.min(y, thumbRect.y);
  836           int maxX = Math.max(x + width, thumbRect.x + thumbRect.width);
  837           int maxY = Math.max(y + height, thumbRect.y + thumbRect.height);
  838   
  839           thumbRect.setBounds(x, y, width, height);
  840           scrollbar.repaint(minX, minY, maxX - minX, maxY - minY);
  841   
  842           // Once there is API to determine the mouse location this will need
  843           // to be changed.
  844           setThumbRollover(false);
  845       }
  846   
  847   
  848       /**
  849        * Return the current size/location of the thumb.
  850        * <p>
  851        * <b>Warning </b>: the value returned by this method should not be
  852        * be modified, it's a reference to the actual rectangle, not a copy.
  853        *
  854        * @return The current size/location of the thumb.
  855        * @see #setThumbBounds
  856        */
  857       protected Rectangle getThumbBounds() {
  858           return thumbRect;
  859       }
  860   
  861   
  862       /**
  863        * Returns the current bounds of the track, i.e. the space in between
  864        * the increment and decrement buttons, less the insets.  The value
  865        * returned by this method is updated each time the scrollbar is
  866        * laid out (validated).
  867        * <p>
  868        * <b>Warning </b>: the value returned by this method should not be
  869        * be modified, it's a reference to the actual rectangle, not a copy.
  870        *
  871        * @return the current bounds of the scrollbar track
  872        * @see #layoutContainer
  873        */
  874       protected Rectangle getTrackBounds() {
  875           return trackRect;
  876       }
  877   
  878       /*
  879        * Method for scrolling by a block increment.
  880        * Added for mouse wheel scrolling support, RFE 4202656.
  881        */
  882       static void scrollByBlock(JScrollBar scrollbar, int direction) {
  883           // This method is called from BasicScrollPaneUI to implement wheel
  884           // scrolling, and also from scrollByBlock().
  885               int oldValue = scrollbar.getValue();
  886               int blockIncrement = scrollbar.getBlockIncrement(direction);
  887               int delta = blockIncrement * ((direction > 0) ? +1 : -1);
  888               int newValue = oldValue + delta;
  889   
  890               // Check for overflow.
  891               if (delta > 0 && newValue < oldValue) {
  892                   newValue = scrollbar.getMaximum();
  893               }
  894               else if (delta < 0 && newValue > oldValue) {
  895                   newValue = scrollbar.getMinimum();
  896               }
  897   
  898               scrollbar.setValue(newValue);
  899       }
  900   
  901       protected void scrollByBlock(int direction)
  902       {
  903           scrollByBlock(scrollbar, direction);
  904               trackHighlight = direction > 0 ? INCREASE_HIGHLIGHT : DECREASE_HIGHLIGHT;
  905               Rectangle dirtyRect = getTrackBounds();
  906               scrollbar.repaint(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
  907       }
  908   
  909       /*
  910        * Method for scrolling by a unit increment.
  911        * Added for mouse wheel scrolling support, RFE 4202656.
  912        *
  913        * If limitByBlock is set to true, the scrollbar will scroll at least 1
  914        * unit increment, but will not scroll farther than the block increment.
  915        * See BasicScrollPaneUI.Handler.mouseWheelMoved().
  916        */
  917       static void scrollByUnits(JScrollBar scrollbar, int direction,
  918                                 int units, boolean limitToBlock) {
  919           // This method is called from BasicScrollPaneUI to implement wheel
  920           // scrolling, as well as from scrollByUnit().
  921           int delta;
  922           int limit = -1;
  923   
  924           if (limitToBlock) {
  925               if (direction < 0) {
  926                   limit = scrollbar.getValue() -
  927                                            scrollbar.getBlockIncrement(direction);
  928               }
  929               else {
  930                   limit = scrollbar.getValue() +
  931                                            scrollbar.getBlockIncrement(direction);
  932               }
  933           }
  934   
  935           for (int i=0; i<units; i++) {
  936               if (direction > 0) {
  937                   delta = scrollbar.getUnitIncrement(direction);
  938               }
  939               else {
  940                   delta = -scrollbar.getUnitIncrement(direction);
  941               }
  942   
  943               int oldValue = scrollbar.getValue();
  944               int newValue = oldValue + delta;
  945   
  946               // Check for overflow.
  947               if (delta > 0 && newValue < oldValue) {
  948                   newValue = scrollbar.getMaximum();
  949               }
  950               else if (delta < 0 && newValue > oldValue) {
  951                   newValue = scrollbar.getMinimum();
  952               }
  953               if (oldValue == newValue) {
  954                   break;
  955               }
  956   
  957               if (limitToBlock && i > 0) {
  958                   assert limit != -1;
  959                   if ((direction < 0 && newValue < limit) ||
  960                       (direction > 0 && newValue > limit)) {
  961                       break;
  962                   }
  963               }
  964               scrollbar.setValue(newValue);
  965           }
  966       }
  967   
  968       protected void scrollByUnit(int direction)  {
  969           scrollByUnits(scrollbar, direction, 1, false);
  970       }
  971   
  972       /**
  973        * Indicates whether the user can absolutely position the thumb with
  974        * a mouse gesture (usually the middle mouse button).
  975        *
  976        * @return true if a mouse gesture can absolutely position the thumb
  977        * @since 1.5
  978        */
  979       public boolean getSupportsAbsolutePositioning() {
  980           return supportsAbsolutePositioning;
  981       }
  982   
  983       /**
  984        * A listener to listen for model changes.
  985        *
  986        */
  987       protected class ModelListener implements ChangeListener {
  988           public void stateChanged(ChangeEvent e) {
  989               if (!useCachedValue) {
  990                   scrollBarValue = scrollbar.getValue();
  991               }
  992               layoutContainer(scrollbar);
  993               useCachedValue = false;
  994           }
  995       }
  996   
  997   
  998       /**
  999        * Track mouse drags.
 1000        */
 1001       protected class TrackListener
 1002           extends MouseAdapter implements MouseMotionListener
 1003       {
 1004           protected transient int offset;
 1005           protected transient int currentMouseX, currentMouseY;
 1006           private transient int direction = +1;
 1007   
 1008           public void mouseReleased(MouseEvent e)
 1009           {
 1010               if (isDragging) {
 1011                   updateThumbState(e.getX(), e.getY());
 1012               }
 1013               if (SwingUtilities.isRightMouseButton(e) ||
 1014                   (!getSupportsAbsolutePositioning() &&
 1015                    SwingUtilities.isMiddleMouseButton(e)))
 1016                   return;
 1017               if(!scrollbar.isEnabled())
 1018                   return;
 1019   
 1020               Rectangle r = getTrackBounds();
 1021               scrollbar.repaint(r.x, r.y, r.width, r.height);
 1022   
 1023               trackHighlight = NO_HIGHLIGHT;
 1024               isDragging = false;
 1025               offset = 0;
 1026               scrollTimer.stop();
 1027               useCachedValue = true;
 1028               scrollbar.setValueIsAdjusting(false);
 1029           }
 1030   
 1031   
 1032           /**
 1033            * If the mouse is pressed above the "thumb" component
 1034            * then reduce the scrollbars value by one page ("page up"),
 1035            * otherwise increase it by one page.  If there is no
 1036            * thumb then page up if the mouse is in the upper half
 1037            * of the track.
 1038            */
 1039           public void mousePressed(MouseEvent e)
 1040           {
 1041               if (SwingUtilities.isRightMouseButton(e) ||
 1042                   (!getSupportsAbsolutePositioning() &&
 1043                    SwingUtilities.isMiddleMouseButton(e)))
 1044                   return;
 1045               if(!scrollbar.isEnabled())
 1046                   return;
 1047   
 1048               if (!scrollbar.hasFocus() && scrollbar.isRequestFocusEnabled()) {
 1049                   scrollbar.requestFocus();
 1050               }
 1051   
 1052               useCachedValue = true;
 1053               scrollbar.setValueIsAdjusting(true);
 1054   
 1055               currentMouseX = e.getX();
 1056               currentMouseY = e.getY();
 1057   
 1058               // Clicked in the Thumb area?
 1059               if(getThumbBounds().contains(currentMouseX, currentMouseY)) {
 1060                   switch (scrollbar.getOrientation()) {
 1061                   case JScrollBar.VERTICAL:
 1062                       offset = currentMouseY - getThumbBounds().y;
 1063                       break;
 1064                   case JScrollBar.HORIZONTAL:
 1065                       offset = currentMouseX - getThumbBounds().x;
 1066                       break;
 1067                   }
 1068                   isDragging = true;
 1069                   return;
 1070               }
 1071               else if (getSupportsAbsolutePositioning() &&
 1072                        SwingUtilities.isMiddleMouseButton(e)) {
 1073                   switch (scrollbar.getOrientation()) {
 1074                   case JScrollBar.VERTICAL:
 1075                       offset = getThumbBounds().height / 2;
 1076                       break;
 1077                   case JScrollBar.HORIZONTAL:
 1078                       offset = getThumbBounds().width / 2;
 1079                       break;
 1080                   }
 1081                   isDragging = true;
 1082                   setValueFrom(e);
 1083                   return;
 1084               }
 1085               isDragging = false;
 1086   
 1087               Dimension sbSize = scrollbar.getSize();
 1088               direction = +1;
 1089   
 1090               switch (scrollbar.getOrientation()) {
 1091               case JScrollBar.VERTICAL:
 1092                   if (getThumbBounds().isEmpty()) {
 1093                       int scrollbarCenter = sbSize.height / 2;
 1094                       direction = (currentMouseY < scrollbarCenter) ? -1 : +1;
 1095                   } else {
 1096                       int thumbY = getThumbBounds().y;
 1097                       direction = (currentMouseY < thumbY) ? -1 : +1;
 1098                   }
 1099                   break;
 1100               case JScrollBar.HORIZONTAL:
 1101                   if (getThumbBounds().isEmpty()) {
 1102                       int scrollbarCenter = sbSize.width / 2;
 1103                       direction = (currentMouseX < scrollbarCenter) ? -1 : +1;
 1104                   } else {
 1105                       int thumbX = getThumbBounds().x;
 1106                       direction = (currentMouseX < thumbX) ? -1 : +1;
 1107                   }
 1108                   if (!scrollbar.getComponentOrientation().isLeftToRight()) {
 1109                       direction = -direction;
 1110                   }
 1111                   break;
 1112               }
 1113               scrollByBlock(direction);
 1114   
 1115               scrollTimer.stop();
 1116               scrollListener.setDirection(direction);
 1117               scrollListener.setScrollByBlock(true);
 1118               startScrollTimerIfNecessary();
 1119           }
 1120   
 1121   
 1122           /**
 1123            * Set the models value to the position of the thumb's top of Vertical
 1124            * scrollbar, or the left/right of Horizontal scrollbar in
 1125            * left-to-right/right-to-left scrollbar relative to the origin of the
 1126            * track.
 1127            */
 1128           public void mouseDragged(MouseEvent e) {
 1129               if (SwingUtilities.isRightMouseButton(e) ||
 1130                   (!getSupportsAbsolutePositioning() &&
 1131                    SwingUtilities.isMiddleMouseButton(e)))
 1132                   return;
 1133               if(!scrollbar.isEnabled() || getThumbBounds().isEmpty()) {
 1134                   return;
 1135               }
 1136               if (isDragging) {
 1137                   setValueFrom(e);
 1138               } else {
 1139                   currentMouseX = e.getX();
 1140                   currentMouseY = e.getY();
 1141                   updateThumbState(currentMouseX, currentMouseY);
 1142                   startScrollTimerIfNecessary();
 1143               }
 1144           }
 1145   
 1146           private void setValueFrom(MouseEvent e) {
 1147               boolean active = isThumbRollover();
 1148               BoundedRangeModel model = scrollbar.getModel();
 1149               Rectangle thumbR = getThumbBounds();
 1150               float trackLength;
 1151               int thumbMin, thumbMax, thumbPos;
 1152   
 1153               if (scrollbar.getOrientation() == JScrollBar.VERTICAL) {
 1154                   thumbMin = decrButton.getY() + decrButton.getHeight();
 1155                   thumbMax = incrButton.getY() - thumbR.height;
 1156                   thumbPos = Math.min(thumbMax, Math.max(thumbMin, (e.getY() - offset)));
 1157                   setThumbBounds(thumbR.x, thumbPos, thumbR.width, thumbR.height);
 1158                   trackLength = getTrackBounds().height;
 1159               }
 1160               else {
 1161                   if (scrollbar.getComponentOrientation().isLeftToRight()) {
 1162                       thumbMin = decrButton.getX() + decrButton.getWidth();
 1163                       thumbMax = incrButton.getX() - thumbR.width;
 1164                   } else {
 1165                       thumbMin = incrButton.getX() + incrButton.getWidth();
 1166                       thumbMax = decrButton.getX() - thumbR.width;
 1167                   }
 1168                   thumbPos = Math.min(thumbMax, Math.max(thumbMin, (e.getX() - offset)));
 1169                   setThumbBounds(thumbPos, thumbR.y, thumbR.width, thumbR.height);
 1170                   trackLength = getTrackBounds().width;
 1171               }
 1172   
 1173               /* Set the scrollbars value.  If the thumb has reached the end of
 1174                * the scrollbar, then just set the value to its maximum.  Otherwise
 1175                * compute the value as accurately as possible.
 1176                */
 1177               if (thumbPos == thumbMax) {
 1178                   if (scrollbar.getOrientation() == JScrollBar.VERTICAL ||
 1179                       scrollbar.getComponentOrientation().isLeftToRight()) {
 1180                       scrollbar.setValue(model.getMaximum() - model.getExtent());
 1181                   } else {
 1182                       scrollbar.setValue(model.getMinimum());
 1183                   }
 1184               }
 1185               else {
 1186                   float valueMax = model.getMaximum() - model.getExtent();
 1187                   float valueRange = valueMax - model.getMinimum();
 1188                   float thumbValue = thumbPos - thumbMin;
 1189                   float thumbRange = thumbMax - thumbMin;
 1190                   int value;
 1191                   if (scrollbar.getOrientation() == JScrollBar.VERTICAL ||
 1192                       scrollbar.getComponentOrientation().isLeftToRight()) {
 1193                       value = (int)(0.5 + ((thumbValue / thumbRange) * valueRange));
 1194                   } else {
 1195                       value = (int)(0.5 + (((thumbMax - thumbPos) / thumbRange) * valueRange));
 1196                   }
 1197   
 1198                   useCachedValue = true;
 1199                   scrollBarValue = value + model.getMinimum();
 1200                   scrollbar.setValue(adjustValueIfNecessary(scrollBarValue));
 1201               }
 1202               setThumbRollover(active);
 1203           }
 1204   
 1205           private int adjustValueIfNecessary(int value) {
 1206               if (scrollbar.getParent() instanceof JScrollPane) {
 1207                   JScrollPane scrollpane = (JScrollPane)scrollbar.getParent();
 1208                   JViewport viewport = scrollpane.getViewport();
 1209                   Component view = viewport.getView();
 1210                   if (view instanceof JList) {
 1211                       JList list = (JList)view;
 1212                       if (DefaultLookup.getBoolean(list, list.getUI(),
 1213                                                    "List.lockToPositionOnScroll", false)) {
 1214                           int adjustedValue = value;
 1215                           int mode = list.getLayoutOrientation();
 1216                           int orientation = scrollbar.getOrientation();
 1217                           if (orientation == JScrollBar.VERTICAL && mode == JList.VERTICAL) {
 1218                               int index = list.locationToIndex(new Point(0, value));
 1219                               Rectangle rect = list.getCellBounds(index, index);
 1220                               if (rect != null) {
 1221                                   adjustedValue = rect.y;
 1222                               }
 1223                           }
 1224                           if (orientation == JScrollBar.HORIZONTAL &&
 1225                               (mode == JList.VERTICAL_WRAP || mode == JList.HORIZONTAL_WRAP)) {
 1226                               if (scrollpane.getComponentOrientation().isLeftToRight()) {
 1227                                   int index = list.locationToIndex(new Point(value, 0));
 1228                                   Rectangle rect = list.getCellBounds(index, index);
 1229                                   if (rect != null) {
 1230                                       adjustedValue = rect.x;
 1231                                   }
 1232                               }
 1233                               else {
 1234                                   Point loc = new Point(value, 0);
 1235                                   int extent = viewport.getExtentSize().width;
 1236                                   loc.x += extent - 1;
 1237                                   int index = list.locationToIndex(loc);
 1238                                   Rectangle rect = list.getCellBounds(index, index);
 1239                                   if (rect != null) {
 1240                                       adjustedValue = rect.x + rect.width - extent;
 1241                                   }
 1242                               }
 1243                           }
 1244                           value = adjustedValue;
 1245   
 1246                       }
 1247                   }
 1248               }
 1249               return value;
 1250           }
 1251   
 1252           private void startScrollTimerIfNecessary() {
 1253               if (scrollTimer.isRunning()) {
 1254                   return;
 1255               }
 1256   
 1257               Rectangle tb = getThumbBounds();
 1258   
 1259               switch (scrollbar.getOrientation()) {
 1260               case JScrollBar.VERTICAL:
 1261                   if (direction > 0) {
 1262                       if (tb.y + tb.height < trackListener.currentMouseY) {
 1263                           scrollTimer.start();
 1264                       }
 1265                   } else if (tb.y > trackListener.currentMouseY) {
 1266                       scrollTimer.start();
 1267                   }
 1268                   break;
 1269               case JScrollBar.HORIZONTAL:
 1270                   if ((direction > 0 && isMouseAfterThumb())
 1271                           || (direction < 0 && isMouseBeforeThumb())) {
 1272   
 1273                       scrollTimer.start();
 1274                   }
 1275                   break;
 1276               }
 1277           }
 1278   
 1279           public void mouseMoved(MouseEvent e) {
 1280               if (!isDragging) {
 1281                   updateThumbState(e.getX(), e.getY());
 1282               }
 1283           }
 1284   
 1285           /**
 1286            * Invoked when the mouse exits the scrollbar.
 1287            *
 1288            * @param e MouseEvent further describing the event
 1289            * @since 1.5
 1290            */
 1291           public void mouseExited(MouseEvent e) {
 1292               if (!isDragging) {
 1293                   setThumbRollover(false);
 1294               }
 1295           }
 1296       }
 1297   
 1298   
 1299       /**
 1300        * Listener for cursor keys.
 1301        */
 1302       protected class ArrowButtonListener extends MouseAdapter
 1303       {
 1304           // Because we are handling both mousePressed and Actions
 1305           // we need to make sure we don't fire under both conditions.
 1306           // (keyfocus on scrollbars causes action without mousePress
 1307           boolean handledEvent;
 1308   
 1309           public void mousePressed(MouseEvent e)          {
 1310               if(!scrollbar.isEnabled()) { return; }
 1311               // not an unmodified left mouse button
 1312               //if(e.getModifiers() != InputEvent.BUTTON1_MASK) {return; }
 1313               if( ! SwingUtilities.isLeftMouseButton(e)) { return; }
 1314   
 1315               int direction = (e.getSource() == incrButton) ? 1 : -1;
 1316   
 1317               scrollByUnit(direction);
 1318               scrollTimer.stop();
 1319               scrollListener.setDirection(direction);
 1320               scrollListener.setScrollByBlock(false);
 1321               scrollTimer.start();
 1322   
 1323               handledEvent = true;
 1324               if (!scrollbar.hasFocus() && scrollbar.isRequestFocusEnabled()) {
 1325                   scrollbar.requestFocus();
 1326               }
 1327           }
 1328   
 1329           public void mouseReleased(MouseEvent e)         {
 1330               scrollTimer.stop();
 1331               handledEvent = false;
 1332               scrollbar.setValueIsAdjusting(false);
 1333           }
 1334       }
 1335   
 1336   
 1337       /**
 1338        * Listener for scrolling events initiated in the
 1339        * <code>ScrollPane</code>.
 1340        */
 1341       protected class ScrollListener implements ActionListener
 1342       {
 1343           int direction = +1;
 1344           boolean useBlockIncrement;
 1345   
 1346           public ScrollListener() {
 1347               direction = +1;
 1348               useBlockIncrement = false;
 1349           }
 1350   
 1351           public ScrollListener(int dir, boolean block)   {
 1352               direction = dir;
 1353               useBlockIncrement = block;
 1354           }
 1355   
 1356           public void setDirection(int direction) { this.direction = direction; }
 1357           public void setScrollByBlock(boolean block) { this.useBlockIncrement = block; }
 1358   
 1359           public void actionPerformed(ActionEvent e) {
 1360               if(useBlockIncrement)       {
 1361                   scrollByBlock(direction);
 1362                   // Stop scrolling if the thumb catches up with the mouse
 1363                   if(scrollbar.getOrientation() == JScrollBar.VERTICAL)   {
 1364                       if(direction > 0)   {
 1365                           if(getThumbBounds().y + getThumbBounds().height
 1366                                   >= trackListener.currentMouseY)
 1367                                       ((Timer)e.getSource()).stop();
 1368                       } else if(getThumbBounds().y <= trackListener.currentMouseY)        {
 1369                           ((Timer)e.getSource()).stop();
 1370                       }
 1371                   } else {
 1372                       if ((direction > 0 && !isMouseAfterThumb())
 1373                              || (direction < 0 && !isMouseBeforeThumb())) {
 1374   
 1375                          ((Timer)e.getSource()).stop();
 1376                       }
 1377                   }
 1378               } else {
 1379                   scrollByUnit(direction);
 1380               }
 1381   
 1382               if(direction > 0
 1383                   && scrollbar.getValue()+scrollbar.getVisibleAmount()
 1384                           >= scrollbar.getMaximum())
 1385                   ((Timer)e.getSource()).stop();
 1386               else if(direction < 0
 1387                   && scrollbar.getValue() <= scrollbar.getMinimum())
 1388                   ((Timer)e.getSource()).stop();
 1389           }
 1390       }
 1391   
 1392       private boolean isMouseLeftOfThumb() {
 1393           return trackListener.currentMouseX < getThumbBounds().x;
 1394       }
 1395   
 1396       private boolean isMouseRightOfThumb() {
 1397           Rectangle tb = getThumbBounds();
 1398           return trackListener.currentMouseX > tb.x + tb.width;
 1399       }
 1400   
 1401       private boolean isMouseBeforeThumb() {
 1402           return scrollbar.getComponentOrientation().isLeftToRight()
 1403               ? isMouseLeftOfThumb()
 1404               : isMouseRightOfThumb();
 1405       }
 1406   
 1407       private boolean isMouseAfterThumb() {
 1408           return scrollbar.getComponentOrientation().isLeftToRight()
 1409               ? isMouseRightOfThumb()
 1410               : isMouseLeftOfThumb();
 1411       }
 1412   
 1413       private void updateButtonDirections() {
 1414           int orient = scrollbar.getOrientation();
 1415           if (scrollbar.getComponentOrientation().isLeftToRight()) {
 1416               if (incrButton instanceof BasicArrowButton) {
 1417                   ((BasicArrowButton)incrButton).setDirection(
 1418                           orient == HORIZONTAL? EAST : SOUTH);
 1419               }
 1420               if (decrButton instanceof BasicArrowButton) {
 1421                   ((BasicArrowButton)decrButton).setDirection(
 1422                           orient == HORIZONTAL? WEST : NORTH);
 1423               }
 1424           }
 1425           else {
 1426               if (incrButton instanceof BasicArrowButton) {
 1427                   ((BasicArrowButton)incrButton).setDirection(
 1428                           orient == HORIZONTAL? WEST : SOUTH);
 1429               }
 1430               if (decrButton instanceof BasicArrowButton) {
 1431                   ((BasicArrowButton)decrButton).setDirection(
 1432                           orient == HORIZONTAL ? EAST : NORTH);
 1433               }
 1434           }
 1435       }
 1436   
 1437       public class PropertyChangeHandler implements PropertyChangeListener
 1438       {
 1439           // NOTE: This class exists only for backward compatability. All
 1440           // its functionality has been moved into Handler. If you need to add
 1441           // new functionality add it to the Handler, but make sure this
 1442           // class calls into the Handler.
 1443   
 1444           public void propertyChange(PropertyChangeEvent e) {
 1445               getHandler().propertyChange(e);
 1446           }
 1447       }
 1448   
 1449   
 1450       /**
 1451        * Used for scrolling the scrollbar.
 1452        */
 1453       private static class Actions extends UIAction {
 1454           private static final String POSITIVE_UNIT_INCREMENT =
 1455                                       "positiveUnitIncrement";
 1456           private static final String POSITIVE_BLOCK_INCREMENT =
 1457                                       "positiveBlockIncrement";
 1458           private static final String NEGATIVE_UNIT_INCREMENT =
 1459                                       "negativeUnitIncrement";
 1460           private static final String NEGATIVE_BLOCK_INCREMENT =
 1461                                       "negativeBlockIncrement";
 1462           private static final String MIN_SCROLL = "minScroll";
 1463           private static final String MAX_SCROLL = "maxScroll";
 1464   
 1465           Actions(String name) {
 1466               super(name);
 1467           }
 1468   
 1469           public void actionPerformed(ActionEvent e) {
 1470               JScrollBar scrollBar = (JScrollBar)e.getSource();
 1471               String key = getName();
 1472               if (key == POSITIVE_UNIT_INCREMENT) {
 1473                   scroll(scrollBar, POSITIVE_SCROLL, false);
 1474               }
 1475               else if (key == POSITIVE_BLOCK_INCREMENT) {
 1476                   scroll(scrollBar, POSITIVE_SCROLL, true);
 1477               }
 1478               else if (key == NEGATIVE_UNIT_INCREMENT) {
 1479                   scroll(scrollBar, NEGATIVE_SCROLL, false);
 1480               }
 1481               else if (key == NEGATIVE_BLOCK_INCREMENT) {
 1482                   scroll(scrollBar, NEGATIVE_SCROLL, true);
 1483               }
 1484               else if (key == MIN_SCROLL) {
 1485                   scroll(scrollBar, BasicScrollBarUI.MIN_SCROLL, true);
 1486               }
 1487               else if (key == MAX_SCROLL) {
 1488                   scroll(scrollBar, BasicScrollBarUI.MAX_SCROLL, true);
 1489               }
 1490           }
 1491           private void scroll(JScrollBar scrollBar, int dir, boolean block) {
 1492   
 1493               if (dir == NEGATIVE_SCROLL || dir == POSITIVE_SCROLL) {
 1494                   int amount;
 1495                   // Don't use the BasicScrollBarUI.scrollByXXX methods as we
 1496                   // don't want to use an invokeLater to reset the trackHighlight
 1497                   // via an invokeLater
 1498                   if (block) {
 1499                       if (dir == NEGATIVE_SCROLL) {
 1500                           amount = -1 * scrollBar.getBlockIncrement(-1);
 1501                       }
 1502                       else {
 1503                           amount = scrollBar.getBlockIncrement(1);
 1504                       }
 1505                   }
 1506                   else {
 1507                       if (dir == NEGATIVE_SCROLL) {
 1508                           amount = -1 * scrollBar.getUnitIncrement(-1);
 1509                       }
 1510                       else {
 1511                           amount = scrollBar.getUnitIncrement(1);
 1512                       }
 1513                   }
 1514                   scrollBar.setValue(scrollBar.getValue() + amount);
 1515               }
 1516               else if (dir == BasicScrollBarUI.MIN_SCROLL) {
 1517                   scrollBar.setValue(scrollBar.getMinimum());
 1518               }
 1519               else if (dir == BasicScrollBarUI.MAX_SCROLL) {
 1520                   scrollBar.setValue(scrollBar.getMaximum());
 1521               }
 1522           }
 1523       }
 1524   
 1525   
 1526       //
 1527       // EventHandler
 1528       //
 1529       private class Handler implements FocusListener, PropertyChangeListener {
 1530           //
 1531           // FocusListener
 1532           //
 1533           public void focusGained(FocusEvent e) {
 1534               scrollbar.repaint();
 1535           }
 1536   
 1537           public void focusLost(FocusEvent e) {
 1538               scrollbar.repaint();
 1539           }
 1540   
 1541   
 1542           //
 1543           // PropertyChangeListener
 1544           //
 1545           public void propertyChange(PropertyChangeEvent e) {
 1546               String propertyName = e.getPropertyName();
 1547   
 1548               if ("model" == propertyName) {
 1549                   BoundedRangeModel oldModel = (BoundedRangeModel)e.getOldValue();
 1550                   BoundedRangeModel newModel = (BoundedRangeModel)e.getNewValue();
 1551                   oldModel.removeChangeListener(modelListener);
 1552                   newModel.addChangeListener(modelListener);
 1553                   scrollbar.repaint();
 1554                   scrollbar.revalidate();
 1555               } else if ("orientation" == propertyName) {
 1556                   updateButtonDirections();
 1557               } else if ("componentOrientation" == propertyName) {
 1558                   updateButtonDirections();
 1559                   InputMap inputMap = getInputMap(JComponent.WHEN_FOCUSED);
 1560                   SwingUtilities.replaceUIInputMap(scrollbar, JComponent.WHEN_FOCUSED, inputMap);
 1561               }
 1562           }
 1563       }
 1564   }

Save This Page
Home » openjdk-7 » javax » swing » plaf » basic » [javadoc | source]