KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > plaf > basic > BasicSliderUI


1 /*
2  * @(#)BasicSliderUI.java 1.100 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.swing.plaf.basic;
9
10 import java.awt.Component JavaDoc;
11 import java.awt.Container JavaDoc;
12 import java.awt.Adjustable JavaDoc;
13 import java.awt.event.*;
14 import java.awt.Graphics JavaDoc;
15 import java.awt.Dimension JavaDoc;
16 import java.awt.Rectangle JavaDoc;
17 import java.awt.Point JavaDoc;
18 import java.awt.Insets JavaDoc;
19 import java.awt.Color JavaDoc;
20 import java.awt.IllegalComponentStateException JavaDoc;
21 import java.awt.Polygon JavaDoc;
22 import java.beans.*;
23 import java.util.Dictionary JavaDoc;
24 import java.util.Enumeration JavaDoc;
25
26 import javax.swing.border.AbstractBorder JavaDoc;
27
28 import javax.swing.*;
29 import javax.swing.event.*;
30 import javax.swing.plaf.*;
31 import sun.swing.DefaultLookup;
32 import sun.swing.UIAction;
33
34
35 /**
36  * A Basic L&F implementation of SliderUI.
37  *
38  * @version 1.100 12/19/03
39  * @author Tom Santos
40  */

