jdk/src/share/classes/javax/swing/plaf/basic/BasicSliderUI.java
changeset 2 90ce3da70b43
child 456 8ded0dbe4aaa
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package javax.swing.plaf.basic;
       
    27 
       
    28 import java.awt.Component;
       
    29 import java.awt.Container;
       
    30 import java.awt.Adjustable;
       
    31 import java.awt.event.*;
       
    32 import java.awt.FontMetrics;
       
    33 import java.awt.Graphics;
       
    34 import java.awt.Dimension;
       
    35 import java.awt.Rectangle;
       
    36 import java.awt.Point;
       
    37 import java.awt.Insets;
       
    38 import java.awt.Color;
       
    39 import java.awt.IllegalComponentStateException;
       
    40 import java.awt.Polygon;
       
    41 import java.beans.*;
       
    42 import java.util.Dictionary;
       
    43 import java.util.Enumeration;
       
    44 
       
    45 import javax.swing.border.AbstractBorder;
       
    46 
       
    47 import javax.swing.*;
       
    48 import javax.swing.event.*;
       
    49 import javax.swing.plaf.*;
       
    50 import sun.swing.DefaultLookup;
       
    51 import sun.swing.UIAction;
       
    52 
       
    53 
       
    54 /**
       
    55  * A Basic L&F implementation of SliderUI.
       
    56  *
       
    57  * @author Tom Santos
       
    58  */
       
    59 public class BasicSliderUI extends SliderUI{
       
    60     // Old actions forward to an instance of this.
       
    61     private static final Actions SHARED_ACTION = new Actions();
       
    62 
       
    63     public static final int POSITIVE_SCROLL = +1;
       
    64     public static final int NEGATIVE_SCROLL = -1;
       
    65     public static final int MIN_SCROLL = -2;
       
    66     public static final int MAX_SCROLL = +2;
       
    67 
       
    68     protected Timer scrollTimer;
       
    69     protected JSlider slider;
       
    70 
       
    71     protected Insets focusInsets = null;
       
    72     protected Insets insetCache = null;
       
    73     protected boolean leftToRightCache = true;
       
    74     protected Rectangle focusRect = null;
       
    75     protected Rectangle contentRect = null;
       
    76     protected Rectangle labelRect = null;
       
    77     protected Rectangle tickRect = null;
       
    78     protected Rectangle trackRect = null;
       
    79     protected Rectangle thumbRect = null;
       
    80 
       
    81     protected int trackBuffer = 0;  // The distance that the track is from the side of the control
       
    82 
       
    83     private transient boolean isDragging;
       
    84 
       
    85     protected TrackListener trackListener;
       
    86     protected ChangeListener changeListener;
       
    87     protected ComponentListener componentListener;
       
    88     protected FocusListener focusListener;
       
    89     protected ScrollListener scrollListener;
       
    90     protected PropertyChangeListener propertyChangeListener;
       
    91     private Handler handler;
       
    92     private int lastValue;
       
    93 
       
    94     // Colors
       
    95     private Color shadowColor;
       
    96     private Color highlightColor;
       
    97     private Color focusColor;
       
    98 
       
    99     /**
       
   100      * Whther or not sameLabelBaselines is up to date.
       
   101      */
       
   102     private boolean checkedLabelBaselines;
       
   103     /**
       
   104      * Whether or not all the entries in the labeltable have the same
       
   105      * baseline.
       
   106      */
       
   107     private boolean sameLabelBaselines;
       
   108 
       
   109 
       
   110     protected Color getShadowColor() {
       
   111         return shadowColor;
       
   112     }
       
   113 
       
   114     protected Color getHighlightColor() {
       
   115         return highlightColor;
       
   116     }
       
   117 
       
   118     protected Color getFocusColor() {
       
   119         return focusColor;
       
   120     }
       
   121 
       
   122     /**
       
   123      * Returns true if the user is dragging the slider.
       
   124      *
       
   125      * @return true if the user is dragging the slider
       
   126      * @since 1.5
       
   127      */
       
   128     protected boolean isDragging() {
       
   129         return isDragging;
       
   130     }
       
   131 
       
   132     /////////////////////////////////////////////////////////////////////////////
       
   133     // ComponentUI Interface Implementation methods
       
   134     /////////////////////////////////////////////////////////////////////////////
       
   135     public static ComponentUI createUI(JComponent b)    {
       
   136         return new BasicSliderUI((JSlider)b);
       
   137     }
       
   138 
       
   139     public BasicSliderUI(JSlider b)   {
       
   140     }
       
   141 
       
   142     public void installUI(JComponent c)   {
       
   143         slider = (JSlider) c;
       
   144 
       
   145         checkedLabelBaselines = false;
       
   146 
       
   147         slider.setEnabled(slider.isEnabled());
       
   148         LookAndFeel.installProperty(slider, "opaque", Boolean.TRUE);
       
   149 
       
   150         isDragging = false;
       
   151         trackListener = createTrackListener( slider );
       
   152         changeListener = createChangeListener( slider );
       
   153         componentListener = createComponentListener( slider );
       
   154         focusListener = createFocusListener( slider );
       
   155         scrollListener = createScrollListener( slider );
       
   156         propertyChangeListener = createPropertyChangeListener( slider );
       
   157 
       
   158         installDefaults( slider );
       
   159         installListeners( slider );
       
   160         installKeyboardActions( slider );
       
   161 
       
   162         scrollTimer = new Timer( 100, scrollListener );
       
   163         scrollTimer.setInitialDelay( 300 );
       
   164 
       
   165         insetCache = slider.getInsets();
       
   166         leftToRightCache = BasicGraphicsUtils.isLeftToRight(slider);
       
   167         focusRect = new Rectangle();
       
   168         contentRect = new Rectangle();
       
   169         labelRect = new Rectangle();
       
   170         tickRect = new Rectangle();
       
   171         trackRect = new Rectangle();
       
   172         thumbRect = new Rectangle();
       
   173         lastValue = slider.getValue();
       
   174 
       
   175         calculateGeometry(); // This figures out where the labels, ticks, track, and thumb are.
       
   176     }
       
   177 
       
   178     public void uninstallUI(JComponent c) {
       
   179         if ( c != slider )
       
   180             throw new IllegalComponentStateException(
       
   181                                                     this + " was asked to deinstall() "
       
   182                                                     + c + " when it only knows about "
       
   183                                                     + slider + ".");
       
   184 
       
   185         LookAndFeel.uninstallBorder(slider);
       
   186 
       
   187         scrollTimer.stop();
       
   188         scrollTimer = null;
       
   189 
       
   190         uninstallListeners( slider );
       
   191         uninstallKeyboardActions(slider);
       
   192 
       
   193         focusInsets = null;
       
   194         insetCache = null;
       
   195         leftToRightCache = true;
       
   196         focusRect = null;
       
   197         contentRect = null;
       
   198         labelRect = null;
       
   199         tickRect = null;
       
   200         trackRect = null;
       
   201         thumbRect = null;
       
   202         trackListener = null;
       
   203         changeListener = null;
       
   204         componentListener = null;
       
   205         focusListener = null;
       
   206         scrollListener = null;
       
   207         propertyChangeListener = null;
       
   208         slider = null;
       
   209     }
       
   210 
       
   211     protected void installDefaults( JSlider slider ) {
       
   212         LookAndFeel.installBorder(slider, "Slider.border");
       
   213         LookAndFeel.installColorsAndFont(slider, "Slider.background",
       
   214                                          "Slider.foreground", "Slider.font");
       
   215         highlightColor = UIManager.getColor("Slider.highlight");
       
   216 
       
   217         shadowColor = UIManager.getColor("Slider.shadow");
       
   218         focusColor = UIManager.getColor("Slider.focus");
       
   219 
       
   220         focusInsets = (Insets)UIManager.get( "Slider.focusInsets" );
       
   221     }
       
   222 
       
   223     protected TrackListener createTrackListener(JSlider slider) {
       
   224         return new TrackListener();
       
   225     }
       
   226 
       
   227     protected ChangeListener createChangeListener(JSlider slider) {
       
   228         return getHandler();
       
   229     }
       
   230 
       
   231     protected ComponentListener createComponentListener(JSlider slider) {
       
   232         return getHandler();
       
   233     }
       
   234 
       
   235     protected FocusListener createFocusListener(JSlider slider) {
       
   236         return getHandler();
       
   237     }
       
   238 
       
   239     protected ScrollListener createScrollListener( JSlider slider ) {
       
   240         return new ScrollListener();
       
   241     }
       
   242 
       
   243     protected PropertyChangeListener createPropertyChangeListener(
       
   244             JSlider slider) {
       
   245         return getHandler();
       
   246     }
       
   247 
       
   248     private Handler getHandler() {
       
   249         if (handler == null) {
       
   250             handler = new Handler();
       
   251         }
       
   252         return handler;
       
   253     }
       
   254 
       
   255     protected void installListeners( JSlider slider ) {
       
   256         slider.addMouseListener(trackListener);
       
   257         slider.addMouseMotionListener(trackListener);
       
   258         slider.addFocusListener(focusListener);
       
   259         slider.addComponentListener(componentListener);
       
   260         slider.addPropertyChangeListener( propertyChangeListener );
       
   261         slider.getModel().addChangeListener(changeListener);
       
   262     }
       
   263 
       
   264     protected void uninstallListeners( JSlider slider ) {
       
   265         slider.removeMouseListener(trackListener);
       
   266         slider.removeMouseMotionListener(trackListener);
       
   267         slider.removeFocusListener(focusListener);
       
   268         slider.removeComponentListener(componentListener);
       
   269         slider.removePropertyChangeListener( propertyChangeListener );
       
   270         slider.getModel().removeChangeListener(changeListener);
       
   271         handler = null;
       
   272     }
       
   273 
       
   274     protected void installKeyboardActions( JSlider slider ) {
       
   275         InputMap km = getInputMap(JComponent.WHEN_FOCUSED, slider);
       
   276         SwingUtilities.replaceUIInputMap(slider, JComponent.WHEN_FOCUSED, km);
       
   277         LazyActionMap.installLazyActionMap(slider, BasicSliderUI.class,
       
   278                 "Slider.actionMap");
       
   279     }
       
   280 
       
   281     InputMap getInputMap(int condition, JSlider slider) {
       
   282         if (condition == JComponent.WHEN_FOCUSED) {
       
   283             InputMap keyMap = (InputMap)DefaultLookup.get(slider, this,
       
   284                   "Slider.focusInputMap");
       
   285             InputMap rtlKeyMap;
       
   286 
       
   287             if (slider.getComponentOrientation().isLeftToRight() ||
       
   288                 ((rtlKeyMap = (InputMap)DefaultLookup.get(slider, this,
       
   289                           "Slider.focusInputMap.RightToLeft")) == null)) {
       
   290                 return keyMap;
       
   291             } else {
       
   292                 rtlKeyMap.setParent(keyMap);
       
   293                 return rtlKeyMap;
       
   294             }
       
   295         }
       
   296         return null;
       
   297     }
       
   298 
       
   299     /**
       
   300      * Populates ComboBox's actions.
       
   301      */
       
   302     static void loadActionMap(LazyActionMap map) {
       
   303         map.put(new Actions(Actions.POSITIVE_UNIT_INCREMENT));
       
   304         map.put(new Actions(Actions.POSITIVE_BLOCK_INCREMENT));
       
   305         map.put(new Actions(Actions.NEGATIVE_UNIT_INCREMENT));
       
   306         map.put(new Actions(Actions.NEGATIVE_BLOCK_INCREMENT));
       
   307         map.put(new Actions(Actions.MIN_SCROLL_INCREMENT));
       
   308         map.put(new Actions(Actions.MAX_SCROLL_INCREMENT));
       
   309     }
       
   310 
       
   311     protected void uninstallKeyboardActions( JSlider slider ) {
       
   312         SwingUtilities.replaceUIActionMap(slider, null);
       
   313         SwingUtilities.replaceUIInputMap(slider, JComponent.WHEN_FOCUSED,
       
   314                                          null);
       
   315     }
       
   316 
       
   317 
       
   318     /**
       
   319      * Returns the baseline.
       
   320      *
       
   321      * @throws NullPointerException {@inheritDoc}
       
   322      * @throws IllegalArgumentException {@inheritDoc}
       
   323      * @see javax.swing.JComponent#getBaseline(int, int)
       
   324      * @since 1.6
       
   325      */
       
   326     public int getBaseline(JComponent c, int width, int height) {
       
   327         super.getBaseline(c, width, height);
       
   328         if (slider.getPaintLabels() && labelsHaveSameBaselines()) {
       
   329             FontMetrics metrics = slider.getFontMetrics(slider.getFont());
       
   330             Insets insets = slider.getInsets();
       
   331             Dimension thumbSize = getThumbSize();
       
   332             if (slider.getOrientation() == JSlider.HORIZONTAL) {
       
   333                 int tickLength = getTickLength();
       
   334                 int contentHeight = height - insets.top - insets.bottom -
       
   335                     focusInsets.top - focusInsets.bottom;
       
   336                 int thumbHeight = thumbSize.height;
       
   337                 int centerSpacing = thumbHeight;
       
   338                 if (slider.getPaintTicks()) {
       
   339                     centerSpacing += tickLength;
       
   340                 }
       
   341                 // Assume uniform labels.
       
   342                 centerSpacing += getHeightOfTallestLabel();
       
   343                 int trackY = insets.top + focusInsets.top +
       
   344                     (contentHeight - centerSpacing - 1) / 2;
       
   345                 int trackHeight = thumbHeight;
       
   346                 int tickY = trackY + trackHeight;
       
   347                 int tickHeight = tickLength;
       
   348                 if (!slider.getPaintTicks()) {
       
   349                     tickHeight = 0;
       
   350                 }
       
   351                 int labelY = tickY + tickHeight;
       
   352                 return labelY + metrics.getAscent();
       
   353             }
       
   354             else { // vertical
       
   355                 boolean inverted = slider.getInverted();
       
   356                 Integer value = inverted ? getLowestValue() :
       
   357                                            getHighestValue();
       
   358                 if (value != null) {
       
   359                     int thumbHeight = thumbSize.height;
       
   360                     int trackBuffer = Math.max(metrics.getHeight() / 2,
       
   361                                                thumbHeight / 2);
       
   362                     int contentY = focusInsets.top + insets.top;
       
   363                     int trackY = contentY + trackBuffer;
       
   364                     int trackHeight = height - focusInsets.top -
       
   365                         focusInsets.bottom - insets.top - insets.bottom -
       
   366                         trackBuffer - trackBuffer;
       
   367                     int yPosition = yPositionForValue(value, trackY,
       
   368                                                       trackHeight);
       
   369                     return yPosition - metrics.getHeight() / 2 +
       
   370                         metrics.getAscent();
       
   371                 }
       
   372             }
       
   373         }
       
   374         return 0;
       
   375     }
       
   376 
       
   377     /**
       
   378      * Returns an enum indicating how the baseline of the component
       
   379      * changes as the size changes.
       
   380      *
       
   381      * @throws NullPointerException {@inheritDoc}
       
   382      * @see javax.swing.JComponent#getBaseline(int, int)
       
   383      * @since 1.6
       
   384      */
       
   385     public Component.BaselineResizeBehavior getBaselineResizeBehavior(
       
   386             JComponent c) {
       
   387         super.getBaselineResizeBehavior(c);
       
   388         // NOTE: BasicSpinner really provides for CENTER_OFFSET, but
       
   389         // the default min/pref size is smaller than it should be
       
   390         // so that getBaseline() doesn't implement the contract
       
   391         // for CENTER_OFFSET as defined in Component.
       
   392         return Component.BaselineResizeBehavior.OTHER;
       
   393     }
       
   394 
       
   395     /**
       
   396      * Returns true if all the labels from the label table have the same
       
   397      * baseline.
       
   398      *
       
   399      * @return true if all the labels from the label table have the
       
   400      *         same baseline
       
   401      * @since 1.6
       
   402      */
       
   403     protected boolean labelsHaveSameBaselines() {
       
   404         if (!checkedLabelBaselines) {
       
   405             checkedLabelBaselines = true;
       
   406             Dictionary dictionary = slider.getLabelTable();
       
   407             if (dictionary != null) {
       
   408                 sameLabelBaselines = true;
       
   409                 Enumeration elements = dictionary.elements();
       
   410                 int baseline = -1;
       
   411                 while (elements.hasMoreElements()) {
       
   412                     Component label = (Component)elements.nextElement();
       
   413                     Dimension pref = label.getPreferredSize();
       
   414                     int labelBaseline = label.getBaseline(pref.width,
       
   415                                                           pref.height);
       
   416                     if (labelBaseline >= 0) {
       
   417                         if (baseline == -1) {
       
   418                             baseline = labelBaseline;
       
   419                         }
       
   420                         else if (baseline != labelBaseline) {
       
   421                             sameLabelBaselines = false;
       
   422                             break;
       
   423                         }
       
   424                     }
       
   425                     else {
       
   426                         sameLabelBaselines = false;
       
   427                         break;
       
   428                     }
       
   429                 }
       
   430             }
       
   431             else {
       
   432                 sameLabelBaselines = false;
       
   433             }
       
   434         }
       
   435         return sameLabelBaselines;
       
   436     }
       
   437 
       
   438     public Dimension getPreferredHorizontalSize() {
       
   439         Dimension horizDim = (Dimension)DefaultLookup.get(slider,
       
   440                 this, "Slider.horizontalSize");
       
   441         if (horizDim == null) {
       
   442             horizDim = new Dimension(200, 21);
       
   443         }
       
   444         return horizDim;
       
   445     }
       
   446 
       
   447     public Dimension getPreferredVerticalSize() {
       
   448         Dimension vertDim = (Dimension)DefaultLookup.get(slider,
       
   449                 this, "Slider.verticalSize");
       
   450         if (vertDim == null) {
       
   451             vertDim = new Dimension(21, 200);
       
   452         }
       
   453         return vertDim;
       
   454     }
       
   455 
       
   456     public Dimension getMinimumHorizontalSize() {
       
   457         Dimension minHorizDim = (Dimension)DefaultLookup.get(slider,
       
   458                 this, "Slider.minimumHorizontalSize");
       
   459         if (minHorizDim == null) {
       
   460             minHorizDim = new Dimension(36, 21);
       
   461         }
       
   462         return minHorizDim;
       
   463     }
       
   464 
       
   465     public Dimension getMinimumVerticalSize() {
       
   466         Dimension minVertDim = (Dimension)DefaultLookup.get(slider,
       
   467                 this, "Slider.minimumVerticalSize");
       
   468         if (minVertDim == null) {
       
   469             minVertDim = new Dimension(21, 36);
       
   470         }
       
   471         return minVertDim;
       
   472     }
       
   473 
       
   474     public Dimension getPreferredSize(JComponent c)    {
       
   475         recalculateIfInsetsChanged();
       
   476         Dimension d;
       
   477         if ( slider.getOrientation() == JSlider.VERTICAL ) {
       
   478             d = new Dimension(getPreferredVerticalSize());
       
   479             d.width = insetCache.left + insetCache.right;
       
   480             d.width += focusInsets.left + focusInsets.right;
       
   481             d.width += trackRect.width + tickRect.width + labelRect.width;
       
   482         }
       
   483         else {
       
   484             d = new Dimension(getPreferredHorizontalSize());
       
   485             d.height = insetCache.top + insetCache.bottom;
       
   486             d.height += focusInsets.top + focusInsets.bottom;
       
   487             d.height += trackRect.height + tickRect.height + labelRect.height;
       
   488         }
       
   489 
       
   490         return d;
       
   491     }
       
   492 
       
   493     public Dimension getMinimumSize(JComponent c)  {
       
   494         recalculateIfInsetsChanged();
       
   495         Dimension d;
       
   496 
       
   497         if ( slider.getOrientation() == JSlider.VERTICAL ) {
       
   498             d = new Dimension(getMinimumVerticalSize());
       
   499             d.width = insetCache.left + insetCache.right;
       
   500             d.width += focusInsets.left + focusInsets.right;
       
   501             d.width += trackRect.width + tickRect.width + labelRect.width;
       
   502         }
       
   503         else {
       
   504             d = new Dimension(getMinimumHorizontalSize());
       
   505             d.height = insetCache.top + insetCache.bottom;
       
   506             d.height += focusInsets.top + focusInsets.bottom;
       
   507             d.height += trackRect.height + tickRect.height + labelRect.height;
       
   508         }
       
   509 
       
   510         return d;
       
   511     }
       
   512 
       
   513     public Dimension getMaximumSize(JComponent c) {
       
   514         Dimension d = getPreferredSize(c);
       
   515         if ( slider.getOrientation() == JSlider.VERTICAL ) {
       
   516             d.height = Short.MAX_VALUE;
       
   517         }
       
   518         else {
       
   519             d.width = Short.MAX_VALUE;
       
   520         }
       
   521 
       
   522         return d;
       
   523     }
       
   524 
       
   525     protected void calculateGeometry() {
       
   526         calculateFocusRect();
       
   527         calculateContentRect();
       
   528         calculateThumbSize();
       
   529         calculateTrackBuffer();
       
   530         calculateTrackRect();
       
   531         calculateTickRect();
       
   532         calculateLabelRect();
       
   533         calculateThumbLocation();
       
   534     }
       
   535 
       
   536     protected void calculateFocusRect() {
       
   537         focusRect.x = insetCache.left;
       
   538         focusRect.y = insetCache.top;
       
   539         focusRect.width = slider.getWidth() - (insetCache.left + insetCache.right);
       
   540         focusRect.height = slider.getHeight() - (insetCache.top + insetCache.bottom);
       
   541     }
       
   542 
       
   543     protected void calculateThumbSize() {
       
   544         Dimension size = getThumbSize();
       
   545         thumbRect.setSize( size.width, size.height );
       
   546     }
       
   547 
       
   548     protected void calculateContentRect() {
       
   549         contentRect.x = focusRect.x + focusInsets.left;
       
   550         contentRect.y = focusRect.y + focusInsets.top;
       
   551         contentRect.width = focusRect.width - (focusInsets.left + focusInsets.right);
       
   552         contentRect.height = focusRect.height - (focusInsets.top + focusInsets.bottom);
       
   553     }
       
   554 
       
   555     protected void calculateThumbLocation() {
       
   556         if ( slider.getSnapToTicks() ) {
       
   557             int sliderValue = slider.getValue();
       
   558             int snappedValue = sliderValue;
       
   559             int majorTickSpacing = slider.getMajorTickSpacing();
       
   560             int minorTickSpacing = slider.getMinorTickSpacing();
       
   561             int tickSpacing = 0;
       
   562 
       
   563             if ( minorTickSpacing > 0 ) {
       
   564                 tickSpacing = minorTickSpacing;
       
   565             }
       
   566             else if ( majorTickSpacing > 0 ) {
       
   567                 tickSpacing = majorTickSpacing;
       
   568             }
       
   569 
       
   570             if ( tickSpacing != 0 ) {
       
   571                 // If it's not on a tick, change the value
       
   572                 if ( (sliderValue - slider.getMinimum()) % tickSpacing != 0 ) {
       
   573                     float temp = (float)(sliderValue - slider.getMinimum()) / (float)tickSpacing;
       
   574                     int whichTick = Math.round( temp );
       
   575 
       
   576                     // This is the fix for the bug #6401380
       
   577                     if (temp - (int)temp == .5 && sliderValue < lastValue) {
       
   578                       whichTick --;
       
   579                     }
       
   580                     snappedValue = slider.getMinimum() + (whichTick * tickSpacing);
       
   581                 }
       
   582 
       
   583                 if( snappedValue != sliderValue ) {
       
   584                     slider.setValue( snappedValue );
       
   585                 }
       
   586             }
       
   587         }
       
   588 
       
   589         if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
       
   590             int valuePosition = xPositionForValue(slider.getValue());
       
   591 
       
   592             thumbRect.x = valuePosition - (thumbRect.width / 2);
       
   593             thumbRect.y = trackRect.y;
       
   594         }
       
   595         else {
       
   596             int valuePosition = yPositionForValue(slider.getValue());
       
   597 
       
   598             thumbRect.x = trackRect.x;
       
   599             thumbRect.y = valuePosition - (thumbRect.height / 2);
       
   600         }
       
   601     }
       
   602 
       
   603     protected void calculateTrackBuffer() {
       
   604         if ( slider.getPaintLabels() && slider.getLabelTable()  != null ) {
       
   605             Component highLabel = getHighestValueLabel();
       
   606             Component lowLabel = getLowestValueLabel();
       
   607 
       
   608             if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
       
   609                 trackBuffer = Math.max( highLabel.getBounds().width, lowLabel.getBounds().width ) / 2;
       
   610                 trackBuffer = Math.max( trackBuffer, thumbRect.width / 2 );
       
   611             }
       
   612             else {
       
   613                 trackBuffer = Math.max( highLabel.getBounds().height, lowLabel.getBounds().height ) / 2;
       
   614                 trackBuffer = Math.max( trackBuffer, thumbRect.height / 2 );
       
   615             }
       
   616         }
       
   617         else {
       
   618             if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
       
   619                 trackBuffer = thumbRect.width / 2;
       
   620             }
       
   621             else {
       
   622                 trackBuffer = thumbRect.height / 2;
       
   623             }
       
   624         }
       
   625     }
       
   626 
       
   627 
       
   628     protected void calculateTrackRect() {
       
   629         int centerSpacing = 0; // used to center sliders added using BorderLayout.CENTER (bug 4275631)
       
   630         if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
       
   631             centerSpacing = thumbRect.height;
       
   632             if ( slider.getPaintTicks() ) centerSpacing += getTickLength();
       
   633             if ( slider.getPaintLabels() ) centerSpacing += getHeightOfTallestLabel();
       
   634             trackRect.x = contentRect.x + trackBuffer;
       
   635             trackRect.y = contentRect.y + (contentRect.height - centerSpacing - 1)/2;
       
   636             trackRect.width = contentRect.width - (trackBuffer * 2);
       
   637             trackRect.height = thumbRect.height;
       
   638         }
       
   639         else {
       
   640             centerSpacing = thumbRect.width;
       
   641             if (BasicGraphicsUtils.isLeftToRight(slider)) {
       
   642                 if ( slider.getPaintTicks() ) centerSpacing += getTickLength();
       
   643                 if ( slider.getPaintLabels() ) centerSpacing += getWidthOfWidestLabel();
       
   644             } else {
       
   645                 if ( slider.getPaintTicks() ) centerSpacing -= getTickLength();
       
   646                 if ( slider.getPaintLabels() ) centerSpacing -= getWidthOfWidestLabel();
       
   647             }
       
   648             trackRect.x = contentRect.x + (contentRect.width - centerSpacing - 1)/2;
       
   649             trackRect.y = contentRect.y + trackBuffer;
       
   650             trackRect.width = thumbRect.width;
       
   651             trackRect.height = contentRect.height - (trackBuffer * 2);
       
   652         }
       
   653 
       
   654     }
       
   655 
       
   656     /**
       
   657      * Gets the height of the tick area for horizontal sliders and the width of the
       
   658      * tick area for vertical sliders.  BasicSliderUI uses the returned value to
       
   659      * determine the tick area rectangle.  If you want to give your ticks some room,
       
   660      * make this larger than you need and paint your ticks away from the sides in paintTicks().
       
   661      */
       
   662     protected int getTickLength() {
       
   663         return 8;
       
   664     }
       
   665 
       
   666     protected void calculateTickRect() {
       
   667         if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
       
   668             tickRect.x = trackRect.x;
       
   669             tickRect.y = trackRect.y + trackRect.height;
       
   670             tickRect.width = trackRect.width;
       
   671             tickRect.height = (slider.getPaintTicks()) ? getTickLength() : 0;
       
   672         }
       
   673         else {
       
   674             tickRect.width = (slider.getPaintTicks()) ? getTickLength() : 0;
       
   675             if(BasicGraphicsUtils.isLeftToRight(slider)) {
       
   676                 tickRect.x = trackRect.x + trackRect.width;
       
   677             }
       
   678             else {
       
   679                 tickRect.x = trackRect.x - tickRect.width;
       
   680             }
       
   681             tickRect.y = trackRect.y;
       
   682             tickRect.height = trackRect.height;
       
   683         }
       
   684     }
       
   685 
       
   686     protected void calculateLabelRect() {
       
   687         if ( slider.getPaintLabels() ) {
       
   688             if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
       
   689                 labelRect.x = tickRect.x - trackBuffer;
       
   690                 labelRect.y = tickRect.y + tickRect.height;
       
   691                 labelRect.width = tickRect.width + (trackBuffer * 2);
       
   692                 labelRect.height = getHeightOfTallestLabel();
       
   693             }
       
   694             else {
       
   695                 if(BasicGraphicsUtils.isLeftToRight(slider)) {
       
   696                     labelRect.x = tickRect.x + tickRect.width;
       
   697                     labelRect.width = getWidthOfWidestLabel();
       
   698                 }
       
   699                 else {
       
   700                     labelRect.width = getWidthOfWidestLabel();
       
   701                     labelRect.x = tickRect.x - labelRect.width;
       
   702                 }
       
   703                 labelRect.y = tickRect.y - trackBuffer;
       
   704                 labelRect.height = tickRect.height + (trackBuffer * 2);
       
   705             }
       
   706         }
       
   707         else {
       
   708             if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
       
   709                 labelRect.x = tickRect.x;
       
   710                 labelRect.y = tickRect.y + tickRect.height;
       
   711                 labelRect.width = tickRect.width;
       
   712                 labelRect.height = 0;
       
   713             }
       
   714             else {
       
   715                 if(BasicGraphicsUtils.isLeftToRight(slider)) {
       
   716                     labelRect.x = tickRect.x + tickRect.width;
       
   717                 }
       
   718                 else {
       
   719                     labelRect.x = tickRect.x;
       
   720                 }
       
   721                 labelRect.y = tickRect.y;
       
   722                 labelRect.width = 0;
       
   723                 labelRect.height = tickRect.height;
       
   724             }
       
   725         }
       
   726     }
       
   727 
       
   728     protected Dimension getThumbSize() {
       
   729         Dimension size = new Dimension();
       
   730 
       
   731         if ( slider.getOrientation() == JSlider.VERTICAL ) {
       
   732             size.width = 20;
       
   733             size.height = 11;
       
   734         }
       
   735         else {
       
   736             size.width = 11;
       
   737             size.height = 20;
       
   738         }
       
   739 
       
   740         return size;
       
   741     }
       
   742 
       
   743     public class PropertyChangeHandler implements PropertyChangeListener {
       
   744         // NOTE: This class exists only for backward compatability. All
       
   745         // its functionality has been moved into Handler. If you need to add
       
   746         // new functionality add it to the Handler, but make sure this
       
   747         // class calls into the Handler.
       
   748         public void propertyChange( PropertyChangeEvent e ) {
       
   749             getHandler().propertyChange(e);
       
   750         }
       
   751     }
       
   752 
       
   753     protected int getWidthOfWidestLabel() {
       
   754         Dictionary dictionary = slider.getLabelTable();
       
   755         int widest = 0;
       
   756         if ( dictionary != null ) {
       
   757             Enumeration keys = dictionary.keys();
       
   758             while ( keys.hasMoreElements() ) {
       
   759                 Component label = (Component)dictionary.get( keys.nextElement() );
       
   760                 widest = Math.max( label.getPreferredSize().width, widest );
       
   761             }
       
   762         }
       
   763         return widest;
       
   764     }
       
   765 
       
   766     protected int getHeightOfTallestLabel() {
       
   767         Dictionary dictionary = slider.getLabelTable();
       
   768         int tallest = 0;
       
   769         if ( dictionary != null ) {
       
   770             Enumeration keys = dictionary.keys();
       
   771             while ( keys.hasMoreElements() ) {
       
   772                 Component label = (Component)dictionary.get( keys.nextElement() );
       
   773                 tallest = Math.max( label.getPreferredSize().height, tallest );
       
   774             }
       
   775         }
       
   776         return tallest;
       
   777     }
       
   778 
       
   779     protected int getWidthOfHighValueLabel() {
       
   780         Component label = getHighestValueLabel();
       
   781         int width = 0;
       
   782 
       
   783         if ( label != null ) {
       
   784             width = label.getPreferredSize().width;
       
   785         }
       
   786 
       
   787         return width;
       
   788     }
       
   789 
       
   790     protected int getWidthOfLowValueLabel() {
       
   791         Component label = getLowestValueLabel();
       
   792         int width = 0;
       
   793 
       
   794         if ( label != null ) {
       
   795             width = label.getPreferredSize().width;
       
   796         }
       
   797 
       
   798         return width;
       
   799     }
       
   800 
       
   801     protected int getHeightOfHighValueLabel() {
       
   802         Component label = getHighestValueLabel();
       
   803         int height = 0;
       
   804 
       
   805         if ( label != null ) {
       
   806             height = label.getPreferredSize().height;
       
   807         }
       
   808 
       
   809         return height;
       
   810     }
       
   811 
       
   812     protected int getHeightOfLowValueLabel() {
       
   813         Component label = getLowestValueLabel();
       
   814         int height = 0;
       
   815 
       
   816         if ( label != null ) {
       
   817             height = label.getPreferredSize().height;
       
   818         }
       
   819 
       
   820         return height;
       
   821     }
       
   822 
       
   823     protected boolean drawInverted() {
       
   824         if (slider.getOrientation()==JSlider.HORIZONTAL) {
       
   825             if(BasicGraphicsUtils.isLeftToRight(slider)) {
       
   826                 return slider.getInverted();
       
   827             } else {
       
   828                 return !slider.getInverted();
       
   829             }
       
   830         } else {
       
   831             return slider.getInverted();
       
   832         }
       
   833     }
       
   834 
       
   835     /**
       
   836      * Returns the biggest value that has an entry in the label table.
       
   837      *
       
   838      * @return biggest value that has an entry in the label table, or
       
   839      *         null.
       
   840      * @since 1.6
       
   841      */
       
   842     protected Integer getHighestValue() {
       
   843         Dictionary dictionary = slider.getLabelTable();
       
   844         if (dictionary != null) {
       
   845             Enumeration keys = dictionary.keys();
       
   846             int max = slider.getMinimum() - 1;
       
   847             while (keys.hasMoreElements()) {
       
   848                 max = Math.max(max, ((Integer)keys.nextElement()).intValue());
       
   849             }
       
   850             if (max == slider.getMinimum() - 1) {
       
   851                 return null;
       
   852             }
       
   853             return max;
       
   854         }
       
   855         return null;
       
   856     }
       
   857 
       
   858     /**
       
   859      * Returns the smallest value that has an entry in the label table.
       
   860      *
       
   861      * @return smallest value that has an entry in the label table, or
       
   862      *         null.
       
   863      * @since 1.6
       
   864      */
       
   865     protected Integer getLowestValue() {
       
   866         Dictionary dictionary = slider.getLabelTable();
       
   867         if (dictionary != null) {
       
   868             Enumeration keys = dictionary.keys();
       
   869             int min = slider.getMaximum() + 1;
       
   870             while (keys.hasMoreElements()) {
       
   871                 min = Math.min(min, ((Integer)keys.nextElement()).intValue());
       
   872             }
       
   873             if (min == slider.getMaximum() + 1) {
       
   874                 return null;
       
   875             }
       
   876             return min;
       
   877         }
       
   878         return null;
       
   879     }
       
   880 
       
   881 
       
   882     /**
       
   883      * Returns the label that corresponds to the highest slider value in the label table.
       
   884      * @see JSlider#setLabelTable
       
   885      */
       
   886     protected Component getLowestValueLabel() {
       
   887         Integer min = getLowestValue();
       
   888         if (min != null) {
       
   889             return (Component)slider.getLabelTable().get(min);
       
   890         }
       
   891         return null;
       
   892     }
       
   893 
       
   894     /**
       
   895      * Returns the label that corresponds to the lowest slider value in the label table.
       
   896      * @see JSlider#setLabelTable
       
   897      */
       
   898     protected Component getHighestValueLabel() {
       
   899         Integer max = getHighestValue();
       
   900         if (max != null) {
       
   901             return (Component)slider.getLabelTable().get(max);
       
   902         }
       
   903         return null;
       
   904     }
       
   905 
       
   906     public void paint( Graphics g, JComponent c )   {
       
   907         recalculateIfInsetsChanged();
       
   908         recalculateIfOrientationChanged();
       
   909         Rectangle clip = g.getClipBounds();
       
   910 
       
   911         if ( !clip.intersects(trackRect) && slider.getPaintTrack())
       
   912             calculateGeometry();
       
   913 
       
   914         if ( slider.getPaintTrack() && clip.intersects( trackRect ) ) {
       
   915             paintTrack( g );
       
   916         }
       
   917         if ( slider.getPaintTicks() && clip.intersects( tickRect ) ) {
       
   918             paintTicks( g );
       
   919         }
       
   920         if ( slider.getPaintLabels() && clip.intersects( labelRect ) ) {
       
   921             paintLabels( g );
       
   922         }
       
   923         if ( slider.hasFocus() && clip.intersects( focusRect ) ) {
       
   924             paintFocus( g );
       
   925         }
       
   926         if ( clip.intersects( thumbRect ) ) {
       
   927             paintThumb( g );
       
   928         }
       
   929     }
       
   930 
       
   931     protected void recalculateIfInsetsChanged() {
       
   932         Insets newInsets = slider.getInsets();
       
   933         if ( !newInsets.equals( insetCache ) ) {
       
   934             insetCache = newInsets;
       
   935             calculateGeometry();
       
   936         }
       
   937     }
       
   938 
       
   939     protected void recalculateIfOrientationChanged() {
       
   940         boolean ltr = BasicGraphicsUtils.isLeftToRight(slider);
       
   941         if ( ltr!=leftToRightCache ) {
       
   942             leftToRightCache = ltr;
       
   943             calculateGeometry();
       
   944         }
       
   945     }
       
   946 
       
   947     public void paintFocus(Graphics g)  {
       
   948         g.setColor( getFocusColor() );
       
   949 
       
   950         BasicGraphicsUtils.drawDashedRect( g, focusRect.x, focusRect.y,
       
   951                                            focusRect.width, focusRect.height );
       
   952     }
       
   953 
       
   954     public void paintTrack(Graphics g)  {
       
   955 
       
   956         Rectangle trackBounds = trackRect;
       
   957 
       
   958         if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
       
   959             int cy = (trackBounds.height / 2) - 2;
       
   960             int cw = trackBounds.width;
       
   961 
       
   962             g.translate(trackBounds.x, trackBounds.y + cy);
       
   963 
       
   964             g.setColor(getShadowColor());
       
   965             g.drawLine(0, 0, cw - 1, 0);
       
   966             g.drawLine(0, 1, 0, 2);
       
   967             g.setColor(getHighlightColor());
       
   968             g.drawLine(0, 3, cw, 3);
       
   969             g.drawLine(cw, 0, cw, 3);
       
   970             g.setColor(Color.black);
       
   971             g.drawLine(1, 1, cw-2, 1);
       
   972 
       
   973             g.translate(-trackBounds.x, -(trackBounds.y + cy));
       
   974         }
       
   975         else {
       
   976             int cx = (trackBounds.width / 2) - 2;
       
   977             int ch = trackBounds.height;
       
   978 
       
   979             g.translate(trackBounds.x + cx, trackBounds.y);
       
   980 
       
   981             g.setColor(getShadowColor());
       
   982             g.drawLine(0, 0, 0, ch - 1);
       
   983             g.drawLine(1, 0, 2, 0);
       
   984             g.setColor(getHighlightColor());
       
   985             g.drawLine(3, 0, 3, ch);
       
   986             g.drawLine(0, ch, 3, ch);
       
   987             g.setColor(Color.black);
       
   988             g.drawLine(1, 1, 1, ch-2);
       
   989 
       
   990             g.translate(-(trackBounds.x + cx), -trackBounds.y);
       
   991         }
       
   992     }
       
   993 
       
   994     public void paintTicks(Graphics g)  {
       
   995         Rectangle tickBounds = tickRect;
       
   996         int i;
       
   997         int maj, min, max;
       
   998         int w = tickBounds.width;
       
   999         int h = tickBounds.height;
       
  1000         int centerEffect, tickHeight;
       
  1001 
       
  1002         g.setColor(DefaultLookup.getColor(slider, this, "Slider.tickColor", Color.black));
       
  1003 
       
  1004         maj = slider.getMajorTickSpacing();
       
  1005         min = slider.getMinorTickSpacing();
       
  1006 
       
  1007         if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
       
  1008            g.translate( 0, tickBounds.y);
       
  1009 
       
  1010             int value = slider.getMinimum();
       
  1011             int xPos = 0;
       
  1012 
       
  1013             if ( slider.getMinorTickSpacing() > 0 ) {
       
  1014                 while ( value <= slider.getMaximum() ) {
       
  1015                     xPos = xPositionForValue( value );
       
  1016                     paintMinorTickForHorizSlider( g, tickBounds, xPos );
       
  1017                     value += slider.getMinorTickSpacing();
       
  1018                 }
       
  1019             }
       
  1020 
       
  1021             if ( slider.getMajorTickSpacing() > 0 ) {
       
  1022                 value = slider.getMinimum();
       
  1023 
       
  1024                 while ( value <= slider.getMaximum() ) {
       
  1025                     xPos = xPositionForValue( value );
       
  1026                     paintMajorTickForHorizSlider( g, tickBounds, xPos );
       
  1027                     value += slider.getMajorTickSpacing();
       
  1028                 }
       
  1029             }
       
  1030 
       
  1031             g.translate( 0, -tickBounds.y);
       
  1032         }
       
  1033         else {
       
  1034            g.translate(tickBounds.x, 0);
       
  1035 
       
  1036             int value = slider.getMinimum();
       
  1037             int yPos = 0;
       
  1038 
       
  1039             if ( slider.getMinorTickSpacing() > 0 ) {
       
  1040                 int offset = 0;
       
  1041                 if(!BasicGraphicsUtils.isLeftToRight(slider)) {
       
  1042                     offset = tickBounds.width - tickBounds.width / 2;
       
  1043                     g.translate(offset, 0);
       
  1044                 }
       
  1045 
       
  1046                 while ( value <= slider.getMaximum() ) {
       
  1047                     yPos = yPositionForValue( value );
       
  1048                     paintMinorTickForVertSlider( g, tickBounds, yPos );
       
  1049                     value += slider.getMinorTickSpacing();
       
  1050                 }
       
  1051 
       
  1052                 if(!BasicGraphicsUtils.isLeftToRight(slider)) {
       
  1053                     g.translate(-offset, 0);
       
  1054                 }
       
  1055             }
       
  1056 
       
  1057             if ( slider.getMajorTickSpacing() > 0 ) {
       
  1058                 value = slider.getMinimum();
       
  1059                 if(!BasicGraphicsUtils.isLeftToRight(slider)) {
       
  1060                     g.translate(2, 0);
       
  1061                 }
       
  1062 
       
  1063                 while ( value <= slider.getMaximum() ) {
       
  1064                     yPos = yPositionForValue( value );
       
  1065                     paintMajorTickForVertSlider( g, tickBounds, yPos );
       
  1066                     value += slider.getMajorTickSpacing();
       
  1067                 }
       
  1068 
       
  1069                 if(!BasicGraphicsUtils.isLeftToRight(slider)) {
       
  1070                     g.translate(-2, 0);
       
  1071                 }
       
  1072             }
       
  1073             g.translate(-tickBounds.x, 0);
       
  1074         }
       
  1075     }
       
  1076 
       
  1077     protected void paintMinorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) {
       
  1078         g.drawLine( x, 0, x, tickBounds.height / 2 - 1 );
       
  1079     }
       
  1080 
       
  1081     protected void paintMajorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) {
       
  1082         g.drawLine( x, 0, x, tickBounds.height - 2 );
       
  1083     }
       
  1084 
       
  1085     protected void paintMinorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) {
       
  1086         g.drawLine( 0, y, tickBounds.width / 2 - 1, y );
       
  1087     }
       
  1088 
       
  1089     protected void paintMajorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) {
       
  1090         g.drawLine( 0, y,  tickBounds.width - 2, y );
       
  1091     }
       
  1092 
       
  1093     public void paintLabels( Graphics g ) {
       
  1094         Rectangle labelBounds = labelRect;
       
  1095 
       
  1096         Dictionary dictionary = slider.getLabelTable();
       
  1097         if ( dictionary != null ) {
       
  1098             Enumeration keys = dictionary.keys();
       
  1099             int minValue = slider.getMinimum();
       
  1100             int maxValue = slider.getMaximum();
       
  1101             boolean enabled = slider.isEnabled();
       
  1102             while ( keys.hasMoreElements() ) {
       
  1103                 Integer key = (Integer)keys.nextElement();
       
  1104                 int value = key.intValue();
       
  1105                 if (value >= minValue && value <= maxValue) {
       
  1106                     Component label = (Component)dictionary.get( key );
       
  1107                     if (label instanceof JComponent) {
       
  1108                         ((JComponent)label).setEnabled(enabled);
       
  1109                     }
       
  1110                     if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
       
  1111                         g.translate( 0, labelBounds.y );
       
  1112                         paintHorizontalLabel( g, value, label );
       
  1113                         g.translate( 0, -labelBounds.y );
       
  1114                     }
       
  1115                     else {
       
  1116                         int offset = 0;
       
  1117                         if (!BasicGraphicsUtils.isLeftToRight(slider)) {
       
  1118                             offset = labelBounds.width -
       
  1119                                 label.getPreferredSize().width;
       
  1120                         }
       
  1121                         g.translate( labelBounds.x + offset, 0 );
       
  1122                         paintVerticalLabel( g, value, label );
       
  1123                         g.translate( -labelBounds.x - offset, 0 );
       
  1124                     }
       
  1125                 }
       
  1126             }
       
  1127         }
       
  1128 
       
  1129     }
       
  1130 
       
  1131     /**
       
  1132      * Called for every label in the label table.  Used to draw the labels for horizontal sliders.
       
  1133      * The graphics have been translated to labelRect.y already.
       
  1134      * @see JSlider#setLabelTable
       
  1135      */
       
  1136     protected void paintHorizontalLabel( Graphics g, int value, Component label ) {
       
  1137         int labelCenter = xPositionForValue( value );
       
  1138         int labelLeft = labelCenter - (label.getPreferredSize().width / 2);
       
  1139         g.translate( labelLeft, 0 );
       
  1140         label.paint( g );
       
  1141         g.translate( -labelLeft, 0 );
       
  1142     }
       
  1143 
       
  1144     /**
       
  1145      * Called for every label in the label table.  Used to draw the labels for vertical sliders.
       
  1146      * The graphics have been translated to labelRect.x already.
       
  1147      * @see JSlider#setLabelTable
       
  1148      */
       
  1149     protected void paintVerticalLabel( Graphics g, int value, Component label ) {
       
  1150         int labelCenter = yPositionForValue( value );
       
  1151         int labelTop = labelCenter - (label.getPreferredSize().height / 2);
       
  1152         g.translate( 0, labelTop );
       
  1153         label.paint( g );
       
  1154         g.translate( 0, -labelTop );
       
  1155     }
       
  1156 
       
  1157     public void paintThumb(Graphics g)  {
       
  1158         Rectangle knobBounds = thumbRect;
       
  1159         int w = knobBounds.width;
       
  1160         int h = knobBounds.height;
       
  1161 
       
  1162         g.translate(knobBounds.x, knobBounds.y);
       
  1163 
       
  1164         if ( slider.isEnabled() ) {
       
  1165             g.setColor(slider.getBackground());
       
  1166         }
       
  1167         else {
       
  1168             g.setColor(slider.getBackground().darker());
       
  1169         }
       
  1170 
       
  1171         Boolean paintThumbArrowShape =
       
  1172             (Boolean)slider.getClientProperty("Slider.paintThumbArrowShape");
       
  1173 
       
  1174         if ((!slider.getPaintTicks() && paintThumbArrowShape == null) ||
       
  1175             paintThumbArrowShape == Boolean.FALSE) {
       
  1176 
       
  1177             // "plain" version
       
  1178             g.fillRect(0, 0, w, h);
       
  1179 
       
  1180             g.setColor(Color.black);
       
  1181             g.drawLine(0, h-1, w-1, h-1);
       
  1182             g.drawLine(w-1, 0, w-1, h-1);
       
  1183 
       
  1184             g.setColor(highlightColor);
       
  1185             g.drawLine(0, 0, 0, h-2);
       
  1186             g.drawLine(1, 0, w-2, 0);
       
  1187 
       
  1188             g.setColor(shadowColor);
       
  1189             g.drawLine(1, h-2, w-2, h-2);
       
  1190             g.drawLine(w-2, 1, w-2, h-3);
       
  1191         }
       
  1192         else if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
       
  1193             int cw = w / 2;
       
  1194             g.fillRect(1, 1, w-3, h-1-cw);
       
  1195             Polygon p = new Polygon();
       
  1196             p.addPoint(1, h-cw);
       
  1197             p.addPoint(cw-1, h-1);
       
  1198             p.addPoint(w-2, h-1-cw);
       
  1199             g.fillPolygon(p);
       
  1200 
       
  1201             g.setColor(highlightColor);
       
  1202             g.drawLine(0, 0, w-2, 0);
       
  1203             g.drawLine(0, 1, 0, h-1-cw);
       
  1204             g.drawLine(0, h-cw, cw-1, h-1);
       
  1205 
       
  1206             g.setColor(Color.black);
       
  1207             g.drawLine(w-1, 0, w-1, h-2-cw);
       
  1208             g.drawLine(w-1, h-1-cw, w-1-cw, h-1);
       
  1209 
       
  1210             g.setColor(shadowColor);
       
  1211             g.drawLine(w-2, 1, w-2, h-2-cw);
       
  1212             g.drawLine(w-2, h-1-cw, w-1-cw, h-2);
       
  1213         }
       
  1214         else {  // vertical
       
  1215             int cw = h / 2;
       
  1216             if(BasicGraphicsUtils.isLeftToRight(slider)) {
       
  1217                   g.fillRect(1, 1, w-1-cw, h-3);
       
  1218                   Polygon p = new Polygon();
       
  1219                   p.addPoint(w-cw-1, 0);
       
  1220                   p.addPoint(w-1, cw);
       
  1221                   p.addPoint(w-1-cw, h-2);
       
  1222                   g.fillPolygon(p);
       
  1223 
       
  1224                   g.setColor(highlightColor);
       
  1225                   g.drawLine(0, 0, 0, h - 2);                  // left
       
  1226                   g.drawLine(1, 0, w-1-cw, 0);                 // top
       
  1227                   g.drawLine(w-cw-1, 0, w-1, cw);              // top slant
       
  1228 
       
  1229                   g.setColor(Color.black);
       
  1230                   g.drawLine(0, h-1, w-2-cw, h-1);             // bottom
       
  1231                   g.drawLine(w-1-cw, h-1, w-1, h-1-cw);        // bottom slant
       
  1232 
       
  1233                   g.setColor(shadowColor);
       
  1234                   g.drawLine(1, h-2, w-2-cw,  h-2 );         // bottom
       
  1235                   g.drawLine(w-1-cw, h-2, w-2, h-cw-1 );     // bottom slant
       
  1236             }
       
  1237             else {
       
  1238                   g.fillRect(5, 1, w-1-cw, h-3);
       
  1239                   Polygon p = new Polygon();
       
  1240                   p.addPoint(cw, 0);
       
  1241                   p.addPoint(0, cw);
       
  1242                   p.addPoint(cw, h-2);
       
  1243                   g.fillPolygon(p);
       
  1244 
       
  1245                   g.setColor(highlightColor);
       
  1246                   g.drawLine(cw-1, 0, w-2, 0);             // top
       
  1247                   g.drawLine(0, cw, cw, 0);                // top slant
       
  1248 
       
  1249                   g.setColor(Color.black);
       
  1250                   g.drawLine(0, h-1-cw, cw, h-1 );         // bottom slant
       
  1251                   g.drawLine(cw, h-1, w-1, h-1);           // bottom
       
  1252 
       
  1253                   g.setColor(shadowColor);
       
  1254                   g.drawLine(cw, h-2, w-2,  h-2 );         // bottom
       
  1255                   g.drawLine(w-1, 1, w-1,  h-2 );          // right
       
  1256             }
       
  1257         }
       
  1258 
       
  1259         g.translate(-knobBounds.x, -knobBounds.y);
       
  1260     }
       
  1261 
       
  1262     // Used exclusively by setThumbLocation()
       
  1263     private static Rectangle unionRect = new Rectangle();
       
  1264 
       
  1265     public void setThumbLocation(int x, int y)  {
       
  1266         unionRect.setBounds( thumbRect );
       
  1267 
       
  1268         thumbRect.setLocation( x, y );
       
  1269 
       
  1270         SwingUtilities.computeUnion( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height, unionRect );
       
  1271         slider.repaint( unionRect.x, unionRect.y, unionRect.width, unionRect.height );
       
  1272     }
       
  1273 
       
  1274     public void scrollByBlock(int direction)    {
       
  1275         synchronized(slider)    {
       
  1276 
       
  1277             int oldValue = slider.getValue();
       
  1278             int blockIncrement =
       
  1279                 (slider.getMaximum() - slider.getMinimum()) / 10;
       
  1280             if (blockIncrement <= 0 &&
       
  1281                 slider.getMaximum() > slider.getMinimum()) {
       
  1282 
       
  1283                 blockIncrement = 1;
       
  1284             }
       
  1285 
       
  1286             int delta = blockIncrement * ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL);
       
  1287             slider.setValue(oldValue + delta);
       
  1288         }
       
  1289     }
       
  1290 
       
  1291     public void scrollByUnit(int direction) {
       
  1292         synchronized(slider)    {
       
  1293 
       
  1294             int oldValue = slider.getValue();
       
  1295             int delta = 1 * ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL);
       
  1296 
       
  1297             slider.setValue(oldValue + delta);
       
  1298         }
       
  1299     }
       
  1300 
       
  1301     /**
       
  1302      * This function is called when a mousePressed was detected in the track, not
       
  1303      * in the thumb.  The default behavior is to scroll by block.  You can
       
  1304      *  override this method to stop it from scrolling or to add additional behavior.
       
  1305      */
       
  1306     protected void scrollDueToClickInTrack( int dir ) {
       
  1307         scrollByBlock( dir );
       
  1308     }
       
  1309 
       
  1310     protected int xPositionForValue( int value )    {
       
  1311         int min = slider.getMinimum();
       
  1312         int max = slider.getMaximum();
       
  1313         int trackLength = trackRect.width;
       
  1314         double valueRange = (double)max - (double)min;
       
  1315         double pixelsPerValue = (double)trackLength / valueRange;
       
  1316         int trackLeft = trackRect.x;
       
  1317         int trackRight = trackRect.x + (trackRect.width - 1);
       
  1318         int xPosition;
       
  1319 
       
  1320         if ( !drawInverted() ) {
       
  1321             xPosition = trackLeft;
       
  1322             xPosition += Math.round( pixelsPerValue * ((double)value - min) );
       
  1323         }
       
  1324         else {
       
  1325             xPosition = trackRight;
       
  1326             xPosition -= Math.round( pixelsPerValue * ((double)value - min) );
       
  1327         }
       
  1328 
       
  1329         xPosition = Math.max( trackLeft, xPosition );
       
  1330         xPosition = Math.min( trackRight, xPosition );
       
  1331 
       
  1332         return xPosition;
       
  1333     }
       
  1334 
       
  1335     protected int yPositionForValue( int value )  {
       
  1336         return yPositionForValue(value, trackRect.y, trackRect.height);
       
  1337     }
       
  1338 
       
  1339     /**
       
  1340      * Returns the y location for the specified value.  No checking is
       
  1341      * done on the arguments.  In particular if <code>trackHeight</code> is
       
  1342      * negative undefined results may occur.
       
  1343      *
       
  1344      * @param value the slider value to get the location for
       
  1345      * @param trackY y-origin of the track
       
  1346      * @param trackHeight the height of the track
       
  1347      * @since 1.6
       
  1348      */
       
  1349     protected int yPositionForValue(int value, int trackY, int trackHeight) {
       
  1350         int min = slider.getMinimum();
       
  1351         int max = slider.getMaximum();
       
  1352         double valueRange = (double)max - (double)min;
       
  1353         double pixelsPerValue = (double)trackHeight / (double)valueRange;
       
  1354         int trackBottom = trackY + (trackHeight - 1);
       
  1355         int yPosition;
       
  1356 
       
  1357         if ( !drawInverted() ) {
       
  1358             yPosition = trackY;
       
  1359             yPosition += Math.round( pixelsPerValue * ((double)max - value ) );
       
  1360         }
       
  1361         else {
       
  1362             yPosition = trackY;
       
  1363             yPosition += Math.round( pixelsPerValue * ((double)value - min) );
       
  1364         }
       
  1365 
       
  1366         yPosition = Math.max( trackY, yPosition );
       
  1367         yPosition = Math.min( trackBottom, yPosition );
       
  1368 
       
  1369         return yPosition;
       
  1370     }
       
  1371 
       
  1372     /**
       
  1373      * Returns a value give a y position.  If yPos is past the track at the top or the
       
  1374      * bottom it will set the value to the min or max of the slider, depending if the
       
  1375      * slider is inverted or not.
       
  1376      */
       
  1377     public int valueForYPosition( int yPos ) {
       
  1378         int value;
       
  1379         final int minValue = slider.getMinimum();
       
  1380         final int maxValue = slider.getMaximum();
       
  1381         final int trackLength = trackRect.height;
       
  1382         final int trackTop = trackRect.y;
       
  1383         final int trackBottom = trackRect.y + (trackRect.height - 1);
       
  1384 
       
  1385         if ( yPos <= trackTop ) {
       
  1386             value = drawInverted() ? minValue : maxValue;
       
  1387         }
       
  1388         else if ( yPos >= trackBottom ) {
       
  1389             value = drawInverted() ? maxValue : minValue;
       
  1390         }
       
  1391         else {
       
  1392             int distanceFromTrackTop = yPos - trackTop;
       
  1393             double valueRange = (double)maxValue - (double)minValue;
       
  1394             double valuePerPixel = valueRange / (double)trackLength;
       
  1395             int valueFromTrackTop = (int)Math.round( distanceFromTrackTop * valuePerPixel );
       
  1396 
       
  1397             value = drawInverted() ? minValue + valueFromTrackTop : maxValue - valueFromTrackTop;
       
  1398         }
       
  1399 
       
  1400         return value;
       
  1401     }
       
  1402 
       
  1403     /**
       
  1404      * Returns a value give an x position.  If xPos is past the track at the left or the
       
  1405      * right it will set the value to the min or max of the slider, depending if the
       
  1406      * slider is inverted or not.
       
  1407      */
       
  1408     public int valueForXPosition( int xPos ) {
       
  1409         int value;
       
  1410         final int minValue = slider.getMinimum();
       
  1411         final int maxValue = slider.getMaximum();
       
  1412         final int trackLength = trackRect.width;
       
  1413         final int trackLeft = trackRect.x;
       
  1414         final int trackRight = trackRect.x + (trackRect.width - 1);
       
  1415 
       
  1416         if ( xPos <= trackLeft ) {
       
  1417             value = drawInverted() ? maxValue : minValue;
       
  1418         }
       
  1419         else if ( xPos >= trackRight ) {
       
  1420             value = drawInverted() ? minValue : maxValue;
       
  1421         }
       
  1422         else {
       
  1423             int distanceFromTrackLeft = xPos - trackLeft;
       
  1424             double valueRange = (double)maxValue - (double)minValue;
       
  1425             double valuePerPixel = valueRange / (double)trackLength;
       
  1426             int valueFromTrackLeft = (int)Math.round( distanceFromTrackLeft * valuePerPixel );
       
  1427 
       
  1428             value = drawInverted() ? maxValue - valueFromTrackLeft :
       
  1429               minValue + valueFromTrackLeft;
       
  1430         }
       
  1431 
       
  1432         return value;
       
  1433     }
       
  1434 
       
  1435 
       
  1436     private class Handler implements ChangeListener,
       
  1437             ComponentListener, FocusListener, PropertyChangeListener {
       
  1438         // Change Handler
       
  1439         public void stateChanged(ChangeEvent e) {
       
  1440             if (!isDragging) {
       
  1441                 calculateThumbLocation();
       
  1442                 slider.repaint();
       
  1443             }
       
  1444             lastValue = slider.getValue();
       
  1445         }
       
  1446 
       
  1447         // Component Handler
       
  1448         public void componentHidden(ComponentEvent e) { }
       
  1449         public void componentMoved(ComponentEvent e) { }
       
  1450         public void componentResized(ComponentEvent e) {
       
  1451             calculateGeometry();
       
  1452             slider.repaint();
       
  1453         }
       
  1454         public void componentShown(ComponentEvent e) { }
       
  1455 
       
  1456         // Focus Handler
       
  1457         public void focusGained(FocusEvent e) { slider.repaint(); }
       
  1458         public void focusLost(FocusEvent e) { slider.repaint(); }
       
  1459 
       
  1460         // Property Change Handler
       
  1461         public void propertyChange(PropertyChangeEvent e) {
       
  1462             String propertyName = e.getPropertyName();
       
  1463             if (propertyName == "orientation" ||
       
  1464                     propertyName == "inverted" ||
       
  1465                     propertyName == "labelTable" ||
       
  1466                     propertyName == "majorTickSpacing" ||
       
  1467                     propertyName == "minorTickSpacing" ||
       
  1468                     propertyName == "paintTicks" ||
       
  1469                     propertyName == "paintTrack" ||
       
  1470                     propertyName == "font" ||
       
  1471                     propertyName == "paintLabels") {
       
  1472                 checkedLabelBaselines = false;
       
  1473                 calculateGeometry();
       
  1474                 slider.repaint();
       
  1475             } else if (propertyName == "componentOrientation") {
       
  1476                 calculateGeometry();
       
  1477                 slider.repaint();
       
  1478                 InputMap km = getInputMap(JComponent.WHEN_FOCUSED, slider);
       
  1479                 SwingUtilities.replaceUIInputMap(slider,
       
  1480                     JComponent.WHEN_FOCUSED, km);
       
  1481             } else if (propertyName == "model") {
       
  1482                 ((BoundedRangeModel)e.getOldValue()).removeChangeListener(
       
  1483                     changeListener);
       
  1484                 ((BoundedRangeModel)e.getNewValue()).addChangeListener(
       
  1485                     changeListener);
       
  1486                 calculateThumbLocation();
       
  1487                 slider.repaint();
       
  1488             }
       
  1489         }
       
  1490     }
       
  1491 
       
  1492     /////////////////////////////////////////////////////////////////////////
       
  1493     /// Model Listener Class
       
  1494     /////////////////////////////////////////////////////////////////////////
       
  1495     /**
       
  1496      * Data model listener.
       
  1497      *
       
  1498      * This class should be treated as a &quot;protected&quot; inner class.
       
  1499      * Instantiate it only within subclasses of <Foo>.
       
  1500      */
       
  1501     public class ChangeHandler implements ChangeListener {
       
  1502         // NOTE: This class exists only for backward compatability. All
       
  1503         // its functionality has been moved into Handler. If you need to add
       
  1504         // new functionality add it to the Handler, but make sure this
       
  1505         // class calls into the Handler.
       
  1506         public void stateChanged(ChangeEvent e) {
       
  1507             getHandler().stateChanged(e);
       
  1508         }
       
  1509     }
       
  1510 
       
  1511     /////////////////////////////////////////////////////////////////////////
       
  1512     /// Track Listener Class
       
  1513     /////////////////////////////////////////////////////////////////////////
       
  1514     /**
       
  1515      * Track mouse movements.
       
  1516      *
       
  1517      * This class should be treated as a &quot;protected&quot; inner class.
       
  1518      * Instantiate it only within subclasses of <Foo>.
       
  1519      */
       
  1520     public class TrackListener extends MouseInputAdapter {
       
  1521         protected transient int offset;
       
  1522         protected transient int currentMouseX, currentMouseY;
       
  1523 
       
  1524         public void mouseReleased(MouseEvent e) {
       
  1525             if (!slider.isEnabled()) {
       
  1526                 return;
       
  1527             }
       
  1528 
       
  1529             offset = 0;
       
  1530             scrollTimer.stop();
       
  1531 
       
  1532             // This is the way we have to determine snap-to-ticks.  It's
       
  1533             // hard to explain but since ChangeEvents don't give us any
       
  1534             // idea what has changed we don't have a way to stop the thumb
       
  1535             // bounds from being recalculated.  Recalculating the thumb
       
  1536             // bounds moves the thumb over the current value (i.e., snapping
       
  1537             // to the ticks).
       
  1538             if (slider.getSnapToTicks() /*|| slider.getSnapToValue()*/ ) {
       
  1539                 isDragging = false;
       
  1540                 slider.setValueIsAdjusting(false);
       
  1541             }
       
  1542             else {
       
  1543                 slider.setValueIsAdjusting(false);
       
  1544                 isDragging = false;
       
  1545             }
       
  1546             slider.repaint();
       
  1547         }
       
  1548 
       
  1549         /**
       
  1550         * If the mouse is pressed above the "thumb" component
       
  1551         * then reduce the scrollbars value by one page ("page up"),
       
  1552         * otherwise increase it by one page.  If there is no
       
  1553         * thumb then page up if the mouse is in the upper half
       
  1554         * of the track.
       
  1555         */
       
  1556         public void mousePressed(MouseEvent e) {
       
  1557             if (!slider.isEnabled()) {
       
  1558                 return;
       
  1559             }
       
  1560 
       
  1561             // We should recalculate geometry just before
       
  1562             // calculation of the thumb movement direction.
       
  1563             // It is important for the case, when JSlider
       
  1564             // is a cell editor in JTable. See 6348946.
       
  1565             calculateGeometry();
       
  1566 
       
  1567             currentMouseX = e.getX();
       
  1568             currentMouseY = e.getY();
       
  1569 
       
  1570             if (slider.isRequestFocusEnabled()) {
       
  1571                 slider.requestFocus();
       
  1572             }
       
  1573 
       
  1574             // Clicked in the Thumb area?
       
  1575             if (thumbRect.contains(currentMouseX, currentMouseY)) {
       
  1576                 switch (slider.getOrientation()) {
       
  1577                 case JSlider.VERTICAL:
       
  1578                     offset = currentMouseY - thumbRect.y;
       
  1579                     break;
       
  1580                 case JSlider.HORIZONTAL:
       
  1581                     offset = currentMouseX - thumbRect.x;
       
  1582                     break;
       
  1583                 }
       
  1584                 isDragging = true;
       
  1585                 return;
       
  1586             }
       
  1587             isDragging = false;
       
  1588             slider.setValueIsAdjusting(true);
       
  1589 
       
  1590             Dimension sbSize = slider.getSize();
       
  1591             int direction = POSITIVE_SCROLL;
       
  1592 
       
  1593             switch (slider.getOrientation()) {
       
  1594             case JSlider.VERTICAL:
       
  1595                 if ( thumbRect.isEmpty() ) {
       
  1596                     int scrollbarCenter = sbSize.height / 2;
       
  1597                     if ( !drawInverted() ) {
       
  1598                         direction = (currentMouseY < scrollbarCenter) ?
       
  1599                             POSITIVE_SCROLL : NEGATIVE_SCROLL;
       
  1600                     }
       
  1601                     else {
       
  1602                         direction = (currentMouseY < scrollbarCenter) ?
       
  1603                             NEGATIVE_SCROLL : POSITIVE_SCROLL;
       
  1604                     }
       
  1605                 }
       
  1606                 else {
       
  1607                     int thumbY = thumbRect.y;
       
  1608                     if ( !drawInverted() ) {
       
  1609                         direction = (currentMouseY < thumbY) ?
       
  1610                             POSITIVE_SCROLL : NEGATIVE_SCROLL;
       
  1611                     }
       
  1612                     else {
       
  1613                         direction = (currentMouseY < thumbY) ?
       
  1614                             NEGATIVE_SCROLL : POSITIVE_SCROLL;
       
  1615                     }
       
  1616                 }
       
  1617                 break;
       
  1618             case JSlider.HORIZONTAL:
       
  1619                 if ( thumbRect.isEmpty() ) {
       
  1620                     int scrollbarCenter = sbSize.width / 2;
       
  1621                     if ( !drawInverted() ) {
       
  1622                         direction = (currentMouseX < scrollbarCenter) ?
       
  1623                             NEGATIVE_SCROLL : POSITIVE_SCROLL;
       
  1624                     }
       
  1625                     else {
       
  1626                         direction = (currentMouseX < scrollbarCenter) ?
       
  1627                             POSITIVE_SCROLL : NEGATIVE_SCROLL;
       
  1628                     }
       
  1629                 }
       
  1630                 else {
       
  1631                     int thumbX = thumbRect.x;
       
  1632                     if ( !drawInverted() ) {
       
  1633                         direction = (currentMouseX < thumbX) ?
       
  1634                             NEGATIVE_SCROLL : POSITIVE_SCROLL;
       
  1635                     }
       
  1636                     else {
       
  1637                         direction = (currentMouseX < thumbX) ?
       
  1638                             POSITIVE_SCROLL : NEGATIVE_SCROLL;
       
  1639                     }
       
  1640                 }
       
  1641                 break;
       
  1642             }
       
  1643 
       
  1644             if (shouldScroll(direction)) {
       
  1645                 scrollDueToClickInTrack(direction);
       
  1646             }
       
  1647             if (shouldScroll(direction)) {
       
  1648                 scrollTimer.stop();
       
  1649                 scrollListener.setDirection(direction);
       
  1650                 scrollTimer.start();
       
  1651             }
       
  1652         }
       
  1653 
       
  1654         public boolean shouldScroll(int direction) {
       
  1655             Rectangle r = thumbRect;
       
  1656             if (slider.getOrientation() == JSlider.VERTICAL) {
       
  1657                 if (drawInverted() ? direction < 0 : direction > 0) {
       
  1658                     if (r.y  <= currentMouseY) {
       
  1659                         return false;
       
  1660                     }
       
  1661                 }
       
  1662                 else if (r.y + r.height >= currentMouseY) {
       
  1663                     return false;
       
  1664                 }
       
  1665             }
       
  1666             else {
       
  1667                 if (drawInverted() ? direction < 0 : direction > 0) {
       
  1668                     if (r.x + r.width  >= currentMouseX) {
       
  1669                         return false;
       
  1670                     }
       
  1671                 }
       
  1672                 else if (r.x <= currentMouseX) {
       
  1673                     return false;
       
  1674                 }
       
  1675             }
       
  1676 
       
  1677             if (direction > 0 && slider.getValue() + slider.getExtent() >=
       
  1678                     slider.getMaximum()) {
       
  1679                 return false;
       
  1680             }
       
  1681             else if (direction < 0 && slider.getValue() <=
       
  1682                     slider.getMinimum()) {
       
  1683                 return false;
       
  1684             }
       
  1685 
       
  1686             return true;
       
  1687         }
       
  1688 
       
  1689         /**
       
  1690         * Set the models value to the position of the top/left
       
  1691         * of the thumb relative to the origin of the track.
       
  1692         */
       
  1693         public void mouseDragged(MouseEvent e) {
       
  1694             int thumbMiddle = 0;
       
  1695 
       
  1696             if (!slider.isEnabled()) {
       
  1697                 return;
       
  1698             }
       
  1699 
       
  1700             currentMouseX = e.getX();
       
  1701             currentMouseY = e.getY();
       
  1702 
       
  1703             if (!isDragging) {
       
  1704                 return;
       
  1705             }
       
  1706 
       
  1707             slider.setValueIsAdjusting(true);
       
  1708 
       
  1709             switch (slider.getOrientation()) {
       
  1710             case JSlider.VERTICAL:
       
  1711                 int halfThumbHeight = thumbRect.height / 2;
       
  1712                 int thumbTop = e.getY() - offset;
       
  1713                 int trackTop = trackRect.y;
       
  1714                 int trackBottom = trackRect.y + (trackRect.height - 1);
       
  1715                 int vMax = yPositionForValue(slider.getMaximum() -
       
  1716                                             slider.getExtent());
       
  1717 
       
  1718                 if (drawInverted()) {
       
  1719                     trackBottom = vMax;
       
  1720                 }
       
  1721                 else {
       
  1722                     trackTop = vMax;
       
  1723                 }
       
  1724                 thumbTop = Math.max(thumbTop, trackTop - halfThumbHeight);
       
  1725                 thumbTop = Math.min(thumbTop, trackBottom - halfThumbHeight);
       
  1726 
       
  1727                 setThumbLocation(thumbRect.x, thumbTop);
       
  1728 
       
  1729                 thumbMiddle = thumbTop + halfThumbHeight;
       
  1730                 slider.setValue( valueForYPosition( thumbMiddle ) );
       
  1731                 break;
       
  1732             case JSlider.HORIZONTAL:
       
  1733                 int halfThumbWidth = thumbRect.width / 2;
       
  1734                 int thumbLeft = e.getX() - offset;
       
  1735                 int trackLeft = trackRect.x;
       
  1736                 int trackRight = trackRect.x + (trackRect.width - 1);
       
  1737                 int hMax = xPositionForValue(slider.getMaximum() -
       
  1738                                             slider.getExtent());
       
  1739 
       
  1740                 if (drawInverted()) {
       
  1741                     trackLeft = hMax;
       
  1742                 }
       
  1743                 else {
       
  1744                     trackRight = hMax;
       
  1745                 }
       
  1746                 thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth);
       
  1747                 thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth);
       
  1748 
       
  1749                 setThumbLocation(thumbLeft, thumbRect.y);
       
  1750 
       
  1751                 thumbMiddle = thumbLeft + halfThumbWidth;
       
  1752                 slider.setValue(valueForXPosition(thumbMiddle));
       
  1753                 break;
       
  1754             default:
       
  1755                 return;
       
  1756             }
       
  1757         }
       
  1758 
       
  1759         public void mouseMoved(MouseEvent e) { }
       
  1760     }
       
  1761 
       
  1762     /**
       
  1763      * Scroll-event listener.
       
  1764      *
       
  1765      * This class should be treated as a &quot;protected&quot; inner class.
       
  1766      * Instantiate it only within subclasses of <Foo>.
       
  1767      */
       
  1768     public class ScrollListener implements ActionListener {
       
  1769         // changed this class to public to avoid bogus IllegalAccessException
       
  1770         // bug in InternetExplorer browser.  It was protected.  Work around
       
  1771         // for 4109432
       
  1772         int direction = POSITIVE_SCROLL;
       
  1773         boolean useBlockIncrement;
       
  1774 
       
  1775         public ScrollListener() {
       
  1776             direction = POSITIVE_SCROLL;
       
  1777             useBlockIncrement = true;
       
  1778         }
       
  1779 
       
  1780         public ScrollListener(int dir, boolean block)   {
       
  1781             direction = dir;
       
  1782             useBlockIncrement = block;
       
  1783         }
       
  1784 
       
  1785         public void setDirection(int direction) {
       
  1786             this.direction = direction;
       
  1787         }
       
  1788 
       
  1789         public void setScrollByBlock(boolean block) {
       
  1790             this.useBlockIncrement = block;
       
  1791         }
       
  1792 
       
  1793         public void actionPerformed(ActionEvent e) {
       
  1794             if (useBlockIncrement) {
       
  1795                 scrollByBlock(direction);
       
  1796             }
       
  1797             else {
       
  1798                 scrollByUnit(direction);
       
  1799             }
       
  1800             if (!trackListener.shouldScroll(direction)) {
       
  1801                 ((Timer)e.getSource()).stop();
       
  1802             }
       
  1803         }
       
  1804     }
       
  1805 
       
  1806     /**
       
  1807      * Listener for resizing events.
       
  1808      * <p>
       
  1809      * This class should be treated as a &quot;protected&quot; inner class.
       
  1810      * Instantiate it only within subclasses of <Foo>.
       
  1811      */
       
  1812     public class ComponentHandler extends ComponentAdapter {
       
  1813         // NOTE: This class exists only for backward compatability. All
       
  1814         // its functionality has been moved into Handler. If you need to add
       
  1815         // new functionality add it to the Handler, but make sure this
       
  1816         // class calls into the Handler.
       
  1817         public void componentResized(ComponentEvent e)  {
       
  1818             getHandler().componentResized(e);
       
  1819         }
       
  1820     };
       
  1821 
       
  1822     /**
       
  1823      * Focus-change listener.
       
  1824      * <p>
       
  1825      * This class should be treated as a &quot;protected&quot; inner class.
       
  1826      * Instantiate it only within subclasses of <Foo>.
       
  1827      */
       
  1828     public class FocusHandler implements FocusListener {
       
  1829         // NOTE: This class exists only for backward compatability. All
       
  1830         // its functionality has been moved into Handler. If you need to add
       
  1831         // new functionality add it to the Handler, but make sure this
       
  1832         // class calls into the Handler.
       
  1833         public void focusGained(FocusEvent e) {
       
  1834             getHandler().focusGained(e);
       
  1835         }
       
  1836 
       
  1837         public void focusLost(FocusEvent e) {
       
  1838             getHandler().focusLost(e);
       
  1839         }
       
  1840     }
       
  1841 
       
  1842     /**
       
  1843      * As of Java 2 platform v1.3 this undocumented class is no longer used.
       
  1844      * The recommended approach to creating bindings is to use a
       
  1845      * combination of an <code>ActionMap</code>, to contain the action,
       
  1846      * and an <code>InputMap</code> to contain the mapping from KeyStroke
       
  1847      * to action description. The InputMap is is usually described in the
       
  1848      * LookAndFeel tables.
       
  1849      * <p>
       
  1850      * Please refer to the key bindings specification for further details.
       
  1851      * <p>
       
  1852      * This class should be treated as a &quot;protected&quot; inner class.
       
  1853      * Instantiate it only within subclasses of <Foo>.
       
  1854      */
       
  1855     public class ActionScroller extends AbstractAction {
       
  1856         // NOTE: This class exists only for backward compatability. All
       
  1857         // its functionality has been moved into Actions. If you need to add
       
  1858         // new functionality add it to the Actions, but make sure this
       
  1859         // class calls into the Actions.
       
  1860         int dir;
       
  1861         boolean block;
       
  1862         JSlider slider;
       
  1863 
       
  1864         public ActionScroller( JSlider slider, int dir, boolean block) {
       
  1865             this.dir = dir;
       
  1866             this.block = block;
       
  1867             this.slider = slider;
       
  1868         }
       
  1869 
       
  1870         public void actionPerformed(ActionEvent e) {
       
  1871             SHARED_ACTION.scroll(slider, BasicSliderUI.this, dir, block);
       
  1872         }
       
  1873 
       
  1874         public boolean isEnabled() {
       
  1875             boolean b = true;
       
  1876             if (slider != null) {
       
  1877                 b = slider.isEnabled();
       
  1878             }
       
  1879             return b;
       
  1880         }
       
  1881 
       
  1882     };
       
  1883 
       
  1884 
       
  1885     /**
       
  1886      * A static version of the above.
       
  1887      */
       
  1888     static class SharedActionScroller extends AbstractAction {
       
  1889         // NOTE: This class exists only for backward compatability. All
       
  1890         // its functionality has been moved into Actions. If you need to add
       
  1891         // new functionality add it to the Actions, but make sure this
       
  1892         // class calls into the Actions.
       
  1893         int dir;
       
  1894         boolean block;
       
  1895 
       
  1896         public SharedActionScroller(int dir, boolean block) {
       
  1897             this.dir = dir;
       
  1898             this.block = block;
       
  1899         }
       
  1900 
       
  1901         public void actionPerformed(ActionEvent evt) {
       
  1902             JSlider slider = (JSlider)evt.getSource();
       
  1903             BasicSliderUI ui = (BasicSliderUI)BasicLookAndFeel.getUIOfType(
       
  1904                     slider.getUI(), BasicSliderUI.class);
       
  1905             if (ui == null) {
       
  1906                 return;
       
  1907             }
       
  1908             SHARED_ACTION.scroll(slider, ui, dir, block);
       
  1909         }
       
  1910     }
       
  1911 
       
  1912     private static class Actions extends UIAction {
       
  1913         public static final String POSITIVE_UNIT_INCREMENT =
       
  1914             "positiveUnitIncrement";
       
  1915         public static final String POSITIVE_BLOCK_INCREMENT =
       
  1916             "positiveBlockIncrement";
       
  1917         public static final String NEGATIVE_UNIT_INCREMENT =
       
  1918             "negativeUnitIncrement";
       
  1919         public static final String NEGATIVE_BLOCK_INCREMENT =
       
  1920             "negativeBlockIncrement";
       
  1921         public static final String MIN_SCROLL_INCREMENT = "minScroll";
       
  1922         public static final String MAX_SCROLL_INCREMENT = "maxScroll";
       
  1923 
       
  1924 
       
  1925         Actions() {
       
  1926             super(null);
       
  1927         }
       
  1928 
       
  1929         public Actions(String name) {
       
  1930             super(name);
       
  1931         }
       
  1932 
       
  1933         public void actionPerformed(ActionEvent evt) {
       
  1934             JSlider slider = (JSlider)evt.getSource();
       
  1935             BasicSliderUI ui = (BasicSliderUI)BasicLookAndFeel.getUIOfType(
       
  1936                      slider.getUI(), BasicSliderUI.class);
       
  1937             String name = getName();
       
  1938 
       
  1939             if (ui == null) {
       
  1940                 return;
       
  1941             }
       
  1942             if (POSITIVE_UNIT_INCREMENT == name) {
       
  1943                 scroll(slider, ui, POSITIVE_SCROLL, false);
       
  1944             } else if (NEGATIVE_UNIT_INCREMENT == name) {
       
  1945                 scroll(slider, ui, NEGATIVE_SCROLL, false);
       
  1946             } else if (POSITIVE_BLOCK_INCREMENT == name) {
       
  1947                 scroll(slider, ui, POSITIVE_SCROLL, true);
       
  1948             } else if (NEGATIVE_BLOCK_INCREMENT == name) {
       
  1949                 scroll(slider, ui, NEGATIVE_SCROLL, true);
       
  1950             } else if (MIN_SCROLL_INCREMENT == name) {
       
  1951                 scroll(slider, ui, MIN_SCROLL, false);
       
  1952             } else if (MAX_SCROLL_INCREMENT == name) {
       
  1953                 scroll(slider, ui, MAX_SCROLL, false);
       
  1954             }
       
  1955         }
       
  1956 
       
  1957         private void scroll(JSlider slider, BasicSliderUI ui, int direction,
       
  1958                 boolean isBlock) {
       
  1959             boolean invert = slider.getInverted();
       
  1960 
       
  1961             if (direction == NEGATIVE_SCROLL || direction == POSITIVE_SCROLL) {
       
  1962                 if (invert) {
       
  1963                     direction = (direction == POSITIVE_SCROLL) ?
       
  1964                         NEGATIVE_SCROLL : POSITIVE_SCROLL;
       
  1965                 }
       
  1966 
       
  1967                 if (isBlock) {
       
  1968                     ui.scrollByBlock(direction);
       
  1969                 } else {
       
  1970                     ui.scrollByUnit(direction);
       
  1971                 }
       
  1972             } else {  // MIN or MAX
       
  1973                 if (invert) {
       
  1974                     direction = (direction == MIN_SCROLL) ?
       
  1975                         MAX_SCROLL : MIN_SCROLL;
       
  1976                 }
       
  1977 
       
  1978                 slider.setValue((direction == MIN_SCROLL) ?
       
  1979                     slider.getMinimum() : slider.getMaximum());
       
  1980             }
       
  1981         }
       
  1982     }
       
  1983 }