1/*
2 * Copyright (c) 1997, 2015, 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 */
25package javax.swing;
26
27import java.io.Serializable;
28import java.awt.Component;
29import java.awt.Adjustable;
30import java.awt.Dimension;
31import java.awt.event.AdjustmentListener;
32import java.awt.event.AdjustmentEvent;
33import java.beans.JavaBean;
34import java.beans.BeanProperty;
35
36import javax.swing.event.*;
37import javax.swing.plaf.*;
38import javax.accessibility.*;
39
40import java.io.ObjectOutputStream;
41import java.io.IOException;
42
43/**
44 * An implementation of a scrollbar. The user positions the knob in the
45 * scrollbar to determine the contents of the viewing area. The
46 * program typically adjusts the display so that the end of the
47 * scrollbar represents the end of the displayable contents, or 100%
48 * of the contents. The start of the scrollbar is the beginning of the
49 * displayable contents, or 0%. The position of the knob within
50 * those bounds then translates to the corresponding percentage of
51 * the displayable contents.
52 * <p>
53 * Typically, as the position of the knob in the scrollbar changes
54 * a corresponding change is made to the position of the JViewport on
55 * the underlying view, changing the contents of the JViewport.
56 * <p>
57 * <strong>Warning:</strong> Swing is not thread safe. For more
58 * information see <a
59 * href="package-summary.html#threading">Swing's Threading
60 * Policy</a>.
61 * <p>
62 * <strong>Warning:</strong>
63 * Serialized objects of this class will not be compatible with
64 * future Swing releases. The current serialization support is
65 * appropriate for short term storage or RMI between applications running
66 * the same version of Swing.  As of 1.4, support for long term storage
67 * of all JavaBeans&trade;
68 * has been added to the <code>java.beans</code> package.
69 * Please see {@link java.beans.XMLEncoder}.
70 *
71 * @see JScrollPane
72 *
73 * @author David Kloba
74 * @since 1.2
75 */
76@JavaBean(defaultProperty = "UI", description = "A component that helps determine the visible content range of an area.")
77@SwingContainer(false)
78@SuppressWarnings("serial") // Same-version serialization only
79public class JScrollBar extends JComponent implements Adjustable, Accessible
80{
81    /**
82     * @see #getUIClassID
83     * @see #readObject
84     */
85    private static final String uiClassID = "ScrollBarUI";
86
87    /**
88     * All changes from the model are treated as though the user moved
89     * the scrollbar knob.
90     */
91    private ChangeListener fwdAdjustmentEvents = new ModelListener();
92
93
94    /**
95     * The model that represents the scrollbar's minimum, maximum, extent
96     * (aka "visibleAmount") and current value.
97     * @see #setModel
98     */
99    protected BoundedRangeModel model;
100
101
102    /**
103     * @see #setOrientation
104     */
105    protected int orientation;
106
107
108    /**
109     * @see #setUnitIncrement
110     */
111    protected int unitIncrement;
112
113
114    /**
115     * @see #setBlockIncrement
116     */
117    protected int blockIncrement;
118
119
120    private void checkOrientation(int orientation) {
121        switch (orientation) {
122        case VERTICAL:
123        case HORIZONTAL:
124            break;
125        default:
126            throw new IllegalArgumentException("orientation must be one of: VERTICAL, HORIZONTAL");
127        }
128    }
129
130
131    /**
132     * Creates a scrollbar with the specified orientation,
133     * value, extent, minimum, and maximum.
134     * The "extent" is the size of the viewable area. It is also known
135     * as the "visible amount".
136     * <p>
137     * Note: Use <code>setBlockIncrement</code> to set the block
138     * increment to a size slightly smaller than the view's extent.
139     * That way, when the user jumps the knob to an adjacent position,
140     * one or two lines of the original contents remain in view.
141     *
142     * @exception IllegalArgumentException if orientation is not one of VERTICAL, HORIZONTAL
143     *
144     * @see #setOrientation
145     * @see #setValue
146     * @see #setVisibleAmount
147     * @see #setMinimum
148     * @see #setMaximum
149     *
150     * @param orientation an orientation of the {@code JScrollBar}
151     * @param value an int giving the current value
152     * @param extent an int giving the amount by which the value can "jump"
153     * @param min an int giving the minimum value
154     * @param max an int giving the maximum value
155     */
156    public JScrollBar(int orientation, int value, int extent, int min, int max)
157    {
158        checkOrientation(orientation);
159        this.unitIncrement = 1;
160        this.blockIncrement = (extent == 0) ? 1 : extent;
161        this.orientation = orientation;
162        this.model = new DefaultBoundedRangeModel(value, extent, min, max);
163        this.model.addChangeListener(fwdAdjustmentEvents);
164        setRequestFocusEnabled(false);
165        updateUI();
166    }
167
168
169    /**
170     * Creates a scrollbar with the specified orientation
171     * and the following initial values:
172     * <pre>
173     * minimum = 0
174     * maximum = 100
175     * value = 0
176     * extent = 10
177     * </pre>
178     *
179     * @param orientation an orientation of the {@code JScrollBar}
180     */
181    public JScrollBar(int orientation) {
182        this(orientation, 0, 10, 0, 100);
183    }
184
185
186    /**
187     * Creates a vertical scrollbar with the following initial values:
188     * <pre>
189     * minimum = 0
190     * maximum = 100
191     * value = 0
192     * extent = 10
193     * </pre>
194     */
195    public JScrollBar() {
196        this(VERTICAL);
197    }
198
199
200    /**
201     * Sets the {@literal L&F} object that renders this component.
202     *
203     * @param ui  the <code>ScrollBarUI</code> {@literal L&F} object
204     * @see UIDefaults#getUI
205     * @since 1.4
206     */
207    @BeanProperty(hidden = true, visualUpdate = true, description
208            = "The UI object that implements the Component's LookAndFeel")
209    public void setUI(ScrollBarUI ui) {
210        super.setUI(ui);
211    }
212
213
214    /**
215     * Returns the delegate that implements the look and feel for
216     * this component.
217     *
218     * @return the scroll bar's current UI.
219     * @see JComponent#setUI
220     */
221    public ScrollBarUI getUI() {
222        return (ScrollBarUI)ui;
223    }
224
225
226    /**
227     * Overrides <code>JComponent.updateUI</code>.
228     * @see JComponent#updateUI
229     */
230    public void updateUI() {
231        setUI((ScrollBarUI)UIManager.getUI(this));
232    }
233
234
235    /**
236     * Returns the name of the LookAndFeel class for this component.
237     *
238     * @return "ScrollBarUI"
239     * @see JComponent#getUIClassID
240     * @see UIDefaults#getUI
241     */
242    @BeanProperty(bound = false)
243    public String getUIClassID() {
244        return uiClassID;
245    }
246
247
248
249    /**
250     * Returns the component's orientation (horizontal or vertical).
251     *
252     * @return VERTICAL or HORIZONTAL
253     * @see #setOrientation
254     * @see java.awt.Adjustable#getOrientation
255     */
256    public int getOrientation() {
257        return orientation;
258    }
259
260
261    /**
262     * Set the scrollbar's orientation to either VERTICAL or
263     * HORIZONTAL.
264     *
265     * @param orientation an orientation of the {@code JScrollBar}
266     * @exception IllegalArgumentException if orientation is not one of VERTICAL, HORIZONTAL
267     * @see #getOrientation
268     */
269    @BeanProperty(preferred = true, visualUpdate = true, enumerationValues = {
270            "JScrollBar.VERTICAL",
271            "JScrollBar.HORIZONTAL"}, description
272            = "The scrollbar's orientation.")
273    public void setOrientation(int orientation)
274    {
275        checkOrientation(orientation);
276        int oldValue = this.orientation;
277        this.orientation = orientation;
278        firePropertyChange("orientation", oldValue, orientation);
279
280        if ((oldValue != orientation) && (accessibleContext != null)) {
281            accessibleContext.firePropertyChange(
282                    AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
283                    ((oldValue == VERTICAL)
284                     ? AccessibleState.VERTICAL : AccessibleState.HORIZONTAL),
285                    ((orientation == VERTICAL)
286                     ? AccessibleState.VERTICAL : AccessibleState.HORIZONTAL));
287        }
288        if (orientation != oldValue) {
289            revalidate();
290        }
291    }
292
293
294    /**
295     * Returns data model that handles the scrollbar's four
296     * fundamental properties: minimum, maximum, value, extent.
297     *
298     * @return the data model
299     *
300     * @see #setModel
301     */
302    public BoundedRangeModel getModel() {
303        return model;
304    }
305
306
307    /**
308     * Sets the model that handles the scrollbar's four
309     * fundamental properties: minimum, maximum, value, extent.
310     *
311     * @param newModel a new model
312     * @see #getModel
313     */
314    @BeanProperty(expert = true, description
315            = "The scrollbar's BoundedRangeModel.")
316    public void setModel(BoundedRangeModel newModel) {
317        Integer oldValue = null;
318        BoundedRangeModel oldModel = model;
319        if (model != null) {
320            model.removeChangeListener(fwdAdjustmentEvents);
321            oldValue = Integer.valueOf(model.getValue());
322        }
323        model = newModel;
324        if (model != null) {
325            model.addChangeListener(fwdAdjustmentEvents);
326        }
327
328        firePropertyChange("model", oldModel, model);
329
330        if (accessibleContext != null) {
331            accessibleContext.firePropertyChange(
332                    AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
333                    oldValue, model.getValue());
334        }
335    }
336
337
338    /**
339     * Returns the amount to change the scrollbar's value by,
340     * given a unit up/down request.  A ScrollBarUI implementation
341     * typically calls this method when the user clicks on a scrollbar
342     * up/down arrow and uses the result to update the scrollbar's
343     * value.   Subclasses my override this method to compute
344     * a value, e.g. the change required to scroll up or down one
345     * (variable height) line text or one row in a table.
346     * <p>
347     * The JScrollPane component creates scrollbars (by default)
348     * that override this method and delegate to the viewports
349     * Scrollable view, if it has one.  The Scrollable interface
350     * provides a more specialized version of this method.
351     * <p>
352     * Some look and feels implement custom scrolling behavior
353     * and ignore this property.
354     *
355     * @param direction is -1 or 1 for up/down respectively
356     * @return the value of the unitIncrement property
357     * @see #setUnitIncrement
358     * @see #setValue
359     * @see Scrollable#getScrollableUnitIncrement
360     */
361    public int getUnitIncrement(int direction) {
362        return unitIncrement;
363    }
364
365
366    /**
367     * Sets the unitIncrement property.
368     * <p>
369     * Note, that if the argument is equal to the value of Integer.MIN_VALUE,
370     * the most look and feels will not provide the scrolling to the right/down.
371     * <p>
372     * Some look and feels implement custom scrolling behavior
373     * and ignore this property.
374     *
375     * @see #getUnitIncrement
376     */
377    @BeanProperty(preferred = true, description
378            = "The scrollbar's unit increment.")
379    public void setUnitIncrement(int unitIncrement) {
380        int oldValue = this.unitIncrement;
381        this.unitIncrement = unitIncrement;
382        firePropertyChange("unitIncrement", oldValue, unitIncrement);
383    }
384
385
386    /**
387     * Returns the amount to change the scrollbar's value by,
388     * given a block (usually "page") up/down request.  A ScrollBarUI
389     * implementation typically calls this method when the user clicks
390     * above or below the scrollbar "knob" to change the value
391     * up or down by large amount.  Subclasses my override this
392     * method to compute a value, e.g. the change required to scroll
393     * up or down one paragraph in a text document.
394     * <p>
395     * The JScrollPane component creates scrollbars (by default)
396     * that override this method and delegate to the viewports
397     * Scrollable view, if it has one.  The Scrollable interface
398     * provides a more specialized version of this method.
399     * <p>
400     * Some look and feels implement custom scrolling behavior
401     * and ignore this property.
402     *
403     * @param direction is -1 or 1 for up/down respectively
404     * @return the value of the blockIncrement property
405     * @see #setBlockIncrement
406     * @see #setValue
407     * @see Scrollable#getScrollableBlockIncrement
408     */
409    public int getBlockIncrement(int direction) {
410        return blockIncrement;
411    }
412
413
414    /**
415     * Sets the blockIncrement property.
416     * <p>
417     * Note, that if the argument is equal to the value of Integer.MIN_VALUE,
418     * the most look and feels will not provide the scrolling to the right/down.
419     * <p>
420     * Some look and feels implement custom scrolling behavior
421     * and ignore this property.
422     *
423     * @see #getBlockIncrement()
424     */
425    @BeanProperty(preferred = true, description
426            = "The scrollbar's block increment.")
427    public void setBlockIncrement(int blockIncrement) {
428        int oldValue = this.blockIncrement;
429        this.blockIncrement = blockIncrement;
430        firePropertyChange("blockIncrement", oldValue, blockIncrement);
431    }
432
433
434    /**
435     * For backwards compatibility with java.awt.Scrollbar.
436     * @see Adjustable#getUnitIncrement
437     * @see #getUnitIncrement(int)
438     */
439    public int getUnitIncrement() {
440        return unitIncrement;
441    }
442
443
444    /**
445     * For backwards compatibility with java.awt.Scrollbar.
446     * @see Adjustable#getBlockIncrement
447     * @see #getBlockIncrement(int)
448     */
449    public int getBlockIncrement() {
450        return blockIncrement;
451    }
452
453
454    /**
455     * Returns the scrollbar's value.
456     * @return the model's value property
457     * @see #setValue
458     */
459    public int getValue() {
460        return getModel().getValue();
461    }
462
463
464    /**
465     * Sets the scrollbar's value.  This method just forwards the value
466     * to the model.
467     *
468     * @see #getValue
469     * @see BoundedRangeModel#setValue
470     */
471    @BeanProperty(bound = false, preferred = true, description
472            = "The scrollbar's current value.")
473    public void setValue(int value) {
474        BoundedRangeModel m = getModel();
475        int oldValue = m.getValue();
476        m.setValue(value);
477
478        if (accessibleContext != null) {
479            accessibleContext.firePropertyChange(
480                    AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
481                    Integer.valueOf(oldValue),
482                    Integer.valueOf(m.getValue()));
483        }
484    }
485
486
487    /**
488     * Returns the scrollbar's extent, aka its "visibleAmount".  In many
489     * scrollbar look and feel implementations the size of the
490     * scrollbar "knob" or "thumb" is proportional to the extent.
491     *
492     * @return the value of the model's extent property
493     * @see #setVisibleAmount
494     */
495    public int getVisibleAmount() {
496        return getModel().getExtent();
497    }
498
499
500    /**
501     * Set the model's extent property.
502     *
503     * @see #getVisibleAmount
504     * @see BoundedRangeModel#setExtent
505     */
506    @BeanProperty(bound = false, preferred = true, description
507            = "The amount of the view that is currently visible.")
508    public void setVisibleAmount(int extent) {
509        getModel().setExtent(extent);
510    }
511
512
513    /**
514     * Returns the minimum value supported by the scrollbar
515     * (usually zero).
516     *
517     * @return the value of the model's minimum property
518     * @see #setMinimum
519     */
520    public int getMinimum() {
521        return getModel().getMinimum();
522    }
523
524
525    /**
526     * Sets the model's minimum property.
527     *
528     * @see #getMinimum
529     * @see BoundedRangeModel#setMinimum
530     */
531    @BeanProperty(bound = false, preferred = true, description
532            = "The scrollbar's minimum value.")
533    public void setMinimum(int minimum) {
534        getModel().setMinimum(minimum);
535    }
536
537
538    /**
539     * The maximum value of the scrollbar is maximum - extent.
540     *
541     * @return the value of the model's maximum property
542     * @see #setMaximum
543     */
544    public int getMaximum() {
545        return getModel().getMaximum();
546    }
547
548
549    /**
550     * Sets the model's maximum property.  Note that the scrollbar's value
551     * can only be set to maximum - extent.
552     *
553     * @see #getMaximum
554     * @see BoundedRangeModel#setMaximum
555     */
556    @BeanProperty(bound = false, preferred = true, description
557            = "The scrollbar's maximum value.")
558    public void setMaximum(int maximum) {
559        getModel().setMaximum(maximum);
560    }
561
562
563    /**
564     * True if the scrollbar knob is being dragged.
565     *
566     * @return the value of the model's valueIsAdjusting property
567     * @see #setValueIsAdjusting
568     */
569    public boolean getValueIsAdjusting() {
570        return getModel().getValueIsAdjusting();
571    }
572
573
574    /**
575     * Sets the model's valueIsAdjusting property.  Scrollbar look and
576     * feel implementations should set this property to true when
577     * a knob drag begins, and to false when the drag ends.  The
578     * scrollbar model will not generate ChangeEvents while
579     * valueIsAdjusting is true.
580     *
581     * @param b {@code true} if the upcoming changes to the value property are part of a series
582     *
583     * @see #getValueIsAdjusting
584     * @see BoundedRangeModel#setValueIsAdjusting
585     */
586    @BeanProperty(bound = false, expert = true, description
587            = "True if the scrollbar thumb is being dragged.")
588    public void setValueIsAdjusting(boolean b) {
589        BoundedRangeModel m = getModel();
590        boolean oldValue = m.getValueIsAdjusting();
591        m.setValueIsAdjusting(b);
592
593        if ((oldValue != b) && (accessibleContext != null)) {
594            accessibleContext.firePropertyChange(
595                    AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
596                    ((oldValue) ? AccessibleState.BUSY : null),
597                    ((b) ? AccessibleState.BUSY : null));
598        }
599    }
600
601
602    /**
603     * Sets the four BoundedRangeModel properties after forcing
604     * the arguments to obey the usual constraints:
605     * <pre>
606     * minimum &le; value &le; value+extent &le; maximum
607     * </pre>
608     *
609     * @param newValue an int giving the current value
610     * @param newExtent an int giving the amount by which the value can "jump"
611     * @param newMin an int giving the minimum value
612     * @param newMax an int giving the maximum value
613     *
614     * @see BoundedRangeModel#setRangeProperties
615     * @see #setValue
616     * @see #setVisibleAmount
617     * @see #setMinimum
618     * @see #setMaximum
619     */
620    public void setValues(int newValue, int newExtent, int newMin, int newMax)
621    {
622        BoundedRangeModel m = getModel();
623        int oldValue = m.getValue();
624        m.setRangeProperties(newValue, newExtent, newMin, newMax, m.getValueIsAdjusting());
625
626        if (accessibleContext != null) {
627            accessibleContext.firePropertyChange(
628                    AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
629                    Integer.valueOf(oldValue),
630                    Integer.valueOf(m.getValue()));
631        }
632    }
633
634
635    /**
636     * Adds an AdjustmentListener.  Adjustment listeners are notified
637     * each time the scrollbar's model changes.  Adjustment events are
638     * provided for backwards compatibility with java.awt.Scrollbar.
639     * <p>
640     * Note that the AdjustmentEvents type property will always have a
641     * placeholder value of AdjustmentEvent.TRACK because all changes
642     * to a BoundedRangeModels value are considered equivalent.  To change
643     * the value of a BoundedRangeModel one just sets its value property,
644     * i.e. model.setValue(123).  No information about the origin of the
645     * change, e.g. it's a block decrement, is provided.  We don't try
646     * fabricate the origin of the change here.
647     *
648     * @param l the AdjustmentLister to add
649     * @see #removeAdjustmentListener
650     * @see BoundedRangeModel#addChangeListener
651     */
652    public void addAdjustmentListener(AdjustmentListener l)   {
653        listenerList.add(AdjustmentListener.class, l);
654    }
655
656
657    /**
658     * Removes an AdjustmentEvent listener.
659     *
660     * @param l the AdjustmentLister to remove
661     * @see #addAdjustmentListener
662     */
663    public void removeAdjustmentListener(AdjustmentListener l)  {
664        listenerList.remove(AdjustmentListener.class, l);
665    }
666
667
668    /**
669     * Returns an array of all the <code>AdjustmentListener</code>s added
670     * to this JScrollBar with addAdjustmentListener().
671     *
672     * @return all of the <code>AdjustmentListener</code>s added or an empty
673     *         array if no listeners have been added
674     * @since 1.4
675     */
676    @BeanProperty(bound = false)
677    public AdjustmentListener[] getAdjustmentListeners() {
678        return listenerList.getListeners(AdjustmentListener.class);
679    }
680
681
682    /**
683     * Notify listeners that the scrollbar's model has changed.
684     *
685     * @param id an integer indicating the type of event.
686     * @param type an integer indicating the adjustment type.
687     * @param value the current value of the adjustment
688     *
689     * @see #addAdjustmentListener
690     * @see EventListenerList
691     */
692    protected void fireAdjustmentValueChanged(int id, int type, int value) {
693        fireAdjustmentValueChanged(id, type, value, getValueIsAdjusting());
694    }
695
696    /**
697     * Notify listeners that the scrollbar's model has changed.
698     *
699     * @see #addAdjustmentListener
700     * @see EventListenerList
701     */
702    private void fireAdjustmentValueChanged(int id, int type, int value,
703                                            boolean isAdjusting) {
704        Object[] listeners = listenerList.getListenerList();
705        AdjustmentEvent e = null;
706        for (int i = listeners.length - 2; i >= 0; i -= 2) {
707            if (listeners[i]==AdjustmentListener.class) {
708                if (e == null) {
709                    e = new AdjustmentEvent(this, id, type, value, isAdjusting);
710                }
711                ((AdjustmentListener)listeners[i+1]).adjustmentValueChanged(e);
712            }
713        }
714    }
715
716
717    /**
718     * This class listens to ChangeEvents on the model and forwards
719     * AdjustmentEvents for the sake of backwards compatibility.
720     * Unfortunately there's no way to determine the proper
721     * type of the AdjustmentEvent as all updates to the model's
722     * value are considered equivalent.
723     */
724    private class ModelListener implements ChangeListener, Serializable {
725        public void stateChanged(ChangeEvent e)   {
726            Object obj = e.getSource();
727            if (obj instanceof BoundedRangeModel) {
728                int id = AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED;
729                int type = AdjustmentEvent.TRACK;
730                BoundedRangeModel model = (BoundedRangeModel)obj;
731                int value = model.getValue();
732                boolean isAdjusting = model.getValueIsAdjusting();
733                fireAdjustmentValueChanged(id, type, value, isAdjusting);
734            }
735        }
736    }
737
738    // PENDING(hmuller) - the next three methods should be removed
739
740    /**
741     * The scrollbar is flexible along it's scrolling axis and
742     * rigid along the other axis.
743     */
744    public Dimension getMinimumSize() {
745        Dimension pref = getPreferredSize();
746        if (orientation == VERTICAL) {
747            return new Dimension(pref.width, 5);
748        } else {
749            return new Dimension(5, pref.height);
750        }
751    }
752
753    /**
754     * The scrollbar is flexible along it's scrolling axis and
755     * rigid along the other axis.
756     */
757    public Dimension getMaximumSize() {
758        Dimension pref = getPreferredSize();
759        if (getOrientation() == VERTICAL) {
760            return new Dimension(pref.width, Short.MAX_VALUE);
761        } else {
762            return new Dimension(Short.MAX_VALUE, pref.height);
763        }
764    }
765
766    /**
767     * Enables the component so that the knob position can be changed.
768     * When the disabled, the knob position cannot be changed.
769     *
770     * @param x a boolean value, where true enables the component and
771     *          false disables it
772     */
773    public void setEnabled(boolean x)  {
774        super.setEnabled(x);
775        Component[] children = getComponents();
776        for (Component child : children) {
777            child.setEnabled(x);
778        }
779    }
780
781    /**
782     * See readObject() and writeObject() in JComponent for more
783     * information about serialization in Swing.
784     */
785    private void writeObject(ObjectOutputStream s) throws IOException {
786        s.defaultWriteObject();
787        if (getUIClassID().equals(uiClassID)) {
788            byte count = JComponent.getWriteObjCounter(this);
789            JComponent.setWriteObjCounter(this, --count);
790            if (count == 0 && ui != null) {
791                ui.installUI(this);
792            }
793        }
794    }
795
796
797    /**
798     * Returns a string representation of this JScrollBar. This method
799     * is intended to be used only for debugging purposes, and the
800     * content and format of the returned string may vary between
801     * implementations. The returned string may be empty but may not
802     * be <code>null</code>.
803     *
804     * @return  a string representation of this JScrollBar.
805     */
806    protected String paramString() {
807        String orientationString = (orientation == HORIZONTAL ?
808                                    "HORIZONTAL" : "VERTICAL");
809
810        return super.paramString() +
811        ",blockIncrement=" + blockIncrement +
812        ",orientation=" + orientationString +
813        ",unitIncrement=" + unitIncrement;
814    }
815
816/////////////////
817// Accessibility support
818////////////////
819
820    /**
821     * Gets the AccessibleContext associated with this JScrollBar.
822     * For JScrollBar, the AccessibleContext takes the form of an
823     * AccessibleJScrollBar.
824     * A new AccessibleJScrollBar instance is created if necessary.
825     *
826     * @return an AccessibleJScrollBar that serves as the
827     *         AccessibleContext of this JScrollBar
828     */
829    @BeanProperty(bound = false)
830    public AccessibleContext getAccessibleContext() {
831        if (accessibleContext == null) {
832            accessibleContext = new AccessibleJScrollBar();
833        }
834        return accessibleContext;
835    }
836
837    /**
838     * This class implements accessibility support for the
839     * <code>JScrollBar</code> class.  It provides an implementation of the
840     * Java Accessibility API appropriate to scroll bar user-interface
841     * elements.
842     * <p>
843     * <strong>Warning:</strong>
844     * Serialized objects of this class will not be compatible with
845     * future Swing releases. The current serialization support is
846     * appropriate for short term storage or RMI between applications running
847     * the same version of Swing.  As of 1.4, support for long term storage
848     * of all JavaBeans&trade;
849     * has been added to the <code>java.beans</code> package.
850     * Please see {@link java.beans.XMLEncoder}.
851     */
852    @SuppressWarnings("serial") // Same-version serialization only
853    protected class AccessibleJScrollBar extends AccessibleJComponent
854        implements AccessibleValue {
855
856        /**
857         * Get the state set of this object.
858         *
859         * @return an instance of AccessibleState containing the current state
860         * of the object
861         * @see AccessibleState
862         */
863        public AccessibleStateSet getAccessibleStateSet() {
864            AccessibleStateSet states = super.getAccessibleStateSet();
865            if (getValueIsAdjusting()) {
866                states.add(AccessibleState.BUSY);
867            }
868            if (getOrientation() == VERTICAL) {
869                states.add(AccessibleState.VERTICAL);
870            } else {
871                states.add(AccessibleState.HORIZONTAL);
872            }
873            return states;
874        }
875
876        /**
877         * Get the role of this object.
878         *
879         * @return an instance of AccessibleRole describing the role of the
880         * object
881         */
882        public AccessibleRole getAccessibleRole() {
883            return AccessibleRole.SCROLL_BAR;
884        }
885
886        /**
887         * Get the AccessibleValue associated with this object.  In the
888         * implementation of the Java Accessibility API for this class,
889         * return this object, which is responsible for implementing the
890         * AccessibleValue interface on behalf of itself.
891         *
892         * @return this object
893         */
894        public AccessibleValue getAccessibleValue() {
895            return this;
896        }
897
898        /**
899         * Get the accessible value of this object.
900         *
901         * @return The current value of this object.
902         */
903        public Number getCurrentAccessibleValue() {
904            return Integer.valueOf(getValue());
905        }
906
907        /**
908         * Set the value of this object as a Number.
909         *
910         * @return True if the value was set.
911         */
912        public boolean setCurrentAccessibleValue(Number n) {
913            // TIGER - 4422535
914            if (n == null) {
915                return false;
916            }
917            setValue(n.intValue());
918            return true;
919        }
920
921        /**
922         * Get the minimum accessible value of this object.
923         *
924         * @return The minimum value of this object.
925         */
926        public Number getMinimumAccessibleValue() {
927            return Integer.valueOf(getMinimum());
928        }
929
930        /**
931         * Get the maximum accessible value of this object.
932         *
933         * @return The maximum value of this object.
934         */
935        public Number getMaximumAccessibleValue() {
936            // TIGER - 4422362
937            return model.getMaximum() - model.getExtent();
938        }
939
940    } // AccessibleJScrollBar
941}
942