< prev index next >

src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSliderUI.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


  30 import java.beans.*;
  31 import java.util.Dictionary;
  32 import java.util.Enumeration;
  33 
  34 import javax.swing.*;
  35 import javax.swing.event.*;
  36 import javax.swing.plaf.*;
  37 import sun.swing.DefaultLookup;
  38 import sun.swing.UIAction;
  39 
  40 
  41 /**
  42  * A Basic L&amp;F implementation of SliderUI.
  43  *
  44  * @author Tom Santos
  45  */
  46 public class BasicSliderUI extends SliderUI{
  47     // Old actions forward to an instance of this.
  48     private static final Actions SHARED_ACTION = new Actions();
  49 

  50     public static final int POSITIVE_SCROLL = +1;

  51     public static final int NEGATIVE_SCROLL = -1;

  52     public static final int MIN_SCROLL = -2;

  53     public static final int MAX_SCROLL = +2;
  54 

  55     protected Timer scrollTimer;

  56     protected JSlider slider;
  57 

  58     protected Insets focusInsets = null;

  59     protected Insets insetCache = null;

  60     protected boolean leftToRightCache = true;

  61     protected Rectangle focusRect = null;

  62     protected Rectangle contentRect = null;

  63     protected Rectangle labelRect = null;

  64     protected Rectangle tickRect = null;

  65     protected Rectangle trackRect = null;

  66     protected Rectangle thumbRect = null;
  67 
  68     protected int trackBuffer = 0;  // The distance that the track is from the side of the control

  69 
  70     private transient boolean isDragging;
  71 

  72     protected TrackListener trackListener;

  73     protected ChangeListener changeListener;

  74     protected ComponentListener componentListener;

  75     protected FocusListener focusListener;

  76     protected ScrollListener scrollListener;

  77     protected PropertyChangeListener propertyChangeListener;
  78     private Handler handler;
  79     private int lastValue;
  80 
  81     // Colors
  82     private Color shadowColor;
  83     private Color highlightColor;
  84     private Color focusColor;
  85 
  86     /**
  87      * Whther or not sameLabelBaselines is up to date.
  88      */
  89     private boolean checkedLabelBaselines;
  90     /**
  91      * Whether or not all the entries in the labeltable have the same
  92      * baseline.
  93      */
  94     private boolean sameLabelBaselines;
  95 
  96 



  97     protected Color getShadowColor() {
  98         return shadowColor;
  99     }
 100 




 101     protected Color getHighlightColor() {
 102         return highlightColor;
 103     }
 104 




 105     protected Color getFocusColor() {
 106         return focusColor;
 107     }
 108 
 109     /**
 110      * Returns true if the user is dragging the slider.
 111      *
 112      * @return true if the user is dragging the slider
 113      * @since 1.5
 114      */
 115     protected boolean isDragging() {
 116         return isDragging;
 117     }
 118 
 119     /////////////////////////////////////////////////////////////////////////////
 120     // ComponentUI Interface Implementation methods
 121     /////////////////////////////////////////////////////////////////////////////





 122     public static ComponentUI createUI(JComponent b)    {
 123         return new BasicSliderUI((JSlider)b);
 124     }
 125 




 126     public BasicSliderUI(JSlider b)   {
 127     }
 128 




 129     public void installUI(JComponent c)   {
 130         slider = (JSlider) c;
 131 
 132         checkedLabelBaselines = false;
 133 
 134         slider.setEnabled(slider.isEnabled());
 135         LookAndFeel.installProperty(slider, "opaque", Boolean.TRUE);
 136 
 137         isDragging = false;
 138         trackListener = createTrackListener( slider );
 139         changeListener = createChangeListener( slider );
 140         componentListener = createComponentListener( slider );
 141         focusListener = createFocusListener( slider );
 142         scrollListener = createScrollListener( slider );
 143         propertyChangeListener = createPropertyChangeListener( slider );
 144 
 145         installDefaults( slider );
 146         installListeners( slider );
 147         installKeyboardActions( slider );
 148 
 149         scrollTimer = new Timer( 100, scrollListener );
 150         scrollTimer.setInitialDelay( 300 );
 151 
 152         insetCache = slider.getInsets();
 153         leftToRightCache = BasicGraphicsUtils.isLeftToRight(slider);
 154         focusRect = new Rectangle();
 155         contentRect = new Rectangle();
 156         labelRect = new Rectangle();
 157         tickRect = new Rectangle();
 158         trackRect = new Rectangle();
 159         thumbRect = new Rectangle();
 160         lastValue = slider.getValue();
 161 
 162         calculateGeometry(); // This figures out where the labels, ticks, track, and thumb are.
 163     }
 164 




 165     public void uninstallUI(JComponent c) {
 166         if ( c != slider )
 167             throw new IllegalComponentStateException(
 168                                                     this + " was asked to deinstall() "
 169                                                     + c + " when it only knows about "
 170                                                     + slider + ".");
 171 
 172         scrollTimer.stop();
 173         scrollTimer = null;
 174 
 175         uninstallDefaults(slider);
 176         uninstallListeners( slider );
 177         uninstallKeyboardActions(slider);
 178 
 179         insetCache = null;
 180         leftToRightCache = true;
 181         focusRect = null;
 182         contentRect = null;
 183         labelRect = null;
 184         tickRect = null;
 185         trackRect = null;
 186         thumbRect = null;
 187         trackListener = null;
 188         changeListener = null;
 189         componentListener = null;
 190         focusListener = null;
 191         scrollListener = null;
 192         propertyChangeListener = null;
 193         slider = null;
 194     }
 195 




 196     protected void installDefaults( JSlider slider ) {
 197         LookAndFeel.installBorder(slider, "Slider.border");
 198         LookAndFeel.installColorsAndFont(slider, "Slider.background",
 199                                          "Slider.foreground", "Slider.font");
 200         highlightColor = UIManager.getColor("Slider.highlight");
 201 
 202         shadowColor = UIManager.getColor("Slider.shadow");
 203         focusColor = UIManager.getColor("Slider.focus");
 204 
 205         focusInsets = (Insets)UIManager.get( "Slider.focusInsets" );
 206         // use default if missing so that BasicSliderUI can be used in other
 207         // LAFs like Nimbus
 208         if (focusInsets == null) focusInsets = new InsetsUIResource(2,2,2,2);
 209     }
 210 




 211     protected void uninstallDefaults(JSlider slider) {
 212         LookAndFeel.uninstallBorder(slider);
 213 
 214         focusInsets = null;
 215     }
 216 





 217     protected TrackListener createTrackListener(JSlider slider) {
 218         return new TrackListener();
 219     }
 220 





 221     protected ChangeListener createChangeListener(JSlider slider) {
 222         return getHandler();
 223     }
 224 





 225     protected ComponentListener createComponentListener(JSlider slider) {
 226         return getHandler();
 227     }
 228 





 229     protected FocusListener createFocusListener(JSlider slider) {
 230         return getHandler();
 231     }
 232 





 233     protected ScrollListener createScrollListener( JSlider slider ) {
 234         return new ScrollListener();
 235     }
 236 





 237     protected PropertyChangeListener createPropertyChangeListener(
 238             JSlider slider) {
 239         return getHandler();
 240     }
 241 
 242     private Handler getHandler() {
 243         if (handler == null) {
 244             handler = new Handler();
 245         }
 246         return handler;
 247     }
 248 




 249     protected void installListeners( JSlider slider ) {
 250         slider.addMouseListener(trackListener);
 251         slider.addMouseMotionListener(trackListener);
 252         slider.addFocusListener(focusListener);
 253         slider.addComponentListener(componentListener);
 254         slider.addPropertyChangeListener( propertyChangeListener );
 255         slider.getModel().addChangeListener(changeListener);
 256     }
 257 




 258     protected void uninstallListeners( JSlider slider ) {
 259         slider.removeMouseListener(trackListener);
 260         slider.removeMouseMotionListener(trackListener);
 261         slider.removeFocusListener(focusListener);
 262         slider.removeComponentListener(componentListener);
 263         slider.removePropertyChangeListener( propertyChangeListener );
 264         slider.getModel().removeChangeListener(changeListener);
 265         handler = null;
 266     }
 267 




 268     protected void installKeyboardActions( JSlider slider ) {
 269         InputMap km = getInputMap(JComponent.WHEN_FOCUSED, slider);
 270         SwingUtilities.replaceUIInputMap(slider, JComponent.WHEN_FOCUSED, km);
 271         LazyActionMap.installLazyActionMap(slider, BasicSliderUI.class,
 272                 "Slider.actionMap");
 273     }
 274 
 275     InputMap getInputMap(int condition, JSlider slider) {
 276         if (condition == JComponent.WHEN_FOCUSED) {
 277             InputMap keyMap = (InputMap)DefaultLookup.get(slider, this,
 278                   "Slider.focusInputMap");
 279             InputMap rtlKeyMap;
 280 
 281             if (slider.getComponentOrientation().isLeftToRight() ||
 282                 ((rtlKeyMap = (InputMap)DefaultLookup.get(slider, this,
 283                           "Slider.focusInputMap.RightToLeft")) == null)) {
 284                 return keyMap;
 285             } else {
 286                 rtlKeyMap.setParent(keyMap);
 287                 return rtlKeyMap;
 288             }
 289         }
 290         return null;
 291     }
 292 
 293     /**
 294      * Populates ComboBox's actions.
 295      */
 296     static void loadActionMap(LazyActionMap map) {
 297         map.put(new Actions(Actions.POSITIVE_UNIT_INCREMENT));
 298         map.put(new Actions(Actions.POSITIVE_BLOCK_INCREMENT));
 299         map.put(new Actions(Actions.NEGATIVE_UNIT_INCREMENT));
 300         map.put(new Actions(Actions.NEGATIVE_BLOCK_INCREMENT));
 301         map.put(new Actions(Actions.MIN_SCROLL_INCREMENT));
 302         map.put(new Actions(Actions.MAX_SCROLL_INCREMENT));
 303     }
 304 




 305     protected void uninstallKeyboardActions( JSlider slider ) {
 306         SwingUtilities.replaceUIActionMap(slider, null);
 307         SwingUtilities.replaceUIInputMap(slider, JComponent.WHEN_FOCUSED,
 308                                          null);
 309     }
 310 
 311 
 312     /**
 313      * Returns the baseline.
 314      *
 315      * @throws NullPointerException {@inheritDoc}
 316      * @throws IllegalArgumentException {@inheritDoc}
 317      * @see javax.swing.JComponent#getBaseline(int, int)
 318      * @since 1.6
 319      */
 320     public int getBaseline(JComponent c, int width, int height) {
 321         super.getBaseline(c, width, height);
 322         if (slider.getPaintLabels() && labelsHaveSameBaselines()) {
 323             FontMetrics metrics = slider.getFontMetrics(slider.getFont());
 324             Insets insets = slider.getInsets();


 413                             baseline = labelBaseline;
 414                         }
 415                         else if (baseline != labelBaseline) {
 416                             sameLabelBaselines = false;
 417                             break;
 418                         }
 419                     }
 420                     else {
 421                         sameLabelBaselines = false;
 422                         break;
 423                     }
 424                 }
 425             }
 426             else {
 427                 sameLabelBaselines = false;
 428             }
 429         }
 430         return sameLabelBaselines;
 431     }
 432 




 433     public Dimension getPreferredHorizontalSize() {
 434         Dimension horizDim = (Dimension)DefaultLookup.get(slider,
 435                 this, "Slider.horizontalSize");
 436         if (horizDim == null) {
 437             horizDim = new Dimension(200, 21);
 438         }
 439         return horizDim;
 440     }
 441 




 442     public Dimension getPreferredVerticalSize() {
 443         Dimension vertDim = (Dimension)DefaultLookup.get(slider,
 444                 this, "Slider.verticalSize");
 445         if (vertDim == null) {
 446             vertDim = new Dimension(21, 200);
 447         }
 448         return vertDim;
 449     }
 450 




 451     public Dimension getMinimumHorizontalSize() {
 452         Dimension minHorizDim = (Dimension)DefaultLookup.get(slider,
 453                 this, "Slider.minimumHorizontalSize");
 454         if (minHorizDim == null) {
 455             minHorizDim = new Dimension(36, 21);
 456         }
 457         return minHorizDim;
 458     }
 459 




 460     public Dimension getMinimumVerticalSize() {
 461         Dimension minVertDim = (Dimension)DefaultLookup.get(slider,
 462                 this, "Slider.minimumVerticalSize");
 463         if (minVertDim == null) {
 464             minVertDim = new Dimension(21, 36);
 465         }
 466         return minVertDim;
 467     }
 468 





 469     public Dimension getPreferredSize(JComponent c)    {
 470         recalculateIfInsetsChanged();
 471         Dimension d;
 472         if ( slider.getOrientation() == JSlider.VERTICAL ) {
 473             d = new Dimension(getPreferredVerticalSize());
 474             d.width = insetCache.left + insetCache.right;
 475             d.width += focusInsets.left + focusInsets.right;
 476             d.width += trackRect.width + tickRect.width + labelRect.width;
 477         }
 478         else {
 479             d = new Dimension(getPreferredHorizontalSize());
 480             d.height = insetCache.top + insetCache.bottom;
 481             d.height += focusInsets.top + focusInsets.bottom;
 482             d.height += trackRect.height + tickRect.height + labelRect.height;
 483         }
 484 
 485         return d;
 486     }
 487 





 488     public Dimension getMinimumSize(JComponent c)  {
 489         recalculateIfInsetsChanged();
 490         Dimension d;
 491 
 492         if ( slider.getOrientation() == JSlider.VERTICAL ) {
 493             d = new Dimension(getMinimumVerticalSize());
 494             d.width = insetCache.left + insetCache.right;
 495             d.width += focusInsets.left + focusInsets.right;
 496             d.width += trackRect.width + tickRect.width + labelRect.width;
 497         }
 498         else {
 499             d = new Dimension(getMinimumHorizontalSize());
 500             d.height = insetCache.top + insetCache.bottom;
 501             d.height += focusInsets.top + focusInsets.bottom;
 502             d.height += trackRect.height + tickRect.height + labelRect.height;
 503         }
 504 
 505         return d;
 506     }
 507 





 508     public Dimension getMaximumSize(JComponent c) {
 509         Dimension d = getPreferredSize(c);
 510         if ( slider.getOrientation() == JSlider.VERTICAL ) {
 511             d.height = Short.MAX_VALUE;
 512         }
 513         else {
 514             d.width = Short.MAX_VALUE;
 515         }
 516 
 517         return d;
 518     }
 519 



 520     protected void calculateGeometry() {
 521         calculateFocusRect();
 522         calculateContentRect();
 523         calculateThumbSize();
 524         calculateTrackBuffer();
 525         calculateTrackRect();
 526         calculateTickRect();
 527         calculateLabelRect();
 528         calculateThumbLocation();
 529     }
 530 



 531     protected void calculateFocusRect() {
 532         focusRect.x = insetCache.left;
 533         focusRect.y = insetCache.top;
 534         focusRect.width = slider.getWidth() - (insetCache.left + insetCache.right);
 535         focusRect.height = slider.getHeight() - (insetCache.top + insetCache.bottom);
 536     }
 537 



 538     protected void calculateThumbSize() {
 539         Dimension size = getThumbSize();
 540         thumbRect.setSize( size.width, size.height );
 541     }
 542 



 543     protected void calculateContentRect() {
 544         contentRect.x = focusRect.x + focusInsets.left;
 545         contentRect.y = focusRect.y + focusInsets.top;
 546         contentRect.width = focusRect.width - (focusInsets.left + focusInsets.right);
 547         contentRect.height = focusRect.height - (focusInsets.top + focusInsets.bottom);
 548     }
 549 
 550     private int getTickSpacing() {
 551         int majorTickSpacing = slider.getMajorTickSpacing();
 552         int minorTickSpacing = slider.getMinorTickSpacing();
 553 
 554         int result;
 555 
 556         if (minorTickSpacing > 0) {
 557             result = minorTickSpacing;
 558         } else if (majorTickSpacing > 0) {
 559             result = majorTickSpacing;
 560         } else {
 561             result = 0;
 562         }
 563 
 564         return result;
 565     }
 566 



 567     protected void calculateThumbLocation() {
 568         if ( slider.getSnapToTicks() ) {
 569             int sliderValue = slider.getValue();
 570             int snappedValue = sliderValue;
 571             int tickSpacing = getTickSpacing();
 572 
 573             if ( tickSpacing != 0 ) {
 574                 // If it's not on a tick, change the value
 575                 if ( (sliderValue - slider.getMinimum()) % tickSpacing != 0 ) {
 576                     float temp = (float)(sliderValue - slider.getMinimum()) / (float)tickSpacing;
 577                     int whichTick = Math.round( temp );
 578 
 579                     // This is the fix for the bug #6401380
 580                     if (temp - (int)temp == .5 && sliderValue < lastValue) {
 581                       whichTick --;
 582                     }
 583                     snappedValue = slider.getMinimum() + (whichTick * tickSpacing);
 584                 }
 585 
 586                 if( snappedValue != sliderValue ) {
 587                     slider.setValue( snappedValue );
 588                 }
 589             }
 590         }
 591 
 592         if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
 593             int valuePosition = xPositionForValue(slider.getValue());
 594 
 595             thumbRect.x = valuePosition - (thumbRect.width / 2);
 596             thumbRect.y = trackRect.y;
 597         }
 598         else {
 599             int valuePosition = yPositionForValue(slider.getValue());
 600 
 601             thumbRect.x = trackRect.x;
 602             thumbRect.y = valuePosition - (thumbRect.height / 2);
 603         }
 604     }
 605 



 606     protected void calculateTrackBuffer() {
 607         if ( slider.getPaintLabels() && slider.getLabelTable()  != null ) {
 608             Component highLabel = getHighestValueLabel();
 609             Component lowLabel = getLowestValueLabel();
 610 
 611             if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
 612                 trackBuffer = Math.max( highLabel.getBounds().width, lowLabel.getBounds().width ) / 2;
 613                 trackBuffer = Math.max( trackBuffer, thumbRect.width / 2 );
 614             }
 615             else {
 616                 trackBuffer = Math.max( highLabel.getBounds().height, lowLabel.getBounds().height ) / 2;
 617                 trackBuffer = Math.max( trackBuffer, thumbRect.height / 2 );
 618             }
 619         }
 620         else {
 621             if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
 622                 trackBuffer = thumbRect.width / 2;
 623             }
 624             else {
 625                 trackBuffer = thumbRect.height / 2;
 626             }
 627         }
 628     }
 629 
 630 


 631     protected void calculateTrackRect() {
 632         int centerSpacing; // used to center sliders added using BorderLayout.CENTER (bug 4275631)
 633         if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
 634             centerSpacing = thumbRect.height;
 635             if ( slider.getPaintTicks() ) centerSpacing += getTickLength();
 636             if ( slider.getPaintLabels() ) centerSpacing += getHeightOfTallestLabel();
 637             trackRect.x = contentRect.x + trackBuffer;
 638             trackRect.y = contentRect.y + (contentRect.height - centerSpacing - 1)/2;
 639             trackRect.width = contentRect.width - (trackBuffer * 2);
 640             trackRect.height = thumbRect.height;
 641         }
 642         else {
 643             centerSpacing = thumbRect.width;
 644             if (BasicGraphicsUtils.isLeftToRight(slider)) {
 645                 if ( slider.getPaintTicks() ) centerSpacing += getTickLength();
 646                 if ( slider.getPaintLabels() ) centerSpacing += getWidthOfWidestLabel();
 647             } else {
 648                 if ( slider.getPaintTicks() ) centerSpacing -= getTickLength();
 649                 if ( slider.getPaintLabels() ) centerSpacing -= getWidthOfWidestLabel();
 650             }


 654             trackRect.height = contentRect.height - (trackBuffer * 2);
 655         }
 656 
 657     }
 658 
 659     /**
 660      * Gets the height of the tick area for horizontal sliders and the width of
 661      * the tick area for vertical sliders. BasicSliderUI uses the returned value
 662      * to determine the tick area rectangle. If you want to give your ticks some
 663      * room, make this larger than you need and paint your ticks away from the
 664      * sides in paintTicks().
 665      *
 666      * @return an integer representing the height of the tick area for
 667      * horizontal sliders, and the width of the tick area for the vertical
 668      * sliders
 669      */
 670     protected int getTickLength() {
 671         return 8;
 672     }
 673 



 674     protected void calculateTickRect() {
 675         if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
 676             tickRect.x = trackRect.x;
 677             tickRect.y = trackRect.y + trackRect.height;
 678             tickRect.width = trackRect.width;
 679             tickRect.height = (slider.getPaintTicks()) ? getTickLength() : 0;
 680         }
 681         else {
 682             tickRect.width = (slider.getPaintTicks()) ? getTickLength() : 0;
 683             if(BasicGraphicsUtils.isLeftToRight(slider)) {
 684                 tickRect.x = trackRect.x + trackRect.width;
 685             }
 686             else {
 687                 tickRect.x = trackRect.x - tickRect.width;
 688             }
 689             tickRect.y = trackRect.y;
 690             tickRect.height = trackRect.height;
 691         }
 692     }
 693 



 694     protected void calculateLabelRect() {
 695         if ( slider.getPaintLabels() ) {
 696             if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
 697                 labelRect.x = tickRect.x - trackBuffer;
 698                 labelRect.y = tickRect.y + tickRect.height;
 699                 labelRect.width = tickRect.width + (trackBuffer * 2);
 700                 labelRect.height = getHeightOfTallestLabel();
 701             }
 702             else {
 703                 if(BasicGraphicsUtils.isLeftToRight(slider)) {
 704                     labelRect.x = tickRect.x + tickRect.width;
 705                     labelRect.width = getWidthOfWidestLabel();
 706                 }
 707                 else {
 708                     labelRect.width = getWidthOfWidestLabel();
 709                     labelRect.x = tickRect.x - labelRect.width;
 710                 }
 711                 labelRect.y = tickRect.y - trackBuffer;
 712                 labelRect.height = tickRect.height + (trackBuffer * 2);
 713             }


 716             if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
 717                 labelRect.x = tickRect.x;
 718                 labelRect.y = tickRect.y + tickRect.height;
 719                 labelRect.width = tickRect.width;
 720                 labelRect.height = 0;
 721             }
 722             else {
 723                 if(BasicGraphicsUtils.isLeftToRight(slider)) {
 724                     labelRect.x = tickRect.x + tickRect.width;
 725                 }
 726                 else {
 727                     labelRect.x = tickRect.x;
 728                 }
 729                 labelRect.y = tickRect.y;
 730                 labelRect.width = 0;
 731                 labelRect.height = tickRect.height;
 732             }
 733         }
 734     }
 735 




 736     protected Dimension getThumbSize() {
 737         Dimension size = new Dimension();
 738 
 739         if ( slider.getOrientation() == JSlider.VERTICAL ) {
 740             size.width = 20;
 741             size.height = 11;
 742         }
 743         else {
 744             size.width = 11;
 745             size.height = 20;
 746         }
 747 
 748         return size;
 749     }
 750 



 751     public class PropertyChangeHandler implements PropertyChangeListener {
 752         // NOTE: This class exists only for backward compatibility. All
 753         // its functionality has been moved into Handler. If you need to add
 754         // new functionality add it to the Handler, but make sure this
 755         // class calls into the Handler.

 756         public void propertyChange( PropertyChangeEvent e ) {
 757             getHandler().propertyChange(e);
 758         }
 759     }
 760 




 761     protected int getWidthOfWidestLabel() {
 762         @SuppressWarnings("rawtypes")
 763         Dictionary dictionary = slider.getLabelTable();
 764         int widest = 0;
 765         if ( dictionary != null ) {
 766             Enumeration<?> keys = dictionary.keys();
 767             while ( keys.hasMoreElements() ) {
 768                 JComponent label = (JComponent) dictionary.get(keys.nextElement());
 769                 widest = Math.max( label.getPreferredSize().width, widest );
 770             }
 771         }
 772         return widest;
 773     }
 774 




 775     protected int getHeightOfTallestLabel() {
 776         @SuppressWarnings("rawtypes")
 777         Dictionary dictionary = slider.getLabelTable();
 778         int tallest = 0;
 779         if ( dictionary != null ) {
 780             Enumeration<?> keys = dictionary.keys();
 781             while ( keys.hasMoreElements() ) {
 782                 JComponent label = (JComponent) dictionary.get(keys.nextElement());
 783                 tallest = Math.max( label.getPreferredSize().height, tallest );
 784             }
 785         }
 786         return tallest;
 787     }
 788 




 789     protected int getWidthOfHighValueLabel() {
 790         Component label = getHighestValueLabel();
 791         int width = 0;
 792 
 793         if ( label != null ) {
 794             width = label.getPreferredSize().width;
 795         }
 796 
 797         return width;
 798     }
 799 




 800     protected int getWidthOfLowValueLabel() {
 801         Component label = getLowestValueLabel();
 802         int width = 0;
 803 
 804         if ( label != null ) {
 805             width = label.getPreferredSize().width;
 806         }
 807 
 808         return width;
 809     }
 810 




 811     protected int getHeightOfHighValueLabel() {
 812         Component label = getHighestValueLabel();
 813         int height = 0;
 814 
 815         if ( label != null ) {
 816             height = label.getPreferredSize().height;
 817         }
 818 
 819         return height;
 820     }
 821 




 822     protected int getHeightOfLowValueLabel() {
 823         Component label = getLowestValueLabel();
 824         int height = 0;
 825 
 826         if ( label != null ) {
 827             height = label.getPreferredSize().height;
 828         }
 829 
 830         return height;
 831     }
 832 




 833     protected boolean drawInverted() {
 834         if (slider.getOrientation()==JSlider.HORIZONTAL) {
 835             if(BasicGraphicsUtils.isLeftToRight(slider)) {
 836                 return slider.getInverted();
 837             } else {
 838                 return !slider.getInverted();
 839             }
 840         } else {
 841             return slider.getInverted();
 842         }
 843     }
 844 
 845     /**
 846      * Returns the biggest value that has an entry in the label table.
 847      *
 848      * @return biggest value that has an entry in the label table, or
 849      *         null.
 850      * @since 1.6
 851      */
 852     protected Integer getHighestValue() {


 943         if ( !clip.intersects(trackRect) && slider.getPaintTrack())
 944             calculateGeometry();
 945 
 946         if ( slider.getPaintTrack() && clip.intersects( trackRect ) ) {
 947             paintTrack( g );
 948         }
 949         if ( slider.getPaintTicks() && clip.intersects( tickRect ) ) {
 950             paintTicks( g );
 951         }
 952         if ( slider.getPaintLabels() && clip.intersects( labelRect ) ) {
 953             paintLabels( g );
 954         }
 955         if ( slider.hasFocus() && clip.intersects( focusRect ) ) {
 956             paintFocus( g );
 957         }
 958         if ( clip.intersects( thumbRect ) ) {
 959             paintThumb( g );
 960         }
 961     }
 962 



 963     protected void recalculateIfInsetsChanged() {
 964         Insets newInsets = slider.getInsets();
 965         if ( !newInsets.equals( insetCache ) ) {
 966             insetCache = newInsets;
 967             calculateGeometry();
 968         }
 969     }
 970 



 971     protected void recalculateIfOrientationChanged() {
 972         boolean ltr = BasicGraphicsUtils.isLeftToRight(slider);
 973         if ( ltr!=leftToRightCache ) {
 974             leftToRightCache = ltr;
 975             calculateGeometry();
 976         }
 977     }
 978 




 979     public void paintFocus(Graphics g)  {
 980         g.setColor( getFocusColor() );
 981 
 982         BasicGraphicsUtils.drawDashedRect( g, focusRect.x, focusRect.y,
 983                                            focusRect.width, focusRect.height );
 984     }
 985 




 986     public void paintTrack(Graphics g)  {
 987 
 988         Rectangle trackBounds = trackRect;
 989 
 990         if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
 991             int cy = (trackBounds.height / 2) - 2;
 992             int cw = trackBounds.width;
 993 
 994             g.translate(trackBounds.x, trackBounds.y + cy);
 995 
 996             g.setColor(getShadowColor());
 997             g.drawLine(0, 0, cw - 1, 0);
 998             g.drawLine(0, 1, 0, 2);
 999             g.setColor(getHighlightColor());
1000             g.drawLine(0, 3, cw, 3);
1001             g.drawLine(cw, 0, cw, 3);
1002             g.setColor(Color.black);
1003             g.drawLine(1, 1, cw-2, 1);
1004 
1005             g.translate(-trackBounds.x, -(trackBounds.y + cy));
1006         }
1007         else {
1008             int cx = (trackBounds.width / 2) - 2;
1009             int ch = trackBounds.height;
1010 
1011             g.translate(trackBounds.x + cx, trackBounds.y);
1012 
1013             g.setColor(getShadowColor());
1014             g.drawLine(0, 0, 0, ch - 1);
1015             g.drawLine(1, 0, 2, 0);
1016             g.setColor(getHighlightColor());
1017             g.drawLine(3, 0, 3, ch);
1018             g.drawLine(0, ch, 3, ch);
1019             g.setColor(Color.black);
1020             g.drawLine(1, 1, 1, ch-2);
1021 
1022             g.translate(-(trackBounds.x + cx), -trackBounds.y);
1023         }
1024     }
1025 