41 public class BasicSliderUI extends SliderUI{
42     // Old actions forward to an instance of this.
43
private static final Actions SHARED_ACTION = new Actions();
44
45     public static final int POSITIVE_SCROLL = +1;
46     public static final int NEGATIVE_SCROLL = -1;
47     public static final int MIN_SCROLL = -2;
48     public static final int MAX_SCROLL = +2;
49
50     protected Timer scrollTimer;
51     protected JSlider slider;
52
53     protected Insets JavaDoc focusInsets = null;
54     protected Insets JavaDoc insetCache = null;
55     protected boolean leftToRightCache = true;
56     protected Rectangle JavaDoc focusRect = null;
57     protected Rectangle JavaDoc contentRect = null;
58     protected Rectangle JavaDoc labelRect = null;
59     protected Rectangle JavaDoc tickRect = null;
60     protected Rectangle JavaDoc trackRect = null;
61     protected Rectangle JavaDoc thumbRect = null;
62
63     protected int trackBuffer = 0; // The distance that the track is from the side of the control
64

65     private transient boolean isDragging;
66
67     protected TrackListener trackListener;
68     protected ChangeListener changeListener;
69     protected ComponentListener componentListener;
70     protected FocusListener focusListener;
71     protected ScrollListener scrollListener;
72     protected PropertyChangeListener propertyChangeListener;
73     private Handler handler;
74
75     // Colors
76
private Color JavaDoc shadowColor;
77     private Color JavaDoc highlightColor;
78     private Color JavaDoc focusColor;
79
80
81     protected Color JavaDoc getShadowColor() {
82         return shadowColor;
83     }
84
85     protected Color JavaDoc getHighlightColor() {
86         return highlightColor;
87     }
88
89     protected Color JavaDoc getFocusColor() {
90         return focusColor;
91     }
92
93     /**
94      * Returns true if the user is dragging the slider.
95      *
96      * @return true if the user is dragging the slider
97      * @since 1.5
98      */

99     protected boolean isDragging() {
100         return isDragging;
101     }
102
103     /////////////////////////////////////////////////////////////////////////////
104
// ComponentUI Interface Implementation methods
105
/////////////////////////////////////////////////////////////////////////////
106
public static ComponentUI createUI(JComponent b) {
107         return new BasicSliderUI JavaDoc((JSlider)b);
108     }
109
110     public BasicSliderUI(JSlider b) {
111     }
112
113     public void installUI(JComponent c) {
114         slider = (JSlider) c;
115
116         slider.setEnabled(slider.isEnabled());
117         LookAndFeel.installProperty(slider, "opaque", Boolean.TRUE);
118
119         isDragging = false;
120         trackListener = createTrackListener( slider );
121         changeListener = createChangeListener( slider );
122         componentListener = createComponentListener( slider );
123         focusListener = createFocusListener( slider );
124         scrollListener = createScrollListener( slider );
125     propertyChangeListener = createPropertyChangeListener( slider );
126
127     installDefaults( slider );
128     installListeners( slider );
129     installKeyboardActions( slider );
130
131         scrollTimer = new Timer( 100, scrollListener );
132         scrollTimer.setInitialDelay( 300 );
133
134     insetCache = slider.getInsets();
135     leftToRightCache = BasicGraphicsUtils.isLeftToRight(slider);
136     focusRect = new Rectangle JavaDoc();
137     contentRect = new Rectangle JavaDoc();
138     labelRect = new Rectangle JavaDoc();
139     tickRect = new Rectangle JavaDoc();
140     trackRect = new Rectangle JavaDoc();
141     thumbRect = new Rectangle JavaDoc();
142
143     calculateGeometry(); // This figures out where the labels, ticks, track, and thumb are.
144
}
145
146     public void uninstallUI(JComponent c) {
147         if ( c != slider )
148             throw new IllegalComponentStateException JavaDoc(
149                                                     this + " was asked to deinstall() "
150                                                     + c + " when it only knows about "
151                                                     + slider + ".");
152
153         LookAndFeel.uninstallBorder(slider);
154
155         scrollTimer.stop();
156         scrollTimer = null;
157
158     uninstallListeners( slider );
159     uninstallKeyboardActions(slider);
160
161     focusInsets = null;
162     insetCache = null;
163     leftToRightCache = true;
164     focusRect = null;
165     contentRect = null;
166     labelRect = null;
167     tickRect = null;
168     trackRect = null;
169         thumbRect = null;
170         trackListener = null;
171         changeListener = null;
172         componentListener = null;
173         focusListener = null;
174         scrollListener = null;
175     propertyChangeListener = null;
176         slider = null;
177     }
178
179     protected void installDefaults( JSlider slider ) {
180         LookAndFeel.installBorder(slider, "Slider.border");
181         LookAndFeel.installColors(slider, "Slider.background", "Slider.foreground");
182         highlightColor = UIManager.getColor("Slider.highlight");
183
184         shadowColor = UIManager.getColor("Slider.shadow");
185         focusColor = UIManager.getColor("Slider.focus");
186
187     focusInsets = (Insets JavaDoc)UIManager.get( "Slider.focusInsets" );
188     }
189
190     protected TrackListener createTrackListener(JSlider slider) {
191         return new TrackListener();
192     }
193
194     protected ChangeListener createChangeListener(JSlider slider) {
195         return getHandler();
196     }
197
198     protected ComponentListener createComponentListener(JSlider slider) {
199         return getHandler();
200     }
201
202     protected FocusListener createFocusListener(JSlider slider) {
203         return getHandler();
204     }
205
206     protected ScrollListener createScrollListener( JSlider slider ) {
207         return new ScrollListener();
208     }
209
210     protected PropertyChangeListener createPropertyChangeListener(
211             JSlider slider) {
212         return getHandler();
213     }
214
215     private Handler getHandler() {
216         if (handler == null) {
217             handler = new Handler();
218         }
219         return handler;
220     }
221
222     protected void installListeners( JSlider slider ) {
223         slider.addMouseListener(trackListener);
224         slider.addMouseMotionListener(trackListener);
225         slider.addFocusListener(focusListener);
226         slider.addComponentListener(componentListener);
227         slider.addPropertyChangeListener( propertyChangeListener );
228         slider.getModel().addChangeListener(changeListener);
229     }
230
231     protected void uninstallListeners( JSlider slider ) {
232         slider.removeMouseListener(trackListener);
233         slider.removeMouseMotionListener(trackListener);
234         slider.removeFocusListener(focusListener);
235         slider.removeComponentListener(componentListener);
236         slider.removePropertyChangeListener( propertyChangeListener );
237         slider.getModel().removeChangeListener(changeListener);
238         handler = null;
239     }
240
241     protected void installKeyboardActions( JSlider slider ) {
242     InputMap km = getInputMap(JComponent.WHEN_FOCUSED, slider);
243     SwingUtilities.replaceUIInputMap(slider, JComponent.WHEN_FOCUSED, km);
244         LazyActionMap.installLazyActionMap(slider, BasicSliderUI JavaDoc.class,
245                 "Slider.actionMap");
246     }
247
248     InputMap getInputMap(int condition, JSlider slider) {
249         if (condition == JComponent.WHEN_FOCUSED) {
250             InputMap keyMap = (InputMap)DefaultLookup.get(slider, this,
251                   "Slider.focusInputMap");
252             InputMap rtlKeyMap;
253
254             if (slider.getComponentOrientation().isLeftToRight() ||
255                 ((rtlKeyMap = (InputMap)DefaultLookup.get(slider, this,
256                           "Slider.focusInputMap.RightToLeft")) == null)) {
257                 return keyMap;
258             } else {
259                 rtlKeyMap.setParent(keyMap);
260                 return rtlKeyMap;
261             }
262         }
263         return null;
264     }
265
266     /**
267      * Populates ComboBox's actions.
268      */

269     static void loadActionMap(LazyActionMap JavaDoc map) {
270         map.put(new Actions(Actions.POSITIVE_UNIT_INCREMENT));
271         map.put(new Actions(Actions.POSITIVE_BLOCK_INCREMENT));
272         map.put(new Actions(Actions.NEGATIVE_UNIT_INCREMENT));
273         map.put(new Actions(Actions.NEGATIVE_BLOCK_INCREMENT));
274         map.put(new Actions(Actions.MIN_SCROLL_INCREMENT));
275         map.put(new Actions(Actions.MAX_SCROLL_INCREMENT));
276     }
277
278     protected void uninstallKeyboardActions( JSlider slider ) {
279     SwingUtilities.replaceUIActionMap(slider, null);
280     SwingUtilities.replaceUIInputMap(slider, JComponent.WHEN_FOCUSED,
281                      null);
282     }
283
284     public Dimension JavaDoc getPreferredHorizontalSize() {
285         Dimension JavaDoc horizDim = (Dimension JavaDoc)DefaultLookup.get(slider,
286                 this, "Slider.horizontalSize");
287         if (horizDim == null) {
288             horizDim = new Dimension JavaDoc(200, 21);
289         }
290         return horizDim;
291     }
292
293     public Dimension JavaDoc getPreferredVerticalSize() {
294         Dimension JavaDoc vertDim = (Dimension JavaDoc)DefaultLookup.get(slider,
295                 this, "Slider.verticalSize");
296         if (vertDim == null) {
297             vertDim = new Dimension JavaDoc(21, 200);
298         }
299         return vertDim;
300     }
301
302     public Dimension JavaDoc getMinimumHorizontalSize() {
303         Dimension JavaDoc minHorizDim = (Dimension JavaDoc)DefaultLookup.get(slider,
304                 this, "Slider.minimumHorizontalSize");
305         if (minHorizDim == null) {
306             minHorizDim = new Dimension JavaDoc(36, 21);
307         }
308         return minHorizDim;
309     }
310
311     public Dimension JavaDoc getMinimumVerticalSize() {
312         Dimension JavaDoc minVertDim = (Dimension JavaDoc)DefaultLookup.get(slider,
313                 this, "Slider.minimumVerticalSize");
314         if (minVertDim == null) {
315             minVertDim = new Dimension JavaDoc(21, 36);
316         }
317         return minVertDim;
318     }
319
320     public Dimension JavaDoc getPreferredSize(JComponent c) {
321         recalculateIfInsetsChanged();
322         Dimension JavaDoc d;
323         if ( slider.getOrientation() == JSlider.VERTICAL ) {
324             d = new Dimension JavaDoc(getPreferredVerticalSize());
325         d.width = insetCache.left + insetCache.right;
326         d.width += focusInsets.left + focusInsets.right;
327         d.width += trackRect.width + tickRect.width + labelRect.width;
328         }
329         else {
330             d = new Dimension JavaDoc(getPreferredHorizontalSize());
331         d.height = insetCache.top + insetCache.bottom;
332         d.height += focusInsets.top + focusInsets.bottom;
333         d.height += trackRect.height + tickRect.height + labelRect.height;
334         }
335
336         return d;
337     }
338
339     public Dimension JavaDoc getMinimumSize(JComponent c) {
340         recalculateIfInsetsChanged();
341         Dimension JavaDoc d;
342
343         if ( slider.getOrientation() == JSlider.VERTICAL ) {
344             d = new Dimension JavaDoc(getMinimumVerticalSize());
345         d.width = insetCache.left + insetCache.right;
346         d.width += focusInsets.left + focusInsets.right;
347         d.width += trackRect.width + tickRect.width + labelRect.width;
348         }
349         else {
350             d = new Dimension JavaDoc(getMinimumHorizontalSize());
351         d.height = insetCache.top + insetCache.bottom;
352         d.height += focusInsets.top + focusInsets.bottom;
353         d.height += trackRect.height + tickRect.height + labelRect.height;
354         }
355
356         return d;
357     }
358
359     public Dimension JavaDoc getMaximumSize(JComponent c) {
360         Dimension JavaDoc d = getPreferredSize(c);
361         if ( slider.getOrientation() == JSlider.VERTICAL ) {
362             d.height = Short.MAX_VALUE;
363         }
364         else {
365             d.width = Short.MAX_VALUE;
366         }
367
368         return d;
369     }
370
371     protected void calculateGeometry() {
372         calculateFocusRect();
373         calculateContentRect();
374     calculateThumbSize();
375     calculateTrackBuffer();
376     calculateTrackRect();
377     calculateTickRect();
378     calculateLabelRect();
379     calculateThumbLocation();
380     }
381   
382     protected void calculateFocusRect() {
383         focusRect.x = insetCache.left;
384     focusRect.y = insetCache.top;
385     focusRect.width = slider.getWidth() - (insetCache.left + insetCache.right);
386     focusRect.height = slider.getHeight() - (insetCache.top + insetCache.bottom);
387     }
388   
389     protected void calculateThumbSize() {
390     Dimension JavaDoc size = getThumbSize();
391     thumbRect.setSize( size.width, size.height );
392     }
393   
394     protected void calculateContentRect() {
395         contentRect.x = focusRect.x + focusInsets.left;
396         contentRect.y = focusRect.y + focusInsets.top;
397         contentRect.width = focusRect.width - (focusInsets.left + focusInsets.right);
398         contentRect.height = focusRect.height - (focusInsets.top + focusInsets.bottom);
399     }
400
401     protected void calculateThumbLocation() {
402         if ( slider.getSnapToTicks() ) {
403         int sliderValue = slider.getValue();
404         int snappedValue = sliderValue;
405         int majorTickSpacing = slider.getMajorTickSpacing();
406         int minorTickSpacing = slider.getMinorTickSpacing();
407         int tickSpacing = 0;
408         
409         if ( minorTickSpacing > 0 ) {
410             tickSpacing = minorTickSpacing;
411         }
412         else if ( majorTickSpacing > 0 ) {
413             tickSpacing = majorTickSpacing;
414         }
415
416         if ( tickSpacing != 0 ) {
417             // If it's not on a tick, change the value
418
if ( (sliderValue - slider.getMinimum()) % tickSpacing != 0 ) {
419             float temp = (float)(sliderValue - slider.getMinimum()) / (float)tickSpacing;
420             int whichTick = Math.round( temp );
421             snappedValue = slider.getMinimum() + (whichTick * tickSpacing);
422         }
423         
424         if( snappedValue != sliderValue ) {
425             slider.setValue( snappedValue );
426         }
427         }
428     }
429     
430         if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
431             int valuePosition = xPositionForValue(slider.getValue());
432
433         thumbRect.x = valuePosition - (thumbRect.width / 2);
434         thumbRect.y = trackRect.y;
435         }
436         else {
437             int valuePosition = yPositionForValue(slider.getValue());
438         
439         thumbRect.x = trackRect.x;
440         thumbRect.y = valuePosition - (thumbRect.height / 2);
441         }
442     }
443
444     protected void calculateTrackBuffer() {
445         if ( slider.getPaintLabels() && slider.getLabelTable() != null ) {
446             Component JavaDoc highLabel = getHighestValueLabel();
447             Component JavaDoc lowLabel = getLowestValueLabel();
448
449             if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
450                 trackBuffer = Math.max( highLabel.getBounds().width, lowLabel.getBounds().width ) / 2;
451                 trackBuffer = Math.max( trackBuffer, thumbRect.width / 2 );
452             }
453             else {
454                 trackBuffer = Math.max( highLabel.getBounds().height, lowLabel.getBounds().height ) / 2;
455                 trackBuffer = Math.max( trackBuffer, thumbRect.height / 2 );
456             }
457         }
458         else {
459             if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
460                 trackBuffer = thumbRect.width / 2;
461             }
462             else {
463                 trackBuffer = thumbRect.height / 2;
464             }
465         }
466     }
467
468   
469     protected void calculateTrackRect() {
470     int centerSpacing = 0; // used to center sliders added using BorderLayout.CENTER (bug 4275631)
471
if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
472         centerSpacing = thumbRect.height;
473         if ( slider.getPaintTicks() ) centerSpacing += getTickLength();
474         if ( slider.getPaintLabels() ) centerSpacing += getHeightOfTallestLabel();
475         trackRect.x = contentRect.x + trackBuffer;
476         trackRect.y = contentRect.y + (contentRect.height - centerSpacing - 1)/2;
477         trackRect.width = contentRect.width - (trackBuffer * 2);
478         trackRect.height = thumbRect.height;
479     }
480     else {
481         centerSpacing = thumbRect.width;
482         if (BasicGraphicsUtils.isLeftToRight(slider)) {
483         if ( slider.getPaintTicks() ) centerSpacing += getTickLength();
484             if ( slider.getPaintLabels() ) centerSpacing += getWidthOfWidestLabel();
485         } else {
486             if ( slider.getPaintTicks() ) centerSpacing -= getTickLength();
487             if ( slider.getPaintLabels() ) centerSpacing -= getWidthOfWidestLabel();
488         }
489         trackRect.x = contentRect.x + (contentRect.width - centerSpacing - 1)/2;
490         trackRect.y = contentRect.y + trackBuffer;
491         trackRect.width = thumbRect.width;
492         trackRect.height = contentRect.height - (trackBuffer * 2);
493     }
494
495     }
496
497     /**
498      * Gets the height of the tick area for horizontal sliders and the width of the
499      * tick area for vertical sliders. BasicSliderUI uses the returned value to
500      * determine the tick area rectangle. If you want to give your ticks some room,
501      * make this larger than you need and paint your ticks away from the sides in paintTicks().
502      */

