History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/swing/plaf/basic/BasicSliderUI.java (1 of 18352 files). Show all

Unified · Split

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