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