503     protected int getTickLength() {
504         return 8;
505     }
506
507     protected void calculateTickRect() {
508     if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
509         tickRect.x = trackRect.x;
510         tickRect.y = trackRect.y + trackRect.height;
511         tickRect.width = trackRect.width;
512         tickRect.height = getTickLength();
513         
514         if ( !slider.getPaintTicks() ) {
515             --tickRect.y;
516         tickRect.height = 0;
517         }
518     }
519     else {
520         if(BasicGraphicsUtils.isLeftToRight(slider)) {
521             tickRect.x = trackRect.x + trackRect.width;
522         tickRect.width = getTickLength();
523         }
524         else {
525             tickRect.width = getTickLength();
526             tickRect.x = trackRect.x - tickRect.width;
527         }
528         tickRect.y = trackRect.y;
529         tickRect.height = trackRect.height;
530
531         if ( !slider.getPaintTicks() ) {
532             --tickRect.x;
533         tickRect.width = 0;
534         }
535     }
536     }
537
538     protected void calculateLabelRect() {
539         if ( slider.getPaintLabels() ) {
540         if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
541             labelRect.x = tickRect.x - trackBuffer;
542         labelRect.y = tickRect.y + tickRect.height;
543         labelRect.width = tickRect.width + (trackBuffer * 2);
544                 labelRect.height = getHeightOfTallestLabel();
545             }
546             else {
547             if(BasicGraphicsUtils.isLeftToRight(slider)) {
548             labelRect.x = tickRect.x + tickRect.width;
549             labelRect.width = getWidthOfWidestLabel();
550         }
551         else {
552             labelRect.width = getWidthOfWidestLabel();
553             labelRect.x = tickRect.x - labelRect.width;
554         }
555         labelRect.y = tickRect.y - trackBuffer;
556         labelRect.height = tickRect.height + (trackBuffer * 2);
557             }
558         }
559         else {
560             if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
561             labelRect.x = tickRect.x;
562         labelRect.y = tickRect.y + tickRect.height;
563         labelRect.width = tickRect.width;
564         labelRect.height = 0;
565             }
566             else {
567             if(BasicGraphicsUtils.isLeftToRight(slider)) {
568             labelRect.x = tickRect.x + tickRect.width;
569         }
570         else {
571             labelRect.x = tickRect.x;
572         }
573         labelRect.y = tickRect.y;
574         labelRect.width = 0;
575         labelRect.height = tickRect.height;
576             }
577         }
578     }
579
580     protected Dimension JavaDoc getThumbSize() {
581         Dimension JavaDoc size = new Dimension JavaDoc();
582
583         if ( slider.getOrientation() == JSlider.VERTICAL ) {
584         size.width = 20;
585         size.height = 11;
586     }
587     else {
588         size.width = 11;
589         size.height = 20;
590     }
591
592     return size;
593     }
594
595     public class PropertyChangeHandler implements PropertyChangeListener {
596         // NOTE: This class exists only for backward compatability. All
597
// its functionality has been moved into Handler. If you need to add
598
// new functionality add it to the Handler, but make sure this
599
// class calls into the Handler.
600
public void propertyChange( PropertyChangeEvent e ) {
601             getHandler().propertyChange(e);
602         }
603     }
604
605     protected int getWidthOfWidestLabel() {
606         Dictionary JavaDoc dictionary = slider.getLabelTable();
607         int widest = 0;
608         if ( dictionary != null ) {
609             Enumeration JavaDoc keys = dictionary.keys();
610             while ( keys.hasMoreElements() ) {
611                 Component JavaDoc label = (Component JavaDoc)dictionary.get( keys.nextElement() );
612                 widest = Math.max( label.getPreferredSize().width, widest );
613             }
614         }
615         return widest;
616     }
617
618     protected int getHeightOfTallestLabel() {
619         Dictionary JavaDoc dictionary = slider.getLabelTable();
620         int tallest = 0;
621         if ( dictionary != null ) {
622             Enumeration JavaDoc keys = dictionary.keys();
623             while ( keys.hasMoreElements() ) {
624                 Component JavaDoc label = (Component JavaDoc)dictionary.get( keys.nextElement() );
625                 tallest = Math.max( label.getPreferredSize().height, tallest );
626             }
627         }
628         return tallest;
629     }
630
631     protected int getWidthOfHighValueLabel() {
632         Component JavaDoc label = getHighestValueLabel();
633         int width = 0;
634
635         if ( label != null ) {
636             width = label.getPreferredSize().width;
637         }
638
639         return width;
640     }
641
642     protected int getWidthOfLowValueLabel() {
643         Component JavaDoc label = getLowestValueLabel();
644         int width = 0;
645
646         if ( label != null ) {
647             width = label.getPreferredSize().width;
648         }
649
650         return width;
651     }
652
653     protected int getHeightOfHighValueLabel() {
654         Component JavaDoc label = getHighestValueLabel();
655         int height = 0;
656
657         if ( label != null ) {
658             height = label.getPreferredSize().height;
659         }
660
661         return height;
662     }
663
664     protected int getHeightOfLowValueLabel() {
665         Component JavaDoc label = getLowestValueLabel();
666         int height = 0;
667
668         if ( label != null ) {
669             height = label.getPreferredSize().height;
670         }
671
672         return height;
673     }
674
675     protected boolean drawInverted() {
676         if (slider.getOrientation()==JSlider.HORIZONTAL) {
677         if(BasicGraphicsUtils.isLeftToRight(slider)) {
678             return slider.getInverted();
679         } else {
680             return !slider.getInverted();
681         }
682     } else {
683         return slider.getInverted();
684     }
685     }
686
687     /**
688      * Returns the label that corresponds to the highest slider value in the label table.
689      * @see JSlider#setLabelTable
690      */

