< prev index next >

src/java.desktop/share/classes/javax/swing/plaf/basic/BasicScrollBarUI.java

Print this page


   1 /*
   2  * Copyright (c) 1997, 2014, Oracle and/or its affiliates. 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


  43 
  44 
  45 /**
  46  * Implementation of ScrollBarUI for the Basic Look and Feel
  47  *
  48  * @author Rich Schiavi
  49  * @author David Kloba
  50  * @author Hans Muller
  51  */
  52 public class BasicScrollBarUI
  53     extends ScrollBarUI implements LayoutManager, SwingConstants
  54 {
  55     private static final int POSITIVE_SCROLL = 1;
  56     private static final int NEGATIVE_SCROLL = -1;
  57 
  58     private static final int MIN_SCROLL = 2;
  59     private static final int MAX_SCROLL = 3;
  60 
  61     // NOTE: DO NOT use this field directly, SynthScrollBarUI assumes you'll
  62     // call getMinimumThumbSize to access it.

  63     protected Dimension minimumThumbSize;

  64     protected Dimension maximumThumbSize;
  65 

  66     protected Color thumbHighlightColor;

  67     protected Color thumbLightShadowColor;

  68     protected Color thumbDarkShadowColor;

  69     protected Color thumbColor;

  70     protected Color trackColor;

  71     protected Color trackHighlightColor;
  72 

  73     protected JScrollBar scrollbar;

  74     protected JButton incrButton;

  75     protected JButton decrButton;

  76     protected boolean isDragging;

  77     protected TrackListener trackListener;

  78     protected ArrowButtonListener buttonListener;

  79     protected ModelListener modelListener;
  80 

  81     protected Rectangle thumbRect;

  82     protected Rectangle trackRect;
  83 

  84     protected int trackHighlight;
  85 

  86     protected static final int NO_HIGHLIGHT = 0;

  87     protected static final int DECREASE_HIGHLIGHT = 1;

  88     protected static final int INCREASE_HIGHLIGHT = 2;
  89 

  90     protected ScrollListener scrollListener;

  91     protected PropertyChangeListener propertyChangeListener;

  92     protected Timer scrollTimer;
  93 
  94     private final static int scrollSpeedThrottle = 60; // delay in milli seconds
  95 
  96     /**
  97      * True indicates a middle click will absolutely position the
  98      * scrollbar.
  99      */
 100     private boolean supportsAbsolutePositioning;
 101 
 102     /**
 103      * Hint as to what width (when vertical) or height (when horizontal)
 104      * should be.
 105      *
 106      * @since 1.7
 107      */
 108     protected int scrollBarWidth;
 109 
 110     private Handler handler;
 111 


 131     protected int incrGap;
 132 
 133     /**
 134      * Distance between the decrement button and the track. This may be a negative
 135      * number. If negative, then an overlap between the button and track will occur,
 136      * which is useful for shaped buttons.
 137      *
 138      * @since 1.7
 139      */
 140     protected int decrGap;
 141 
 142     static void loadActionMap(LazyActionMap map) {
 143         map.put(new Actions(Actions.POSITIVE_UNIT_INCREMENT));
 144         map.put(new Actions(Actions.POSITIVE_BLOCK_INCREMENT));
 145         map.put(new Actions(Actions.NEGATIVE_UNIT_INCREMENT));
 146         map.put(new Actions(Actions.NEGATIVE_BLOCK_INCREMENT));
 147         map.put(new Actions(Actions.MIN_SCROLL));
 148         map.put(new Actions(Actions.MAX_SCROLL));
 149     }
 150 
 151 




 152     public static ComponentUI createUI(JComponent c)    {
 153         return new BasicScrollBarUI();
 154     }
 155 
 156 


 157     protected void configureScrollBarColors()
 158     {
 159         LookAndFeel.installColors(scrollbar, "ScrollBar.background",
 160                                   "ScrollBar.foreground");
 161         thumbHighlightColor = UIManager.getColor("ScrollBar.thumbHighlight");
 162         thumbLightShadowColor = UIManager.getColor("ScrollBar.thumbShadow");
 163         thumbDarkShadowColor = UIManager.getColor("ScrollBar.thumbDarkShadow");
 164         thumbColor = UIManager.getColor("ScrollBar.thumb");
 165         trackColor = UIManager.getColor("ScrollBar.track");
 166         trackHighlightColor = UIManager.getColor("ScrollBar.trackHighlight");
 167     }
 168 
 169 



 170     public void installUI(JComponent c)   {
 171         scrollbar = (JScrollBar)c;
 172         thumbRect = new Rectangle(0, 0, 0, 0);
 173         trackRect = new Rectangle(0, 0, 0, 0);
 174         installDefaults();
 175         installComponents();
 176         installListeners();
 177         installKeyboardActions();
 178     }
 179 




 180     public void uninstallUI(JComponent c) {
 181         scrollbar = (JScrollBar)c;
 182         uninstallListeners();
 183         uninstallDefaults();
 184         uninstallComponents();
 185         uninstallKeyboardActions();
 186         thumbRect = null;
 187         scrollbar = null;
 188         incrButton = null;
 189         decrButton = null;
 190     }
 191 
 192 


 193     protected void installDefaults()
 194     {
 195         scrollBarWidth = UIManager.getInt("ScrollBar.width");
 196         if (scrollBarWidth <= 0) {
 197             scrollBarWidth = 16;
 198         }
 199         minimumThumbSize = (Dimension)UIManager.get("ScrollBar.minimumThumbSize");
 200         maximumThumbSize = (Dimension)UIManager.get("ScrollBar.maximumThumbSize");
 201 
 202         Boolean absB = (Boolean)UIManager.get("ScrollBar.allowsAbsolutePositioning");
 203         supportsAbsolutePositioning = (absB != null) ? absB.booleanValue() :
 204                                       false;
 205 
 206         trackHighlight = NO_HIGHLIGHT;
 207         if (scrollbar.getLayout() == null ||
 208                      (scrollbar.getLayout() instanceof UIResource)) {
 209             scrollbar.setLayout(this);
 210         }
 211         configureScrollBarColors();
 212         LookAndFeel.installBorder(scrollbar, "ScrollBar.border");


 223         // components are based on Apples LAF
 224         String scaleKey = (String)scrollbar.getClientProperty(
 225                 "JComponent.sizeVariant");
 226         if (scaleKey != null){
 227             if ("large".equals(scaleKey)){
 228                 scrollBarWidth *= 1.15;
 229                 incrGap *= 1.15;
 230                 decrGap *= 1.15;
 231             } else if ("small".equals(scaleKey)){
 232                 scrollBarWidth *= 0.857;
 233                 incrGap *= 0.857;
 234                 decrGap *= 0.714;
 235             } else if ("mini".equals(scaleKey)){
 236                 scrollBarWidth *= 0.714;
 237                 incrGap *= 0.714;
 238                 decrGap *= 0.714;
 239             }
 240         }
 241     }
 242 
 243 


 244     protected void installComponents(){
 245         switch (scrollbar.getOrientation()) {
 246         case JScrollBar.VERTICAL:
 247             incrButton = createIncreaseButton(SOUTH);
 248             decrButton = createDecreaseButton(NORTH);
 249             break;
 250 
 251         case JScrollBar.HORIZONTAL:
 252             if (scrollbar.getComponentOrientation().isLeftToRight()) {
 253                 incrButton = createIncreaseButton(EAST);
 254                 decrButton = createDecreaseButton(WEST);
 255             } else {
 256                 incrButton = createIncreaseButton(WEST);
 257                 decrButton = createDecreaseButton(EAST);
 258             }
 259             break;
 260         }
 261         scrollbar.add(incrButton);
 262         scrollbar.add(decrButton);
 263         // Force the children's enabled state to be updated.
 264         scrollbar.setEnabled(scrollbar.isEnabled());
 265     }
 266 



 267     protected void uninstallComponents(){
 268         scrollbar.remove(incrButton);
 269         scrollbar.remove(decrButton);
 270     }
 271 
 272 


 273     protected void installListeners(){
 274         trackListener = createTrackListener();
 275         buttonListener = createArrowButtonListener();
 276         modelListener = createModelListener();
 277         propertyChangeListener = createPropertyChangeListener();
 278 
 279         scrollbar.addMouseListener(trackListener);
 280         scrollbar.addMouseMotionListener(trackListener);
 281         scrollbar.getModel().addChangeListener(modelListener);
 282         scrollbar.addPropertyChangeListener(propertyChangeListener);
 283         scrollbar.addFocusListener(getHandler());
 284 
 285         if (incrButton != null) {
 286             incrButton.addMouseListener(buttonListener);
 287         }
 288         if (decrButton != null) {
 289             decrButton.addMouseListener(buttonListener);
 290         }
 291 
 292         scrollListener = createScrollListener();
 293         scrollTimer = new Timer(scrollSpeedThrottle, scrollListener);
 294         scrollTimer.setInitialDelay(300);  // default InitialDelay?
 295     }
 296 
 297 


 298     protected void installKeyboardActions(){
 299         LazyActionMap.installLazyActionMap(scrollbar, BasicScrollBarUI.class,
 300                                            "ScrollBar.actionMap");
 301 
 302         InputMap inputMap = getInputMap(JComponent.WHEN_FOCUSED);
 303         SwingUtilities.replaceUIInputMap(scrollbar, JComponent.WHEN_FOCUSED,
 304                                          inputMap);
 305         inputMap = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
 306         SwingUtilities.replaceUIInputMap(scrollbar,
 307                    JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap);
 308     }
 309 



 310     protected void uninstallKeyboardActions(){
 311         SwingUtilities.replaceUIInputMap(scrollbar, JComponent.WHEN_FOCUSED,
 312                                          null);
 313         SwingUtilities.replaceUIActionMap(scrollbar, null);
 314     }
 315 
 316     private InputMap getInputMap(int condition) {
 317         if (condition == JComponent.WHEN_FOCUSED) {
 318             InputMap keyMap = (InputMap)DefaultLookup.get(
 319                         scrollbar, this, "ScrollBar.focusInputMap");
 320             InputMap rtlKeyMap;
 321 
 322             if (scrollbar.getComponentOrientation().isLeftToRight() ||
 323                 ((rtlKeyMap = (InputMap)DefaultLookup.get(scrollbar, this, "ScrollBar.focusInputMap.RightToLeft")) == null)) {
 324                 return keyMap;
 325             } else {
 326                 rtlKeyMap.setParent(keyMap);
 327                 return rtlKeyMap;
 328             }
 329         }
 330         else if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
 331             InputMap keyMap = (InputMap)DefaultLookup.get(
 332                         scrollbar, this, "ScrollBar.ancestorInputMap");
 333             InputMap rtlKeyMap;
 334 
 335             if (scrollbar.getComponentOrientation().isLeftToRight() ||
 336                 ((rtlKeyMap = (InputMap)DefaultLookup.get(scrollbar, this, "ScrollBar.ancestorInputMap.RightToLeft")) == null)) {
 337                 return keyMap;
 338             } else {
 339                 rtlKeyMap.setParent(keyMap);
 340                 return rtlKeyMap;
 341             }
 342         }
 343         return null;
 344     }
 345 
 346 


 347     protected void uninstallListeners() {
 348         scrollTimer.stop();
 349         scrollTimer = null;
 350 
 351         if (decrButton != null){
 352             decrButton.removeMouseListener(buttonListener);
 353         }
 354         if (incrButton != null){
 355             incrButton.removeMouseListener(buttonListener);
 356         }
 357 
 358         scrollbar.getModel().removeChangeListener(modelListener);
 359         scrollbar.removeMouseListener(trackListener);
 360         scrollbar.removeMouseMotionListener(trackListener);
 361         scrollbar.removePropertyChangeListener(propertyChangeListener);
 362         scrollbar.removeFocusListener(getHandler());
 363         handler = null;
 364     }
 365 
 366 


 367     protected void uninstallDefaults(){
 368         LookAndFeel.uninstallBorder(scrollbar);
 369         if (scrollbar.getLayout() == this) {
 370             scrollbar.setLayout(null);
 371         }
 372     }
 373 
 374 
 375     private Handler getHandler() {
 376         if (handler == null) {
 377             handler = new Handler();
 378         }
 379         return handler;
 380     }
 381 




 382     protected TrackListener createTrackListener(){
 383         return new TrackListener();
 384     }
 385 




 386     protected ArrowButtonListener createArrowButtonListener(){
 387         return new ArrowButtonListener();
 388     }
 389 




 390     protected ModelListener createModelListener(){
 391         return new ModelListener();
 392     }
 393 




 394     protected ScrollListener createScrollListener(){
 395         return new ScrollListener();
 396     }
 397 




 398     protected PropertyChangeListener createPropertyChangeListener() {
 399         return getHandler();
 400     }
 401 
 402     private void updateThumbState(int x, int y) {
 403         Rectangle rect = getThumbBounds();
 404 
 405         setThumbRollover(rect.contains(x, y));
 406     }
 407 
 408     /**
 409      * Sets whether or not the mouse is currently over the thumb.
 410      *
 411      * @param active True indicates the thumb is currently active.
 412      * @since 1.5
 413      */
 414     protected void setThumbRollover(boolean active) {
 415         if (thumbActive != active) {
 416             thumbActive = active;
 417             scrollbar.repaint(getThumbBounds());


 453      * @see #getMaximumSize
 454      * @see #getMinimumSize
 455      */
 456     public Dimension getPreferredSize(JComponent c) {
 457         return (scrollbar.getOrientation() == JScrollBar.VERTICAL)
 458             ? new Dimension(scrollBarWidth, 48)
 459             : new Dimension(48, scrollBarWidth);
 460     }
 461 
 462 
 463     /**
 464      * @param c The JScrollBar that's delegating this method to us.
 465      * @return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
 466      * @see #getMinimumSize
 467      * @see #getPreferredSize
 468      */
 469     public Dimension getMaximumSize(JComponent c) {
 470         return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
 471     }
 472 





 473     protected JButton createDecreaseButton(int orientation)  {
 474         return new BasicArrowButton(orientation,
 475                                     UIManager.getColor("ScrollBar.thumb"),
 476                                     UIManager.getColor("ScrollBar.thumbShadow"),
 477                                     UIManager.getColor("ScrollBar.thumbDarkShadow"),
 478                                     UIManager.getColor("ScrollBar.thumbHighlight"));
 479     }
 480 





 481     protected JButton createIncreaseButton(int orientation)  {
 482         return new BasicArrowButton(orientation,
 483                                     UIManager.getColor("ScrollBar.thumb"),
 484                                     UIManager.getColor("ScrollBar.thumbShadow"),
 485                                     UIManager.getColor("ScrollBar.thumbDarkShadow"),
 486                                     UIManager.getColor("ScrollBar.thumbHighlight"));
 487     }
 488 
 489 




 490     protected void paintDecreaseHighlight(Graphics g)
 491     {
 492         Insets insets = scrollbar.getInsets();
 493         Rectangle thumbR = getThumbBounds();
 494         g.setColor(trackHighlightColor);
 495 
 496         if (scrollbar.getOrientation() == JScrollBar.VERTICAL) {
 497             //paint the distance between the start of the track and top of the thumb
 498             int x = insets.left;
 499             int y = trackRect.y;
 500             int w = scrollbar.getWidth() - (insets.left + insets.right);
 501             int h = thumbR.y - y;
 502             g.fillRect(x, y, w, h);
 503         } else {
 504             //if left-to-right, fill the area between the start of the track and
 505             //the left edge of the thumb. If right-to-left, fill the area between
 506             //the end of the thumb and end of the track.
 507             int x, w;
 508             if (scrollbar.getComponentOrientation().isLeftToRight()) {
 509                x = trackRect.x;
 510                 w = thumbR.x - x;
 511             } else {
 512                 x = thumbR.x + thumbR.width;
 513                 w = trackRect.x + trackRect.width - x;
 514             }
 515             int y = insets.top;
 516             int h = scrollbar.getHeight() - (insets.top + insets.bottom);
 517             g.fillRect(x, y, w, h);
 518         }
 519     }
 520 
 521 




 522     protected void paintIncreaseHighlight(Graphics g)
 523     {
 524         Insets insets = scrollbar.getInsets();
 525         Rectangle thumbR = getThumbBounds();
 526         g.setColor(trackHighlightColor);
 527 
 528         if (scrollbar.getOrientation() == JScrollBar.VERTICAL) {
 529             //fill the area between the bottom of the thumb and the end of the track.
 530             int x = insets.left;
 531             int y = thumbR.y + thumbR.height;
 532             int w = scrollbar.getWidth() - (insets.left + insets.right);
 533             int h = trackRect.y + trackRect.height - y;
 534             g.fillRect(x, y, w, h);
 535         }
 536         else {
 537             //if left-to-right, fill the area between the right of the thumb and the
 538             //end of the track. If right-to-left, then fill the area to the left of
 539             //the thumb and the start of the track.
 540             int x, w;
 541             if (scrollbar.getComponentOrientation().isLeftToRight()) {
 542                 x = thumbR.x + thumbR.width;
 543                 w = trackRect.x + trackRect.width - x;
 544             } else {
 545                 x = trackRect.x;
 546                 w = thumbR.x - x;
 547             }
 548             int y = insets.top;
 549             int h = scrollbar.getHeight() - (insets.top + insets.bottom);
 550             g.fillRect(x, y, w, h);
 551         }
 552     }
 553 
 554 






 555     protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds)
 556     {
 557         g.setColor(trackColor);
 558         g.fillRect(trackBounds.x, trackBounds.y, trackBounds.width, trackBounds.height);
 559 
 560         if(trackHighlight == DECREASE_HIGHLIGHT)        {
 561             paintDecreaseHighlight(g);
 562         }
 563         else if(trackHighlight == INCREASE_HIGHLIGHT)           {
 564             paintIncreaseHighlight(g);
 565         }
 566     }
 567 
 568 





 569     protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds)
 570     {
 571         if(thumbBounds.isEmpty() || !scrollbar.isEnabled())     {
 572             return;
 573         }
 574 
 575         int w = thumbBounds.width;
 576         int h = thumbBounds.height;
 577 
 578         g.translate(thumbBounds.x, thumbBounds.y);
 579 
 580         g.setColor(thumbDarkShadowColor);
 581         drawRect(g, 0, 0, w - 1, h - 1);
 582         g.setColor(thumbColor);
 583         g.fillRect(0, 0, w - 1, h - 1);
 584 
 585         g.setColor(thumbHighlightColor);
 586         drawVLine(g, 1, 1, h - 2);
 587         drawHLine(g, 2, w - 3, 1);
 588 


 627 
 628     /*
 629      * LayoutManager Implementation
 630      */
 631 
 632     public void addLayoutComponent(String name, Component child) {}
 633     public void removeLayoutComponent(Component child) {}
 634 
 635     public Dimension preferredLayoutSize(Container scrollbarContainer)  {
 636         return getPreferredSize((JComponent)scrollbarContainer);
 637     }
 638 
 639     public Dimension minimumLayoutSize(Container scrollbarContainer) {
 640         return getMinimumSize((JComponent)scrollbarContainer);
 641     }
 642 
 643     private int getValue(JScrollBar sb) {
 644         return (useCachedValue) ? scrollBarValue : sb.getValue();
 645     }
 646 




 647     protected void layoutVScrollbar(JScrollBar sb)
 648     {
 649         Dimension sbSize = sb.getSize();
 650         Insets sbInsets = sb.getInsets();
 651 
 652         /*
 653          * Width and left edge of the buttons and thumb.
 654          */
 655         int itemW = sbSize.width - (sbInsets.left + sbInsets.right);
 656         int itemX = sbInsets.left;
 657 
 658         /* Nominal locations of the buttons, assuming their preferred
 659          * size will fit.
 660          */
 661         boolean squareButtons = DefaultLookup.getBoolean(
 662             scrollbar, this, "ScrollBar.squareButtons", false);
 663         int decrButtonH = squareButtons ? itemW :
 664                           decrButton.getPreferredSize().height;
 665         int decrButtonY = sbInsets.top;
 666 


 725             if (UIManager.getBoolean("ScrollBar.alwaysShowThumb")) {
 726                 // This is used primarily for GTK L&F, which expands the
 727                 // thumb to fit the track when it would otherwise be hidden.
 728                 setThumbBounds(itemX, itrackY, itemW, itrackH);
 729             } else {
 730                 // Other L&F's simply hide the thumb in this case.
 731                 setThumbBounds(0, 0, 0, 0);
 732             }
 733         }
 734         else {
 735             if ((thumbY + thumbH) > incrButtonY - incrGap) {
 736                 thumbY = incrButtonY - incrGap - thumbH;
 737             }
 738             if (thumbY  < (decrButtonY + decrButtonH + decrGap)) {
 739                 thumbY = decrButtonY + decrButtonH + decrGap + 1;
 740             }
 741             setThumbBounds(itemX, thumbY, itemW, thumbH);
 742         }
 743     }
 744 
 745 



 746     protected void layoutHScrollbar(JScrollBar sb)
 747     {
 748         Dimension sbSize = sb.getSize();
 749         Insets sbInsets = sb.getInsets();
 750 
 751         /* Height and top edge of the buttons and thumb.
 752          */
 753         int itemH = sbSize.height - (sbInsets.top + sbInsets.bottom);
 754         int itemY = sbInsets.top;
 755 
 756         boolean ltr = sb.getComponentOrientation().isLeftToRight();
 757 
 758         /* Nominal locations of the buttons, assuming their preferred
 759          * size will fit.
 760          */
 761         boolean squareButtons = DefaultLookup.getBoolean(
 762             scrollbar, this, "ScrollBar.squareButtons", false);
 763         int leftButtonW = squareButtons ? itemH :
 764                           decrButton.getPreferredSize().width;
 765         int rightButtonW = squareButtons ? itemH :


 949      */
 950     static void scrollByBlock(JScrollBar scrollbar, int direction) {
 951         // This method is called from BasicScrollPaneUI to implement wheel
 952         // scrolling, and also from scrollByBlock().
 953             int oldValue = scrollbar.getValue();
 954             int blockIncrement = scrollbar.getBlockIncrement(direction);
 955             int delta = blockIncrement * ((direction > 0) ? +1 : -1);
 956             int newValue = oldValue + delta;
 957 
 958             // Check for overflow.
 959             if (delta > 0 && newValue < oldValue) {
 960                 newValue = scrollbar.getMaximum();
 961             }
 962             else if (delta < 0 && newValue > oldValue) {
 963                 newValue = scrollbar.getMinimum();
 964             }
 965 
 966             scrollbar.setValue(newValue);
 967     }
 968 




 969     protected void scrollByBlock(int direction)
 970     {
 971         scrollByBlock(scrollbar, direction);
 972             trackHighlight = direction > 0 ? INCREASE_HIGHLIGHT : DECREASE_HIGHLIGHT;
 973             Rectangle dirtyRect = getTrackBounds();
 974             scrollbar.repaint(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
 975     }
 976 
 977     /*
 978      * Method for scrolling by a unit increment.
 979      * Added for mouse wheel scrolling support, RFE 4202656.
 980      *
 981      * If limitByBlock is set to true, the scrollbar will scroll at least 1
 982      * unit increment, but will not scroll farther than the block increment.
 983      * See BasicScrollPaneUI.Handler.mouseWheelMoved().
 984      */
 985     static void scrollByUnits(JScrollBar scrollbar, int direction,
 986                               int units, boolean limitToBlock) {
 987         // This method is called from BasicScrollPaneUI to implement wheel
 988         // scrolling, as well as from scrollByUnit().


1016                 newValue = scrollbar.getMaximum();
1017             }
1018             else if (delta < 0 && newValue > oldValue) {
1019                 newValue = scrollbar.getMinimum();
1020             }
1021             if (oldValue == newValue) {
1022                 break;
1023             }
1024 
1025             if (limitToBlock && i > 0) {
1026                 assert limit != -1;
1027                 if ((direction < 0 && newValue < limit) ||
1028                     (direction > 0 && newValue > limit)) {
1029                     break;
1030                 }
1031             }
1032             scrollbar.setValue(newValue);
1033         }
1034     }
1035 




