001 /* JScrollBar.java --
002 Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc.
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038
039 package javax.swing;
040
041 import gnu.java.lang.CPStringBuilder;
042
043 import java.awt.Adjustable;
044 import java.awt.Dimension;
045 import java.awt.event.AdjustmentEvent;
046 import java.awt.event.AdjustmentListener;
047 import java.beans.PropertyChangeEvent;
048
049 import javax.accessibility.Accessible;
050 import javax.accessibility.AccessibleContext;
051 import javax.accessibility.AccessibleRole;
052 import javax.accessibility.AccessibleState;
053 import javax.accessibility.AccessibleStateSet;
054 import javax.accessibility.AccessibleValue;
055 import javax.swing.event.ChangeEvent;
056 import javax.swing.event.ChangeListener;
057 import javax.swing.plaf.ScrollBarUI;
058
059 /**
060 * The JScrollBar. Two buttons control how the values that the
061 * scroll bar can take. You can also drag the thumb or click the track
062 * to move the scroll bar. Typically, the JScrollBar is used with
063 * other components to translate the value of the bar to the viewable
064 * contents of the other components.
065 */
066 public class JScrollBar extends JComponent implements Adjustable, Accessible
067 {
068 /**
069 * Provides the accessibility features for the <code>JScrollBar</code>
070 * component.
071 */
072 protected class AccessibleJScrollBar extends JComponent.AccessibleJComponent
073 implements AccessibleValue
074 {
075 private static final long serialVersionUID = -7758162392045586663L;
076
077 /**
078 * Creates a new <code>AccessibleJScrollBar</code> instance.
079 */
080 protected AccessibleJScrollBar()
081 {
082 super();
083 }
084
085 /**
086 * Returns a set containing the current state of the {@link JScrollBar}
087 * component.
088 *
089 * @return The accessible state set.
090 */
091 public AccessibleStateSet getAccessibleStateSet()
092 {
093 AccessibleStateSet result = super.getAccessibleStateSet();
094 if (orientation == JScrollBar.HORIZONTAL)
095 result.add(AccessibleState.HORIZONTAL);
096 else if (orientation == JScrollBar.VERTICAL)
097 result.add(AccessibleState.VERTICAL);
098 return result;
099 }
100
101 /**
102 * Returns the accessible role for the <code>JScrollBar</code> component.
103 *
104 * @return {@link AccessibleRole#SCROLL_BAR}.
105 */
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 */
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 */
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 */
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 */
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 */
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
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
430 public int getUnitIncrement()
431 {
432 return unitIncrement;
433 }
434
435 /**
436 * This method returns the blockIncrement.
437 *
438 * @return The blockIncrement.
439 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
694 public AccessibleContext getAccessibleContext()
695 {
696 if (accessibleContext == null)
697 accessibleContext = new AccessibleJScrollBar();
698 return accessibleContext;
699 }
700 }