691     protected Component JavaDoc getLowestValueLabel() {
692         Dictionary JavaDoc dictionary = slider.getLabelTable();
693         Component JavaDoc label = null;
694
695         if ( dictionary != null ) {
696             Enumeration JavaDoc keys = dictionary.keys();
697             if ( keys.hasMoreElements() ) {
698                 int lowestValue = ((Integer JavaDoc)keys.nextElement()).intValue();
699
700                 while ( keys.hasMoreElements() ) {
701                     int value = ((Integer JavaDoc)keys.nextElement()).intValue();
702                     lowestValue = Math.min( value, lowestValue );
703                 }
704
705                 label = (Component JavaDoc)dictionary.get( new Integer JavaDoc( lowestValue ) );
706             }
707         }
708
709         return label;
710     }
711
712     /**
713      * Returns the label that corresponds to the lowest slider value in the label table.
714      * @see JSlider#setLabelTable
715      */

716     protected Component JavaDoc getHighestValueLabel() {
717         Dictionary JavaDoc dictionary = slider.getLabelTable();
718         Component JavaDoc label = null;
719
720         if ( dictionary != null ) {
721             Enumeration JavaDoc keys = dictionary.keys();
722             if ( keys.hasMoreElements() ) {
723                 int highestValue = ((Integer JavaDoc)keys.nextElement()).intValue();
724
725                 while ( keys.hasMoreElements() ) {
726                     int value = ((Integer JavaDoc)keys.nextElement()).intValue();
727                     highestValue = Math.max( value, highestValue );
728                 }
729
730                 label = (Component JavaDoc)dictionary.get( new Integer JavaDoc( highestValue ) );
731             }
732         }
733
734         return label;
735     }
736
737     public void paint( Graphics JavaDoc g, JComponent c ) {
738         recalculateIfInsetsChanged();
739     recalculateIfOrientationChanged();
740     Rectangle JavaDoc clip = g.getClipBounds();
741
742     if ( !clip.intersects(trackRect) && slider.getPaintTrack())
743         calculateGeometry();
744
745     if ( slider.getPaintTrack() && clip.intersects( trackRect ) ) {
746         paintTrack( g );
747     }
748         if ( slider.getPaintTicks() && clip.intersects( tickRect ) ) {
749             paintTicks( g );
750         }
751         if ( slider.getPaintLabels() && clip.intersects( labelRect ) ) {
752             paintLabels( g );
753         }
754     if ( slider.hasFocus() && clip.intersects( focusRect ) ) {
755         paintFocus( g );
756     }
757     if ( clip.intersects( thumbRect ) ) {
758         paintThumb( g );
759     }
760     }
761
762     protected void recalculateIfInsetsChanged() {
763         Insets JavaDoc newInsets = slider.getInsets();
764         if ( !newInsets.equals( insetCache ) ) {
765         insetCache = newInsets;
766         calculateGeometry();
767     }
768     }
769
770     protected void recalculateIfOrientationChanged() {
771         boolean ltr = BasicGraphicsUtils.isLeftToRight(slider);
772         if ( ltr!=leftToRightCache ) {
773         leftToRightCache = ltr;
774         calculateGeometry();
775     }
776     }
777
778     public void paintFocus(Graphics JavaDoc g) {
779     g.setColor( getFocusColor() );
780
781     BasicGraphicsUtils.drawDashedRect( g, focusRect.x, focusRect.y,
782                        focusRect.width, focusRect.height );
783     }
784
785     public void paintTrack(Graphics JavaDoc g) {
786         int cx, cy, cw, ch;
787         int pad;
788
789         Rectangle JavaDoc trackBounds = trackRect;
790
791         if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
792             pad = trackBuffer;
793             cx = pad;
794             cy = (trackBounds.height / 2) - 2;
795             cw = trackBounds.width;
796
797             g.translate(trackBounds.x, trackBounds.y + cy);
798
799             g.setColor(getShadowColor());
800             g.drawLine(0, 0, cw - 1, 0);
801             g.drawLine(0, 1, 0, 2);
802             g.setColor(getHighlightColor());
803             g.drawLine(0, 3, cw, 3);
804             g.drawLine(cw, 0, cw, 3);
805             g.setColor(Color.black);
806             g.drawLine(1, 1, cw-2, 1);
807
808             g.translate(-trackBounds.x, -(trackBounds.y + cy));
809         }
810         else {
811             pad = trackBuffer;
812             cx = (trackBounds.width / 2) - 2;
813             cy = pad;
814             ch = trackBounds.height;
815
816             g.translate(trackBounds.x + cx, trackBounds.y);
817
818             g.setColor(getShadowColor());
819             g.drawLine(0, 0, 0, ch - 1);
820             g.drawLine(1, 0, 2, 0);
821             g.setColor(getHighlightColor());
822             g.drawLine(3, 0, 3, ch);
823             g.drawLine(0, ch, 3, ch);
824             g.setColor(Color.black);
825             g.drawLine(1, 1, 1, ch-2);
826
827             g.translate(-(trackBounds.x + cx), -trackBounds.y);
828         }
829     }
830
831     public void paintTicks(Graphics JavaDoc g) {
832         Rectangle JavaDoc tickBounds = tickRect;
833         int i;
834         int maj, min, max;
835         int w = tickBounds.width;
836         int h = tickBounds.height;
837         int centerEffect, tickHeight;
838
839         g.setColor(DefaultLookup.getColor(slider, this, "Slider.tickColor", Color.black));
840
841         maj = slider.getMajorTickSpacing();
842         min = slider.getMinorTickSpacing();
843
844         if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
845            g.translate( 0, tickBounds.y);
846
847             int value = slider.getMinimum();
848             int xPos = 0;
849
850             if ( slider.getMinorTickSpacing() > 0 ) {
851                 while ( value <= slider.getMaximum() ) {
852                     xPos = xPositionForValue( value );
853                     paintMinorTickForHorizSlider( g, tickBounds, xPos );
854                     value += slider.getMinorTickSpacing();
855                 }
856             }
857
858             if ( slider.getMajorTickSpacing() > 0 ) {
859                 value = slider.getMinimum();
860
861                 while ( value <= slider.getMaximum() ) {
862                     xPos = xPositionForValue( value );
863                     paintMajorTickForHorizSlider( g, tickBounds, xPos );
864                     value += slider.getMajorTickSpacing();
865                 }
866             }
867
868             g.translate( 0, -tickBounds.y);
869         }
870         else {
871            g.translate(tickBounds.x, 0);
872
873             int value = slider.getMinimum();
874             int yPos = 0;
875
876             if ( slider.getMinorTickSpacing() > 0 ) {
877             int offset = 0;
878             if(!BasicGraphicsUtils.isLeftToRight(slider)) {
879             offset = tickBounds.width - tickBounds.width / 2;
880             g.translate(offset, 0);
881         }
882
883                 while ( value <= slider.getMaximum() ) {
884                     yPos = yPositionForValue( value );
885                     paintMinorTickForVertSlider( g, tickBounds, yPos );
886                     value += slider.getMinorTickSpacing();
887                 }
888
889         if(!BasicGraphicsUtils.isLeftToRight(slider)) {
890             g.translate(-offset, 0);
891         }
892             }
893
894             if ( slider.getMajorTickSpacing() > 0 ) {
895                 value = slider.getMinimum();
896             if(!BasicGraphicsUtils.isLeftToRight(slider)) {
897             g.translate(2, 0);
898         }
899
900                 while ( value <= slider.getMaximum() ) {
901                     yPos = yPositionForValue( value );
902                     paintMajorTickForVertSlider( g, tickBounds, yPos );
903                     value += slider.getMajorTickSpacing();
904                 }
905
906             if(!BasicGraphicsUtils.isLeftToRight(slider)) {
907             g.translate(-2, 0);
908         }
909             }
910             g.translate(-tickBounds.x, 0);
911         }
912     }
913
914     protected void paintMinorTickForHorizSlider( Graphics JavaDoc g, Rectangle JavaDoc tickBounds, int x ) {
915         g.drawLine( x, 0, x, tickBounds.height / 2 - 1 );
916     }
917
918     protected void paintMajorTickForHorizSlider( Graphics JavaDoc g, Rectangle JavaDoc tickBounds, int x ) {
919         g.drawLine( x, 0, x, tickBounds.height - 2 );
920     }
921
922     protected void paintMinorTickForVertSlider( Graphics JavaDoc g, Rectangle JavaDoc tickBounds, int y ) {
923         g.drawLine( 0, y, tickBounds.width / 2 - 1, y );
924     }
925
926     protected void paintMajorTickForVertSlider( Graphics JavaDoc g, Rectangle JavaDoc tickBounds, int y ) {
927         g.drawLine( 0, y, tickBounds.width - 2, y );
928     }
929
930     public void paintLabels( Graphics JavaDoc g ) {
931         Rectangle JavaDoc labelBounds = labelRect;
932
933         Dictionary JavaDoc dictionary = slider.getLabelTable();
934         if ( dictionary != null ) {
935             Enumeration JavaDoc keys = dictionary.keys();
936             int minValue = slider.getMinimum();
937             int maxValue = slider.getMaximum();
938             while ( keys.hasMoreElements() ) {
939                 Integer JavaDoc key = (Integer JavaDoc)keys.nextElement();
940                 int value = key.intValue();
941                 if (value >= minValue && value <= maxValue) {
942                     Component JavaDoc label = (Component JavaDoc)dictionary.get( key );
943                     if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
944                         g.translate( 0, labelBounds.y );
945                         paintHorizontalLabel( g, value, label );
946                         g.translate( 0, -labelBounds.y );
947                     }
948                     else {
949                         int offset = 0;
950                         if (!BasicGraphicsUtils.isLeftToRight(slider)) {
951                             offset = labelBounds.width -
952                                 label.getPreferredSize().width;
953                         }
954                         g.translate( labelBounds.x + offset, 0 );
955                         paintVerticalLabel( g, value, label );
956                         g.translate( -labelBounds.x - offset, 0 );
957                     }
958                 }
959             }
960         }
961
962     }
963
964     /**
965      * Called for every label in the label table. Used to draw the labels for horizontal sliders.
966      * The graphics have been translated to labelRect.y already.
967      * @see JSlider#setLabelTable
968      */