1026     public void paintTicks(Graphics g)  {
1027         Rectangle tickBounds = tickRect;
1028 
1029         g.setColor(DefaultLookup.getColor(slider, this, "Slider.tickColor", Color.black));
1030 
1031         if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
1032             g.translate(0, tickBounds.y);
1033 
1034             if (slider.getMinorTickSpacing() > 0) {
1035                 int value = slider.getMinimum();
1036 
1037                 while ( value <= slider.getMaximum() ) {
1038                     int xPos = xPositionForValue(value);
1039                     paintMinorTickForHorizSlider( g, tickBounds, xPos );
1040 
1041                     // Overflow checking
1042                     if (Integer.MAX_VALUE - slider.getMinorTickSpacing() < value) {
1043                         break;
1044                     }
1045 


1103                 while (value <= slider.getMaximum()) {
1104                     int yPos = yPositionForValue(value);
1105                     paintMajorTickForVertSlider( g, tickBounds, yPos );
1106 
1107                     // Overflow checking
1108                     if (Integer.MAX_VALUE - slider.getMajorTickSpacing() < value) {
1109                         break;
1110                     }
1111 
1112                     value += slider.getMajorTickSpacing();
1113                 }
1114 
1115                 if(!BasicGraphicsUtils.isLeftToRight(slider)) {
1116                     g.translate(-2, 0);
1117                 }
1118             }
1119             g.translate(-tickBounds.x, 0);
1120         }
1121     }
1122 






