1 /* JScrollBar.java --
2    Copyright (C) 2002, 2004, 2005, 2006,  Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package javax.swing;
40 
41 import gnu.java.lang.CPStringBuilder;
42 
43 import java.awt.Adjustable;
44 import java.awt.Dimension;
45 import java.awt.event.AdjustmentEvent;
46 import java.awt.event.AdjustmentListener;
47 import java.beans.PropertyChangeEvent;
48 
49 import javax.accessibility.Accessible;
50 import javax.accessibility.AccessibleContext;
51 import javax.accessibility.AccessibleRole;
52 import javax.accessibility.AccessibleState;
53 import javax.accessibility.AccessibleStateSet;
54 import javax.accessibility.AccessibleValue;
55 import javax.swing.event.ChangeEvent;
56 import javax.swing.event.ChangeListener;
57 import javax.swing.plaf.ScrollBarUI;
58 
59 /**
60  * The JScrollBar. Two buttons control how the values that the
61  * scroll bar can take. You can also drag the thumb or click the track
62  * to move the scroll bar. Typically, the JScrollBar is used with
63  * other components to translate the value of the bar to the viewable
64  * contents of the other components.
65  */
66 public class JScrollBar extends JComponent implements Adjustable, Accessible
67 {
68   /**
69    * Provides the accessibility features for the <code>JScrollBar</code>
70    * component.
71    */
72   protected class AccessibleJScrollBar extends JComponent.AccessibleJComponent
73     implements AccessibleValue
74   {
75     private static final long serialVersionUID = -7758162392045586663L;
76 
77     /**
78      * Creates a new <code>AccessibleJScrollBar</code> instance.
79      */
AccessibleJScrollBar()80     protected AccessibleJScrollBar()
81     {
82       super();
83     }
84 
85     /**
86      * Returns a set containing the current state of the {@link JScrollBar}
87      * component.
88      *
89      * @return The accessible state set.
90      */
getAccessibleStateSet()91     public AccessibleStateSet getAccessibleStateSet()
92     {
93       AccessibleStateSet result = super.getAccessibleStateSet();
94       if (orientation == JScrollBar.HORIZONTAL)
95         result.add(AccessibleState.HORIZONTAL);
96       else if (orientation == JScrollBar.VERTICAL)
97         result.add(AccessibleState.VERTICAL);
98       return result;
99     }
100 
101     /**
102      * Returns the accessible role for the <code>JScrollBar</code> component.
103      *
104      * @return {@link AccessibleRole#SCROLL_BAR}.
105      */
getAccessibleRole()106     public AccessibleRole getAccessibleRole()
107     {
108       return AccessibleRole.SCROLL_BAR;
109     }
110 
111     /**
112      * Returns an object that provides access to the current, minimum and
113      * maximum values.
114      *
115      * @return The accessible value.
116      */
getAccessibleValue()117     public AccessibleValue getAccessibleValue()
118     {
119       return this;
120     }
121 
122     /**
123      * Returns the current value of the {@link JScrollBar} component, as an
124      * {@link Integer}.
125      *
126      * @return The current value of the {@link JScrollBar} component.
127      */
getCurrentAccessibleValue()128     public Number getCurrentAccessibleValue()
129     {
130       return new Integer(getValue());
131     }
132 
133     /**
134      * Sets the current value of the {@link JScrollBar} component and sends a
135      * {@link PropertyChangeEvent} (with the property name
136      * {@link AccessibleContext#ACCESSIBLE_VALUE_PROPERTY}) to all registered
137      * listeners.  If the supplied value is <code>null</code>, this method
138      * does nothing and returns <code>false</code>.
139      *
140      * @param value  the new slider value (<code>null</code> permitted).
141      *
142      * @return <code>true</code> if the slider value is updated, and
143      *     <code>false</code> otherwise.
144      */
setCurrentAccessibleValue(Number value)145     public boolean setCurrentAccessibleValue(Number value)
146     {
147       if (value == null)
148         return false;
149       Number oldValue = getCurrentAccessibleValue();
150       setValue(value.intValue());
151       firePropertyChange(AccessibleContext.ACCESSIBLE_VALUE_PROPERTY, oldValue,
152                          new Integer(getValue()));
153       return true;
154     }
155 
156     /**
157      * Returns the minimum value of the {@link JScrollBar} component, as an
158      * {@link Integer}.
159      *
160      * @return The minimum value of the {@link JScrollBar} component.
161      */
getMinimumAccessibleValue()162     public Number getMinimumAccessibleValue()
163     {
164       return new Integer(getMinimum());
165     }
166 
167     /**
168      * Returns the maximum value of the {@link JScrollBar} component, as an
169      * {@link Integer}.
170      *
171      * @return The maximum value of the {@link JScrollBar} component.
172      */
getMaximumAccessibleValue()173     public Number getMaximumAccessibleValue()
174     {
175       return new Integer(getMaximum() - model.getExtent());
176     }
177   }
178 
179   /**
180    * Listens for changes on the model and fires them to interested
181    * listeners on the JScrollBar, after re-sourcing them.
182    */
183   private class ScrollBarChangeListener
184     implements ChangeListener
185   {
186 
stateChanged(ChangeEvent event)187     public void stateChanged(ChangeEvent event)
188     {
189       Object o = event.getSource();
190       if (o instanceof BoundedRangeModel)
191         {
192           BoundedRangeModel m = (BoundedRangeModel) o;
193           fireAdjustmentValueChanged(AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED,
194                                      AdjustmentEvent.TRACK, m.getValue(),
195                                      m.getValueIsAdjusting());
196         }
197     }
198 
199   }
200 
201   private static final long serialVersionUID = -8195169869225066566L;
202 
203   /** How much the thumb moves when moving in a block. */
204   protected int blockIncrement = 10;
205 
206   /** The model that holds the scroll bar's data. */
207   protected BoundedRangeModel model;
208 
209   /** The orientation of the scroll bar. */
210   protected int orientation = SwingConstants.VERTICAL;
211 
212   /** How much the thumb moves when moving in a unit. */
213   protected int unitIncrement = 1;
214 
215   /**
216    * This ChangeListener forwards events fired from the model and re-sources
217    * them to originate from this JScrollBar.
218    */
219   private ChangeListener sbChangeListener;
220 
221   /**
222    * Creates a new horizontal JScrollBar object with a minimum
223    * of 0, a maxmium of 100, a value of 0 and an extent of 10.
224    */
JScrollBar()225   public JScrollBar()
226   {
227     this(SwingConstants.VERTICAL, 0, 10, 0, 100);
228   }
229 
230   /**
231    * Creates a new JScrollBar object with a minimum of 0, a
232    * maximum of 100, a value of 0, an extent of 10 and the given
233    * orientation.
234    *
235    * @param orientation The orientation of the JScrollBar.
236    */
JScrollBar(int orientation)237   public JScrollBar(int orientation)
238   {
239     this(orientation, 0, 10, 0, 100);
240   }
241 
242   /**
243    * Creates a new JScrollBar object with the given orientation,
244    * value, min, max, and extent.
245    *
246    * @param orientation The orientation to use.
247    * @param value The value to use.
248    * @param extent The extent to use.
249    * @param min The minimum value of the scrollbar.
250    * @param max The maximum value of the scrollbar.
251    */
JScrollBar(int orientation, int value, int extent, int min, int max)252   public JScrollBar(int orientation, int value, int extent, int min, int max)
253   {
254     model = new DefaultBoundedRangeModel(value, extent, min, max);
255     sbChangeListener = new ScrollBarChangeListener();
256     model.addChangeListener(sbChangeListener);
257     if (orientation != SwingConstants.HORIZONTAL
258         && orientation != SwingConstants.VERTICAL)
259       throw new IllegalArgumentException(orientation
260                                          + " is not a legal orientation");
261     this.orientation = orientation;
262     updateUI();
263   }
264 
265   /**
266    * This method sets the UI of this scrollbar to
267    * the given UI.
268    *
269    * @param ui The UI to use with this scrollbar.
270    */
setUI(ScrollBarUI ui)271   public void setUI(ScrollBarUI ui)
272   {
273     super.setUI(ui);
274   }
275 
276   /**
277    * This method returns the UI that is being used
278    * with this scrollbar.
279    *
280    * @return The scrollbar's current UI.
281    */
getUI()282   public ScrollBarUI getUI()
283   {
284     return (ScrollBarUI) ui;
285   }
286 
287   /**
288    * This method changes the UI to be the
289    * default for the current look and feel.
290    */
updateUI()291   public void updateUI()
292   {
293     setUI((ScrollBarUI) UIManager.getUI(this));
294   }
295 
296   /**
297    * This method returns an identifier to
298    * choose the correct UI delegate for the
299    * scrollbar.
300    *
301    * @return The identifer to choose the UI delegate; "ScrollBarUI"
302    */
getUIClassID()303   public String getUIClassID()
304   {
305     return "ScrollBarUI";
306   }
307 
308   /**
309    * This method returns the orientation of the scrollbar.
310    *
311    * @return The orientation of the scrollbar.
312    */
getOrientation()313   public int getOrientation()
314   {
315     return orientation;
316   }
317 
318   /**
319    * This method sets the orientation of the scrollbar.
320    *
321    * @param orientation The orientation of the scrollbar.
322    */
setOrientation(int orientation)323   public void setOrientation(int orientation)
324   {
325     if (orientation != SwingConstants.HORIZONTAL
326         && orientation != SwingConstants.VERTICAL)
327       throw new IllegalArgumentException("orientation must be one of HORIZONTAL or VERTICAL");
328     if (orientation != this.orientation)
329       {
330         int oldOrientation = this.orientation;
331         this.orientation = orientation;
332         firePropertyChange("orientation", oldOrientation,
333                            this.orientation);
334       }
335   }
336 
337   /**
338    * This method returns the model being used with
339    * the scrollbar.
340    *
341    * @return The scrollbar's model.
342    */
getModel()343   public BoundedRangeModel getModel()
344   {
345     return model;
346   }
347 
348   /**
349    * This method sets the model to use with
350    * the scrollbar.
351    *
352    * @param newModel The new model to use with the scrollbar.
353    */
setModel(BoundedRangeModel newModel)354   public void setModel(BoundedRangeModel newModel)
355   {
356     BoundedRangeModel oldModel = model;
357     if (oldModel != null)
358       oldModel.removeChangeListener(sbChangeListener);
359     model = newModel;
360     if (model != null)
361       model.addChangeListener(sbChangeListener);
362     firePropertyChange("model", oldModel, model);
363   }
364 
365   /**
366    * This method returns how much the scrollbar's value
367    * should change for a unit increment depending on the
368    * given direction.
369    *
370    * @param direction The direction to scroll in.
371    *
372    * @return The amount the scrollbar's value will change given the direction.
373    */
getUnitIncrement(int direction)374   public int getUnitIncrement(int direction)
375   {
376     return unitIncrement;
377   }
378 
379   /**
380    * This method sets the unitIncrement property.
381    *
382    * @param unitIncrement The new unitIncrement.
383    */
setUnitIncrement(int unitIncrement)384   public void setUnitIncrement(int unitIncrement)
385   {
386     if (unitIncrement != this.unitIncrement)
387       {
388         int oldInc = this.unitIncrement;
389         this.unitIncrement = unitIncrement;
390         firePropertyChange("unitIncrement", oldInc,
391                            this.unitIncrement);
392       }
393   }
394 
395   /**
396    * The method returns how much the scrollbar's value
397    * should change for a block increment depending on
398    * the given direction.
399    *
400    * @param direction The direction to scroll in.
401    *
402    * @return The amount the scrollbar's value will change given the direction.
403    */
getBlockIncrement(int direction)404   public int getBlockIncrement(int direction)
405   {
406     return blockIncrement;
407   }
408 
409   /**
410    * This method sets the blockIncrement property.
411    *
412    * @param blockIncrement The new blockIncrement.
413    */
setBlockIncrement(int blockIncrement)414   public void setBlockIncrement(int blockIncrement)
415   {
416     if (blockIncrement != this.blockIncrement)
417       {
418         int oldInc = this.blockIncrement;
419         this.blockIncrement = blockIncrement;
420         firePropertyChange("blockIncrement", oldInc,
421                            this.blockIncrement);
422       }
423   }
424 
425   /**
426    * This method returns the unitIncrement.
427    *
428    * @return The unitIncrement.
429    */
getUnitIncrement()430   public int getUnitIncrement()
431   {
432     return unitIncrement;
433   }
434 
435   /**
436    * This method returns the blockIncrement.
437    *
438    * @return The blockIncrement.
439    */
getBlockIncrement()440   public int getBlockIncrement()
441   {
442     return blockIncrement;
443   }
444 
445   /**
446    * This method returns the value of the scrollbar.
447    *
448    * @return The value of the scrollbar.
449    */
getValue()450   public int getValue()
451   {
452     return model.getValue();
453   }
454 
455   /**
456    * This method changes the value of the scrollbar.
457    *
458    * @param value The new value of the scrollbar.
459    */
setValue(int value)460   public void setValue(int value)
461   {
462     model.setValue(value);
463   }
464 
465   /**
466    * This method returns the visible amount (AKA extent).
467    * The visible amount can be used by UI delegates to
468    * determine the size of the thumb.
469    *
470    * @return The visible amount (AKA extent).
471    */
getVisibleAmount()472   public int getVisibleAmount()
473   {
474     return model.getExtent();
475   }
476 
477   /**
478    * This method sets the visible amount (AKA extent).
479    *
480    * @param extent The visible amount (AKA extent).
481    */
setVisibleAmount(int extent)482   public void setVisibleAmount(int extent)
483   {
484     model.setExtent(extent);
485   }
486 
487   /**
488    * This method returns the minimum value of the scrollbar.
489    *
490    * @return The minimum value of the scrollbar.
491    */
getMinimum()492   public int getMinimum()
493   {
494     return model.getMinimum();
495   }
496 
497   /**
498    * This method sets the minimum value of the scrollbar.
499    *
500    * @param minimum The minimum value of the scrollbar.
501    */
setMinimum(int minimum)502   public void setMinimum(int minimum)
503   {
504     model.setMinimum(minimum);
505   }
506 
507   /**
508    * This method returns the maximum value of the scrollbar.
509    *
510    * @return The maximum value of the scrollbar.
511    */
getMaximum()512   public int getMaximum()
513   {
514     return model.getMaximum();
515   }
516 
517   /**
518    * This method sets the maximum value of the scrollbar.
519    *
520    * @param maximum The maximum value of the scrollbar.
521    */
setMaximum(int maximum)522   public void setMaximum(int maximum)
523   {
524     model.setMaximum(maximum);
525   }
526 
527   /**
528    * This method returns the model's isAjusting value.
529    *
530    * @return The model's isAdjusting value.
531    */
getValueIsAdjusting()532   public boolean getValueIsAdjusting()
533   {
534     return model.getValueIsAdjusting();
535   }
536 
537   /**
538    * This method sets the model's isAdjusting value.
539    *
540    * @param b The new isAdjusting value.
541    */
setValueIsAdjusting(boolean b)542   public void setValueIsAdjusting(boolean b)
543   {
544     model.setValueIsAdjusting(b);
545   }
546 
547   /**
548    * This method sets the value, extent, minimum and
549    * maximum.
550    *
551    * @param newValue The new value.
552    * @param newExtent The new extent.
553    * @param newMin The new minimum.
554    * @param newMax The new maximum.
555    */
setValues(int newValue, int newExtent, int newMin, int newMax)556   public void setValues(int newValue, int newExtent, int newMin, int newMax)
557   {
558     model.setRangeProperties(newValue, newExtent, newMin, newMax,
559                              model.getValueIsAdjusting());
560   }
561 
562   /**
563    * This method adds an AdjustmentListener to the scroll bar.
564    *
565    * @param listener The listener to add.
566    */
addAdjustmentListener(AdjustmentListener listener)567   public void addAdjustmentListener(AdjustmentListener listener)
568   {
569     listenerList.add(AdjustmentListener.class, listener);
570   }
571 
572   /**
573    * This method removes an AdjustmentListener from the scroll bar.
574    *
575    * @param listener The listener to remove.
576    */
removeAdjustmentListener(AdjustmentListener listener)577   public void removeAdjustmentListener(AdjustmentListener listener)
578   {
579     listenerList.remove(AdjustmentListener.class, listener);
580   }
581 
582   /**
583    * This method returns an arry of all AdjustmentListeners listening to
584    * this scroll bar.
585    *
586    * @return An array of AdjustmentListeners listening to this scroll bar.
587    */
getAdjustmentListeners()588   public AdjustmentListener[] getAdjustmentListeners()
589   {
590     return (AdjustmentListener[]) listenerList.getListeners(AdjustmentListener.class);
591   }
592 
593   /**
594    * This method is called to fired AdjustmentEvents to the listeners
595    * of this scroll bar. All AdjustmentEvents that are fired
596    * will have an ID of ADJUSTMENT_VALUE_CHANGED and a type of
597    * TRACK.
598    *
599    * @param id The ID of the adjustment event.
600    * @param type The Type of change.
601    * @param value The new value for the property that was changed..
602    */
fireAdjustmentValueChanged(int id, int type, int value)603   protected void fireAdjustmentValueChanged(int id, int type, int value)
604   {
605     fireAdjustmentValueChanged(id, type, value, getValueIsAdjusting());
606   }
607 
608   /**
609    * Helper method for firing adjustment events that can have their
610    * isAdjusting field modified.
611    *
612    * This is package private to avoid an accessor method.
613    *
614    * @param id the ID of the event
615    * @param type the type of the event
616    * @param value the value
617    * @param isAdjusting if the scrollbar is adjusting or not
618    */
fireAdjustmentValueChanged(int id, int type, int value, boolean isAdjusting)619   void fireAdjustmentValueChanged(int id, int type, int value,
620                                           boolean isAdjusting)
621   {
622     Object[] adjustmentListeners = listenerList.getListenerList();
623     AdjustmentEvent adjustmentEvent = new AdjustmentEvent(this, id, type,
624                                                           value, isAdjusting);
625     for (int i = adjustmentListeners.length - 2; i >= 0; i -= 2)
626       {
627         if (adjustmentListeners[i] == AdjustmentListener.class)
628           ((AdjustmentListener) adjustmentListeners[i + 1]).adjustmentValueChanged(adjustmentEvent);
629       }
630   }
631 
632   /**
633    * This method returns the minimum size for this scroll bar.
634    *
635    * @return The minimum size.
636    */
getMinimumSize()637   public Dimension getMinimumSize()
638   {
639     return ui.getMinimumSize(this);
640   }
641 
642   /**
643    * This method returns the maximum size for this scroll bar.
644    *
645    * @return The maximum size.
646    */
getMaximumSize()647   public Dimension getMaximumSize()
648   {
649     return ui.getMaximumSize(this);
650   }
651 
652   /**
653    * This method overrides the setEnabled in JComponent.
654    * When the scroll bar is disabled, the knob cannot
655    * be moved.
656    *
657    * @param x Whether the scrollbar is enabled.
658    */
setEnabled(boolean x)659   public void setEnabled(boolean x)
660   {
661     // nothing special needs to be done here since we
662     // just check the enabled setting before changing the value.
663     super.setEnabled(x);
664   }
665 
666   /**
667    * Returns a string describing the attributes for the <code>JScrollBar</code>
668    * component, for use in debugging.  The return value is guaranteed to be
669    * non-<code>null</code>, but the format of the string may vary between
670    * implementations.
671    *
672    * @return A string describing the attributes of the <code>JScrollBar</code>.
673    */
paramString()674   protected String paramString()
675   {
676     CPStringBuilder sb = new CPStringBuilder(super.paramString());
677     sb.append(",blockIncrement=").append(blockIncrement);
678     sb.append(",orientation=");
679     if (this.orientation == JScrollBar.HORIZONTAL)
680       sb.append("HORIZONTAL");
681     else
682       sb.append("VERTICAL");
683     sb.append(",unitIncrement=").append(unitIncrement);
684     return sb.toString();
685   }
686 
687   /**
688    * Returns the object that provides accessibility features for this
689    * <code>JScrollBar</code> component.
690    *
691    * @return The accessible context (an instance of
692    *     {@link AccessibleJScrollBar}).
693    */
getAccessibleContext()694   public AccessibleContext getAccessibleContext()
695   {
696     if (accessibleContext == null)
697       accessibleContext = new AccessibleJScrollBar();
698     return accessibleContext;
699   }
700 }
701