969     protected void paintHorizontalLabel( Graphics JavaDoc g, int value, Component JavaDoc label ) {
970         int labelCenter = xPositionForValue( value );
971         int labelLeft = labelCenter - (label.getPreferredSize().width / 2);
972         g.translate( labelLeft, 0 );
973         label.paint( g );
974         g.translate( -labelLeft, 0 );
975     }
976
977     /**
978      * Called for every label in the label table. Used to draw the labels for vertical sliders.
979      * The graphics have been translated to labelRect.x already.
980      * @see JSlider#setLabelTable
981      */

982     protected void paintVerticalLabel( Graphics JavaDoc g, int value, Component JavaDoc label ) {
983         int labelCenter = yPositionForValue( value );
984         int labelTop = labelCenter - (label.getPreferredSize().height / 2);
985         g.translate( 0, labelTop );
986         label.paint( g );
987         g.translate( 0, -labelTop );
988     }
989
990     public void paintThumb(Graphics JavaDoc g) {
991         Rectangle JavaDoc knobBounds = thumbRect;
992         int w = knobBounds.width;
993         int h = knobBounds.height;
994
995         g.translate(knobBounds.x, knobBounds.y);
996
997         if ( slider.isEnabled() ) {
998             g.setColor(slider.getBackground());
999         }
1000        else {
1001            g.setColor(slider.getBackground().darker());
1002        }
1003
1004    Boolean JavaDoc paintThumbArrowShape =
1005        (Boolean JavaDoc)slider.getClientProperty("Slider.paintThumbArrowShape");
1006
1007    if ((!slider.getPaintTicks() && paintThumbArrowShape == null) ||
1008        paintThumbArrowShape == Boolean.FALSE) {
1009
1010        // "plain" version
1011
g.fillRect(0, 0, w, h);
1012
1013            g.setColor(Color.black);
1014            g.drawLine(0, h-1, w-1, h-1);
1015            g.drawLine(w-1, 0, w-1, h-1);
1016
1017            g.setColor(highlightColor);
1018            g.drawLine(0, 0, 0, h-2);
1019            g.drawLine(1, 0, w-2, 0);
1020
1021            g.setColor(shadowColor);
1022            g.drawLine(1, h-2, w-2, h-2);
1023            g.drawLine(w-2, 1, w-2, h-3);
1024        }
1025        else if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
1026            int cw = w / 2;
1027            g.fillRect(1, 1, w-3, h-1-cw);
1028            Polygon JavaDoc p = new Polygon JavaDoc();
1029            p.addPoint(1, h-cw);
1030            p.addPoint(cw-1, h-1);
1031            p.addPoint(w-2, h-1-cw);
1032            g.fillPolygon(p);
1033
1034            g.setColor(highlightColor);
1035            g.drawLine(0, 0, w-2, 0);
1036            g.drawLine(0, 1, 0, h-1-cw);
1037            g.drawLine(0, h-cw, cw-1, h-1);
1038
1039            g.setColor(Color.black);
1040            g.drawLine(w-1, 0, w-1, h-2-cw);
1041            g.drawLine(w-1, h-1-cw, w-1-cw, h-1);
1042
1043            g.setColor(shadowColor);
1044            g.drawLine(w-2, 1, w-2, h-2-cw);
1045            g.drawLine(w-2, h-1-cw, w-1-cw, h-2);
1046        }
1047        else { // vertical
1048
int cw = h / 2;
1049        if(BasicGraphicsUtils.isLeftToRight(slider)) {
1050          g.fillRect(1, 1, w-1-cw, h-3);
1051              Polygon JavaDoc p = new Polygon JavaDoc();
1052                  p.addPoint(w-cw-1, 0);
1053                  p.addPoint(w-1, cw);
1054                  p.addPoint(w-1-cw, h-2);
1055                  g.fillPolygon(p);
1056
1057                  g.setColor(highlightColor);
1058              g.drawLine(0, 0, 0, h - 2); // left
1059
g.drawLine(1, 0, w-1-cw, 0); // top
1060
g.drawLine(w-cw-1, 0, w-1, cw); // top slant
1061

1062                  g.setColor(Color.black);
1063              g.drawLine(0, h-1, w-2-cw, h-1); // bottom
1064
g.drawLine(w-1-cw, h-1, w-1, h-1-cw); // bottom slant
1065

1066                  g.setColor(shadowColor);
1067                  g.drawLine(1, h-2, w-2-cw, h-2 ); // bottom
1068
g.drawLine(w-1-cw, h-2, w-2, h-cw-1 ); // bottom slant
1069
}
1070        else {
1071          g.fillRect(5, 1, w-1-cw, h-3);
1072              Polygon JavaDoc p = new Polygon JavaDoc();
1073                  p.addPoint(cw, 0);
1074                  p.addPoint(0, cw);
1075                  p.addPoint(cw, h-2);
1076                  g.fillPolygon(p);
1077
1078                  g.setColor(highlightColor);
1079                  g.drawLine(cw-1, 0, w-2, 0); // top
1080
g.drawLine(0, cw, cw, 0); // top slant
1081

1082                  g.setColor(Color.black);
1083                  g.drawLine(0, h-1-cw, cw, h-1 ); // bottom slant
1084
g.drawLine(cw, h-1, w-1, h-1); // bottom
1085

1086                  g.setColor(shadowColor);
1087                  g.drawLine(cw, h-2, w-2, h-2 ); // bottom
1088
g.drawLine(w-1, 1, w-1, h-2 ); // right
1089
}
1090        }
1091
1092        g.translate(-knobBounds.x, -knobBounds.y);
1093    }
1094
1095    // Used exclusively by setThumbLocation()
1096
private static Rectangle JavaDoc unionRect = new Rectangle JavaDoc();
1097
1098    public void setThumbLocation(int x, int y) {
1099        unionRect.setBounds( thumbRect );
1100
1101        thumbRect.setLocation( x, y );
1102
1103    SwingUtilities.computeUnion( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height, unionRect );
1104        slider.repaint( unionRect.x, unionRect.y, unionRect.width, unionRect.height );
1105    }
1106
1107    public void scrollByBlock(int direction) {
1108        synchronized(slider) {
1109
1110            int oldValue = slider.getValue();
1111            int blockIncrement =
1112                (slider.getMaximum() - slider.getMinimum()) / 10;
1113            if (blockIncrement <= 0 &&
1114                slider.getMaximum() > slider.getMinimum()) {
1115
1116                blockIncrement = 1;
1117            }
1118
1119            int delta = blockIncrement * ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL);
1120            slider.setValue(oldValue + delta);
1121        }
1122    }
1123
1124    public void scrollByUnit(int direction) {
1125        synchronized(slider) {
1126
1127            int oldValue = slider.getValue();
1128            int delta = 1 * ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL);
1129
1130            slider.setValue(oldValue + delta);
1131        }
1132    }
1133
1134    /**
1135     * This function is called when a mousePressed was detected in the track, not
1136     * in the thumb. The default behavior is to scroll by block. You can
1137     * override this method to stop it from scrolling or to add additional behavior.
1138     */