1123     protected void paintMinorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) {
1124         g.drawLine( x, 0, x, tickBounds.height / 2 - 1 );
1125     }
1126 






1127     protected void paintMajorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) {
1128         g.drawLine( x, 0, x, tickBounds.height - 2 );
1129     }
1130 






1131     protected void paintMinorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) {
1132         g.drawLine( 0, y, tickBounds.width / 2 - 1, y );
1133     }
1134 






1135     protected void paintMajorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) {
1136         g.drawLine( 0, y,  tickBounds.width - 2, y );
1137     }
1138 




1139     public void paintLabels( Graphics g ) {
1140         Rectangle labelBounds = labelRect;
1141 
1142         @SuppressWarnings("rawtypes")
1143         Dictionary dictionary = slider.getLabelTable();
1144         if ( dictionary != null ) {
1145             Enumeration<?> keys = dictionary.keys();
1146             int minValue = slider.getMinimum();
1147             int maxValue = slider.getMaximum();
1148             boolean enabled = slider.isEnabled();
1149             while ( keys.hasMoreElements() ) {
1150                 Integer key = (Integer)keys.nextElement();
1151                 int value = key.intValue();
1152                 if (value >= minValue && value <= maxValue) {
1153                     JComponent label = (JComponent) dictionary.get(key);
1154                     label.setEnabled(enabled);
1155 
1156                     if (label instanceof JLabel) {
1157                         Icon icon = label.isEnabled() ? ((JLabel) label).getIcon() : ((JLabel) label).getDisabledIcon();
1158 


1205 
1206     /**
1207      * Called for every label in the label table. Used to draw the labels for
1208      * vertical sliders. The graphics have been translated to labelRect.x
1209      * already.
1210      *
1211      * @param g the graphics context in which to paint
1212      * @param value the value of the slider
1213      * @param label the component label in the label table that needs to be
1214      * painted
1215      * @see JSlider#setLabelTable
1216      */
1217     protected void paintVerticalLabel( Graphics g, int value, Component label ) {
1218         int labelCenter = yPositionForValue( value );
1219         int labelTop = labelCenter - (label.getPreferredSize().height / 2);
1220         g.translate( 0, labelTop );
1221         label.paint( g );
1222         g.translate( 0, -labelTop );
1223     }
1224 




1225     public void paintThumb(Graphics g)  {
1226         Rectangle knobBounds = thumbRect;
1227         int w = knobBounds.width;
1228         int h = knobBounds.height;
1229 
1230         g.translate(knobBounds.x, knobBounds.y);
1231 
1232         if ( slider.isEnabled() ) {
1233             g.setColor(slider.getBackground());
1234         }
1235         else {
1236             g.setColor(slider.getBackground().darker());
1237         }
1238 
1239         Boolean paintThumbArrowShape =
1240             (Boolean)slider.getClientProperty("Slider.paintThumbArrowShape");
1241 
1242         if ((!slider.getPaintTicks() && paintThumbArrowShape == null) ||
1243             paintThumbArrowShape == Boolean.FALSE) {
1244 


1313                   g.setColor(highlightColor);
1314                   g.drawLine(cw-1, 0, w-2, 0);             // top
1315                   g.drawLine(0, cw, cw, 0);                // top slant
1316 
1317                   g.setColor(Color.black);
1318                   g.drawLine(0, h-1-cw, cw, h-1 );         // bottom slant
1319                   g.drawLine(cw, h-1, w-1, h-1);           // bottom
1320 
1321                   g.setColor(shadowColor);
1322                   g.drawLine(cw, h-2, w-2,  h-2 );         // bottom
1323                   g.drawLine(w-1, 1, w-1,  h-2 );          // right
1324             }
1325         }
1326 
1327         g.translate(-knobBounds.x, -knobBounds.y);
1328     }
1329 
1330     // Used exclusively by setThumbLocation()
1331     private static Rectangle unionRect = new Rectangle();
1332 





1333     public void setThumbLocation(int x, int y)  {
1334         unionRect.setBounds( thumbRect );
1335 
1336         thumbRect.setLocation( x, y );
1337 
1338         SwingUtilities.computeUnion( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height, unionRect );
1339         slider.repaint( unionRect.x, unionRect.y, unionRect.width, unionRect.height );
1340     }
1341 




1342     public void scrollByBlock(int direction)    {
1343         synchronized(slider)    {
1344             int blockIncrement =
1345                 (slider.getMaximum() - slider.getMinimum()) / 10;
1346             if (blockIncrement == 0) {
1347                 blockIncrement = 1;
1348             }
1349 
1350             if (slider.getSnapToTicks()) {
1351                 int tickSpacing = getTickSpacing();
1352 
1353                 if (blockIncrement < tickSpacing) {
1354                     blockIncrement = tickSpacing;
1355                 }
1356             }
1357 
1358             int delta = blockIncrement * ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL);
1359             slider.setValue(slider.getValue() + delta);
1360         }
1361     }
1362 




1363     public void scrollByUnit(int direction) {
1364         synchronized(slider)    {
1365             int delta = ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL);
1366 
1367             if (slider.getSnapToTicks()) {
1368                 delta *= getTickSpacing();
1369             }
1370 
1371             slider.setValue(slider.getValue() + delta);
1372         }
1373     }
1374 
1375     /**
1376      * This function is called when a mousePressed was detected in the track,
1377      * not in the thumb. The default behavior is to scroll by block. You can
1378      * override this method to stop it from scrolling or to add additional
1379      * behavior.
1380      *
1381      * @param dir the direction and number of blocks to scroll
1382      */
1383     protected void scrollDueToClickInTrack( int dir ) {
1384         scrollByBlock( dir );
1385     }
1386 





1387     protected int xPositionForValue( int value )    {
1388         int min = slider.getMinimum();
1389         int max = slider.getMaximum();
1390         int trackLength = trackRect.width;
1391         double valueRange = (double)max - (double)min;
1392         double pixelsPerValue = (double)trackLength / valueRange;
1393         int trackLeft = trackRect.x;
1394         int trackRight = trackRect.x + (trackRect.width - 1);
1395         int xPosition;
1396 
1397         if ( !drawInverted() ) {
1398             xPosition = trackLeft;
1399             xPosition += Math.round( pixelsPerValue * ((double)value - min) );
1400         }
1401         else {
1402             xPosition = trackRight;
1403             xPosition -= Math.round( pixelsPerValue * ((double)value - min) );
1404         }
1405 
1406         xPosition = Math.max( trackLeft, xPosition );
1407         xPosition = Math.min( trackRight, xPosition );
1408 
1409         return xPosition;
1410     }
1411 





1412     protected int yPositionForValue( int value )  {
1413         return yPositionForValue(value, trackRect.y, trackRect.height);
1414     }
1415 
1416     /**
1417      * Returns the y location for the specified value.  No checking is
1418      * done on the arguments.  In particular if <code>trackHeight</code> is
1419      * negative undefined results may occur.
1420      *
1421      * @param value the slider value to get the location for
1422      * @param trackY y-origin of the track
1423      * @param trackHeight the height of the track
1424      * @return the y location for the specified value of the slider
1425      * @since 1.6
1426      */
1427     protected int yPositionForValue(int value, int trackY, int trackHeight) {
1428         int min = slider.getMinimum();
1429         int max = slider.getMaximum();
1430         double valueRange = (double)max - (double)min;
1431         double pixelsPerValue = (double)trackHeight / valueRange;


1588     public class ChangeHandler implements ChangeListener {
1589         // NOTE: This class exists only for backward compatibility. All
1590         // its functionality has been moved into Handler. If you need to add
1591         // new functionality add it to the Handler, but make sure this
1592         // class calls into the Handler.
1593         public void stateChanged(ChangeEvent e) {
1594             getHandler().stateChanged(e);
1595         }
1596     }
1597 
1598     /////////////////////////////////////////////////////////////////////////
1599     /// Track Listener Class
1600     /////////////////////////////////////////////////////////////////////////
1601     /**
1602      * Track mouse movements.
1603      *
1604      * This class should be treated as a &quot;protected&quot; inner class.
1605      * Instantiate it only within subclasses of <code>Foo</code>.
1606      */
1607     public class TrackListener extends MouseInputAdapter {

1608         protected transient int offset;
1609         protected transient int currentMouseX, currentMouseY;



1610 



1611         public void mouseReleased(MouseEvent e) {
1612             if (!slider.isEnabled()) {
1613                 return;
1614             }
1615 
1616             offset = 0;
1617             scrollTimer.stop();
1618 
1619             isDragging = false;
1620             slider.setValueIsAdjusting(false);
1621             slider.repaint();
1622         }
1623 
1624         /**
1625         * If the mouse is pressed above the "thumb" component
1626         * then reduce the scrollbars value by one page ("page up"),
1627         * otherwise increase it by one page.  If there is no
1628         * thumb then page up if the mouse is in the upper half
1629         * of the track.
1630         */


1719                             NEGATIVE_SCROLL : POSITIVE_SCROLL;
1720                     }
1721                     else {
1722                         direction = (currentMouseX < thumbX) ?
1723                             POSITIVE_SCROLL : NEGATIVE_SCROLL;
1724                     }
1725                 }
1726                 break;
1727             }
1728 
1729             if (shouldScroll(direction)) {
1730                 scrollDueToClickInTrack(direction);
1731             }
1732             if (shouldScroll(direction)) {
1733                 scrollTimer.stop();
1734                 scrollListener.setDirection(direction);
1735                 scrollTimer.start();
1736             }
1737         }
1738 