1036     protected void scrollByUnit(int direction)  {
1037         scrollByUnits(scrollbar, direction, 1, false);
1038     }
1039 
1040     /**
1041      * Indicates whether the user can absolutely position the thumb with
1042      * a mouse gesture (usually the middle mouse button).
1043      *
1044      * @return true if a mouse gesture can absolutely position the thumb
1045      * @since 1.5
1046      */
1047     public boolean getSupportsAbsolutePositioning() {
1048         return supportsAbsolutePositioning;
1049     }
1050 
1051     /**
1052      * A listener to listen for model changes.
1053      *
1054      */
1055     protected class ModelListener implements ChangeListener {
1056         public void stateChanged(ChangeEvent e) {
1057             if (!useCachedValue) {
1058                 scrollBarValue = scrollbar.getValue();
1059             }
1060             layoutContainer(scrollbar);
1061             useCachedValue = false;
1062         }
1063     }
1064 
1065 
1066     /**
1067      * Track mouse drags.
1068      */
1069     protected class TrackListener
1070         extends MouseAdapter implements MouseMotionListener
1071     {

1072         protected transient int offset;
1073         protected transient int currentMouseX, currentMouseY;



1074         private transient int direction = +1;
1075 

1076         public void mouseReleased(MouseEvent e)
1077         {
1078             if (isDragging) {
1079                 updateThumbState(e.getX(), e.getY());
1080             }
1081             if (SwingUtilities.isRightMouseButton(e) ||
1082                 (!getSupportsAbsolutePositioning() &&
1083                  SwingUtilities.isMiddleMouseButton(e)))
1084                 return;
1085             if(!scrollbar.isEnabled())
1086                 return;
1087 
1088             Rectangle r = getTrackBounds();
1089             scrollbar.repaint(r.x, r.y, r.width, r.height);
1090 
1091             trackHighlight = NO_HIGHLIGHT;
1092             isDragging = false;
1093             offset = 0;
1094             scrollTimer.stop();
1095             useCachedValue = true;


1322             switch (scrollbar.getOrientation()) {
1323             case JScrollBar.VERTICAL:
1324                 if (direction > 0) {
1325                     if (tb.y + tb.height < trackListener.currentMouseY) {
1326                         scrollTimer.start();
1327                     }
1328                 } else if (tb.y > trackListener.currentMouseY) {
1329                     scrollTimer.start();
1330                 }
1331                 break;
1332             case JScrollBar.HORIZONTAL:
1333                 if ((direction > 0 && isMouseAfterThumb())
1334                         || (direction < 0 && isMouseBeforeThumb())) {
1335 
1336                     scrollTimer.start();
1337                 }
1338                 break;
1339             }
1340         }
1341 

1342         public void mouseMoved(MouseEvent e) {
1343             if (!isDragging) {
1344                 updateThumbState(e.getX(), e.getY());
1345             }
1346         }
1347 
1348         /**
1349          * Invoked when the mouse exits the scrollbar.
1350          *
1351          * @param e MouseEvent further describing the event
1352          * @since 1.5
1353          */
1354         public void mouseExited(MouseEvent e) {
1355             if (!isDragging) {
1356                 setThumbRollover(false);
1357             }
1358         }
1359     }
1360 
1361 