1139    protected void scrollDueToClickInTrack( int dir ) {
1140        scrollByBlock( dir );
1141    }
1142
1143    protected int xPositionForValue( int value ) {
1144        int min = slider.getMinimum();
1145        int max = slider.getMaximum();
1146        int trackLength = trackRect.width;
1147        double valueRange = (double)max - (double)min;
1148        double pixelsPerValue = (double)trackLength / valueRange;
1149        int trackLeft = trackRect.x;
1150        int trackRight = trackRect.x + (trackRect.width - 1);
1151        int xPosition;
1152
1153        if ( !drawInverted() ) {
1154            xPosition = trackLeft;
1155            xPosition += Math.round( pixelsPerValue * ((double)value - min) );
1156        }
1157        else {
1158            xPosition = trackRight;
1159            xPosition -= Math.round( pixelsPerValue * ((double)value - min) );
1160        }
1161
1162        xPosition = Math.max( trackLeft, xPosition );
1163        xPosition = Math.min( trackRight, xPosition );
1164
1165        return xPosition;
1166    }
1167
1168    protected int yPositionForValue( int value ) {
1169        int min = slider.getMinimum();
1170        int max = slider.getMaximum();
1171        int trackLength = trackRect.height;
1172        double valueRange = (double)max - (double)min;
1173        double pixelsPerValue = (double)trackLength / (double)valueRange;
1174        int trackTop = trackRect.y;
1175        int trackBottom = trackRect.y + (trackRect.height - 1);
1176        int yPosition;
1177
1178        if ( !drawInverted() ) {
1179            yPosition = trackTop;
1180            yPosition += Math.round( pixelsPerValue * ((double)max - value ) );
1181        }
1182        else {
1183            yPosition = trackTop;
1184            yPosition += Math.round( pixelsPerValue * ((double)value - min) );
1185        }
1186
1187        yPosition = Math.max( trackTop, yPosition );
1188        yPosition = Math.min( trackBottom, yPosition );
1189
1190        return yPosition;
1191    }
1192
1193    /**
1194     * Returns a value give a y position. If yPos is past the track at the top or the
1195     * bottom it will set the value to the min or max of the slider, depending if the
1196     * slider is inverted or not.
1197     */

1198    public int valueForYPosition( int yPos ) {
1199        int value;
1200    final int minValue = slider.getMinimum();
1201    final int maxValue = slider.getMaximum();
1202    final int trackLength = trackRect.height;
1203    final int trackTop = trackRect.y;
1204    final int trackBottom = trackRect.y + (trackRect.height - 1);
1205    
1206    if ( yPos <= trackTop ) {
1207        value = drawInverted() ? minValue : maxValue;
1208    }
1209    else if ( yPos >= trackBottom ) {
1210        value = drawInverted() ? maxValue : minValue;
1211    }
1212    else {
1213        int distanceFromTrackTop = yPos - trackTop;
1214        double valueRange = (double)maxValue - (double)minValue;
1215        double valuePerPixel = valueRange / (double)trackLength;
1216        int valueFromTrackTop = (int)Math.round( distanceFromTrackTop * valuePerPixel );
1217
1218        value = drawInverted() ? minValue + valueFromTrackTop : maxValue - valueFromTrackTop;
1219    }
1220    
1221    return value;
1222    }
1223  
1224    /**
1225     * Returns a value give an x position. If xPos is past the track at the left or the
1226     * right it will set the value to the min or max of the slider, depending if the
1227     * slider is inverted or not.
1228     */

1229    public int valueForXPosition( int xPos ) {
1230        int value;
1231    final int minValue = slider.getMinimum();
1232    final int maxValue = slider.getMaximum();
1233    final int trackLength = trackRect.width;
1234    final int trackLeft = trackRect.x;
1235    final int trackRight = trackRect.x + (trackRect.width - 1);
1236    
1237    if ( xPos <= trackLeft ) {
1238        value = drawInverted() ? maxValue : minValue;
1239    }
1240    else if ( xPos >= trackRight ) {
1241        value = drawInverted() ? minValue : maxValue;
1242    }
1243    else {
1244        int distanceFromTrackLeft = xPos - trackLeft;
1245        double valueRange = (double)maxValue - (double)minValue;
1246        double valuePerPixel = valueRange / (double)trackLength;
1247        int valueFromTrackLeft = (int)Math.round( distanceFromTrackLeft * valuePerPixel );
1248        
1249        value = drawInverted() ? maxValue - valueFromTrackLeft :
1250          minValue + valueFromTrackLeft;
1251    }
1252    
1253    return value;
1254    }
1255
1256
1257    private class Handler implements ChangeListener,
1258            ComponentListener, FocusListener, PropertyChangeListener {
1259        // Change Handler
1260
public void stateChanged(ChangeEvent e) {
1261        if (!isDragging) {
1262            calculateThumbLocation();
1263        slider.repaint();
1264        }
1265        }
1266
1267        // Component Handler
1268
public void componentHidden(ComponentEvent e) { }
1269        public void componentMoved(ComponentEvent e) { }
1270        public void componentResized(ComponentEvent e) {
1271        calculateGeometry();
1272        slider.repaint();
1273        }
1274        public void componentShown(ComponentEvent e) { }
1275
1276        // Focus Handler
1277
public void focusGained(FocusEvent e) { slider.repaint(); }
1278        public void focusLost(FocusEvent e) { slider.repaint(); }
1279
1280        // Property Change Handler
1281
public void propertyChange(PropertyChangeEvent e) {
1282            String JavaDoc propertyName = e.getPropertyName();
1283            if (propertyName == "orientation" ||
1284                    propertyName == "inverted" ||
1285                    propertyName == "labelTable" ||
1286                    propertyName == "majorTickSpacing" ||
1287                    propertyName == "minorTickSpacing" ||
1288                    propertyName == "paintTicks" ||
1289                    propertyName == "paintTrack" ||
1290                    propertyName == "paintLabels") {
1291                calculateGeometry();
1292                slider.repaint();
1293            } else if (propertyName == "componentOrientation") {
1294                calculateGeometry();
1295                slider.repaint();
1296                InputMap km = getInputMap(JComponent.WHEN_FOCUSED, slider);
1297                SwingUtilities.replaceUIInputMap(slider,
1298                    JComponent.WHEN_FOCUSED, km);
1299            } else if (propertyName == "model") {
1300                ((BoundedRangeModel)e.getOldValue()).removeChangeListener(
1301                    changeListener);
1302                ((BoundedRangeModel)e.getNewValue()).addChangeListener(
1303                    changeListener);
1304                calculateThumbLocation();
1305                slider.repaint();
1306            }
1307        }
1308    }
1309
1310    /////////////////////////////////////////////////////////////////////////
1311
/// Model Listener Class
1312
/////////////////////////////////////////////////////////////////////////
1313
/**
1314     * Data model listener.
1315     *
1316     * This class should be treated as a &quot;protected&quot; inner class.
1317     * Instantiate it only within subclasses of <Foo>.
1318     */

1319    public class ChangeHandler implements ChangeListener {
1320        // NOTE: This class exists only for backward compatability. All
1321
// its functionality has been moved into Handler. If you need to add
1322
// new functionality add it to the Handler, but make sure this
1323
// class calls into the Handler.
1324
public void stateChanged(ChangeEvent e) {
1325            getHandler().stateChanged(e);
1326        }
1327    }
1328
1329    /////////////////////////////////////////////////////////////////////////
1330
/// Track Listener Class
1331
/////////////////////////////////////////////////////////////////////////
1332
/**
1333     * Track mouse movements.
1334     *
1335     * This class should be treated as a &quot;protected&quot; inner class.
1336     * Instantiate it only within subclasses of <Foo>.
1337     */