1739         public boolean shouldScroll(int direction) {
1740             Rectangle r = thumbRect;
1741             if (slider.getOrientation() == JSlider.VERTICAL) {
1742                 if (drawInverted() ? direction < 0 : direction > 0) {
1743                     if (r.y  <= currentMouseY) {
1744                         return false;
1745                     }
1746                 }
1747                 else if (r.y + r.height >= currentMouseY) {
1748                     return false;
1749                 }
1750             }
1751             else {
1752                 if (drawInverted() ? direction < 0 : direction > 0) {
1753                     if (r.x + r.width  >= currentMouseX) {
1754                         return false;
1755                     }
1756                 }
1757                 else if (r.x <= currentMouseX) {
1758                     return false;


1822                 int hMax = xPositionForValue(slider.getMaximum() -
1823                                             slider.getExtent());
1824 
1825                 if (drawInverted()) {
1826                     trackLeft = hMax;
1827                 }
1828                 else {
1829                     trackRight = hMax;
1830                 }
1831                 thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth);
1832                 thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth);
1833 
1834                 setThumbLocation(thumbLeft, thumbRect.y);
1835 
1836                 thumbMiddle = thumbLeft + halfThumbWidth;
1837                 slider.setValue(valueForXPosition(thumbMiddle));
1838                 break;
1839             }
1840         }
1841 

