1 /*
2 * Copyright 1997-2008 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package javax.swing;
27
28 import javax.swing.plaf;
29 import javax.swing.border;
30 import javax.swing.event;
31 import javax.accessibility;
32
33 import java.awt.Component;
34 import java.awt.ComponentOrientation;
35 import java.awt.Graphics;
36 import java.awt.Rectangle;
37 import java.awt.Insets;
38 import java.awt.Color;
39 import java.awt.LayoutManager;
40 import java.awt.Point;
41
42 import java.io.ObjectOutputStream;
43 import java.io.ObjectInputStream;
44 import java.io.IOException;
45
46 import java.beans.PropertyChangeEvent;
47 import java.beans.PropertyChangeListener;
48 import java.beans.Transient;
49
50 /**
51 * Provides a scrollable view of a lightweight component.
52 * A <code>JScrollPane</code> manages a viewport, optional
53 * vertical and horizontal scroll bars, and optional row and
54 * column heading viewports.
55 * You can find task-oriented documentation of <code>JScrollPane</code> in
56 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/scrollpane.html">How to Use Scroll Panes</a>,
57 * a section in <em>The Java Tutorial</em>. Note that
58 * <code>JScrollPane</code> does not support heavyweight components.
59 * <p>
60 * <TABLE ALIGN="RIGHT" BORDER="0" SUMMARY="layout">
61 * <TR>
62 * <TD ALIGN="CENTER">
63 * <P ALIGN="CENTER"><IMG SRC="doc-files/JScrollPane-1.gif"
64 * alt="The following text describes this image."
65 * WIDTH="256" HEIGHT="248" ALIGN="BOTTOM" BORDER="0">
66 * </TD>
67 * </TR>
68 * </TABLE>
69 * The <code>JViewport</code> provides a window,
70 * or "viewport" onto a data
71 * source -- for example, a text file. That data source is the
72 * "scrollable client" (aka data model) displayed by the
73 * <code>JViewport</code> view.
74 * A <code>JScrollPane</code> basically consists of <code>JScrollBar</code>s,
75 * a <code>JViewport</code>, and the wiring between them,
76 * as shown in the diagram at right.
77 * <p>
78 * In addition to the scroll bars and viewport,
79 * a <code>JScrollPane</code> can have a
80 * column header and a row header. Each of these is a
81 * <code>JViewport</code> object that
82 * you specify with <code>setRowHeaderView</code>,
83 * and <code>setColumnHeaderView</code>.
84 * The column header viewport automatically scrolls left and right, tracking
85 * the left-right scrolling of the main viewport.
86 * (It never scrolls vertically, however.)
87 * The row header acts in a similar fashion.
88 * <p>
89 * Where two scroll bars meet, the row header meets the column header,
90 * or a scroll bar meets one of the headers, both components stop short
91 * of the corner, leaving a rectangular space which is, by default, empty.
92 * These spaces can potentially exist in any number of the four corners.
93 * In the previous diagram, the top right space is present and identified
94 * by the label "corner component".
95 * <p>
96 * Any number of these empty spaces can be replaced by using the
97 * <code>setCorner</code> method to add a component to a particular corner.
98 * (Note: The same component cannot be added to multiple corners.)
99 * This is useful if there's
100 * some extra decoration or function you'd like to add to the scroll pane.
101 * The size of each corner component is entirely determined by the size of the
102 * headers and/or scroll bars that surround it.
103 * <p>
104 * A corner component will only be visible if there is an empty space in that
105 * corner for it to exist in. For example, consider a component set into the
106 * top right corner of a scroll pane with a column header. If the scroll pane's
107 * vertical scrollbar is not present, perhaps because the view component hasn't
108 * grown large enough to require it, then the corner component will not be
109 * shown (since there is no empty space in that corner created by the meeting
110 * of the header and vertical scroll bar). Forcing the scroll bar to always be
111 * shown, using
112 * <code>setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_ALWAYS)</code>,
113 * will ensure that the space for the corner component always exists.
114 * <p>
115 * To add a border around the main viewport,
116 * you can use <code>setViewportBorder</code>.
117 * (Of course, you can also add a border around the whole scroll pane using
118 * <code>setBorder</code>.)
119 * <p>
120 * A common operation to want to do is to set the background color that will
121 * be used if the main viewport view is smaller than the viewport, or is
122 * not opaque. This can be accomplished by setting the background color
123 * of the viewport, via <code>scrollPane.getViewport().setBackground()</code>.
124 * The reason for setting the color of the viewport and not the scrollpane
125 * is that by default <code>JViewport</code> is opaque
126 * which, among other things, means it will completely fill
127 * in its background using its background color. Therefore when
128 * <code>JScrollPane</code> draws its background the viewport will
129 * usually draw over it.
130 * <p>
131 * By default <code>JScrollPane</code> uses <code>ScrollPaneLayout</code>
132 * to handle the layout of its child Components. <code>ScrollPaneLayout</code>
133 * determines the size to make the viewport view in one of two ways:
134 * <ol>
135 * <li>If the view implements <code>Scrollable</code>
136 * a combination of <code>getPreferredScrollableViewportSize</code>,
137 * <code>getScrollableTracksViewportWidth</code> and
138 * <code>getScrollableTracksViewportHeight</code>is used, otherwise
139 * <li><code>getPreferredSize</code> is used.
140 * </ol>
141 * <p>
142 * <strong>Warning:</strong> Swing is not thread safe. For more
143 * information see <a
144 * href="package-summary.html#threading">Swing's Threading
145 * Policy</a>.
146 * <p>
147 * <strong>Warning:</strong>
148 * Serialized objects of this class will not be compatible with
149 * future Swing releases. The current serialization support is
150 * appropriate for short term storage or RMI between applications running
151 * the same version of Swing. As of 1.4, support for long term storage
152 * of all JavaBeans<sup><font size="-2">TM</font></sup>
153 * has been added to the <code>java.beans</code> package.
154 * Please see {@link java.beans.XMLEncoder}.
155 *
156 * @see JScrollBar
157 * @see JViewport
158 * @see ScrollPaneLayout
159 * @see Scrollable
160 * @see Component#getPreferredSize
161 * @see #setViewportView
162 * @see #setRowHeaderView
163 * @see #setColumnHeaderView
164 * @see #setCorner
165 * @see #setViewportBorder
166 *
167 * @beaninfo
168 * attribute: isContainer true
169 * attribute: containerDelegate getViewport
170 * description: A specialized container that manages a viewport, optional scrollbars and headers
171 *
172 * @author Hans Muller
173 */
174 public class JScrollPane extends JComponent implements ScrollPaneConstants, Accessible
175 {
176 private Border viewportBorder;
177
178 /**
179 * @see #getUIClassID
180 * @see #readObject
181 */
182 private static final String uiClassID = "ScrollPaneUI";
183
184 /**
185 * The display policy for the vertical scrollbar.
186 * The default is
187 * <code>ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED</code>.
188 * @see #setVerticalScrollBarPolicy
189 */
190 protected int verticalScrollBarPolicy = VERTICAL_SCROLLBAR_AS_NEEDED;
191
192
193 /**
194 * The display policy for the horizontal scrollbar.
195 * The default is
196 * <code>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED</code>.
197 * @see #setHorizontalScrollBarPolicy
198 */
199 protected int horizontalScrollBarPolicy = HORIZONTAL_SCROLLBAR_AS_NEEDED;
200
201
202 /**
203 * The scrollpane's viewport child. Default is an empty
204 * <code>JViewport</code>.
205 * @see #setViewport
206 */
207 protected JViewport viewport;
208
209
210 /**
211 * The scrollpane's vertical scrollbar child.
212 * Default is a <code>JScrollBar</code>.
213 * @see #setVerticalScrollBar
214 */
215 protected JScrollBar verticalScrollBar;
216
217
218 /**
219 * The scrollpane's horizontal scrollbar child.
220 * Default is a <code>JScrollBar</code>.
221 * @see #setHorizontalScrollBar
222 */
223 protected JScrollBar horizontalScrollBar;
224
225
226 /**
227 * The row header child. Default is <code>null</code>.
228 * @see #setRowHeader
229 */
230 protected JViewport rowHeader;
231
232
233 /**
234 * The column header child. Default is <code>null</code>.
235 * @see #setColumnHeader
236 */
237 protected JViewport columnHeader;
238
239
240 /**
241 * The component to display in the lower left corner.
242 * Default is <code>null</code>.
243 * @see #setCorner
244 */
245 protected Component lowerLeft;
246
247
248 /**
249 * The component to display in the lower right corner.
250 * Default is <code>null</code>.
251 * @see #setCorner
252 */
253 protected Component lowerRight;
254
255
256 /**
257 * The component to display in the upper left corner.
258 * Default is <code>null</code>.
259 * @see #setCorner
260 */
261 protected Component upperLeft;
262
263
264 /**
265 * The component to display in the upper right corner.
266 * Default is <code>null</code>.
267 * @see #setCorner
268 */
269 protected Component upperRight;
270
271 /*
272 * State flag for mouse wheel scrolling
273 */
274 private boolean wheelScrollState = true;
275
276 /**
277 * Creates a <code>JScrollPane</code> that displays the view
278 * component in a viewport
279 * whose view position can be controlled with a pair of scrollbars.
280 * The scrollbar policies specify when the scrollbars are displayed,
281 * For example, if <code>vsbPolicy</code> is
282 * <code>VERTICAL_SCROLLBAR_AS_NEEDED</code>
283 * then the vertical scrollbar only appears if the view doesn't fit
284 * vertically. The available policy settings are listed at
285 * {@link #setVerticalScrollBarPolicy} and
286 * {@link #setHorizontalScrollBarPolicy}.
287 *
288 * @see #setViewportView
289 *
290 * @param view the component to display in the scrollpanes viewport
291 * @param vsbPolicy an integer that specifies the vertical
292 * scrollbar policy
293 * @param hsbPolicy an integer that specifies the horizontal
294 * scrollbar policy
295 */
296 public JScrollPane(Component view, int vsbPolicy, int hsbPolicy)
297 {
298 setLayout(new ScrollPaneLayout.UIResource());
299 setVerticalScrollBarPolicy(vsbPolicy);
300 setHorizontalScrollBarPolicy(hsbPolicy);
301 setViewport(createViewport());
302 setVerticalScrollBar(createVerticalScrollBar());
303 setHorizontalScrollBar(createHorizontalScrollBar());
304 if (view != null) {
305 setViewportView(view);
306 }
307 setOpaque(true);
308 updateUI();
309
310 if (!this.getComponentOrientation().isLeftToRight()) {
311 viewport.setViewPosition(new Point(Integer.MAX_VALUE, 0));
312 }
313 }
314
315
316 /**
317 * Creates a <code>JScrollPane</code> that displays the
318 * contents of the specified
319 * component, where both horizontal and vertical scrollbars appear
320 * whenever the component's contents are larger than the view.
321 *
322 * @see #setViewportView
323 * @param view the component to display in the scrollpane's viewport
324 */
325 public JScrollPane(Component view) {
326 this(view, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED);
327 }
328
329
330 /**
331 * Creates an empty (no viewport view) <code>JScrollPane</code>
332 * with specified
333 * scrollbar policies. The available policy settings are listed at
334 * {@link #setVerticalScrollBarPolicy} and
335 * {@link #setHorizontalScrollBarPolicy}.
336 *
337 * @see #setViewportView
338 *
339 * @param vsbPolicy an integer that specifies the vertical
340 * scrollbar policy
341 * @param hsbPolicy an integer that specifies the horizontal
342 * scrollbar policy
343 */
344 public JScrollPane(int vsbPolicy, int hsbPolicy) {
345 this(null, vsbPolicy, hsbPolicy);
346 }
347
348
349 /**
350 * Creates an empty (no viewport view) <code>JScrollPane</code>
351 * where both horizontal and vertical scrollbars appear when needed.
352 */
353 public JScrollPane() {
354 this(null, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED);
355 }
356
357
358 /**
359 * Returns the look and feel (L&F) object that renders this component.
360 *
361 * @return the <code>ScrollPaneUI</code> object that renders this
362 * component
363 * @see #setUI
364 * @beaninfo
365 * bound: true
366 * hidden: true
367 * attribute: visualUpdate true
368 * description: The UI object that implements the Component's LookAndFeel.
369 */
370 public ScrollPaneUI getUI() {
371 return (ScrollPaneUI)ui;
372 }
373
374
375 /**
376 * Sets the <code>ScrollPaneUI</code> object that provides the
377 * look and feel (L&F) for this component.
378 *
379 * @param ui the <code>ScrollPaneUI</code> L&F object
380 * @see #getUI
381 */
382 public void setUI(ScrollPaneUI ui) {
383 super.setUI(ui);
384 }
385
386
387 /**
388 * Replaces the current <code>ScrollPaneUI</code> object with a version
389 * from the current default look and feel.
390 * To be called when the default look and feel changes.
391 *
392 * @see JComponent#updateUI
393 * @see UIManager#getUI
394 */
395 public void updateUI() {
396 setUI((ScrollPaneUI)UIManager.getUI(this));
397 }
398
399
400 /**
401 * Returns the suffix used to construct the name of the L&F class used to
402 * render this component.
403 *
404 * @return the string "ScrollPaneUI"
405 * @see JComponent#getUIClassID
406 * @see UIDefaults#getUI
407 *
408 * @beaninfo
409 * hidden: true
410 */
411 public String getUIClassID() {
412 return uiClassID;
413 }
414
415
416
417 /**
418 * Sets the layout manager for this <code>JScrollPane</code>.
419 * This method overrides <code>setLayout</code> in
420 * <code>java.awt.Container</code> to ensure that only
421 * <code>LayoutManager</code>s which
422 * are subclasses of <code>ScrollPaneLayout</code> can be used in a
423 * <code>JScrollPane</code>. If <code>layout</code> is non-null, this
424 * will invoke <code>syncWithScrollPane</code> on it.
425 *
426 * @param layout the specified layout manager
427 * @exception ClassCastException if layout is not a
428 * <code>ScrollPaneLayout</code>
429 * @see java.awt.Container#getLayout
430 * @see java.awt.Container#setLayout
431 *
432 * @beaninfo
433 * hidden: true
434 */
435 public void setLayout(LayoutManager layout) {
436 if (layout instanceof ScrollPaneLayout) {
437 super.setLayout(layout);
438 ((ScrollPaneLayout)layout).syncWithScrollPane(this);
439 }
440 else if (layout == null) {
441 super.setLayout(layout);
442 }
443 else {
444 String s = "layout of JScrollPane must be a ScrollPaneLayout";
445 throw new ClassCastException(s);
446 }
447 }
448
449 /**
450 * Overridden to return true so that any calls to <code>revalidate</code>
451 * on any descendants of this <code>JScrollPane</code> will cause the
452 * entire tree beginning with this <code>JScrollPane</code> to be
453 * validated.
454 *
455 * @return true
456 * @see java.awt.Container#validate
457 * @see JComponent#revalidate
458 * @see JComponent#isValidateRoot
459 *
460 * @beaninfo
461 * hidden: true
462 */
463 public boolean isValidateRoot() {
464 return true;
465 }
466
467
468 /**
469 * Returns the vertical scroll bar policy value.
470 * @return the <code>verticalScrollBarPolicy</code> property
471 * @see #setVerticalScrollBarPolicy
472 */
473 public int getVerticalScrollBarPolicy() {
474 return verticalScrollBarPolicy;
475 }
476
477
478 /**
479 * Determines when the vertical scrollbar appears in the scrollpane.
480 * Legal values are:
481 * <ul>
482 * <li><code>ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED</code>
483 * <li><code>ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER</code>
484 * <li><code>ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS</code>
485 * </ul>
486 *
487 * @param policy one of the three values listed above
488 * @exception IllegalArgumentException if <code>policy</code>
489 * is not one of the legal values shown above
490 * @see #getVerticalScrollBarPolicy
491 *
492 * @beaninfo
493 * preferred: true
494 * bound: true
495 * description: The scrollpane vertical scrollbar policy
496 * enum: VERTICAL_SCROLLBAR_AS_NEEDED ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED
497 * VERTICAL_SCROLLBAR_NEVER ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER
498 * VERTICAL_SCROLLBAR_ALWAYS ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS
499 */
500 public void setVerticalScrollBarPolicy(int policy) {
501 switch (policy) {
502 case VERTICAL_SCROLLBAR_AS_NEEDED:
503 case VERTICAL_SCROLLBAR_NEVER:
504 case VERTICAL_SCROLLBAR_ALWAYS:
505 break;
506 default:
507 throw new IllegalArgumentException("invalid verticalScrollBarPolicy");
508 }
509 int old = verticalScrollBarPolicy;
510 verticalScrollBarPolicy = policy;
511 firePropertyChange("verticalScrollBarPolicy", old, policy);
512 revalidate();
513 repaint();
514 }
515
516
517 /**
518 * Returns the horizontal scroll bar policy value.
519 * @return the <code>horizontalScrollBarPolicy</code> property
520 * @see #setHorizontalScrollBarPolicy
521 */
522 public int getHorizontalScrollBarPolicy() {
523 return horizontalScrollBarPolicy;
524 }
525
526
527 /**
528 * Determines when the horizontal scrollbar appears in the scrollpane.
529 * The options are:<ul>
530 * <li><code>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED</code>
531 * <li><code>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER</code>
532 * <li><code>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS</code>
533 * </ul>
534 *
535 * @param policy one of the three values listed above
536 * @exception IllegalArgumentException if <code>policy</code>
537 * is not one of the legal values shown above
538 * @see #getHorizontalScrollBarPolicy
539 *
540 * @beaninfo
541 * preferred: true
542 * bound: true
543 * description: The scrollpane scrollbar policy
544 * enum: HORIZONTAL_SCROLLBAR_AS_NEEDED ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED
545 * HORIZONTAL_SCROLLBAR_NEVER ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER
546 * HORIZONTAL_SCROLLBAR_ALWAYS ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS
547 */
548 public void setHorizontalScrollBarPolicy(int policy) {
549 switch (policy) {
550 case HORIZONTAL_SCROLLBAR_AS_NEEDED:
551 case HORIZONTAL_SCROLLBAR_NEVER:
552 case HORIZONTAL_SCROLLBAR_ALWAYS:
553 break;
554 default:
555 throw new IllegalArgumentException("invalid horizontalScrollBarPolicy");
556 }
557 int old = horizontalScrollBarPolicy;
558 horizontalScrollBarPolicy = policy;
559 firePropertyChange("horizontalScrollBarPolicy", old, policy);
560 revalidate();
561 repaint();
562 }
563
564
565 /**
566 * Returns the <code>Border</code> object that surrounds the viewport.
567 *
568 * @return the <code>viewportBorder</code> property
569 * @see #setViewportBorder
570 */
571 public Border getViewportBorder() {
572 return viewportBorder;
573 }
574
575
576 /**
577 * Adds a border around the viewport. Note that the border isn't
578 * set on the viewport directly, <code>JViewport</code> doesn't support
579 * the <code>JComponent</code> border property.
580 * Similarly setting the <code>JScrollPane</code>s
581 * viewport doesn't affect the <code>viewportBorder</code> property.
582 * <p>
583 * The default value of this property is computed by the look
584 * and feel implementation.
585 *
586 * @param viewportBorder the border to be added
587 * @see #getViewportBorder
588 * @see #setViewport
589 *
590 * @beaninfo
591 * preferred: true
592 * bound: true
593 * description: The border around the viewport.
594 */
595 public void setViewportBorder(Border viewportBorder) {
596 Border oldValue = this.viewportBorder;
597 this.viewportBorder = viewportBorder;
598 firePropertyChange("viewportBorder", oldValue, viewportBorder);
599 }
600
601
602 /**
603 * Returns the bounds of the viewport's border.
604 *
605 * @return a <code>Rectangle</code> object specifying the viewport border
606 */
607 public Rectangle getViewportBorderBounds()
608 {
609 Rectangle borderR = new Rectangle(getSize());
610
611 Insets insets = getInsets();
612 borderR.x = insets.left;
613 borderR.y = insets.top;
614 borderR.width -= insets.left + insets.right;
615 borderR.height -= insets.top + insets.bottom;
616
617 boolean leftToRight = SwingUtilities.isLeftToRight(this);
618
619 /* If there's a visible column header remove the space it
620 * needs from the top of borderR.
621 */
622
623 JViewport colHead = getColumnHeader();
624 if ((colHead != null) && (colHead.isVisible())) {
625 int colHeadHeight = colHead.getHeight();
626 borderR.y += colHeadHeight;
627 borderR.height -= colHeadHeight;
628 }
629
630 /* If there's a visible row header remove the space it needs
631 * from the left of borderR.
632 */
633
634 JViewport rowHead = getRowHeader();
635 if ((rowHead != null) && (rowHead.isVisible())) {
636 int rowHeadWidth = rowHead.getWidth();
637 if ( leftToRight ) {
638 borderR.x += rowHeadWidth;
639 }
640 borderR.width -= rowHeadWidth;
641 }
642
643 /* If there's a visible vertical scrollbar remove the space it needs
644 * from the width of borderR.
645 */
646 JScrollBar vsb = getVerticalScrollBar();
647 if ((vsb != null) && (vsb.isVisible())) {
648 int vsbWidth = vsb.getWidth();
649 if ( !leftToRight ) {
650 borderR.x += vsbWidth;
651 }
652 borderR.width -= vsbWidth;
653 }
654
655 /* If there's a visible horizontal scrollbar remove the space it needs
656 * from the height of borderR.
657 */
658 JScrollBar hsb = getHorizontalScrollBar();
659 if ((hsb != null) && (hsb.isVisible())) {
660 borderR.height -= hsb.getHeight();
661 }
662
663 return borderR;
664 }
665
666
667 /**
668 * By default <code>JScrollPane</code> creates scrollbars
669 * that are instances
670 * of this class. <code>Scrollbar</code> overrides the
671 * <code>getUnitIncrement</code> and <code>getBlockIncrement</code>
672 * methods so that, if the viewport's view is a <code>Scrollable</code>,
673 * the view is asked to compute these values. Unless
674 * the unit/block increment have been explicitly set.
675 * <p>
676 * <strong>Warning:</strong>
677 * Serialized objects of this class will not be compatible with
678 * future Swing releases. The current serialization support is
679 * appropriate for short term storage or RMI between applications running
680 * the same version of Swing. As of 1.4, support for long term storage
681 * of all JavaBeans<sup><font size="-2">TM</font></sup>
682 * has been added to the <code>java.beans</code> package.
683 * Please see {@link java.beans.XMLEncoder}.
684 *
685 * @see Scrollable
686 * @see JScrollPane#createVerticalScrollBar
687 * @see JScrollPane#createHorizontalScrollBar
688 */
689 protected class ScrollBar extends JScrollBar implements UIResource
690 {
691 /**
692 * Set to true when the unit increment has been explicitly set.
693 * If this is false the viewport's view is obtained and if it
694 * is an instance of <code>Scrollable</code> the unit increment
695 * from it is used.
696 */
697 private boolean unitIncrementSet;
698 /**
699 * Set to true when the block increment has been explicitly set.
700 * If this is false the viewport's view is obtained and if it
701 * is an instance of <code>Scrollable</code> the block increment
702 * from it is used.
703 */
704 private boolean blockIncrementSet;
705
706 /**
707 * Creates a scrollbar with the specified orientation.
708 * The options are:
709 * <ul>
710 * <li><code>ScrollPaneConstants.VERTICAL</code>
711 * <li><code>ScrollPaneConstants.HORIZONTAL</code>
712 * </ul>
713 *
714 * @param orientation an integer specifying one of the legal
715 * orientation values shown above
716 * @since 1.4
717 */
718 public ScrollBar(int orientation) {
719 super(orientation);
720 this.putClientProperty("JScrollBar.fastWheelScrolling",
721 Boolean.TRUE);
722 }
723
724 /**
725 * Messages super to set the value, and resets the
726 * <code>unitIncrementSet</code> instance variable to true.
727 *
728 * @param unitIncrement the new unit increment value, in pixels
729 */
730 public void setUnitIncrement(int unitIncrement) {
731 unitIncrementSet = true;
732 this.putClientProperty("JScrollBar.fastWheelScrolling", null);
733 super.setUnitIncrement(unitIncrement);
734 }
735
736 /**
737 * Computes the unit increment for scrolling if the viewport's
738 * view is a <code>Scrollable</code> object.
739 * Otherwise return <code>super.getUnitIncrement</code>.
740 *
741 * @param direction less than zero to scroll up/left,
742 * greater than zero for down/right
743 * @return an integer, in pixels, containing the unit increment
744 * @see Scrollable#getScrollableUnitIncrement
745 */
746 public int getUnitIncrement(int direction) {
747 JViewport vp = getViewport();
748 if (!unitIncrementSet && (vp != null) &&
749 (vp.getView() instanceof Scrollable)) {
750 Scrollable view = (Scrollable)(vp.getView());
751 Rectangle vr = vp.getViewRect();
752 return view.getScrollableUnitIncrement(vr, getOrientation(), direction);
753 }
754 else {
755 return super.getUnitIncrement(direction);
756 }
757 }
758
759 /**
760 * Messages super to set the value, and resets the
761 * <code>blockIncrementSet</code> instance variable to true.
762 *
763 * @param blockIncrement the new block increment value, in pixels
764 */
765 public void setBlockIncrement(int blockIncrement) {
766 blockIncrementSet = true;
767 this.putClientProperty("JScrollBar.fastWheelScrolling", null);
768 super.setBlockIncrement(blockIncrement);
769 }
770
771 /**
772 * Computes the block increment for scrolling if the viewport's
773 * view is a <code>Scrollable</code> object. Otherwise
774 * the <code>blockIncrement</code> equals the viewport's width
775 * or height. If there's no viewport return
776 * <code>super.getBlockIncrement</code>.
777 *
778 * @param direction less than zero to scroll up/left,
779 * greater than zero for down/right
780 * @return an integer, in pixels, containing the block increment
781 * @see Scrollable#getScrollableBlockIncrement
782 */
783 public int getBlockIncrement(int direction) {
784 JViewport vp = getViewport();
785 if (blockIncrementSet || vp == null) {
786 return super.getBlockIncrement(direction);
787 }
788 else if (vp.getView() instanceof Scrollable) {
789 Scrollable view = (Scrollable)(vp.getView());
790 Rectangle vr = vp.getViewRect();
791 return view.getScrollableBlockIncrement(vr, getOrientation(), direction);
792 }
793 else if (getOrientation() == VERTICAL) {
794 return vp.getExtentSize().height;
795 }
796 else {
797 return vp.getExtentSize().width;
798 }
799 }
800
801 }
802
803
804 /**
805 * Returns a <code>JScrollPane.ScrollBar</code> by default.
806 * Subclasses may override this method to force <code>ScrollPaneUI</code>
807 * implementations to use a <code>JScrollBar</code> subclass.
808 * Used by <code>ScrollPaneUI</code> implementations to
809 * create the horizontal scrollbar.
810 *
811 * @return a <code>JScrollBar</code> with a horizontal orientation
812 * @see JScrollBar
813 */
814 public JScrollBar createHorizontalScrollBar() {
815 return new ScrollBar(JScrollBar.HORIZONTAL);
816 }
817
818
819 /**
820 * Returns the horizontal scroll bar that controls the viewport's
821 * horizontal view position.
822 *
823 * @return the <code>horizontalScrollBar</code> property
824 * @see #setHorizontalScrollBar
825 */
826 @Transient
827 public JScrollBar getHorizontalScrollBar() {
828 return horizontalScrollBar;
829 }
830
831
832 /**
833 * Adds the scrollbar that controls the viewport's horizontal view
834 * position to the scrollpane.
835 * This is usually unnecessary, as <code>JScrollPane</code> creates
836 * horizontal and vertical scrollbars by default.
837 *
838 * @param horizontalScrollBar the horizontal scrollbar to be added
839 * @see #createHorizontalScrollBar
840 * @see #getHorizontalScrollBar
841 *
842 * @beaninfo
843 * expert: true
844 * bound: true
845 * description: The horizontal scrollbar.
846 */
847 public void setHorizontalScrollBar(JScrollBar horizontalScrollBar) {
848 JScrollBar old = getHorizontalScrollBar();
849 this.horizontalScrollBar = horizontalScrollBar;
850 if (horizontalScrollBar != null) {
851 add(horizontalScrollBar, HORIZONTAL_SCROLLBAR);
852 }
853 else if (old != null) {
854 remove(old);
855 }
856 firePropertyChange("horizontalScrollBar", old, horizontalScrollBar);
857
858 revalidate();
859 repaint();
860 }
861
862
863 /**
864 * Returns a <code>JScrollPane.ScrollBar</code> by default. Subclasses
865 * may override this method to force <code>ScrollPaneUI</code>
866 * implementations to use a <code>JScrollBar</code> subclass.
867 * Used by <code>ScrollPaneUI</code> implementations to create the
868 * vertical scrollbar.
869 *
870 * @return a <code>JScrollBar</code> with a vertical orientation
871 * @see JScrollBar
872 */
873 public JScrollBar createVerticalScrollBar() {
874 return new ScrollBar(JScrollBar.VERTICAL);
875 }
876
877
878 /**
879 * Returns the vertical scroll bar that controls the viewports
880 * vertical view position.
881 *
882 * @return the <code>verticalScrollBar</code> property
883 * @see #setVerticalScrollBar
884 */
885 @Transient
886 public JScrollBar getVerticalScrollBar() {
887 return verticalScrollBar;
888 }
889
890
891 /**
892 * Adds the scrollbar that controls the viewports vertical view position
893 * to the scrollpane. This is usually unnecessary,
894 * as <code>JScrollPane</code> creates vertical and
895 * horizontal scrollbars by default.
896 *
897 * @param verticalScrollBar the new vertical scrollbar to be added
898 * @see #createVerticalScrollBar
899 * @see #getVerticalScrollBar
900 *
901 * @beaninfo
902 * expert: true
903 * bound: true
904 * description: The vertical scrollbar.
905 */
906 public void setVerticalScrollBar(JScrollBar verticalScrollBar) {
907 JScrollBar old = getVerticalScrollBar();
908 this.verticalScrollBar = verticalScrollBar;
909 add(verticalScrollBar, VERTICAL_SCROLLBAR);
910 firePropertyChange("verticalScrollBar", old, verticalScrollBar);
911
912 revalidate();
913 repaint();
914 }
915
916
917 /**
918 * Returns a new <code>JViewport</code> by default.
919 * Used to create the
920 * viewport (as needed) in <code>setViewportView</code>,
921 * <code>setRowHeaderView</code>, and <code>setColumnHeaderView</code>.
922 * Subclasses may override this method to return a subclass of
923 * <code>JViewport</code>.
924 *
925 * @return a new <code>JViewport</code>
926 */
927 protected JViewport createViewport() {
928 return new JViewport();
929 }
930
931
932 /**
933 * Returns the current <code>JViewport</code>.
934 *
935 * @see #setViewport
936 * @return the <code>viewport</code> property
937 */
938 public JViewport getViewport() {
939 return viewport;
940 }
941
942
943 /**
944 * Removes the old viewport (if there is one); forces the
945 * viewPosition of the new viewport to be in the +x,+y quadrant;
946 * syncs up the row and column headers (if there are any) with the
947 * new viewport; and finally syncs the scrollbars and
948 * headers with the new viewport.
949 * <p>
950 * Most applications will find it more convenient to use
951 * <code>setViewportView</code>
952 * to add a viewport and a view to the scrollpane.
953 *
954 * @param viewport the new viewport to be used; if viewport is
955 * <code>null</code>, the old viewport is still removed
956 * and the new viewport is set to <code>null</code>
957 * @see #createViewport
958 * @see #getViewport
959 * @see #setViewportView
960 *
961 * @beaninfo
962 * expert: true
963 * bound: true
964 * attribute: visualUpdate true
965 * description: The viewport child for this scrollpane
966 *
967 */
968 public void setViewport(JViewport viewport) {
969 JViewport old = getViewport();
970 this.viewport = viewport;
971 if (viewport != null) {
972 add(viewport, VIEWPORT);
973 }
974 else if (old != null) {
975 remove(old);
976 }
977 firePropertyChange("viewport", old, viewport);
978
979 if (accessibleContext != null) {
980 ((AccessibleJScrollPane)accessibleContext).resetViewPort();
981 }
982
983 revalidate();
984 repaint();
985 }
986
987
988 /**
989 * Creates a viewport if necessary and then sets its view. Applications
990 * that don't provide the view directly to the <code>JScrollPane</code>
991 * constructor
992 * should use this method to specify the scrollable child that's going
993 * to be displayed in the scrollpane. For example:
994 * <pre>
995 * JScrollPane scrollpane = new JScrollPane();
996 * scrollpane.setViewportView(myBigComponentToScroll);
997 * </pre>
998 * Applications should not add children directly to the scrollpane.
999 *
1000 * @param view the component to add to the viewport
1001 * @see #setViewport
1002 * @see JViewport#setView
1003 */
1004 public void setViewportView(Component view) {
1005 if (getViewport() == null) {
1006 setViewport(createViewport());
1007 }
1008 getViewport().setView(view);
1009 }
1010
1011
1012
1013 /**
1014 * Returns the row header.
1015 * @return the <code>rowHeader</code> property
1016 * @see #setRowHeader
1017 */
1018 @Transient
1019 public JViewport getRowHeader() {
1020 return rowHeader;
1021 }
1022
1023
1024 /**
1025 * Removes the old rowHeader, if it exists; if the new rowHeader
1026 * isn't <code>null</code>, syncs the y coordinate of its
1027 * viewPosition with
1028 * the viewport (if there is one) and then adds it to the scroll pane.
1029 * <p>
1030 * Most applications will find it more convenient to use
1031 * <code>setRowHeaderView</code>
1032 * to add a row header component and its viewport to the scroll pane.
1033 *
1034 * @param rowHeader the new row header to be used; if <code>null</code>
1035 * the old row header is still removed and the new rowHeader
1036 * is set to <code>null</code>
1037 * @see #getRowHeader
1038 * @see #setRowHeaderView
1039 *
1040 * @beaninfo
1041 * bound: true
1042 * expert: true
1043 * description: The row header child for this scrollpane
1044 */
1045 public void setRowHeader(JViewport rowHeader) {
1046 JViewport old = getRowHeader();
1047 this.rowHeader = rowHeader;
1048 if (rowHeader != null) {
1049 add(rowHeader, ROW_HEADER);
1050 }
1051 else if (old != null) {
1052 remove(old);
1053 }
1054 firePropertyChange("rowHeader", old, rowHeader);
1055 revalidate();
1056 repaint();
1057 }
1058
1059
1060 /**
1061 * Creates a row-header viewport if necessary, sets
1062 * its view and then adds the row-header viewport
1063 * to the scrollpane. For example:
1064 * <pre>
1065 * JScrollPane scrollpane = new JScrollPane();
1066 * scrollpane.setViewportView(myBigComponentToScroll);
1067 * scrollpane.setRowHeaderView(myBigComponentsRowHeader);
1068 * </pre>
1069 *
1070 * @see #setRowHeader
1071 * @see JViewport#setView
1072 * @param view the component to display as the row header
1073 */
1074 public void setRowHeaderView(Component view) {
1075 if (getRowHeader() == null) {
1076 setRowHeader(createViewport());
1077 }
1078 getRowHeader().setView(view);
1079 }
1080
1081
1082
1083 /**
1084 * Returns the column header.
1085 * @return the <code>columnHeader</code> property
1086 * @see #setColumnHeader
1087 */
1088 @Transient
1089 public JViewport getColumnHeader() {
1090 return columnHeader;
1091 }
1092
1093
1094 /**
1095 * Removes the old columnHeader, if it exists; if the new columnHeader
1096 * isn't <code>null</code>, syncs the x coordinate of its viewPosition
1097 * with the viewport (if there is one) and then adds it to the scroll pane.
1098 * <p>
1099 * Most applications will find it more convenient to use
1100 * <code>setColumnHeaderView</code>
1101 * to add a column header component and its viewport to the scroll pane.
1102 *
1103 * @see #getColumnHeader
1104 * @see #setColumnHeaderView
1105 *
1106 * @beaninfo
1107 * bound: true
1108 * description: The column header child for this scrollpane
1109 * attribute: visualUpdate true
1110 */
1111 public void setColumnHeader(JViewport columnHeader) {
1112 JViewport old = getColumnHeader();
1113 this.columnHeader = columnHeader;
1114 if (columnHeader != null) {
1115 add(columnHeader, COLUMN_HEADER);
1116 }
1117 else if (old != null) {
1118 remove(old);
1119 }
1120 firePropertyChange("columnHeader", old, columnHeader);
1121
1122 revalidate();
1123 repaint();
1124 }
1125
1126
1127
1128 /**
1129 * Creates a column-header viewport if necessary, sets
1130 * its view, and then adds the column-header viewport
1131 * to the scrollpane. For example:
1132 * <pre>
1133 * JScrollPane scrollpane = new JScrollPane();
1134 * scrollpane.setViewportView(myBigComponentToScroll);
1135 * scrollpane.setColumnHeaderView(myBigComponentsColumnHeader);
1136 * </pre>
1137 *
1138 * @see #setColumnHeader
1139 * @see JViewport#setView
1140 *
1141 * @param view the component to display as the column header
1142 */
1143 public void setColumnHeaderView(Component view) {
1144 if (getColumnHeader() == null) {
1145 setColumnHeader(createViewport());
1146 }
1147 getColumnHeader().setView(view);
1148 }
1149
1150
1151 /**
1152 * Returns the component at the specified corner. The
1153 * <code>key</code> value specifying the corner is one of:
1154 * <ul>
1155 * <li>ScrollPaneConstants.LOWER_LEFT_CORNER
1156 * <li>ScrollPaneConstants.LOWER_RIGHT_CORNER
1157 * <li>ScrollPaneConstants.UPPER_LEFT_CORNER
1158 * <li>ScrollPaneConstants.UPPER_RIGHT_CORNER
1159 * <li>ScrollPaneConstants.LOWER_LEADING_CORNER
1160 * <li>ScrollPaneConstants.LOWER_TRAILING_CORNER
1161 * <li>ScrollPaneConstants.UPPER_LEADING_CORNER
1162 * <li>ScrollPaneConstants.UPPER_TRAILING_CORNER
1163 * </ul>
1164 *
1165 * @param key one of the values as shown above
1166 * @return the corner component (which may be <code>null</code>)
1167 * identified by the given key, or <code>null</code>
1168 * if the key is invalid
1169 * @see #setCorner
1170 */
1171 public Component getCorner(String key) {
1172 boolean isLeftToRight = getComponentOrientation().isLeftToRight();
1173 if (key.equals(LOWER_LEADING_CORNER)) {
1174 key = isLeftToRight ? LOWER_LEFT_CORNER : LOWER_RIGHT_CORNER;
1175 } else if (key.equals(LOWER_TRAILING_CORNER)) {
1176 key = isLeftToRight ? LOWER_RIGHT_CORNER : LOWER_LEFT_CORNER;
1177 } else if (key.equals(UPPER_LEADING_CORNER)) {
1178 key = isLeftToRight ? UPPER_LEFT_CORNER : UPPER_RIGHT_CORNER;
1179 } else if (key.equals(UPPER_TRAILING_CORNER)) {
1180 key = isLeftToRight ? UPPER_RIGHT_CORNER : UPPER_LEFT_CORNER;
1181 }
1182 if (key.equals(LOWER_LEFT_CORNER)) {
1183 return lowerLeft;
1184 }
1185 else if (key.equals(LOWER_RIGHT_CORNER)) {
1186 return lowerRight;
1187 }
1188 else if (key.equals(UPPER_LEFT_CORNER)) {
1189 return upperLeft;
1190 }
1191 else if (key.equals(UPPER_RIGHT_CORNER)) {
1192 return upperRight;
1193 }
1194 else {
1195 return null;
1196 }
1197 }
1198
1199
1200 /**
1201 * Adds a child that will appear in one of the scroll panes
1202 * corners, if there's room. For example with both scrollbars
1203 * showing (on the right and bottom edges of the scrollpane)
1204 * the lower left corner component will be shown in the space
1205 * between ends of the two scrollbars. Legal values for
1206 * the <b>key</b> are:
1207 * <ul>
1208 * <li>ScrollPaneConstants.LOWER_LEFT_CORNER
1209 * <li>ScrollPaneConstants.LOWER_RIGHT_CORNER
1210 * <li>ScrollPaneConstants.UPPER_LEFT_CORNER
1211 * <li>ScrollPaneConstants.UPPER_RIGHT_CORNER
1212 * <li>ScrollPaneConstants.LOWER_LEADING_CORNER
1213 * <li>ScrollPaneConstants.LOWER_TRAILING_CORNER
1214 * <li>ScrollPaneConstants.UPPER_LEADING_CORNER
1215 * <li>ScrollPaneConstants.UPPER_TRAILING_CORNER
1216 * </ul>
1217 * <p>
1218 * Although "corner" doesn't match any beans property
1219 * signature, <code>PropertyChange</code> events are generated with the
1220 * property name set to the corner key.
1221 *
1222 * @param key identifies which corner the component will appear in
1223 * @param corner one of the following components:
1224 * <ul>
1225 * <li>lowerLeft
1226 * <li>lowerRight
1227 * <li>upperLeft
1228 * <li>upperRight
1229 * </ul>
1230 * @exception IllegalArgumentException if corner key is invalid
1231 */
1232 public void setCorner(String key, Component corner)
1233 {
1234 Component old;
1235 boolean isLeftToRight = getComponentOrientation().isLeftToRight();
1236 if (key.equals(LOWER_LEADING_CORNER)) {
1237 key = isLeftToRight ? LOWER_LEFT_CORNER : LOWER_RIGHT_CORNER;
1238 } else if (key.equals(LOWER_TRAILING_CORNER)) {
1239 key = isLeftToRight ? LOWER_RIGHT_CORNER : LOWER_LEFT_CORNER;
1240 } else if (key.equals(UPPER_LEADING_CORNER)) {
1241 key = isLeftToRight ? UPPER_LEFT_CORNER : UPPER_RIGHT_CORNER;
1242 } else if (key.equals(UPPER_TRAILING_CORNER)) {
1243 key = isLeftToRight ? UPPER_RIGHT_CORNER : UPPER_LEFT_CORNER;
1244 }
1245 if (key.equals(LOWER_LEFT_CORNER)) {
1246 old = lowerLeft;
1247 lowerLeft = corner;
1248 }
1249 else if (key.equals(LOWER_RIGHT_CORNER)) {
1250 old = lowerRight;
1251 lowerRight = corner;
1252 }
1253 else if (key.equals(UPPER_LEFT_CORNER)) {
1254 old = upperLeft;
1255 upperLeft = corner;
1256 }
1257 else if (key.equals(UPPER_RIGHT_CORNER)) {
1258 old = upperRight;
1259 upperRight = corner;
1260 }
1261 else {
1262 throw new IllegalArgumentException("invalid corner key");
1263 }
1264 if (old != null) {
1265 remove(old);
1266 }
1267 if (corner != null) {
1268 add(corner, key);
1269 }
1270 firePropertyChange(key, old, corner);
1271 revalidate();
1272 repaint();
1273 }
1274
1275 /**
1276 * Sets the orientation for the vertical and horizontal
1277 * scrollbars as determined by the
1278 * <code>ComponentOrientation</code> argument.
1279 *
1280 * @param co one of the following values:
1281 * <ul>
1282 * <li>java.awt.ComponentOrientation.LEFT_TO_RIGHT
1283 * <li>java.awt.ComponentOrientation.RIGHT_TO_LEFT
1284 * <li>java.awt.ComponentOrientation.UNKNOWN
1285 * </ul>
1286 * @see java.awt.ComponentOrientation
1287 */
1288 public void setComponentOrientation( ComponentOrientation co ) {
1289 super.setComponentOrientation( co );
1290 if( verticalScrollBar != null )
1291 verticalScrollBar.setComponentOrientation( co );
1292 if( horizontalScrollBar != null )
1293 horizontalScrollBar.setComponentOrientation( co );
1294 }
1295
1296 /**
1297 * Indicates whether or not scrolling will take place in response to the
1298 * mouse wheel. Wheel scrolling is enabled by default.
1299 *
1300 * @see #setWheelScrollingEnabled
1301 * @since 1.4
1302 * @beaninfo
1303 * bound: true
1304 * description: Flag for enabling/disabling mouse wheel scrolling
1305 */
1306 public boolean isWheelScrollingEnabled() {return wheelScrollState;}
1307
1308 /**
1309 * Enables/disables scrolling in response to movement of the mouse wheel.
1310 * Wheel scrolling is enabled by default.
1311 *
1312 * @param handleWheel <code>true</code> if scrolling should be done
1313 * automatically for a MouseWheelEvent,
1314 * <code>false</code> otherwise.
1315 * @see #isWheelScrollingEnabled
1316 * @see java.awt.event.MouseWheelEvent
1317 * @see java.awt.event.MouseWheelListener
1318 * @since 1.4
1319 * @beaninfo
1320 * bound: true
1321 * description: Flag for enabling/disabling mouse wheel scrolling
1322 */
1323 public void setWheelScrollingEnabled(boolean handleWheel) {
1324 boolean old = wheelScrollState;
1325 wheelScrollState = handleWheel;
1326 firePropertyChange("wheelScrollingEnabled", old, handleWheel);
1327 }
1328
1329 /**
1330 * See <code>readObject</code> and <code>writeObject</code> in
1331 * <code>JComponent</code> for more
1332 * information about serialization in Swing.
1333 */
1334 private void writeObject(ObjectOutputStream s) throws IOException {
1335 s.defaultWriteObject();
1336 if (getUIClassID().equals(uiClassID)) {
1337 byte count = JComponent.getWriteObjCounter(this);
1338 JComponent.setWriteObjCounter(this, --count);
1339 if (count == 0 && ui != null) {
1340 ui.installUI(this);
1341 }
1342 }
1343 }
1344
1345
1346 /**
1347 * Returns a string representation of this <code>JScrollPane</code>.
1348 * This method
1349 * is intended to be used only for debugging purposes, and the
1350 * content and format of the returned string may vary between
1351 * implementations. The returned string may be empty but may not
1352 * be <code>null</code>.
1353 *
1354 * @return a string representation of this <code>JScrollPane</code>.
1355 */
1356 protected String paramString() {
1357 String viewportBorderString = (viewportBorder != null ?
1358 viewportBorder.toString() : "");
1359 String viewportString = (viewport != null ?
1360 viewport.toString() : "");
1361 String verticalScrollBarPolicyString;
1362 if (verticalScrollBarPolicy == VERTICAL_SCROLLBAR_AS_NEEDED) {
1363 verticalScrollBarPolicyString = "VERTICAL_SCROLLBAR_AS_NEEDED";
1364 } else if (verticalScrollBarPolicy == VERTICAL_SCROLLBAR_NEVER) {
1365 verticalScrollBarPolicyString = "VERTICAL_SCROLLBAR_NEVER";
1366 } else if (verticalScrollBarPolicy == VERTICAL_SCROLLBAR_ALWAYS) {
1367 verticalScrollBarPolicyString = "VERTICAL_SCROLLBAR_ALWAYS";
1368 } else verticalScrollBarPolicyString = "";
1369 String horizontalScrollBarPolicyString;
1370 if (horizontalScrollBarPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED) {
1371 horizontalScrollBarPolicyString = "HORIZONTAL_SCROLLBAR_AS_NEEDED";
1372 } else if (horizontalScrollBarPolicy == HORIZONTAL_SCROLLBAR_NEVER) {
1373 horizontalScrollBarPolicyString = "HORIZONTAL_SCROLLBAR_NEVER";
1374 } else if (horizontalScrollBarPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) {
1375 horizontalScrollBarPolicyString = "HORIZONTAL_SCROLLBAR_ALWAYS";
1376 } else horizontalScrollBarPolicyString = "";
1377 String horizontalScrollBarString = (horizontalScrollBar != null ?
1378 horizontalScrollBar.toString()
1379 : "");
1380 String verticalScrollBarString = (verticalScrollBar != null ?
1381 verticalScrollBar.toString() : "");
1382 String columnHeaderString = (columnHeader != null ?
1383 columnHeader.toString() : "");
1384 String rowHeaderString = (rowHeader != null ?
1385 rowHeader.toString() : "");
1386 String lowerLeftString = (lowerLeft != null ?
1387 lowerLeft.toString() : "");
1388 String lowerRightString = (lowerRight != null ?
1389 lowerRight.toString() : "");
1390 String upperLeftString = (upperLeft != null ?
1391 upperLeft.toString() : "");
1392 String upperRightString = (upperRight != null ?
1393 upperRight.toString() : "");
1394
1395 return super.paramString() +
1396 ",columnHeader=" + columnHeaderString +
1397 ",horizontalScrollBar=" + horizontalScrollBarString +
1398 ",horizontalScrollBarPolicy=" + horizontalScrollBarPolicyString +
1399 ",lowerLeft=" + lowerLeftString +
1400 ",lowerRight=" + lowerRightString +
1401 ",rowHeader=" + rowHeaderString +
1402 ",upperLeft=" + upperLeftString +
1403 ",upperRight=" + upperRightString +
1404 ",verticalScrollBar=" + verticalScrollBarString +
1405 ",verticalScrollBarPolicy=" + verticalScrollBarPolicyString +
1406 ",viewport=" + viewportString +
1407 ",viewportBorder=" + viewportBorderString;
1408 }
1409
1410 /////////////////
1411 // Accessibility support
1412 ////////////////
1413
1414 /**
1415 * Gets the AccessibleContext associated with this JScrollPane.
1416 * For scroll panes, the AccessibleContext takes the form of an
1417 * AccessibleJScrollPane.
1418 * A new AccessibleJScrollPane instance is created if necessary.
1419 *
1420 * @return an AccessibleJScrollPane that serves as the
1421 * AccessibleContext of this JScrollPane
1422 */
1423 public AccessibleContext getAccessibleContext() {
1424 if (accessibleContext == null) {
1425 accessibleContext = new AccessibleJScrollPane();
1426 }
1427 return accessibleContext;
1428 }
1429
1430 /**
1431 * This class implements accessibility support for the
1432 * <code>JScrollPane</code> class. It provides an implementation of the
1433 * Java Accessibility API appropriate to scroll pane user-interface
1434 * elements.
1435 * <p>
1436 * <strong>Warning:</strong>
1437 * Serialized objects of this class will not be compatible with
1438 * future Swing releases. The current serialization support is
1439 * appropriate for short term storage or RMI between applications running
1440 * the same version of Swing. As of 1.4, support for long term storage
1441 * of all JavaBeans<sup><font size="-2">TM</font></sup>
1442 * has been added to the <code>java.beans</code> package.
1443 * Please see {@link java.beans.XMLEncoder}.
1444 */
1445 protected class AccessibleJScrollPane extends AccessibleJComponent
1446 implements ChangeListener, PropertyChangeListener {
1447
1448 protected JViewport viewPort = null;
1449
1450 /*
1451 * Resets the viewport ChangeListener and PropertyChangeListener
1452 */
1453 public void resetViewPort() {
1454 if (viewPort != null) {
1455 viewPort.removeChangeListener(this);
1456 viewPort.removePropertyChangeListener(this);
1457 }
1458 viewPort = JScrollPane.this.getViewport();
1459 if (viewPort != null) {
1460 viewPort.addChangeListener(this);
1461 viewPort.addPropertyChangeListener(this);
1462 }
1463 }
1464
1465 /**
1466 * AccessibleJScrollPane constructor
1467 */
1468 public AccessibleJScrollPane() {
1469 super();
1470
1471 resetViewPort();
1472
1473 // initialize the AccessibleRelationSets for the JScrollPane
1474 // and JScrollBar(s)
1475 JScrollBar scrollBar = getHorizontalScrollBar();
1476 if (scrollBar != null) {
1477 setScrollBarRelations(scrollBar);
1478 }
1479 scrollBar = getVerticalScrollBar();
1480 if (scrollBar != null) {
1481 setScrollBarRelations(scrollBar);
1482 }
1483 }
1484
1485 /**
1486 * Get the role of this object.
1487 *
1488 * @return an instance of AccessibleRole describing the role of the
1489 * object
1490 * @see AccessibleRole
1491 */
1492 public AccessibleRole getAccessibleRole() {
1493 return AccessibleRole.SCROLL_PANE;
1494 }
1495
1496 /**
1497 * Invoked when the target of the listener has changed its state.
1498 *
1499 * @param e a <code>ChangeEvent</code> object. Must not be null.
1500 *
1501 * @throws NullPointerException if the parameter is null.
1502 */
1503 public void stateChanged(ChangeEvent e) {
1504 if (e == null) {
1505 throw new NullPointerException();
1506 }
1507 firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY,
1508 Boolean.valueOf(false),
1509 Boolean.valueOf(true));
1510 }
1511
1512 /**
1513 * This method gets called when a bound property is changed.
1514 * @param e A <code>PropertyChangeEvent</code> object describing
1515 * the event source and the property that has changed. Must not be null.
1516 *
1517 * @throws NullPointerException if the parameter is null.
1518 * @since 1.5
1519 */
1520 public void propertyChange(PropertyChangeEvent e) {
1521 String propertyName = e.getPropertyName();
1522 if (propertyName == "horizontalScrollBar" ||
1523 propertyName == "verticalScrollBar") {
1524
1525 if (e.getNewValue() instanceof JScrollBar) {
1526 setScrollBarRelations((JScrollBar)e.getNewValue());
1527 }
1528 }
1529 }
1530
1531
1532 /*
1533 * Sets the CONTROLLER_FOR and CONTROLLED_BY AccessibleRelations for
1534 * the JScrollPane and JScrollBar. JScrollBar must not be null.
1535 */
1536 void setScrollBarRelations(JScrollBar scrollBar) {
1537 /*
1538 * The JScrollBar is a CONTROLLER_FOR the JScrollPane.
1539 * The JScrollPane is CONTROLLED_BY the JScrollBar.
1540 */
1541 AccessibleRelation controlledBy =
1542 new AccessibleRelation(AccessibleRelation.CONTROLLED_BY,
1543 scrollBar);
1544 AccessibleRelation controllerFor =
1545 new AccessibleRelation(AccessibleRelation.CONTROLLER_FOR,
1546 JScrollPane.this);
1547
1548 // set the relation set for the scroll bar
1549 AccessibleContext ac = scrollBar.getAccessibleContext();
1550 ac.getAccessibleRelationSet().add(controllerFor);
1551
1552 // set the relation set for the scroll pane
1553 getAccessibleRelationSet().add(controlledBy);
1554 }
1555 }
1556 }