1338    public class TrackListener extends MouseInputAdapter {
1339        protected transient int offset;
1340        protected transient int currentMouseX, currentMouseY;
1341
1342        public void mouseReleased(MouseEvent e) {
1343            if (!slider.isEnabled()) {
1344                return;
1345            }
1346
1347            offset = 0;
1348            scrollTimer.stop();
1349
1350            // This is the way we have to determine snap-to-ticks. It's
1351
// hard to explain but since ChangeEvents don't give us any
1352
// idea what has changed we don't have a way to stop the thumb
1353
// bounds from being recalculated. Recalculating the thumb
1354
// bounds moves the thumb over the current value (i.e., snapping
1355
// to the ticks).
1356
if (slider.getSnapToTicks() /*|| slider.getSnapToValue()*/ ) {
1357                isDragging = false;
1358                slider.setValueIsAdjusting(false);
1359            }
1360            else {
1361                slider.setValueIsAdjusting(false);
1362                isDragging = false;
1363            }
1364            slider.repaint();
1365        }
1366
1367        /**
1368        * If the mouse is pressed above the "thumb" component
1369        * then reduce the scrollbars value by one page ("page up"),
1370        * otherwise increase it by one page. If there is no
1371        * thumb then page up if the mouse is in the upper half
1372        * of the track.
1373        */

1374        public void mousePressed(MouseEvent e) {
1375            if (!slider.isEnabled()) {
1376                return;
1377            }
1378
1379            currentMouseX = e.getX();
1380            currentMouseY = e.getY();
1381
1382            if (slider.isRequestFocusEnabled()) {
1383                slider.requestFocus();
1384            }
1385
1386            // Clicked in the Thumb area?
1387
if (thumbRect.contains(currentMouseX, currentMouseY)) {
1388                switch (slider.getOrientation()) {
1389                case JSlider.VERTICAL:
1390                    offset = currentMouseY - thumbRect.y;
1391                    break;
1392                case JSlider.HORIZONTAL:
1393                    offset = currentMouseX - thumbRect.x;
1394                    break;
1395                }
1396                isDragging = true;
1397                return;
1398            }
1399            isDragging = false;
1400            slider.setValueIsAdjusting(true);
1401
1402            Dimension JavaDoc sbSize = slider.getSize();
1403            int direction = POSITIVE_SCROLL;
1404
1405            switch (slider.getOrientation()) {
1406            case JSlider.VERTICAL:
1407                if ( thumbRect.isEmpty() ) {
1408                    int scrollbarCenter = sbSize.height / 2;
1409                    if ( !drawInverted() ) {
1410                        direction = (currentMouseY < scrollbarCenter) ?
1411                            POSITIVE_SCROLL : NEGATIVE_SCROLL;
1412                    }
1413                    else {
1414                        direction = (currentMouseY < scrollbarCenter) ?
1415                            NEGATIVE_SCROLL : POSITIVE_SCROLL;
1416                    }
1417                }
1418                else {
1419                    int thumbY = thumbRect.y;
1420                    if ( !drawInverted() ) {
1421                        direction = (currentMouseY < thumbY) ?
1422                            POSITIVE_SCROLL : NEGATIVE_SCROLL;
1423                    }
1424                    else {
1425                        direction = (currentMouseY < thumbY) ?
1426                            NEGATIVE_SCROLL : POSITIVE_SCROLL;
1427                    }
1428                }
1429                break;
1430            case JSlider.HORIZONTAL:
1431                if ( thumbRect.isEmpty() ) {
1432                    int scrollbarCenter = sbSize.width / 2;
1433                    if ( !drawInverted() ) {
1434                        direction = (currentMouseX < scrollbarCenter) ?
1435                            NEGATIVE_SCROLL : POSITIVE_SCROLL;
1436                    }
1437                    else {
1438                        direction = (currentMouseX < scrollbarCenter) ?
1439                            POSITIVE_SCROLL : NEGATIVE_SCROLL;
1440                    }
1441                }
1442                else {
1443                    int thumbX = thumbRect.x;
1444                    if ( !drawInverted() ) {
1445                        direction = (currentMouseX < thumbX) ?
1446                            NEGATIVE_SCROLL : POSITIVE_SCROLL;
1447                    }
1448                    else {
1449                        direction = (currentMouseX < thumbX) ?
1450                            POSITIVE_SCROLL : NEGATIVE_SCROLL;
1451                    }
1452                }
1453                break;
1454            }
1455            scrollDueToClickInTrack(direction);
1456            Rectangle JavaDoc r = thumbRect;
1457            if (!r.contains(currentMouseX, currentMouseY)) {
1458                if (shouldScroll(direction)) {
1459                    scrollTimer.stop();
1460                    scrollListener.setDirection(direction);
1461                    scrollTimer.start();
1462                }
1463            }
1464        }
1465
1466        public boolean shouldScroll(int direction) {
1467            Rectangle JavaDoc r = thumbRect;
1468            if (slider.getOrientation() == JSlider.VERTICAL) {
1469                if (drawInverted() ? direction < 0 : direction > 0) {
1470                    if (r.y + r.height <= currentMouseY) {
1471                        return false;
1472                    }
1473                }
1474                else if (r.y >= currentMouseY) {
1475                    return false;
1476                }
1477            }
1478            else {
1479                if (drawInverted() ? direction < 0 : direction > 0) {
1480                    if (r.x + r.width >= currentMouseX) {
1481                        return false;
1482                    }
1483                }
1484                else if (r.x <= currentMouseX) {
1485                    return false;
1486                }
1487            }
1488
1489            if (direction > 0 && slider.getValue() + slider.getExtent() >=
1490                    slider.getMaximum()) {
1491                return false;
1492            }
1493            else if (direction < 0 && slider.getValue() <=
1494                    slider.getMinimum()) {
1495                return false;
1496            }
1497
1498            return true;
1499        }
1500
1501        /**
1502        * Set the models value to the position of the top/left
1503        * of the thumb relative to the origin of the track.
1504        */

1505        public void mouseDragged(MouseEvent e) {
1506            int thumbMiddle = 0;
1507
1508            if (!slider.isEnabled()) {
1509                return;
1510            }
1511
1512            currentMouseX = e.getX();
1513            currentMouseY = e.getY();
1514
1515            if (!isDragging) {
1516                return;
1517            }
1518
1519            slider.setValueIsAdjusting(true);
1520
1521            switch (slider.getOrientation()) {
1522            case JSlider.VERTICAL:
1523                int halfThumbHeight = thumbRect.height / 2;
1524                int thumbTop = e.getY() - offset;
1525                int trackTop = trackRect.y;
1526                int trackBottom = trackRect.y + (trackRect.height - 1);
1527                int vMax = yPositionForValue(slider.getMaximum() -
1528                                            slider.getExtent());
1529
1530                if (drawInverted()) {
1531                    trackBottom = vMax;
1532                }
1533                else {
1534                    trackTop = vMax;
1535                }
1536                thumbTop = Math.max(thumbTop, trackTop - halfThumbHeight);
1537                thumbTop = Math.min(thumbTop, trackBottom - halfThumbHeight);
1538
1539                setThumbLocation(thumbRect.x, thumbTop);
1540
1541                thumbMiddle = thumbTop + halfThumbHeight;
1542                slider.setValue( valueForYPosition( thumbMiddle ) );
1543                break;
1544            case JSlider.HORIZONTAL:
1545                int halfThumbWidth = thumbRect.width / 2;
1546                int thumbLeft = e.getX() - offset;
1547                int trackLeft = trackRect.x;
1548                int trackRight = trackRect.x + (trackRect.width - 1);
1549                int hMax = xPositionForValue(slider.getMaximum() -
1550                                            slider.getExtent());
1551
1552                if (drawInverted()) {
1553                    trackLeft = hMax;
1554                }
1555                else {
1556                    trackRight = hMax;
1557                }
1558                thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth);
1559                thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth);
1560
1561                setThumbLocation(thumbLeft, thumbRect.y);
1562
1563                thumbMiddle = thumbLeft + halfThumbWidth;
1564                slider.setValue(valueForXPosition(thumbMiddle));
1565                break;
1566            default:
1567                return;
1568            }
1569        }
1570
1571        public void mouseMoved(MouseEvent e) { }
1572    }
1573
1574    /**
1575     * Scroll-event listener.
1576     *
1577     * This class should be treated as a &quot;protected&quot; inner class.
1578     * Instantiate it only within subclasses of <Foo>.
1579     */