1842         public void mouseMoved(MouseEvent e) { }
1843     }
1844 
1845     /**
1846      * Scroll-event listener.
1847      *
1848      * This class should be treated as a &quot;protected&quot; inner class.
1849      * Instantiate it only within subclasses of <code>Foo</code>.
1850      */
1851     public class ScrollListener implements ActionListener {
1852         // changed this class to public to avoid bogus IllegalAccessException
1853         // bug in InternetExplorer browser.  It was protected.  Work around
1854         // for 4109432
1855         int direction = POSITIVE_SCROLL;
1856         boolean useBlockIncrement;
1857 



1858         public ScrollListener() {
1859             direction = POSITIVE_SCROLL;
1860             useBlockIncrement = true;
1861         }
1862 





1863         public ScrollListener(int dir, boolean block)   {
1864             direction = dir;
1865             useBlockIncrement = block;
1866         }
1867 




1868         public void setDirection(int direction) {
1869             this.direction = direction;
1870         }
1871 




1872         public void setScrollByBlock(boolean block) {
1873             this.useBlockIncrement = block;
1874         }
1875 

1876         public void actionPerformed(ActionEvent e) {
1877             if (useBlockIncrement) {
1878                 scrollByBlock(direction);
1879             }
1880             else {
1881                 scrollByUnit(direction);
1882             }
1883             if (!trackListener.shouldScroll(direction)) {
1884                 ((Timer)e.getSource()).stop();
1885             }
1886         }
1887     }
1888 
1889     /**
1890      * Listener for resizing events.
1891      * <p>
1892      * This class should be treated as a &quot;protected&quot; inner class.
1893      * Instantiate it only within subclasses of <code>Foo</code>.
1894      */
1895     public class ComponentHandler extends ComponentAdapter {


1928      * combination of an <code>ActionMap</code>, to contain the action,
1929      * and an <code>InputMap</code> to contain the mapping from KeyStroke
1930      * to action description. The InputMap is usually described in the
1931      * LookAndFeel tables.
1932      * <p>
1933      * Please refer to the key bindings specification for further details.
1934      * <p>
1935      * This class should be treated as a &quot;protected&quot; inner class.
1936      * Instantiate it only within subclasses of <code>Foo</code>.
1937      */
1938     @SuppressWarnings("serial") // Superclass is not serializable across versions
1939     public class ActionScroller extends AbstractAction {
1940         // NOTE: This class exists only for backward compatibility. All
1941         // its functionality has been moved into Actions. If you need to add
1942         // new functionality add it to the Actions, but make sure this
1943         // class calls into the Actions.
1944         int dir;
1945         boolean block;
1946         JSlider slider;
1947 






1948         public ActionScroller( JSlider slider, int dir, boolean block) {
1949             this.dir = dir;
1950             this.block = block;
1951             this.slider = slider;
1952         }
1953 

1954         public void actionPerformed(ActionEvent e) {
1955             SHARED_ACTION.scroll(slider, BasicSliderUI.this, dir, block);
1956         }
1957 

1958         public boolean isEnabled() {
1959             boolean b = true;
1960             if (slider != null) {
1961                 b = slider.isEnabled();
1962             }
1963             return b;
1964         }
1965 
1966     }
1967 
1968 
1969     /**
1970      * A static version of the above.
1971      */
1972     @SuppressWarnings("serial") // Superclass is not serializable across versions
1973     static class SharedActionScroller extends AbstractAction {
1974         // NOTE: This class exists only for backward compatibility. All
1975         // its functionality has been moved into Actions. If you need to add
1976         // new functionality add it to the Actions, but make sure this
1977         // class calls into the Actions.


   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


  30 import java.beans.*;
  31 import java.util.Dictionary;
  32 import java.util.Enumeration;
  33 
  34 import javax.swing.*;
  35 import javax.swing.event.*;
  36 import javax.swing.plaf.*;
  37 import sun.swing.DefaultLookup;
  38 import sun.swing.UIAction;
  39 
  40 
  41 /**
  42  * A Basic L&amp;F implementation of SliderUI.
  43  *
  44  * @author Tom Santos
  45  */
  46 public class BasicSliderUI extends SliderUI{
  47     // Old actions forward to an instance of this.
  48     private static final Actions SHARED_ACTION = new Actions();
  49 
  50     /** Positive scroll */
  51     public static final int POSITIVE_SCROLL = +1;
  52     /** Negative scroll */
  53     public static final int NEGATIVE_SCROLL = -1;
  54     /** Minimum scroll */
  55     public static final int MIN_SCROLL = -2;
  56     /** Maximum scroll */
  57     public static final int MAX_SCROLL = +2;
  58 
  59     /** Scroll timer */
  60     protected Timer scrollTimer;
  61     /** Slider */
  62     protected JSlider slider;
  63 
  64     /** Focus insets */
  65     protected Insets focusInsets = null;
  66     /** Inset cache */
  67     protected Insets insetCache = null;
  68     /** Left-to-right cache */
  69     protected boolean leftToRightCache = true;
  70     /** Focus rectangle */
  71     protected Rectangle focusRect = null;
  72     /** Content rectangle */
  73     protected Rectangle contentRect = null;
  74     /** Label rectangle */
  75     protected Rectangle labelRect = null;
  76     /** Tick rectangle */
  77     protected Rectangle tickRect = null;
  78     /** Track rectangle */
  79     protected Rectangle trackRect = null;
  80     /** Thumb rectangle */
  81     protected Rectangle thumbRect = null;
  82 
  83     /** The distance that the track is from the side of the control */
  84     protected int trackBuffer = 0;
  85 
  86     private transient boolean isDragging;
  87 
  88     /** Track listener */
  89     protected TrackListener trackListener;
  90     /** Change listener */
  91     protected ChangeListener changeListener;
  92     /** Component listener */
  93     protected ComponentListener componentListener;
  94     /** Focus listener */
  95     protected FocusListener focusListener;
  96     /** Scroll listener */
  97     protected ScrollListener scrollListener;
  98     /** Property chane listener */
  99     protected PropertyChangeListener propertyChangeListener;
 100     private Handler handler;
 101     private int lastValue;
 102 
 103     // Colors
 104     private Color shadowColor;
 105     private Color highlightColor;
 106     private Color focusColor;
 107 
 108     /**
 109      * Whther or not sameLabelBaselines is up to date.
 110      */
 111     private boolean checkedLabelBaselines;
 112     /**
 113      * Whether or not all the entries in the labeltable have the same
 114      * baseline.
 115      */
 116     private boolean sameLabelBaselines;
 117 
 118     /**
 119      * Returns the shadow color.
 120      * @return the shadow color
 121      */
 122     protected Color getShadowColor() {
 123         return shadowColor;
 124     }
 125 
 126     /**
 127      * Returns the highlight color.
 128      * @return the highlight color
 129      */
 130     protected Color getHighlightColor() {
 131         return highlightColor;
 132     }
 133 
 134     /**
 135      * Returns the focus color.
 136      * @return the focus color
 137      */
 138     protected Color getFocusColor() {
 139         return focusColor;
 140     }
 141 
 142     /**
 143      * Returns true if the user is dragging the slider.
 144      *
 145      * @return true if the user is dragging the slider
 146      * @since 1.5
 147      */
 148     protected boolean isDragging() {
 149         return isDragging;
 150     }
 151 
 152     /////////////////////////////////////////////////////////////////////////////
 153     // ComponentUI Interface Implementation methods
 154     /////////////////////////////////////////////////////////////////////////////
 155     /**
 156      * Creates a UI.
 157      * @param b a component
 158      * @return a UI
 159      */
 160     public static ComponentUI createUI(JComponent b)    {
 161         return new BasicSliderUI((JSlider)b);
 162     }
 163 
 164     /**
 165      * Constructs a {@code BasicSliderUI}.
 166      * @param b a slider
 167      */
 168     public BasicSliderUI(JSlider b)   {
 169     }
 170 
 171     /**
 172      * Installs a UI.
 173      * @param c a component
 174      */
 175     public void installUI(JComponent c)   {
 176         slider = (JSlider) c;
 177 
 178         checkedLabelBaselines = false;
 179 
 180         slider.setEnabled(slider.isEnabled());
 181         LookAndFeel.installProperty(slider, "opaque", Boolean.TRUE);
 182 
 183         isDragging = false;
 184         trackListener = createTrackListener( slider );
 185         changeListener = createChangeListener( slider );
 186         componentListener = createComponentListener( slider );
 187         focusListener = createFocusListener( slider );
 188         scrollListener = createScrollListener( slider );
 189         propertyChangeListener = createPropertyChangeListener( slider );
 190 
 191         installDefaults( slider );
 192         installListeners( slider );
 193         installKeyboardActions( slider );
 194 
 195         scrollTimer = new Timer( 100, scrollListener );
 196         scrollTimer.setInitialDelay( 300 );
 197 
 198         insetCache = slider.getInsets();
 199         leftToRightCache = BasicGraphicsUtils.isLeftToRight(slider);
 200         focusRect = new Rectangle();
 201         contentRect = new Rectangle();
 202         labelRect = new Rectangle();
 203         tickRect = new Rectangle();
 204         trackRect = new Rectangle();
 205         thumbRect = new Rectangle();
 206         lastValue = slider.getValue();
 207 
 208         calculateGeometry(); // This figures out where the labels, ticks, track, and thumb are.
 209     }
 210 
 211     /**
 212      * Uninstalls a UI.
 213      * @param c a component
 214      */
 215     public void uninstallUI(JComponent c) {
 216         if ( c != slider )
 217             throw new IllegalComponentStateException(
 218                                                     this + " was asked to deinstall() "
 219                                                     + c + " when it only knows about "
 220                                                     + slider + ".");
 221 
 222         scrollTimer.stop();
 223         scrollTimer = null;
 224 
 225         uninstallDefaults(slider);
 226         uninstallListeners( slider );
 227         uninstallKeyboardActions(slider);
 228 
 229         insetCache = null;
 230         leftToRightCache = true;
 231         focusRect = null;
 232         contentRect = null;
 233         labelRect = null;
 234         tickRect = null;
 235         trackRect = null;
 236         thumbRect = null;
 237         trackListener = null;
 238         changeListener = null;
 239         componentListener = null;
 240         focusListener = null;
 241         scrollListener = null;
 242         propertyChangeListener = null;
 243         slider = null;
 244     }
 245 
 246     /**
 247      * Installs the defaults.
 248      * @param slider a slider
 249      */
 250     protected void installDefaults( JSlider slider ) {
 251         LookAndFeel.installBorder(slider, "Slider.border");
 252         LookAndFeel.installColorsAndFont(slider, "Slider.background",
 253                                          "Slider.foreground", "Slider.font");
 254         highlightColor = UIManager.getColor("Slider.highlight");
 255 
 256         shadowColor = UIManager.getColor("Slider.shadow");
 257         focusColor = UIManager.getColor("Slider.focus");
 258 
 259         focusInsets = (Insets)UIManager.get( "Slider.focusInsets" );
 260         // use default if missing so that BasicSliderUI can be used in other
 261         // LAFs like Nimbus
 262         if (focusInsets == null) focusInsets = new InsetsUIResource(2,2,2,2);
 263     }
 264 
 265     /**
 266      * Uninstalls the defaults.
 267      * @param slider a slider
 268      */
 269     protected void uninstallDefaults(JSlider slider) {
 270         LookAndFeel.uninstallBorder(slider);
 271 
 272         focusInsets = null;
 273     }
 274 
 275     /**
 276      * Creates a track listener.
 277      * @return a track listener
 278      * @param slider a slider
 279      */
 280     protected TrackListener createTrackListener(JSlider slider) {
 281         return new TrackListener();
 282     }
 283 
 284     /**
 285      * Creates a change listener.
 286      * @return a change listener
 287      * @param slider a slider
 288      */
 289     protected ChangeListener createChangeListener(JSlider slider) {
 290         return getHandler();
 291     }
 292 
 293     /**
 294      * Creates a composite listener.
 295      * @return a composite listener
 296      * @param slider a slider
 297      */
 298     protected ComponentListener createComponentListener(JSlider slider) {
 299         return getHandler();
 300     }
 301 
 302     /**
 303      * Creates a focus listener.
 304      * @return a focus listener
 305      * @param slider a slider
 306      */
 307     protected FocusListener createFocusListener(JSlider slider) {
 308         return getHandler();
 309     }
 310 
 311     /**
 312      * Creates a scroll listener.
 313      * @return a scroll listener
 314      * @param slider a slider
 315      */
 316     protected ScrollListener createScrollListener( JSlider slider ) {
 317         return new ScrollListener();
 318     }
 319 
 320     /**
 321      * Creates a property change listener.
 322      * @return a property change listener
 323      * @param slider a slider
 324      */
 325     protected PropertyChangeListener createPropertyChangeListener(
 326             JSlider slider) {
 327         return getHandler();
 328     }
 329 
 330     private Handler getHandler() {
 331         if (handler == null) {
 332             handler = new Handler();
 333         }
 334         return handler;
 335     }
 336 
 337     /**
 338      * Installs listeners.
 339      * @param slider a slider
 340      */
 341     protected void installListeners( JSlider slider ) {
 342         slider.addMouseListener(trackListener);
 343         slider.addMouseMotionListener(trackListener);
 344         slider.addFocusListener(focusListener);
 345         slider.addComponentListener(componentListener);
 346         slider.addPropertyChangeListener( propertyChangeListener );
 347         slider.getModel().addChangeListener(changeListener);
 348     }
 349 
 350     /**
 351      * Uninstalls listeners.
 352      * @param slider a slider
 353      */
 354     protected void uninstallListeners( JSlider slider ) {
 355         slider.removeMouseListener(trackListener);
 356         slider.removeMouseMotionListener(trackListener);
 357         slider.removeFocusListener(focusListener);
 358         slider.removeComponentListener(componentListener);
 359         slider.removePropertyChangeListener( propertyChangeListener );
 360         slider.getModel().removeChangeListener(changeListener);
 361         handler = null;
 362     }
 363 
 364     /**
 365      * Installs keyboard actions.
 366      * @param slider a slider
 367      */
 368     protected void installKeyboardActions( JSlider slider ) {
 369         InputMap km = getInputMap(JComponent.WHEN_FOCUSED, slider);
 370         SwingUtilities.replaceUIInputMap(slider, JComponent.WHEN_FOCUSED, km);
 371         LazyActionMap.installLazyActionMap(slider, BasicSliderUI.class,
 372                 "Slider.actionMap");
 373     }
 374 
 375     InputMap getInputMap(int condition, JSlider slider) {
 376         if (condition == JComponent.WHEN_FOCUSED) {
 377             InputMap keyMap = (InputMap)DefaultLookup.get(slider, this,
 378                   "Slider.focusInputMap");
 379             InputMap rtlKeyMap;
 380 
 381             if (slider.getComponentOrientation().isLeftToRight() ||
 382                 ((rtlKeyMap = (InputMap)DefaultLookup.get(slider, this,
 383                           "Slider.focusInputMap.RightToLeft")) == null)) {
 384                 return keyMap;
 385             } else {
 386                 rtlKeyMap.setParent(keyMap);
 387                 return rtlKeyMap;
 388             }
 389         }
 390         return null;
 391     }
 392 
 393     /**
 394      * Populates ComboBox's actions.
 395      */
 396     static void loadActionMap(LazyActionMap map) {
 397         map.put(new Actions(Actions.POSITIVE_UNIT_INCREMENT));
 398         map.put(new Actions(Actions.POSITIVE_BLOCK_INCREMENT));
 399         map.put(new Actions(Actions.NEGATIVE_UNIT_INCREMENT));
 400         map.put(new Actions(Actions.NEGATIVE_BLOCK_INCREMENT));
 401         map.put(new Actions(Actions.MIN_SCROLL_INCREMENT));
 402         map.put(new Actions(Actions.MAX_SCROLL_INCREMENT));
 403     }
 404 
 405     /**
 406      * Uninstalls keyboard actions.
 407      * @param slider a slider
 408      */
 409     protected void uninstallKeyboardActions( JSlider slider ) {
 410         SwingUtilities.replaceUIActionMap(slider, null);
 411         SwingUtilities.replaceUIInputMap(slider, JComponent.WHEN_FOCUSED,
 412                                          null);
 413     }
 414 
 415 
 416     /**
 417      * Returns the baseline.
 418      *
 419      * @throws NullPointerException {@inheritDoc}
 420      * @throws IllegalArgumentException {@inheritDoc}
 421      * @see javax.swing.JComponent#getBaseline(int, int)
 422      * @since 1.6
 423      */
 424     public int getBaseline(JComponent c, int width, int height) {
 425         super.getBaseline(c, width, height);
 426         if (slider.getPaintLabels() && labelsHaveSameBaselines()) {
 427             FontMetrics metrics = slider.getFontMetrics(slider.getFont());
 428             Insets insets = slider.getInsets();


 517                             baseline = labelBaseline;
 518                         }
 519                         else if (baseline != labelBaseline) {
 520                             sameLabelBaselines = false;
 521                             break;
 522                         }
 523                     }
 524                     else {
 525                         sameLabelBaselines = false;
 526                         break;
 527                     }
 528                 }
 529             }
 530             else {
 531                 sameLabelBaselines = false;
 532             }
 533         }
 534         return sameLabelBaselines;
 535     }
 536 
 537     /**
 538      * Returns the preferred horizontal size.
 539      * @return the preferred horizontal size
 540      */
 541     public Dimension getPreferredHorizontalSize() {
 542         Dimension horizDim = (Dimension)DefaultLookup.get(slider,
 543                 this, "Slider.horizontalSize");
 544         if (horizDim == null) {
 545             horizDim = new Dimension(200, 21);
 546         }
 547         return horizDim;
 548     }
 549 
 550     /**
 551      * Returns the preferred vertical size.
 552      * @return the preferred vertical size
 553      */
 554     public Dimension getPreferredVerticalSize() {
 555         Dimension vertDim = (Dimension)DefaultLookup.get(slider,
 556                 this, "Slider.verticalSize");
 557         if (vertDim == null) {
 558             vertDim = new Dimension(21, 200);
 559         }
 560         return vertDim;
 561     }
 562 
 563     /**
 564      * Returns the minimum horizontal size.
 565      * @return the minimum horizontal size
 566      */
 567     public Dimension getMinimumHorizontalSize() {
 568         Dimension minHorizDim = (Dimension)DefaultLookup.get(slider,
 569                 this, "Slider.minimumHorizontalSize");
 570         if (minHorizDim == null) {
 571             minHorizDim = new Dimension(36, 21);
 572         }
 573         return minHorizDim;
 574     }
 575 
 576     /**
 577      * Returns the minimum vertical size.
 578      * @return the minimum vertical size
 579      */
 580     public Dimension getMinimumVerticalSize() {
 581         Dimension minVertDim = (Dimension)DefaultLookup.get(slider,
 582                 this, "Slider.minimumVerticalSize");
 583         if (minVertDim == null) {
 584             minVertDim = new Dimension(21, 36);
 585         }
 586         return minVertDim;
 587     }
 588 
 589     /**
 590      * Returns the preferred size.
 591      * @param c a component
 592      * @return the preferred size
 593      */
 594     public Dimension getPreferredSize(JComponent c)    {
 595         recalculateIfInsetsChanged();
 596         Dimension d;
 597         if ( slider.getOrientation() == JSlider.VERTICAL ) {
 598             d = new Dimension(getPreferredVerticalSize());
 599             d.width = insetCache.left + insetCache.right;
 600             d.width += focusInsets.left + focusInsets.right;
 601             d.width += trackRect.width + tickRect.width + labelRect.width;
 602         }
 603         else {
 604             d = new Dimension(getPreferredHorizontalSize());
 605             d.height = insetCache.top + insetCache.bottom;
 606             d.height += focusInsets.top + focusInsets.bottom;
 607             d.height += trackRect.height + tickRect.height + labelRect.height;
 608         }
 609 
 610         return d;
 611     }
 612 
 613     /**
 614      * Returns the minimum size.
 615      * @param c a component
 616      * @return the minimum size
 617      */
 618     public Dimension getMinimumSize(JComponent c)  {
 619         recalculateIfInsetsChanged();
 620         Dimension d;
 621 
 622         if ( slider.getOrientation() == JSlider.VERTICAL ) {
 623             d = new Dimension(getMinimumVerticalSize());
 624             d.width = insetCache.left + insetCache.right;
 625             d.width += focusInsets.left + focusInsets.right;
 626             d.width += trackRect.width + tickRect.width + labelRect.width;
 627         }
 628         else {
 629             d = new Dimension(getMinimumHorizontalSize());
 630             d.height = insetCache.top + insetCache.bottom;
 631             d.height += focusInsets.top + focusInsets.bottom;
 632             d.height += trackRect.height + tickRect.height + labelRect.height;
 633         }
 634 
 635         return d;
 636     }
 637 
 638     /**
 639      * Returns the maximum size.
 640      * @param c a component
 641      * @return the maximum size
 642      */
 643     public Dimension getMaximumSize(JComponent c) {
 644         Dimension d = getPreferredSize(c);
 645         if ( slider.getOrientation() == JSlider.VERTICAL ) {
 646             d.height = Short.MAX_VALUE;
 647         }
 648         else {
 649             d.width = Short.MAX_VALUE;
 650         }
 651 
 652         return d;
 653     }
 654 
 655     /**
 656      * Calculates the geometry.
 657      */
 658     protected void calculateGeometry() {
 659         calculateFocusRect();
 660         calculateContentRect();
 661         calculateThumbSize();
 662         calculateTrackBuffer();
 663         calculateTrackRect();
 664         calculateTickRect();
 665         calculateLabelRect();
 666         calculateThumbLocation();
 667     }
 668 
 669     /**
 670      * Calculates the focus rectangle.
 671      */
 672     protected void calculateFocusRect() {
 673         focusRect.x = insetCache.left;
 674         focusRect.y = insetCache.top;
 675         focusRect.width = slider.getWidth() - (insetCache.left + insetCache.right);
 676         focusRect.height = slider.getHeight() - (insetCache.top + insetCache.bottom);
 677     }
 678 
 679     /**
 680      * Calculates the thumb size rectangle.
 681      */
 682     protected void calculateThumbSize() {
 683         Dimension size = getThumbSize();
 684         thumbRect.setSize( size.width, size.height );
 685     }
 686 
 687     /**
 688      * Calculates the content rectangle.
 689      */
 690     protected void calculateContentRect() {
 691         contentRect.x = focusRect.x + focusInsets.left;
 692         contentRect.y = focusRect.y + focusInsets.top;
 693         contentRect.width = focusRect.width - (focusInsets.left + focusInsets.right);
 694         contentRect.height = focusRect.height - (focusInsets.top + focusInsets.bottom);
 695     }
 696 
 697     private int getTickSpacing() {
 698         int majorTickSpacing = slider.getMajorTickSpacing();
 699         int minorTickSpacing = slider.getMinorTickSpacing();
 700 
 701         int result;
 702 
 703         if (minorTickSpacing > 0) {
 704             result = minorTickSpacing;
 705         } else if (majorTickSpacing > 0) {
 706             result = majorTickSpacing;
 707         } else {
 708             result = 0;
 709         }
 710 
 711         return result;
 712     }
 713 
 714     /**
 715      * Calculates the thumb location.
 716      */
 717     protected void calculateThumbLocation() {
 718         if ( slider.getSnapToTicks() ) {
 719             int sliderValue = slider.getValue();
 720             int snappedValue = sliderValue;
 721             int tickSpacing = getTickSpacing();
 722 
 723             if ( tickSpacing != 0 ) {
 724                 // If it's not on a tick, change the value
 725                 if ( (sliderValue - slider.getMinimum()) % tickSpacing != 0 ) {
 726                     float temp = (float)(sliderValue - slider.getMinimum()) / (float)tickSpacing;
 727                     int whichTick = Math.round( temp );
 728 
 729                     // This is the fix for the bug #6401380
 730                     if (temp - (int)temp == .5 && sliderValue < lastValue) {
 731                       whichTick --;
 732                     }
 733                     snappedValue = slider.getMinimum() + (whichTick * tickSpacing);
 734                 }
 735 
 736                 if( snappedValue != sliderValue ) {
 737                     slider.setValue( snappedValue );
 738                 }
 739             }
 740         }
 741 
 742         if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
 743             int valuePosition = xPositionForValue(slider.getValue());
 744 
 745             thumbRect.x = valuePosition - (thumbRect.width / 2);
 746             thumbRect.y = trackRect.y;
 747         }
 748         else {
 749             int valuePosition = yPositionForValue(slider.getValue());
 750 
 751             thumbRect.x = trackRect.x;
 752             thumbRect.y = valuePosition - (thumbRect.height / 2);
 753         }
 754     }
 755 
 756     /**
 757      * Calculates the track buffer.
 758      */
 759     protected void calculateTrackBuffer() {
 760         if ( slider.getPaintLabels() && slider.getLabelTable()  != null ) {
 761             Component highLabel = getHighestValueLabel();
 762             Component lowLabel = getLowestValueLabel();
 763 
 764             if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
 765                 trackBuffer = Math.max( highLabel.getBounds().width, lowLabel.getBounds().width ) / 2;
 766                 trackBuffer = Math.max( trackBuffer, thumbRect.width / 2 );
 767             }
 768             else {
 769                 trackBuffer = Math.max( highLabel.getBounds().height, lowLabel.getBounds().height ) / 2;
 770                 trackBuffer = Math.max( trackBuffer, thumbRect.height / 2 );
 771             }
 772         }
 773         else {
 774             if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
 775                 trackBuffer = thumbRect.width / 2;
 776             }
 777             else {
 778                 trackBuffer = thumbRect.height / 2;
 779             }
 780         }
 781     }
 782 
 783     /**
 784      * Calculates the track rectangle.
 785      */
 786     protected void calculateTrackRect() {
 787         int centerSpacing; // used to center sliders added using BorderLayout.CENTER (bug 4275631)
 788         if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
 789             centerSpacing = thumbRect.height;
 790             if ( slider.getPaintTicks() ) centerSpacing += getTickLength();
 791             if ( slider.getPaintLabels() ) centerSpacing += getHeightOfTallestLabel();
 792             trackRect.x = contentRect.x + trackBuffer;
 793             trackRect.y = contentRect.y + (contentRect.height - centerSpacing - 1)/2;
 794             trackRect.width = contentRect.width - (trackBuffer * 2);
 795             trackRect.height = thumbRect.height;
 796         }
 797         else {
 798             centerSpacing = thumbRect.width;
 799             if (BasicGraphicsUtils.isLeftToRight(slider)) {
 800                 if ( slider.getPaintTicks() ) centerSpacing += getTickLength();
 801                 if ( slider.getPaintLabels() ) centerSpacing += getWidthOfWidestLabel();
 802             } else {
 803                 if ( slider.getPaintTicks() ) centerSpacing -= getTickLength();
 804                 if ( slider.getPaintLabels() ) centerSpacing -= getWidthOfWidestLabel();
 805             }


 809             trackRect.height = contentRect.height - (trackBuffer * 2);
 810         }
 811 
 812     }
 813 
 814     /**
 815      * Gets the height of the tick area for horizontal sliders and the width of
 816      * the tick area for vertical sliders. BasicSliderUI uses the returned value
 817      * to determine the tick area rectangle. If you want to give your ticks some
 818      * room, make this larger than you need and paint your ticks away from the
 819      * sides in paintTicks().
 820      *
 821      * @return an integer representing the height of the tick area for
 822      * horizontal sliders, and the width of the tick area for the vertical
 823      * sliders
 824      */
 825     protected int getTickLength() {
 826         return 8;
 827     }
 828 
 829     /**
 830      * Calculates the tick rectangle.
 831      */
 832     protected void calculateTickRect() {
 833         if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
 834             tickRect.x = trackRect.x;
 835             tickRect.y = trackRect.y + trackRect.height;
 836             tickRect.width = trackRect.width;
 837             tickRect.height = (slider.getPaintTicks()) ? getTickLength() : 0;
 838         }
 839         else {
 840             tickRect.width = (slider.getPaintTicks()) ? getTickLength() : 0;
 841             if(BasicGraphicsUtils.isLeftToRight(slider)) {
 842                 tickRect.x = trackRect.x + trackRect.width;
 843             }
 844             else {
 845                 tickRect.x = trackRect.x - tickRect.width;
 846             }
 847             tickRect.y = trackRect.y;
 848             tickRect.height = trackRect.height;
 849         }
 850     }
 851 
 852     /**
 853      * Calculates the label rectangle.
 854      */
 855     protected void calculateLabelRect() {
 856         if ( slider.getPaintLabels() ) {
 857             if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
 858                 labelRect.x = tickRect.x - trackBuffer;
 859                 labelRect.y = tickRect.y + tickRect.height;
 860                 labelRect.width = tickRect.width + (trackBuffer * 2);
 861                 labelRect.height = getHeightOfTallestLabel();
 862             }
 863             else {
 864                 if(BasicGraphicsUtils.isLeftToRight(slider)) {
 865                     labelRect.x = tickRect.x + tickRect.width;
 866                     labelRect.width = getWidthOfWidestLabel();
 867                 }
 868                 else {
 869                     labelRect.width = getWidthOfWidestLabel();
 870                     labelRect.x = tickRect.x - labelRect.width;
 871                 }
 872                 labelRect.y = tickRect.y - trackBuffer;
 873                 labelRect.height = tickRect.height + (trackBuffer * 2);
 874             }


 877             if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
 878                 labelRect.x = tickRect.x;
 879                 labelRect.y = tickRect.y + tickRect.height;
 880                 labelRect.width = tickRect.width;
 881                 labelRect.height = 0;
 882             }
 883             else {
 884                 if(BasicGraphicsUtils.isLeftToRight(slider)) {
 885                     labelRect.x = tickRect.x + tickRect.width;
 886                 }
 887                 else {
 888                     labelRect.x = tickRect.x;
 889                 }
 890                 labelRect.y = tickRect.y;
 891                 labelRect.width = 0;
 892                 labelRect.height = tickRect.height;
 893             }
 894         }
 895     }
 896 
 897     /**
 898      * Returns the thumb size.
 899      * @return the thumb size
 900      */
 901     protected Dimension getThumbSize() {
 902         Dimension size = new Dimension();
 903 
 904         if ( slider.getOrientation() == JSlider.VERTICAL ) {
 905             size.width = 20;
 906             size.height = 11;
 907         }
 908         else {
 909             size.width = 11;
 910             size.height = 20;
 911         }
 912 
 913         return size;
 914     }
 915 
 916     /**
 917      * A property change handler.
 918      */
 919     public class PropertyChangeHandler implements PropertyChangeListener {
 920         // NOTE: This class exists only for backward compatibility. All
 921         // its functionality has been moved into Handler. If you need to add
 922         // new functionality add it to the Handler, but make sure this
 923         // class calls into the Handler.
 924         /** {@inheritDoc} */
 925         public void propertyChange( PropertyChangeEvent e ) {
 926             getHandler().propertyChange(e);
 927         }
 928     }
 929 
 930     /**
 931      * Returns the width of the widest label.
 932      * @return the width of the widest label
 933      */
 934     protected int getWidthOfWidestLabel() {
 935         @SuppressWarnings("rawtypes")
 936         Dictionary dictionary = slider.getLabelTable();
 937         int widest = 0;
 938         if ( dictionary != null ) {
 939             Enumeration<?> keys = dictionary.keys();
 940             while ( keys.hasMoreElements() ) {
 941                 JComponent label = (JComponent) dictionary.get(keys.nextElement());
 942                 widest = Math.max( label.getPreferredSize().width, widest );
 943             }
 944         }
 945         return widest;
 946     }
 947 
 948     /**
 949      * Returns the height of the tallest label.
 950      * @return the height of the tallest label
 951      */
 952     protected int getHeightOfTallestLabel() {
 953         @SuppressWarnings("rawtypes")
 954         Dictionary dictionary = slider.getLabelTable();
 955         int tallest = 0;
 956         if ( dictionary != null ) {
 957             Enumeration<?> keys = dictionary.keys();
 958             while ( keys.hasMoreElements() ) {
 959                 JComponent label = (JComponent) dictionary.get(keys.nextElement());
 960                 tallest = Math.max( label.getPreferredSize().height, tallest );
 961             }
 962         }
 963         return tallest;
 964     }
 965 
 966     /**
 967      * Returns the width of the highest value label.
 968      * @return the width of the highest value label
 969      */
 970     protected int getWidthOfHighValueLabel() {
 971         Component label = getHighestValueLabel();
 972         int width = 0;
 973 
 974         if ( label != null ) {
 975             width = label.getPreferredSize().width;
 976         }
 977 
 978         return width;
 979     }
 980 
 981     /**
 982      * Returns the width of the lowest value label.
 983      * @return the width of the lowest value label
 984      */
 985     protected int getWidthOfLowValueLabel() {
 986         Component label = getLowestValueLabel();
 987         int width = 0;
 988 
 989         if ( label != null ) {
 990             width = label.getPreferredSize().width;
 991         }
 992 
 993         return width;
 994     }
 995 
 996     /**
 997      * Returns the height of the highest value label.
 998      * @return the height of the highest value label
 999      */