1389             }
1390         }
1391 
1392         public void mouseReleased(MouseEvent e)         {
1393             scrollTimer.stop();
1394             handledEvent = false;
1395             scrollbar.setValueIsAdjusting(false);
1396         }
1397     }
1398 
1399 
1400     /**
1401      * Listener for scrolling events initiated in the
1402      * <code>ScrollPane</code>.
1403      */
1404     protected class ScrollListener implements ActionListener
1405     {
1406         int direction = +1;
1407         boolean useBlockIncrement;
1408 

1409         public ScrollListener() {
1410             direction = +1;
1411             useBlockIncrement = false;
1412         }
1413 





1414         public ScrollListener(int dir, boolean block)   {
1415             direction = dir;
1416             useBlockIncrement = block;
1417         }
1418 




1419         public void setDirection(int direction) { this.direction = direction; }




1420         public void setScrollByBlock(boolean block) { this.useBlockIncrement = block; }
1421 

1422         public void actionPerformed(ActionEvent e) {
1423             if(useBlockIncrement)       {
1424                 scrollByBlock(direction);
1425                 // Stop scrolling if the thumb catches up with the mouse
1426                 if(scrollbar.getOrientation() == JScrollBar.VERTICAL)   {
1427                     if(direction > 0)   {
1428                         if(getThumbBounds().y + getThumbBounds().height
1429                                 >= trackListener.currentMouseY)
1430                                     ((Timer)e.getSource()).stop();
1431                     } else if(getThumbBounds().y <= trackListener.currentMouseY)        {
1432                         ((Timer)e.getSource()).stop();
1433                     }
1434                 } else {
1435                     if ((direction > 0 && !isMouseAfterThumb())
1436                            || (direction < 0 && !isMouseBeforeThumb())) {
1437 
1438                        ((Timer)e.getSource()).stop();
1439                     }
1440                 }
1441             } else {


1480                 ((BasicArrowButton)incrButton).setDirection(
1481                         orient == HORIZONTAL? EAST : SOUTH);
1482             }
1483             if (decrButton instanceof BasicArrowButton) {
1484                 ((BasicArrowButton)decrButton).setDirection(
1485                         orient == HORIZONTAL? WEST : NORTH);
1486             }
1487         }
1488         else {
1489             if (incrButton instanceof BasicArrowButton) {
1490                 ((BasicArrowButton)incrButton).setDirection(
1491                         orient == HORIZONTAL? WEST : SOUTH);
1492             }
1493             if (decrButton instanceof BasicArrowButton) {
1494                 ((BasicArrowButton)decrButton).setDirection(
1495                         orient == HORIZONTAL ? EAST : NORTH);
1496             }
1497         }
1498     }
1499 