1580    public class ScrollListener implements ActionListener {
1581        // changed this class to public to avoid bogus IllegalAccessException
1582
// bug in InternetExplorer browser. It was protected. Work around
1583
// for 4109432
1584
int direction = POSITIVE_SCROLL;
1585        boolean useBlockIncrement;
1586
1587        public ScrollListener() {
1588            direction = POSITIVE_SCROLL;
1589            useBlockIncrement = true;
1590        }
1591
1592        public ScrollListener(int dir, boolean block) {
1593            direction = dir;
1594            useBlockIncrement = block;
1595        }
1596
1597        public void setDirection(int direction) {
1598            this.direction = direction;
1599        }
1600
1601        public void setScrollByBlock(boolean block) {
1602            this.useBlockIncrement = block;
1603        }
1604
1605        public void actionPerformed(ActionEvent e) {
1606            if (useBlockIncrement) {
1607                scrollByBlock(direction);
1608            }
1609            else {
1610                scrollByUnit(direction);
1611            }
1612            if (!trackListener.shouldScroll(direction)) {
1613                ((Timer)e.getSource()).stop();
1614            }
1615        }
1616    }
1617
1618    /**
1619     * Listener for resizing events.
1620     * <p>
1621     * This class should be treated as a &quot;protected&quot; inner class.
1622     * Instantiate it only within subclasses of <Foo>.
1623     */

1624    public class ComponentHandler extends ComponentAdapter {
1625        // NOTE: This class exists only for backward compatability. All
1626
// its functionality has been moved into Handler. If you need to add
1627
// new functionality add it to the Handler, but make sure this
1628
// class calls into the Handler.
1629
public void componentResized(ComponentEvent e) {
1630            getHandler().componentResized(e);
1631        }
1632    };
1633
1634    /**
1635     * Focus-change listener.
1636     * <p>
1637     * This class should be treated as a &quot;protected&quot; inner class.
1638     * Instantiate it only within subclasses of <Foo>.
1639     */

1640    public class FocusHandler implements FocusListener {
1641        // NOTE: This class exists only for backward compatability. All
1642
// its functionality has been moved into Handler. If you need to add
1643
// new functionality add it to the Handler, but make sure this
1644
// class calls into the Handler.
1645
public void focusGained(FocusEvent e) {
1646            getHandler().focusGained(e);
1647        }
1648
1649        public void focusLost(FocusEvent e) {
1650            getHandler().focusLost(e);
1651        }
1652    }
1653
1654    /**
1655     * As of Java 2 platform v1.3 this undocumented class is no longer used.
1656     * The recommended approach to creating bindings is to use a
1657     * combination of an <code>ActionMap</code>, to contain the action,
1658     * and an <code>InputMap</code> to contain the mapping from KeyStroke
1659     * to action description. The InputMap is is usually described in the
1660     * LookAndFeel tables.
1661     * <p>
1662     * Please refer to the key bindings specification for further details.
1663     * <p>
1664     * This class should be treated as a &quot;protected&quot; inner class.
1665     * Instantiate it only within subclasses of <Foo>.
1666     */

1667    public class ActionScroller extends AbstractAction {
1668        // NOTE: This class exists only for backward compatability. All
1669
// its functionality has been moved into Actions. If you need to add
1670
// new functionality add it to the Actions, but make sure this
1671
// class calls into the Actions.
1672
int dir;
1673        boolean block;
1674        JSlider slider;
1675
1676        public ActionScroller( JSlider slider, int dir, boolean block) {
1677            this.dir = dir;
1678            this.block = block;
1679            this.slider = slider;
1680        }
1681
1682        public void actionPerformed(ActionEvent e) {
1683            SHARED_ACTION.scroll(slider, BasicSliderUI.this, dir, block);
1684    }
1685
1686    public boolean isEnabled() {
1687        boolean b = true;
1688        if (slider != null) {
1689        b = slider.isEnabled();
1690        }
1691        return b;
1692    }
1693
1694    };
1695
1696
1697    /**
1698     * A static version of the above.
1699     */

1700    static class SharedActionScroller extends AbstractAction {
1701        // NOTE: This class exists only for backward compatability. All
1702
// its functionality has been moved into Actions. If you need to add
1703
// new functionality add it to the Actions, but make sure this
1704
// class calls into the Actions.
1705
int dir;
1706        boolean block;
1707
1708        public SharedActionScroller(int dir, boolean block) {
1709            this.dir = dir;
1710            this.block = block;
1711        }
1712
1713        public void actionPerformed(ActionEvent evt) {
1714            JSlider slider = (JSlider)evt.getSource();
1715            BasicSliderUI JavaDoc ui = (BasicSliderUI JavaDoc)BasicLookAndFeel.getUIOfType(
1716                    slider.getUI(), BasicSliderUI JavaDoc.class);
1717            if (ui == null) {
1718                return;
1719            }
1720            SHARED_ACTION.scroll(slider, ui, dir, block);
1721    }
1722    }
1723
1724    private static class Actions extends UIAction {
1725        public static final String JavaDoc POSITIVE_UNIT_INCREMENT =
1726            "positiveUnitIncrement";
1727        public static final String JavaDoc POSITIVE_BLOCK_INCREMENT =
1728            "positiveBlockIncrement";
1729        public static final String JavaDoc NEGATIVE_UNIT_INCREMENT =
1730            "negativeUnitIncrement";
1731        public static final String JavaDoc NEGATIVE_BLOCK_INCREMENT =
1732            "negativeBlockIncrement";
1733        public static final String JavaDoc MIN_SCROLL_INCREMENT = "minScroll";
1734        public static final String JavaDoc MAX_SCROLL_INCREMENT = "maxScroll";
1735
1736
1737        Actions() {
1738            super(null);
1739        }
1740
1741        public Actions(String JavaDoc name) {
1742            super(name);
1743        }
1744
1745        public void actionPerformed(ActionEvent evt) {
1746            JSlider slider = (JSlider)evt.getSource();
1747            BasicSliderUI JavaDoc ui = (BasicSliderUI JavaDoc)BasicLookAndFeel.getUIOfType(
1748                     slider.getUI(), BasicSliderUI JavaDoc.class);
1749            String JavaDoc name = getName();
1750
1751            if (ui == null) {
1752                return;
1753            }
1754            if (POSITIVE_UNIT_INCREMENT == name) {
1755                scroll(slider, ui, POSITIVE_SCROLL, false);
1756            } else if (NEGATIVE_UNIT_INCREMENT == name) {
1757                scroll(slider, ui, NEGATIVE_SCROLL, false);
1758            } else if (POSITIVE_BLOCK_INCREMENT == name) {
1759                scroll(slider, ui, POSITIVE_SCROLL, true);
1760            } else if (NEGATIVE_BLOCK_INCREMENT == name) {
1761                scroll(slider, ui, NEGATIVE_SCROLL, true);
1762            } else if (MIN_SCROLL_INCREMENT == name) {
1763                scroll(slider, ui, MIN_SCROLL, false);
1764            } else if (MAX_SCROLL_INCREMENT == name) {
1765                scroll(slider, ui, MAX_SCROLL, false);
1766            }
1767        }
1768
1769        private void scroll(JSlider slider, BasicSliderUI JavaDoc ui, int direction,
1770                boolean isBlock) {
1771            boolean invert = slider.getInverted();
1772
1773            if (direction == NEGATIVE_SCROLL || direction == POSITIVE_SCROLL) {
1774                if (invert) {
1775                    direction = (direction == POSITIVE_SCROLL) ?
1776                        NEGATIVE_SCROLL : POSITIVE_SCROLL;
1777                }
1778
1779                if (isBlock) {
1780                    ui.scrollByBlock(direction);
1781                } else {
1782                    ui.scrollByUnit(direction);
1783                }
1784            } else { // MIN or MAX
1785
if (invert) {
1786                    direction = (direction == MIN_SCROLL) ?
1787                        MAX_SCROLL : MIN_SCROLL;
1788                }
1789
1790                slider.setValue((direction == MIN_SCROLL) ?
1791                    slider.getMinimum() : slider.getMaximum());
1792            }
1793        }
1794    }
1795}
1796
Popular Tags