1000     protected int getHeightOfHighValueLabel() {
1001         Component label = getHighestValueLabel();
1002         int height = 0;
1003 
1004         if ( label != null ) {
1005             height = label.getPreferredSize().height;
1006         }
1007 
1008         return height;
1009     }
1010 
1011     /**
1012      * Returns the height of the lowest value label.
1013      * @return the height of the lowest value label
1014      */
1015     protected int getHeightOfLowValueLabel() {
1016         Component label = getLowestValueLabel();
1017         int height = 0;
1018 
1019         if ( label != null ) {
1020             height = label.getPreferredSize().height;
1021         }
1022 
1023         return height;
1024     }
1025 
1026     /**
1027      * Draws inverted.
1028      * @return the inverted-ness
1029      */
1030     protected boolean drawInverted() {
1031         if (slider.getOrientation()==JSlider.HORIZONTAL) {
1032             if(BasicGraphicsUtils.isLeftToRight(slider)) {
1033                 return slider.getInverted();
1034             } else {
1035                 return !slider.getInverted();
1036             }
1037         } else {
1038             return slider.getInverted();
1039         }
1040     }
1041 
1042     /**
1043      * Returns the biggest value that has an entry in the label table.
1044      *
1045      * @return biggest value that has an entry in the label table, or
1046      *         null.
1047      * @since 1.6
1048      */
1049     protected Integer getHighestValue() {


1140         if ( !clip.intersects(trackRect) && slider.getPaintTrack())
1141             calculateGeometry();
1142 
1143         if ( slider.getPaintTrack() && clip.intersects( trackRect ) ) {
1144             paintTrack( g );
1145         }
1146         if ( slider.getPaintTicks() && clip.intersects( tickRect ) ) {
1147             paintTicks( g );
1148         }
1149         if ( slider.getPaintLabels() && clip.intersects( labelRect ) ) {
1150             paintLabels( g );
1151         }
1152         if ( slider.hasFocus() && clip.intersects( focusRect ) ) {
1153             paintFocus( g );
1154         }
1155         if ( clip.intersects( thumbRect ) ) {
1156             paintThumb( g );
1157         }
1158     }
1159 
1160     /**
1161      * Recalculates if the insets have changed.
1162      */
1163     protected void recalculateIfInsetsChanged() {
1164         Insets newInsets = slider.getInsets();
1165         if ( !newInsets.equals( insetCache ) ) {
1166             insetCache = newInsets;
1167             calculateGeometry();
1168         }
1169     }
1170 
1171     /**
1172      * Recalculates if the orientation has changed.
1173      */
1174     protected void recalculateIfOrientationChanged() {
1175         boolean ltr = BasicGraphicsUtils.isLeftToRight(slider);
1176         if ( ltr!=leftToRightCache ) {
1177             leftToRightCache = ltr;
1178             calculateGeometry();
1179         }
1180     }
1181 
1182     /**
1183      * Paints focus.
1184      * @param g the graphics
1185      */
1186     public void paintFocus(Graphics g)  {
1187         g.setColor( getFocusColor() );
1188 
1189         BasicGraphicsUtils.drawDashedRect( g, focusRect.x, focusRect.y,
1190                                            focusRect.width, focusRect.height );
1191     }
1192 
1193     /**
1194      * Paints track.
1195      * @param g the graphics
1196      */
1197     public void paintTrack(Graphics g)  {
1198 
1199         Rectangle trackBounds = trackRect;
1200 
1201         if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
1202             int cy = (trackBounds.height / 2) - 2;
1203             int cw = trackBounds.width;
1204 
1205             g.translate(trackBounds.x, trackBounds.y + cy);
1206 
1207             g.setColor(getShadowColor());
1208             g.drawLine(0, 0, cw - 1, 0);
1209             g.drawLine(0, 1, 0, 2);
1210             g.setColor(getHighlightColor());
1211             g.drawLine(0, 3, cw, 3);
1212             g.drawLine(cw, 0, cw, 3);
1213             g.setColor(Color.black);
1214             g.drawLine(1, 1, cw-2, 1);
1215 
1216             g.translate(-trackBounds.x, -(trackBounds.y + cy));
1217         }
1218         else {
1219             int cx = (trackBounds.width / 2) - 2;
1220             int ch = trackBounds.height;
1221 
1222             g.translate(trackBounds.x + cx, trackBounds.y);
1223 
1224             g.setColor(getShadowColor());
1225             g.drawLine(0, 0, 0, ch - 1);
1226             g.drawLine(1, 0, 2, 0);
1227             g.setColor(getHighlightColor());
1228             g.drawLine(3, 0, 3, ch);
1229             g.drawLine(0, ch, 3, ch);
1230             g.setColor(Color.black);
1231             g.drawLine(1, 1, 1, ch-2);
1232 
1233             g.translate(-(trackBounds.x + cx), -trackBounds.y);
1234         }
1235     }
1236 
1237     /**
1238      * Paints ticks.
1239      * @param g the graphics
1240      */
1241     public void paintTicks(Graphics g)  {
1242         Rectangle tickBounds = tickRect;
1243 
1244         g.setColor(DefaultLookup.getColor(slider, this, "Slider.tickColor", Color.black));
1245 
1246         if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
1247             g.translate(0, tickBounds.y);
1248 
1249             if (slider.getMinorTickSpacing() > 0) {
1250                 int value = slider.getMinimum();
1251 
1252                 while ( value <= slider.getMaximum() ) {
1253                     int xPos = xPositionForValue(value);
1254                     paintMinorTickForHorizSlider( g, tickBounds, xPos );
1255 
1256                     // Overflow checking
1257                     if (Integer.MAX_VALUE - slider.getMinorTickSpacing() < value) {
1258                         break;
1259                     }
1260 


1318                 while (value <= slider.getMaximum()) {
1319                     int yPos = yPositionForValue(value);
1320                     paintMajorTickForVertSlider( g, tickBounds, yPos );
1321 
1322                     // Overflow checking
1323                     if (Integer.MAX_VALUE - slider.getMajorTickSpacing() < value) {
1324                         break;
1325                     }
1326 
1327                     value += slider.getMajorTickSpacing();
1328                 }
1329 
1330                 if(!BasicGraphicsUtils.isLeftToRight(slider)) {
1331                     g.translate(-2, 0);
1332                 }
1333             }
1334             g.translate(-tickBounds.x, 0);
1335         }
1336     }
1337 
1338     /**
1339      * Paints minor tick for horizontal slider.
1340      * @param g the graphics
1341      * @param tickBounds the tick bounds
1342      * @param x the x coordinate
1343      */
1344     protected void paintMinorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) {
1345         g.drawLine( x, 0, x, tickBounds.height / 2 - 1 );
1346     }
1347 
1348     /**
1349      * Paints major tick for horizontal slider.
1350      * @param g the graphics
1351      * @param tickBounds the tick bounds
1352      * @param x the x coordinate
1353      */
1354     protected void paintMajorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) {
1355         g.drawLine( x, 0, x, tickBounds.height - 2 );
1356     }
1357 
1358     /**
1359      * Paints minor tick for vertical slider.
1360      * @param g the graphics
1361      * @param tickBounds the tick bounds
1362      * @param y the y coordinate
1363      */
1364     protected void paintMinorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) {
1365         g.drawLine( 0, y, tickBounds.width / 2 - 1, y );
1366     }
1367 
1368     /**
1369      * Paints major tick for vertical slider.
1370      * @param g the graphics
1371      * @param tickBounds the tick bounds
1372      * @param y the y coordinate
1373      */
1374     protected void paintMajorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) {
1375         g.drawLine( 0, y,  tickBounds.width - 2, y );
1376     }
1377 
1378     /**
1379      * Paints the labels.
1380      * @param g the graphics
1381      */
1382     public void paintLabels( Graphics g ) {
1383         Rectangle labelBounds = labelRect;
1384 
1385         @SuppressWarnings("rawtypes")
1386         Dictionary dictionary = slider.getLabelTable();
1387         if ( dictionary != null ) {
1388             Enumeration<?> keys = dictionary.keys();
1389             int minValue = slider.getMinimum();
1390             int maxValue = slider.getMaximum();
1391             boolean enabled = slider.isEnabled();
1392             while ( keys.hasMoreElements() ) {
1393                 Integer key = (Integer)keys.nextElement();
1394                 int value = key.intValue();
1395                 if (value >= minValue && value <= maxValue) {
1396                     JComponent label = (JComponent) dictionary.get(key);
1397                     label.setEnabled(enabled);
1398 
1399                     if (label instanceof JLabel) {
1400                         Icon icon = label.isEnabled() ? ((JLabel) label).getIcon() : ((JLabel) label).getDisabledIcon();
1401 


1448 
1449     /**
1450      * Called for every label in the label table. Used to draw the labels for
1451      * vertical sliders. The graphics have been translated to labelRect.x
1452      * already.
1453      *
1454      * @param g the graphics context in which to paint
1455      * @param value the value of the slider
1456      * @param label the component label in the label table that needs to be
1457      * painted
1458      * @see JSlider#setLabelTable
1459      */
1460     protected void paintVerticalLabel( Graphics g, int value, Component label ) {
1461         int labelCenter = yPositionForValue( value );
1462         int labelTop = labelCenter - (label.getPreferredSize().height / 2);
1463         g.translate( 0, labelTop );
1464         label.paint( g );
1465         g.translate( 0, -labelTop );
1466     }
1467 
1468     /**
1469      * Paints the thumb.
1470      * @param g the graphics
1471      */
1472     public void paintThumb(Graphics g)  {
1473         Rectangle knobBounds = thumbRect;
1474         int w = knobBounds.width;
1475         int h = knobBounds.height;
1476 
1477         g.translate(knobBounds.x, knobBounds.y);
1478 
1479         if ( slider.isEnabled() ) {
1480             g.setColor(slider.getBackground());
1481         }
1482         else {
1483             g.setColor(slider.getBackground().darker());
1484         }
1485 
1486         Boolean paintThumbArrowShape =
1487             (Boolean)slider.getClientProperty("Slider.paintThumbArrowShape");
1488 
1489         if ((!slider.getPaintTicks() && paintThumbArrowShape == null) ||
1490             paintThumbArrowShape == Boolean.FALSE) {
1491 


1560                   g.setColor(highlightColor);
1561                   g.drawLine(cw-1, 0, w-2, 0);             // top
1562                   g.drawLine(0, cw, cw, 0);                // top slant
1563 
1564                   g.setColor(Color.black);
1565                   g.drawLine(0, h-1-cw, cw, h-1 );         // bottom slant
1566                   g.drawLine(cw, h-1, w-1, h-1);           // bottom
1567 
1568                   g.setColor(shadowColor);
1569                   g.drawLine(cw, h-2, w-2,  h-2 );         // bottom
1570                   g.drawLine(w-1, 1, w-1,  h-2 );          // right
1571             }
1572         }
1573 
1574         g.translate(-knobBounds.x, -knobBounds.y);
1575     }
1576 
1577     // Used exclusively by setThumbLocation()
1578     private static Rectangle unionRect = new Rectangle();
1579 
1580     /**
1581      * Sets the thumb location.
1582      * @param x the x coordinate
1583      * @param y the y coordinate
1584      */
1585     public void setThumbLocation(int x, int y)  {
1586         unionRect.setBounds( thumbRect );
1587 
1588         thumbRect.setLocation( x, y );
1589 
1590         SwingUtilities.computeUnion( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height, unionRect );
1591         slider.repaint( unionRect.x, unionRect.y, unionRect.width, unionRect.height );
1592     }
1593 
1594     /**
1595      * Scrolls by block.
1596      * @param direction the direction
1597      */
1598     public void scrollByBlock(int direction)    {
1599         synchronized(slider)    {
1600             int blockIncrement =
1601                 (slider.getMaximum() - slider.getMinimum()) / 10;
1602             if (blockIncrement == 0) {
1603                 blockIncrement = 1;
1604             }
1605 
1606             if (slider.getSnapToTicks()) {
1607                 int tickSpacing = getTickSpacing();
1608 
1609                 if (blockIncrement < tickSpacing) {
1610                     blockIncrement = tickSpacing;
1611                 }
1612             }
1613 
1614             int delta = blockIncrement * ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL);
1615             slider.setValue(slider.getValue() + delta);
1616         }
1617     }
1618 
1619     /**
1620      * Scrolls by unit.
1621      * @param direction the direction
1622      */
1623     public void scrollByUnit(int direction) {
1624         synchronized(slider)    {
1625             int delta = ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL);
1626 
1627             if (slider.getSnapToTicks()) {
1628                 delta *= getTickSpacing();
1629             }
1630 
1631             slider.setValue(slider.getValue() + delta);
1632         }
1633     }
1634 
1635     /**
1636      * This function is called when a mousePressed was detected in the track,
1637      * not in the thumb. The default behavior is to scroll by block. You can
1638      * override this method to stop it from scrolling or to add additional
1639      * behavior.
1640      *
1641      * @param dir the direction and number of blocks to scroll
1642      */
1643     protected void scrollDueToClickInTrack( int dir ) {
1644         scrollByBlock( dir );
1645     }
1646 
1647     /**
1648      * Returns the x position for a value.
1649      * @param value the value
1650      * @return the x position for a value
1651      */
1652     protected int xPositionForValue( int value )    {
1653         int min = slider.getMinimum();
1654         int max = slider.getMaximum();
1655         int trackLength = trackRect.width;
1656         double valueRange = (double)max - (double)min;
1657         double pixelsPerValue = (double)trackLength / valueRange;
1658         int trackLeft = trackRect.x;
1659         int trackRight = trackRect.x + (trackRect.width - 1);
1660         int xPosition;
1661 
1662         if ( !drawInverted() ) {
1663             xPosition = trackLeft;
1664             xPosition += Math.round( pixelsPerValue * ((double)value - min) );
1665         }
1666         else {
1667             xPosition = trackRight;
1668             xPosition -= Math.round( pixelsPerValue * ((double)value - min) );
1669         }
1670 
1671         xPosition = Math.max( trackLeft, xPosition );
1672         xPosition = Math.min( trackRight, xPosition );
1673 
1674         return xPosition;
1675     }
1676 
1677     /**
1678      * Returns the y position for a value.
1679      * @param value the value
1680      * @return the y position for a value
1681      */
1682     protected int yPositionForValue( int value )  {
1683         return yPositionForValue(value, trackRect.y, trackRect.height);
1684     }
1685 
1686     /**
1687      * Returns the y location for the specified value.  No checking is
1688      * done on the arguments.  In particular if <code>trackHeight</code> is
1689      * negative undefined results may occur.
1690      *
1691      * @param value the slider value to get the location for
1692      * @param trackY y-origin of the track
1693      * @param trackHeight the height of the track
1694      * @return the y location for the specified value of the slider
1695      * @since 1.6
1696      */
1697     protected int yPositionForValue(int value, int trackY, int trackHeight) {
1698         int min = slider.getMinimum();
1699         int max = slider.getMaximum();
1700         double valueRange = (double)max - (double)min;
1701         double pixelsPerValue = (double)trackHeight / valueRange;


1858     public class ChangeHandler implements ChangeListener {
1859         // NOTE: This class exists only for backward compatibility. All
1860         // its functionality has been moved into Handler. If you need to add
1861         // new functionality add it to the Handler, but make sure this
1862         // class calls into the Handler.
1863         public void stateChanged(ChangeEvent e) {
1864             getHandler().stateChanged(e);
1865         }
1866     }
1867 
1868     /////////////////////////////////////////////////////////////////////////
1869     /// Track Listener Class
1870     /////////////////////////////////////////////////////////////////////////
1871     /**
1872      * Track mouse movements.
1873      *
1874      * This class should be treated as a &quot;protected&quot; inner class.
1875      * Instantiate it only within subclasses of <code>Foo</code>.
1876      */
1877     public class TrackListener extends MouseInputAdapter {
1878         /** The offset */
1879         protected transient int offset;
1880         /** Current mouse x. */
1881         protected transient int currentMouseX;
1882         /** Current mouse y. */
1883         protected transient int currentMouseY;
1884 
1885         /**
1886          * {@inheritDoc}
1887          */
1888         public void mouseReleased(MouseEvent e) {
1889             if (!slider.isEnabled()) {
1890                 return;
1891             }
1892 
1893             offset = 0;
1894             scrollTimer.stop();
1895 
1896             isDragging = false;
1897             slider.setValueIsAdjusting(false);
1898             slider.repaint();
1899         }
1900 
1901         /**
1902         * If the mouse is pressed above the "thumb" component
1903         * then reduce the scrollbars value by one page ("page up"),
1904         * otherwise increase it by one page.  If there is no
1905         * thumb then page up if the mouse is in the upper half
1906         * of the track.
1907         */


1996                             NEGATIVE_SCROLL : POSITIVE_SCROLL;
1997                     }
1998                     else {
1999                         direction = (currentMouseX < thumbX) ?
2000                             POSITIVE_SCROLL : NEGATIVE_SCROLL;
2001                     }
2002                 }
2003                 break;
2004             }
2005 
2006             if (shouldScroll(direction)) {
2007                 scrollDueToClickInTrack(direction);
2008             }
2009             if (shouldScroll(direction)) {
2010                 scrollTimer.stop();
2011                 scrollListener.setDirection(direction);
2012                 scrollTimer.start();
2013             }
2014         }
2015 
2016         /**
2017          * Returns if scrolling should occur
2018          * @param direction the direction.
2019          * @return if scrolling should occur
2020          */
2021         public boolean shouldScroll(int direction) {
2022             Rectangle r = thumbRect;
2023             if (slider.getOrientation() == JSlider.VERTICAL) {
2024                 if (drawInverted() ? direction < 0 : direction > 0) {
2025                     if (r.y  <= currentMouseY) {
2026                         return false;
2027                     }
2028                 }
2029                 else if (r.y + r.height >= currentMouseY) {
2030                     return false;
2031                 }
2032             }
2033             else {
2034                 if (drawInverted() ? direction < 0 : direction > 0) {
2035                     if (r.x + r.width  >= currentMouseX) {
2036                         return false;
2037                     }
2038                 }
2039                 else if (r.x <= currentMouseX) {
2040                     return false;


2104                 int hMax = xPositionForValue(slider.getMaximum() -
2105                                             slider.getExtent());
2106 
2107                 if (drawInverted()) {
2108                     trackLeft = hMax;
2109                 }
2110                 else {
2111                     trackRight = hMax;
2112                 }
2113                 thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth);
2114                 thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth);
2115 
2116                 setThumbLocation(thumbLeft, thumbRect.y);
2117 
2118                 thumbMiddle = thumbLeft + halfThumbWidth;
2119                 slider.setValue(valueForXPosition(thumbMiddle));
2120                 break;
2121             }
2122         }
2123 
2124         /** {@inheritDoc} */
2125         public void mouseMoved(MouseEvent e) { }
2126     }
2127 
2128     /**
2129      * Scroll-event listener.
2130      *
2131      * This class should be treated as a &quot;protected&quot; inner class.
2132      * Instantiate it only within subclasses of <code>Foo</code>.
2133      */
2134     public class ScrollListener implements ActionListener {
2135         // changed this class to public to avoid bogus IllegalAccessException
2136         // bug in InternetExplorer browser.  It was protected.  Work around
2137         // for 4109432
2138         int direction = POSITIVE_SCROLL;
2139         boolean useBlockIncrement;
2140 
2141         /**
2142          * Constructs a {@code ScrollListener}
2143          */
2144         public ScrollListener() {
2145             direction = POSITIVE_SCROLL;
2146             useBlockIncrement = true;
2147         }
2148 
2149         /**
2150          * Constructs a {@code ScrollListener}
2151          * @param dir the direction
2152          * @param block whether or not to scroll by block
2153          */
2154         public ScrollListener(int dir, boolean block)   {
2155             direction = dir;
2156             useBlockIncrement = block;
2157         }
2158 
2159         /**
2160          * Sets the direction.
2161          * @param direction the new direction
2162          */
2163         public void setDirection(int direction) {
2164             this.direction = direction;
2165         }
2166 
2167         /**
2168          * Sets scrolling by block
2169          * @param block the new scroll by block value
2170          */
2171         public void setScrollByBlock(boolean block) {
2172             this.useBlockIncrement = block;
2173         }
2174 
2175         /** {@inheritDoc} */
2176         public void actionPerformed(ActionEvent e) {
2177             if (useBlockIncrement) {
2178                 scrollByBlock(direction);
2179             }
2180             else {
2181                 scrollByUnit(direction);
2182             }
2183             if (!trackListener.shouldScroll(direction)) {
2184                 ((Timer)e.getSource()).stop();
2185             }
2186         }
2187     }
2188 
2189     /**
2190      * Listener for resizing events.
2191      * <p>
2192      * This class should be treated as a &quot;protected&quot; inner class.
2193      * Instantiate it only within subclasses of <code>Foo</code>.
2194      */
2195     public class ComponentHandler extends ComponentAdapter {


2228      * combination of an <code>ActionMap</code>, to contain the action,
2229      * and an <code>InputMap</code> to contain the mapping from KeyStroke
2230      * to action description. The InputMap is usually described in the
2231      * LookAndFeel tables.
2232      * <p>
2233      * Please refer to the key bindings specification for further details.
2234      * <p>
2235      * This class should be treated as a &quot;protected&quot; inner class.
2236      * Instantiate it only within subclasses of <code>Foo</code>.
2237      */
2238     @SuppressWarnings("serial") // Superclass is not serializable across versions
2239     public class ActionScroller extends AbstractAction {
2240         // NOTE: This class exists only for backward compatibility. All
2241         // its functionality has been moved into Actions. If you need to add
2242         // new functionality add it to the Actions, but make sure this
2243         // class calls into the Actions.
2244         int dir;
2245         boolean block;
2246         JSlider slider;
2247 
2248         /**
2249          * Constructs an {@code ActionScroller}.
2250          * @param slider a slider
2251          * @param dir the direction
2252          * @param block block scrolling or not
2253          */
2254         public ActionScroller( JSlider slider, int dir, boolean block) {
2255             this.dir = dir;
2256             this.block = block;
2257             this.slider = slider;
2258         }
2259         
2260         /** {@inheritDoc} */
2261         public void actionPerformed(ActionEvent e) {
2262             SHARED_ACTION.scroll(slider, BasicSliderUI.this, dir, block);
2263         }
2264         
2265         /** {@inheritDoc} */
2266         public boolean isEnabled() {
2267             boolean b = true;
2268             if (slider != null) {
2269                 b = slider.isEnabled();
2270             }
2271             return b;
2272         }
2273 
2274     }
2275 
2276 
2277     /**
2278      * A static version of the above.
2279      */
2280     @SuppressWarnings("serial") // Superclass is not serializable across versions
2281     static class SharedActionScroller extends AbstractAction {
2282         // NOTE: This class exists only for backward compatibility. All
2283         // its functionality has been moved into Actions. If you need to add
2284         // new functionality add it to the Actions, but make sure this
2285         // class calls into the Actions.


< prev index next >