1500     public class PropertyChangeHandler implements PropertyChangeListener
1501     {
1502         // NOTE: This class exists only for backward compatibility. All
1503         // its functionality has been moved into Handler. If you need to add
1504         // new functionality add it to the Handler, but make sure this
1505         // class calls into the Handler.
1506 
1507         public void propertyChange(PropertyChangeEvent e) {
1508             getHandler().propertyChange(e);
1509         }
1510     }
1511 
1512 
1513     /**
1514      * Used for scrolling the scrollbar.
1515      */
1516     private static class Actions extends UIAction {
1517         private static final String POSITIVE_UNIT_INCREMENT =
1518                                     "positiveUnitIncrement";
1519         private static final String POSITIVE_BLOCK_INCREMENT =
1520                                     "positiveBlockIncrement";
1521         private static final String NEGATIVE_UNIT_INCREMENT =
1522                                     "negativeUnitIncrement";
1523         private static final String NEGATIVE_BLOCK_INCREMENT =
1524                                     "negativeBlockIncrement";
1525         private static final String MIN_SCROLL = "minScroll";
1526         private static final String MAX_SCROLL = "maxScroll";


   1 /*
   2  * Copyright (c) 1997, 2015, Oracle and/or its affiliates. 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


  43 
  44 
  45 /**
  46  * Implementation of ScrollBarUI for the Basic Look and Feel
  47  *
  48  * @author Rich Schiavi
  49  * @author David Kloba
  50  * @author Hans Muller
  51  */
  52 public class BasicScrollBarUI
  53     extends ScrollBarUI implements LayoutManager, SwingConstants
  54 {
  55     private static final int POSITIVE_SCROLL = 1;
  56     private static final int NEGATIVE_SCROLL = -1;
  57 
  58     private static final int MIN_SCROLL = 2;
  59     private static final int MAX_SCROLL = 3;
  60 
  61     // NOTE: DO NOT use this field directly, SynthScrollBarUI assumes you'll
  62     // call getMinimumThumbSize to access it.
  63     /** Minimum thumb size */
  64     protected Dimension minimumThumbSize;
  65     /** Maximum thumb size */
  66     protected Dimension maximumThumbSize;
  67 
  68     /** Thumb highlight color */
  69     protected Color thumbHighlightColor;
  70     /** Thumb light shadow color */
  71     protected Color thumbLightShadowColor;
  72     /** Thumb dark shadow color */
  73     protected Color thumbDarkShadowColor;
  74     /** Thumb color */
  75     protected Color thumbColor;
  76     /** Track color */
  77     protected Color trackColor;
  78     /** Track highlight color */
  79     protected Color trackHighlightColor;
  80 
  81     /** Scrollbar */
  82     protected JScrollBar scrollbar;
  83     /** Increment button */
  84     protected JButton incrButton;
  85     /** Decrement button */
  86     protected JButton decrButton;
  87     /** Dragging */
  88     protected boolean isDragging;
  89     /** Track listener */
  90     protected TrackListener trackListener;
  91     /** Button listener */
  92     protected ArrowButtonListener buttonListener;
  93     /** Model listener */
  94     protected ModelListener modelListener;
  95 
  96     /** Thumb rectangle */
  97     protected Rectangle thumbRect;
  98     /** Track rectangle */
  99     protected Rectangle trackRect;
 100 
 101     /** Track highlight */
 102     protected int trackHighlight;
 103 
 104     /** No highlight */
 105     protected static final int NO_HIGHLIGHT = 0;
 106     /** Decrease highlight */
 107     protected static final int DECREASE_HIGHLIGHT = 1;
 108     /** Increase highlight */
 109     protected static final int INCREASE_HIGHLIGHT = 2;
 110 
 111     /** Scroll listener */
 112     protected ScrollListener scrollListener;
 113     /** Property change listener */
 114     protected PropertyChangeListener propertyChangeListener;
 115     /** Scroll timer */
 116     protected Timer scrollTimer;
 117 
 118     private final static int scrollSpeedThrottle = 60; // delay in milli seconds
 119 
 120     /**
 121      * True indicates a middle click will absolutely position the
 122      * scrollbar.
 123      */
 124     private boolean supportsAbsolutePositioning;
 125 
 126     /**
 127      * Hint as to what width (when vertical) or height (when horizontal)
 128      * should be.
 129      *
 130      * @since 1.7
 131      */
 132     protected int scrollBarWidth;
 133 
 134     private Handler handler;
 135 


 155     protected int incrGap;
 156 
 157     /**
 158      * Distance between the decrement button and the track. This may be a negative
 159      * number. If negative, then an overlap between the button and track will occur,
 160      * which is useful for shaped buttons.
 161      *
 162      * @since 1.7
 163      */
 164     protected int decrGap;
 165 
 166     static void loadActionMap(LazyActionMap map) {
 167         map.put(new Actions(Actions.POSITIVE_UNIT_INCREMENT));
 168         map.put(new Actions(Actions.POSITIVE_BLOCK_INCREMENT));
 169         map.put(new Actions(Actions.NEGATIVE_UNIT_INCREMENT));
 170         map.put(new Actions(Actions.NEGATIVE_BLOCK_INCREMENT));
 171         map.put(new Actions(Actions.MIN_SCROLL));
 172         map.put(new Actions(Actions.MAX_SCROLL));
 173     }
 174 
 175     /**
 176      * Creates the UI.
 177      * @param c the component
 178      * @return the UI
 179      */
 180     public static ComponentUI createUI(JComponent c)    {
 181         return new BasicScrollBarUI();
 182     }
 183 
 184     /**
 185      * Configures the scroll bar colors.
 186      */
 187     protected void configureScrollBarColors()
 188     {
 189         LookAndFeel.installColors(scrollbar, "ScrollBar.background",
 190                                   "ScrollBar.foreground");
 191         thumbHighlightColor = UIManager.getColor("ScrollBar.thumbHighlight");
 192         thumbLightShadowColor = UIManager.getColor("ScrollBar.thumbShadow");
 193         thumbDarkShadowColor = UIManager.getColor("ScrollBar.thumbDarkShadow");
 194         thumbColor = UIManager.getColor("ScrollBar.thumb");
 195         trackColor = UIManager.getColor("ScrollBar.track");
 196         trackHighlightColor = UIManager.getColor("ScrollBar.trackHighlight");
 197     }
 198 
 199     /**
 200      * Installs the UI.
 201      * @param c the component
 202      */
 203     public void installUI(JComponent c)   {
 204         scrollbar = (JScrollBar)c;
 205         thumbRect = new Rectangle(0, 0, 0, 0);
 206         trackRect = new Rectangle(0, 0, 0, 0);
 207         installDefaults();
 208         installComponents();
 209         installListeners();
 210         installKeyboardActions();
 211     }
 212 
 213     /**
 214      * Uninstalls the UI.
 215      * @param c the component
 216      */
 217     public void uninstallUI(JComponent c) {
 218         scrollbar = (JScrollBar)c;
 219         uninstallListeners();
 220         uninstallDefaults();
 221         uninstallComponents();
 222         uninstallKeyboardActions();
 223         thumbRect = null;
 224         scrollbar = null;
 225         incrButton = null;
 226         decrButton = null;
 227     }
 228 
 229     /**
 230      * Installs the defaults.
 231      */
 232     protected void installDefaults()
 233     {
 234         scrollBarWidth = UIManager.getInt("ScrollBar.width");
 235         if (scrollBarWidth <= 0) {
 236             scrollBarWidth = 16;
 237         }
 238         minimumThumbSize = (Dimension)UIManager.get("ScrollBar.minimumThumbSize");
 239         maximumThumbSize = (Dimension)UIManager.get("ScrollBar.maximumThumbSize");
 240 
 241         Boolean absB = (Boolean)UIManager.get("ScrollBar.allowsAbsolutePositioning");
 242         supportsAbsolutePositioning = (absB != null) ? absB.booleanValue() :
 243                                       false;
 244 
 245         trackHighlight = NO_HIGHLIGHT;
 246         if (scrollbar.getLayout() == null ||
 247                      (scrollbar.getLayout() instanceof UIResource)) {
 248             scrollbar.setLayout(this);
 249         }
 250         configureScrollBarColors();
 251         LookAndFeel.installBorder(scrollbar, "ScrollBar.border");


 262         // components are based on Apples LAF
 263         String scaleKey = (String)scrollbar.getClientProperty(
 264                 "JComponent.sizeVariant");
 265         if (scaleKey != null){
 266             if ("large".equals(scaleKey)){
 267                 scrollBarWidth *= 1.15;
 268                 incrGap *= 1.15;
 269                 decrGap *= 1.15;
 270             } else if ("small".equals(scaleKey)){
 271                 scrollBarWidth *= 0.857;
 272                 incrGap *= 0.857;
 273                 decrGap *= 0.714;
 274             } else if ("mini".equals(scaleKey)){
 275                 scrollBarWidth *= 0.714;
 276                 incrGap *= 0.714;
 277                 decrGap *= 0.714;
 278             }
 279         }
 280     }
 281 
 282     /**
 283      * Installs the components.
 284      */
 285     protected void installComponents(){
 286         switch (scrollbar.getOrientation()) {
 287         case JScrollBar.VERTICAL:
 288             incrButton = createIncreaseButton(SOUTH);
 289             decrButton = createDecreaseButton(NORTH);
 290             break;
 291 
 292         case JScrollBar.HORIZONTAL:
 293             if (scrollbar.getComponentOrientation().isLeftToRight()) {
 294                 incrButton = createIncreaseButton(EAST);
 295                 decrButton = createDecreaseButton(WEST);
 296             } else {
 297                 incrButton = createIncreaseButton(WEST);
 298                 decrButton = createDecreaseButton(EAST);
 299             }
 300             break;
 301         }
 302         scrollbar.add(incrButton);
 303         scrollbar.add(decrButton);
 304         // Force the children's enabled state to be updated.
 305         scrollbar.setEnabled(scrollbar.isEnabled());
 306     }
 307 
 308     /**
 309      * Uninstalls the components.
 310      */
 311     protected void uninstallComponents(){
 312         scrollbar.remove(incrButton);
 313         scrollbar.remove(decrButton);
 314     }
 315 
 316     /**
 317      * Installs the listeners.
 318      */
 319     protected void installListeners(){
 320         trackListener = createTrackListener();
 321         buttonListener = createArrowButtonListener();
 322         modelListener = createModelListener();
 323         propertyChangeListener = createPropertyChangeListener();
 324 
 325         scrollbar.addMouseListener(trackListener);
 326         scrollbar.addMouseMotionListener(trackListener);
 327         scrollbar.getModel().addChangeListener(modelListener);
 328         scrollbar.addPropertyChangeListener(propertyChangeListener);
 329         scrollbar.addFocusListener(getHandler());
 330 
 331         if (incrButton != null) {
 332             incrButton.addMouseListener(buttonListener);
 333         }
 334         if (decrButton != null) {
 335             decrButton.addMouseListener(buttonListener);
 336         }
 337 
 338         scrollListener = createScrollListener();
 339         scrollTimer = new Timer(scrollSpeedThrottle, scrollListener);
 340         scrollTimer.setInitialDelay(300);  // default InitialDelay?
 341     }
 342 
 343     /**
 344      * Installs the keyboard actions.
 345      */
 346     protected void installKeyboardActions(){
 347         LazyActionMap.installLazyActionMap(scrollbar, BasicScrollBarUI.class,
 348                                            "ScrollBar.actionMap");
 349 
 350         InputMap inputMap = getInputMap(JComponent.WHEN_FOCUSED);
 351         SwingUtilities.replaceUIInputMap(scrollbar, JComponent.WHEN_FOCUSED,
 352                                          inputMap);
 353         inputMap = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
 354         SwingUtilities.replaceUIInputMap(scrollbar,
 355                    JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap);
 356     }
 357 
 358     /**
 359      * Uninstalls the keyboard actions.
 360      */
 361     protected void uninstallKeyboardActions(){
 362         SwingUtilities.replaceUIInputMap(scrollbar, JComponent.WHEN_FOCUSED,
 363                                          null);
 364         SwingUtilities.replaceUIActionMap(scrollbar, null);
 365     }
 366 
 367     private InputMap getInputMap(int condition) {
 368         if (condition == JComponent.WHEN_FOCUSED) {
 369             InputMap keyMap = (InputMap)DefaultLookup.get(
 370                         scrollbar, this, "ScrollBar.focusInputMap");
 371             InputMap rtlKeyMap;
 372 
 373             if (scrollbar.getComponentOrientation().isLeftToRight() ||
 374                 ((rtlKeyMap = (InputMap)DefaultLookup.get(scrollbar, this, "ScrollBar.focusInputMap.RightToLeft")) == null)) {
 375                 return keyMap;
 376             } else {
 377                 rtlKeyMap.setParent(keyMap);
 378                 return rtlKeyMap;
 379             }
 380         }
 381         else if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
 382             InputMap keyMap = (InputMap)DefaultLookup.get(
 383                         scrollbar, this, "ScrollBar.ancestorInputMap");
 384             InputMap rtlKeyMap;
 385 
 386             if (scrollbar.getComponentOrientation().isLeftToRight() ||
 387                 ((rtlKeyMap = (InputMap)DefaultLookup.get(scrollbar, this, "ScrollBar.ancestorInputMap.RightToLeft")) == null)) {
 388                 return keyMap;
 389             } else {
 390                 rtlKeyMap.setParent(keyMap);
 391                 return rtlKeyMap;
 392             }
 393         }
 394         return null;
 395     }
 396 
 397     /**
 398      * Uninstall the listeners.
 399      */
 400     protected void uninstallListeners() {
 401         scrollTimer.stop();
 402         scrollTimer = null;
 403 
 404         if (decrButton != null){
 405             decrButton.removeMouseListener(buttonListener);
 406         }
 407         if (incrButton != null){
 408             incrButton.removeMouseListener(buttonListener);
 409         }
 410 
 411         scrollbar.getModel().removeChangeListener(modelListener);
 412         scrollbar.removeMouseListener(trackListener);
 413         scrollbar.removeMouseMotionListener(trackListener);
 414         scrollbar.removePropertyChangeListener(propertyChangeListener);
 415         scrollbar.removeFocusListener(getHandler());
 416         handler = null;
 417     }
 418 
 419     /**
 420      * Uninstalls the defaults.
 421      */
 422     protected void uninstallDefaults(){
 423         LookAndFeel.uninstallBorder(scrollbar);
 424         if (scrollbar.getLayout() == this) {
 425             scrollbar.setLayout(null);
 426         }
 427     }
 428 
 429 
 430     private Handler getHandler() {
 431         if (handler == null) {
 432             handler = new Handler();
 433         }
 434         return handler;
 435     }
 436 
 437     /**
 438      * Creates a track listener.
 439      * @return a track listener
 440      */
 441     protected TrackListener createTrackListener(){
 442         return new TrackListener();
 443     }
 444 
 445     /**
 446      * Creates an arrow button listener.
 447      * @return an arrow button   listener
 448      */
 449     protected ArrowButtonListener createArrowButtonListener(){
 450         return new ArrowButtonListener();
 451     }
 452 
 453     /**
 454      * Creates a model listener.
 455      * @return a model listener
 456      */
 457     protected ModelListener createModelListener(){
 458         return new ModelListener();
 459     }
 460 
 461     /**
 462      * Creates a scroll listener.
 463      * @return a scroll listener
 464      */
 465     protected ScrollListener createScrollListener(){
 466         return new ScrollListener();
 467     }
 468 
 469     /**
 470      * Creates a property change listener.
 471      * @return a property change listener
 472      */
 473     protected PropertyChangeListener createPropertyChangeListener() {
 474         return getHandler();
 475     }
 476 
 477     private void updateThumbState(int x, int y) {
 478         Rectangle rect = getThumbBounds();
 479 
 480         setThumbRollover(rect.contains(x, y));
 481     }
 482 
 483     /**
 484      * Sets whether or not the mouse is currently over the thumb.
 485      *
 486      * @param active True indicates the thumb is currently active.
 487      * @since 1.5
 488      */
 489     protected void setThumbRollover(boolean active) {
 490         if (thumbActive != active) {
 491             thumbActive = active;
 492             scrollbar.repaint(getThumbBounds());


 528      * @see #getMaximumSize
 529      * @see #getMinimumSize
 530      */
 531     public Dimension getPreferredSize(JComponent c) {
 532         return (scrollbar.getOrientation() == JScrollBar.VERTICAL)
 533             ? new Dimension(scrollBarWidth, 48)
 534             : new Dimension(48, scrollBarWidth);
 535     }
 536 
 537 
 538     /**
 539      * @param c The JScrollBar that's delegating this method to us.
 540      * @return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
 541      * @see #getMinimumSize
 542      * @see #getPreferredSize
 543      */
 544     public Dimension getMaximumSize(JComponent c) {
 545         return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
 546     }
 547 
 548     /**
 549      * Creates a decrease button.
 550      * @param orientation the orientation
 551      * @return a decrease button
 552      */
 553     protected JButton createDecreaseButton(int orientation)  {
 554         return new BasicArrowButton(orientation,
 555                                     UIManager.getColor("ScrollBar.thumb"),
 556                                     UIManager.getColor("ScrollBar.thumbShadow"),
 557                                     UIManager.getColor("ScrollBar.thumbDarkShadow"),
 558                                     UIManager.getColor("ScrollBar.thumbHighlight"));
 559     }
 560 
 561     /**
 562      * Creates an increase button.
 563      * @param orientation the orientation
 564      * @return an increase button
 565      */
 566     protected JButton createIncreaseButton(int orientation)  {
 567         return new BasicArrowButton(orientation,
 568                                     UIManager.getColor("ScrollBar.thumb"),
 569                                     UIManager.getColor("ScrollBar.thumbShadow"),
 570                                     UIManager.getColor("ScrollBar.thumbDarkShadow"),
 571                                     UIManager.getColor("ScrollBar.thumbHighlight"));
 572     }
 573 
 574 
 575     /**
 576      * Paints the decrease highlight.
 577      * @param g the graphics
 578      */
 579     protected void paintDecreaseHighlight(Graphics g)
 580     {
 581         Insets insets = scrollbar.getInsets();
 582         Rectangle thumbR = getThumbBounds();
 583         g.setColor(trackHighlightColor);
 584 
 585         if (scrollbar.getOrientation() == JScrollBar.VERTICAL) {
 586             //paint the distance between the start of the track and top of the thumb
 587             int x = insets.left;
 588             int y = trackRect.y;
 589             int w = scrollbar.getWidth() - (insets.left + insets.right);
 590             int h = thumbR.y - y;
 591             g.fillRect(x, y, w, h);
 592         } else {
 593             //if left-to-right, fill the area between the start of the track and
 594             //the left edge of the thumb. If right-to-left, fill the area between
 595             //the end of the thumb and end of the track.
 596             int x, w;
 597             if (scrollbar.getComponentOrientation().isLeftToRight()) {
 598                x = trackRect.x;
 599                 w = thumbR.x - x;
 600             } else {
 601                 x = thumbR.x + thumbR.width;
 602                 w = trackRect.x + trackRect.width - x;
 603             }
 604             int y = insets.top;
 605             int h = scrollbar.getHeight() - (insets.top + insets.bottom);
 606             g.fillRect(x, y, w, h);
 607         }
 608     }
 609 
 610 
 611     /**
 612      * Paints the increase highlight.
 613      * @param g the graphics
 614      */
 615     protected void paintIncreaseHighlight(Graphics g)
 616     {
 617         Insets insets = scrollbar.getInsets();
 618         Rectangle thumbR = getThumbBounds();
 619         g.setColor(trackHighlightColor);
 620 
 621         if (scrollbar.getOrientation() == JScrollBar.VERTICAL) {
 622             //fill the area between the bottom of the thumb and the end of the track.
 623             int x = insets.left;
 624             int y = thumbR.y + thumbR.height;
 625             int w = scrollbar.getWidth() - (insets.left + insets.right);
 626             int h = trackRect.y + trackRect.height - y;
 627             g.fillRect(x, y, w, h);
 628         }
 629         else {
 630             //if left-to-right, fill the area between the right of the thumb and the
 631             //end of the track. If right-to-left, then fill the area to the left of
 632             //the thumb and the start of the track.
 633             int x, w;
 634             if (scrollbar.getComponentOrientation().isLeftToRight()) {
 635                 x = thumbR.x + thumbR.width;
 636                 w = trackRect.x + trackRect.width - x;
 637             } else {
 638                 x = trackRect.x;
 639                 w = thumbR.x - x;
 640             }
 641             int y = insets.top;
 642             int h = scrollbar.getHeight() - (insets.top + insets.bottom);
 643             g.fillRect(x, y, w, h);
 644         }
 645     }
 646 
 647 
 648     /**
 649      * Paints the track.
 650      * @param g the graphics
 651      * @param c the component
 652      * @param trackBounds the track bounds
 653      */
 654     protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds)
 655     {
 656         g.setColor(trackColor);
 657         g.fillRect(trackBounds.x, trackBounds.y, trackBounds.width, trackBounds.height);
 658 
 659         if(trackHighlight == DECREASE_HIGHLIGHT)        {
 660             paintDecreaseHighlight(g);
 661         }
 662         else if(trackHighlight == INCREASE_HIGHLIGHT)           {
 663             paintIncreaseHighlight(g);
 664         }
 665     }
 666 
 667     /**
 668      * Paints the thumb.
 669      * @param g the graphics
 670      * @param c the component
 671      * @param thumbBounds the thumb bounds
 672      */
 673     protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds)
 674     {
 675         if(thumbBounds.isEmpty() || !scrollbar.isEnabled())     {
 676             return;
 677         }
 678 
 679         int w = thumbBounds.width;
 680         int h = thumbBounds.height;
 681 
 682         g.translate(thumbBounds.x, thumbBounds.y);
 683 
 684         g.setColor(thumbDarkShadowColor);
 685         drawRect(g, 0, 0, w - 1, h - 1);
 686         g.setColor(thumbColor);
 687         g.fillRect(0, 0, w - 1, h - 1);
 688 
 689         g.setColor(thumbHighlightColor);
 690         drawVLine(g, 1, 1, h - 2);
 691         drawHLine(g, 2, w - 3, 1);
 692 


 731 
 732     /*
 733      * LayoutManager Implementation
 734      */
 735 
 736     public void addLayoutComponent(String name, Component child) {}
 737     public void removeLayoutComponent(Component child) {}
 738 
 739     public Dimension preferredLayoutSize(Container scrollbarContainer)  {
 740         return getPreferredSize((JComponent)scrollbarContainer);
 741     }
 742 
 743     public Dimension minimumLayoutSize(Container scrollbarContainer) {
 744         return getMinimumSize((JComponent)scrollbarContainer);
 745     }
 746 
 747     private int getValue(JScrollBar sb) {
 748         return (useCachedValue) ? scrollBarValue : sb.getValue();
 749     }
 750 
 751     /**
 752      * Laysouts a  vertical scroll bar.
 753      * @param sb the scroll bar
 754      */
 755     protected void layoutVScrollbar(JScrollBar sb)
 756     {
 757         Dimension sbSize = sb.getSize();
 758         Insets sbInsets = sb.getInsets();
 759 
 760         /*
 761          * Width and left edge of the buttons and thumb.
 762          */
 763         int itemW = sbSize.width - (sbInsets.left + sbInsets.right);
 764         int itemX = sbInsets.left;
 765 
 766         /* Nominal locations of the buttons, assuming their preferred
 767          * size will fit.
 768          */
 769         boolean squareButtons = DefaultLookup.getBoolean(
 770             scrollbar, this, "ScrollBar.squareButtons", false);
 771         int decrButtonH = squareButtons ? itemW :
 772                           decrButton.getPreferredSize().height;
 773         int decrButtonY = sbInsets.top;
 774 


 833             if (UIManager.getBoolean("ScrollBar.alwaysShowThumb")) {
 834                 // This is used primarily for GTK L&F, which expands the
 835                 // thumb to fit the track when it would otherwise be hidden.
 836                 setThumbBounds(itemX, itrackY, itemW, itrackH);
 837             } else {
 838                 // Other L&F's simply hide the thumb in this case.
 839                 setThumbBounds(0, 0, 0, 0);
 840             }
 841         }
 842         else {
 843             if ((thumbY + thumbH) > incrButtonY - incrGap) {
 844                 thumbY = incrButtonY - incrGap - thumbH;
 845             }
 846             if (thumbY  < (decrButtonY + decrButtonH + decrGap)) {
 847                 thumbY = decrButtonY + decrButtonH + decrGap + 1;
 848             }
 849             setThumbBounds(itemX, thumbY, itemW, thumbH);
 850         }
 851     }
 852 
 853     /**
 854      * Laysouts a  vertical scroll bar.
 855      * @param sb the scroll bar
 856      */
 857     protected void layoutHScrollbar(JScrollBar sb)
 858     {
 859         Dimension sbSize = sb.getSize();
 860         Insets sbInsets = sb.getInsets();
 861 
 862         /* Height and top edge of the buttons and thumb.
 863          */
 864         int itemH = sbSize.height - (sbInsets.top + sbInsets.bottom);
 865         int itemY = sbInsets.top;
 866 
 867         boolean ltr = sb.getComponentOrientation().isLeftToRight();
 868 
 869         /* Nominal locations of the buttons, assuming their preferred
 870          * size will fit.
 871          */
 872         boolean squareButtons = DefaultLookup.getBoolean(
 873             scrollbar, this, "ScrollBar.squareButtons", false);
 874         int leftButtonW = squareButtons ? itemH :
 875                           decrButton.getPreferredSize().width;
 876         int rightButtonW = squareButtons ? itemH :


1060      */
1061     static void scrollByBlock(JScrollBar scrollbar, int direction) {
1062         // This method is called from BasicScrollPaneUI to implement wheel
1063         // scrolling, and also from scrollByBlock().
1064             int oldValue = scrollbar.getValue();
1065             int blockIncrement = scrollbar.getBlockIncrement(direction);
1066             int delta = blockIncrement * ((direction > 0) ? +1 : -1);
1067             int newValue = oldValue + delta;
1068 
1069             // Check for overflow.
1070             if (delta > 0 && newValue < oldValue) {
1071                 newValue = scrollbar.getMaximum();
1072             }
1073             else if (delta < 0 && newValue > oldValue) {
1074                 newValue = scrollbar.getMinimum();
1075             }
1076 
1077             scrollbar.setValue(newValue);
1078     }
1079 
1080     /**
1081      * Scrolls by block.
1082      * @param direction the direction to scroll
1083      */
1084     protected void scrollByBlock(int direction)
1085     {
1086         scrollByBlock(scrollbar, direction);
1087             trackHighlight = direction > 0 ? INCREASE_HIGHLIGHT : DECREASE_HIGHLIGHT;
1088             Rectangle dirtyRect = getTrackBounds();
1089             scrollbar.repaint(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
1090     }
1091 
1092     /*
1093      * Method for scrolling by a unit increment.
1094      * Added for mouse wheel scrolling support, RFE 4202656.
1095      *
1096      * If limitByBlock is set to true, the scrollbar will scroll at least 1
1097      * unit increment, but will not scroll farther than the block increment.
1098      * See BasicScrollPaneUI.Handler.mouseWheelMoved().
1099      */
1100     static void scrollByUnits(JScrollBar scrollbar, int direction,
1101                               int units, boolean limitToBlock) {
1102         // This method is called from BasicScrollPaneUI to implement wheel
1103         // scrolling, as well as from scrollByUnit().


1131                 newValue = scrollbar.getMaximum();
1132             }
1133             else if (delta < 0 && newValue > oldValue) {
1134                 newValue = scrollbar.getMinimum();
1135             }
1136             if (oldValue == newValue) {
1137                 break;
1138             }
1139 
1140             if (limitToBlock && i > 0) {
1141                 assert limit != -1;
1142                 if ((direction < 0 && newValue < limit) ||
1143                     (direction > 0 && newValue > limit)) {
1144                     break;
1145                 }
1146             }
1147             scrollbar.setValue(newValue);
1148         }
1149     }
1150 
1151     /**
1152      * Scrolls by unit.
1153      * @param direction the direction to scroll
1154      */
1155     protected void scrollByUnit(int direction)  {
1156         scrollByUnits(scrollbar, direction, 1, false);
1157     }
1158 
1159     /**
1160      * Indicates whether the user can absolutely position the thumb with
1161      * a mouse gesture (usually the middle mouse button).
1162      *
1163      * @return true if a mouse gesture can absolutely position the thumb
1164      * @since 1.5
1165      */
1166     public boolean getSupportsAbsolutePositioning() {
1167         return supportsAbsolutePositioning;
1168     }
1169 
1170     /**
1171      * A listener to listen for model changes.

1172      */
1173     protected class ModelListener implements ChangeListener {
1174         public void stateChanged(ChangeEvent e) {
1175             if (!useCachedValue) {
1176                 scrollBarValue = scrollbar.getValue();
1177             }
1178             layoutContainer(scrollbar);
1179             useCachedValue = false;
1180         }
1181     }
1182 
1183 
1184     /**
1185      * Track mouse drags.
1186      */
1187     protected class TrackListener
1188         extends MouseAdapter implements MouseMotionListener
1189     {
1190         /** The offset */
1191         protected transient int offset;
1192         /** Current mouse x position */
1193         protected transient int currentMouseX;
1194         /** Current mouse y position */
1195         protected transient int currentMouseY;
1196         private transient int direction = +1;
1197 
1198         /** {@inheritDoc} */
1199         public void mouseReleased(MouseEvent e)
1200         {
1201             if (isDragging) {
1202                 updateThumbState(e.getX(), e.getY());
1203             }
1204             if (SwingUtilities.isRightMouseButton(e) ||
1205                 (!getSupportsAbsolutePositioning() &&
1206                  SwingUtilities.isMiddleMouseButton(e)))
1207                 return;
1208             if(!scrollbar.isEnabled())
1209                 return;
1210 
1211             Rectangle r = getTrackBounds();
1212             scrollbar.repaint(r.x, r.y, r.width, r.height);
1213 
1214             trackHighlight = NO_HIGHLIGHT;
1215             isDragging = false;
1216             offset = 0;
1217             scrollTimer.stop();
1218             useCachedValue = true;


1445             switch (scrollbar.getOrientation()) {
1446             case JScrollBar.VERTICAL:
1447                 if (direction > 0) {
1448                     if (tb.y + tb.height < trackListener.currentMouseY) {
1449                         scrollTimer.start();
1450                     }
1451                 } else if (tb.y > trackListener.currentMouseY) {
1452                     scrollTimer.start();
1453                 }
1454                 break;
1455             case JScrollBar.HORIZONTAL:
1456                 if ((direction > 0 && isMouseAfterThumb())
1457                         || (direction < 0 && isMouseBeforeThumb())) {
1458 
1459                     scrollTimer.start();
1460                 }
1461                 break;
1462             }
1463         }
1464 
1465         /** {@inheritDoc} */
1466         public void mouseMoved(MouseEvent e) {
1467             if (!isDragging) {
1468                 updateThumbState(e.getX(), e.getY());
1469             }
1470         }
1471 
1472         /**
1473          * Invoked when the mouse exits the scrollbar.
1474          *
1475          * @param e MouseEvent further describing the event
1476          * @since 1.5
1477          */
1478         public void mouseExited(MouseEvent e) {
1479             if (!isDragging) {
1480                 setThumbRollover(false);
1481             }
1482         }
1483     }
1484 
1485 


1513             }
1514         }
1515 
1516         public void mouseReleased(MouseEvent e)         {
1517             scrollTimer.stop();
1518             handledEvent = false;
1519             scrollbar.setValueIsAdjusting(false);
1520         }
1521     }
1522 
1523 
1524     /**
1525      * Listener for scrolling events initiated in the
1526      * <code>ScrollPane</code>.
1527      */
1528     protected class ScrollListener implements ActionListener
1529     {
1530         int direction = +1;
1531         boolean useBlockIncrement;
1532 
1533         /** Constructs a {@code ScrollListener}. */
1534         public ScrollListener() {
1535             direction = +1;
1536             useBlockIncrement = false;
1537         }
1538 
1539         /**
1540          * Constructs a {@code ScrollListener}.
1541          * @param dir direction
1542          * @param block use block increment
1543          */
1544         public ScrollListener(int dir, boolean block)   {
1545             direction = dir;
1546             useBlockIncrement = block;
1547         }
1548 
1549         /**
1550          * Sets the direction.
1551          * @param direction the new direction
1552          */
1553         public void setDirection(int direction) { this.direction = direction; }
1554         /**
1555          * Sets the scrolling by block
1556          * @param block whether or not to scroll by block
1557          */
1558         public void setScrollByBlock(boolean block) { this.useBlockIncrement = block; }
1559 
1560         /** {@inheritDoc} */
1561         public void actionPerformed(ActionEvent e) {
1562             if(useBlockIncrement)       {
1563                 scrollByBlock(direction);
1564                 // Stop scrolling if the thumb catches up with the mouse
1565                 if(scrollbar.getOrientation() == JScrollBar.VERTICAL)   {
1566                     if(direction > 0)   {
1567                         if(getThumbBounds().y + getThumbBounds().height
1568                                 >= trackListener.currentMouseY)
1569                                     ((Timer)e.getSource()).stop();
1570                     } else if(getThumbBounds().y <= trackListener.currentMouseY)        {
1571                         ((Timer)e.getSource()).stop();
1572                     }
1573                 } else {
1574                     if ((direction > 0 && !isMouseAfterThumb())
1575                            || (direction < 0 && !isMouseBeforeThumb())) {
1576 
1577                        ((Timer)e.getSource()).stop();
1578                     }
1579                 }
1580             } else {


1619                 ((BasicArrowButton)incrButton).setDirection(
1620                         orient == HORIZONTAL? EAST : SOUTH);
1621             }
1622             if (decrButton instanceof BasicArrowButton) {
1623                 ((BasicArrowButton)decrButton).setDirection(
1624                         orient == HORIZONTAL? WEST : NORTH);
1625             }
1626         }
1627         else {
1628             if (incrButton instanceof BasicArrowButton) {
1629                 ((BasicArrowButton)incrButton).setDirection(
1630                         orient == HORIZONTAL? WEST : SOUTH);
1631             }
1632             if (decrButton instanceof BasicArrowButton) {
1633                 ((BasicArrowButton)decrButton).setDirection(
1634                         orient == HORIZONTAL ? EAST : NORTH);
1635             }
1636         }
1637     }
1638 
1639     /** Property change handler */
1640     public class PropertyChangeHandler implements PropertyChangeListener
1641     {
1642         // NOTE: This class exists only for backward compatibility. All
1643         // its functionality has been moved into Handler. If you need to add
1644         // new functionality add it to the Handler, but make sure this
1645         // class calls into the Handler.
1646         /** {@inheritDoc} */
1647         public void propertyChange(PropertyChangeEvent e) {
1648             getHandler().propertyChange(e);
1649         }
1650     }
1651 
1652 
1653     /**
1654      * Used for scrolling the scrollbar.
1655      */
1656     private static class Actions extends UIAction {
1657         private static final String POSITIVE_UNIT_INCREMENT =
1658                                     "positiveUnitIncrement";
1659         private static final String POSITIVE_BLOCK_INCREMENT =
1660                                     "positiveBlockIncrement";
1661         private static final String NEGATIVE_UNIT_INCREMENT =
1662                                     "negativeUnitIncrement";
1663         private static final String NEGATIVE_BLOCK_INCREMENT =
1664                                     "negativeBlockIncrement";
1665         private static final String MIN_SCROLL = "minScroll";
1666         private static final String MAX_SCROLL = "maxScroll";


< prev index next >