1 /* 2 * Copyright (c) 1997, 2014, 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 * 57 * <TABLE STYLE="FLOAT:RIGHT" BORDER="0" SUMMARY="layout"> 58 * <TR> 59 * <TD ALIGN="CENTER"> 60 * <P STYLE="TEXT-ALIGN:CENTER"><IMG SRC="doc-files/JScrollPane-1.gif" 61 * alt="The following text describes this image." 62 * WIDTH="256" HEIGHT="248" STYLE="FLOAT:BOTTOM; BORDER:0px"> 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™ 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 @SuppressWarnings("serial") // Same-version serialization only 172 public class JScrollPane extends JComponent implements ScrollPaneConstants, Accessible 173 { 174 private Border viewportBorder; 175 176 /** 177 * @see #getUIClassID 178 * @see #readObject 179 */ 180 private static final String uiClassID = "ScrollPaneUI"; 181 182 /** 183 * The display policy for the vertical scrollbar. 184 * The default is 185 * <code>ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED</code>. 186 * @see #setVerticalScrollBarPolicy 187 */ 188 protected int verticalScrollBarPolicy = VERTICAL_SCROLLBAR_AS_NEEDED; 189 190 191 /** 192 * The display policy for the horizontal scrollbar. 193 * The default is 194 * <code>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED</code>. 195 * @see #setHorizontalScrollBarPolicy 196 */ 197 protected int horizontalScrollBarPolicy = HORIZONTAL_SCROLLBAR_AS_NEEDED; 198 199 200 /** 201 * The scrollpane's viewport child. Default is an empty 202 * <code>JViewport</code>. 203 * @see #setViewport 204 */ 205 protected JViewport viewport; 206 207 208 /** 209 * The scrollpane's vertical scrollbar child. 210 * Default is a <code>JScrollBar</code>. 211 * @see #setVerticalScrollBar 212 */ 213 protected JScrollBar verticalScrollBar; 214 215 216 /** 217 * The scrollpane's horizontal scrollbar child. 218 * Default is a <code>JScrollBar</code>. 219 * @see #setHorizontalScrollBar 220 */ 221 protected JScrollBar horizontalScrollBar; 222 223 224 /** 225 * The row header child. Default is <code>null</code>. 226 * @see #setRowHeader 227 */ 228 protected JViewport rowHeader; 229 230 231 /** 232 * The column header child. Default is <code>null</code>. 233 * @see #setColumnHeader 234 */ 235 protected JViewport columnHeader; 236 237 238 /** 239 * The component to display in the lower left corner. 240 * Default is <code>null</code>. 241 * @see #setCorner 242 */ 243 protected Component lowerLeft; 244 245 246 /** 247 * The component to display in the lower right corner. 248 * Default is <code>null</code>. 249 * @see #setCorner 250 */ 251 protected Component lowerRight; 252 253 254 /** 255 * The component to display in the upper left corner. 256 * Default is <code>null</code>. 257 * @see #setCorner 258 */ 259 protected Component upperLeft; 260 261 262 /** 263 * The component to display in the upper right corner. 264 * Default is <code>null</code>. 265 * @see #setCorner 266 */ 267 protected Component upperRight; 268 269 /* 270 * State flag for mouse wheel scrolling 271 */ 272 private boolean wheelScrollState = true; 273 274 /** 275 * Creates a <code>JScrollPane</code> that displays the view 276 * component in a viewport 277 * whose view position can be controlled with a pair of scrollbars. 278 * The scrollbar policies specify when the scrollbars are displayed, 279 * For example, if <code>vsbPolicy</code> is 280 * <code>VERTICAL_SCROLLBAR_AS_NEEDED</code> 281 * then the vertical scrollbar only appears if the view doesn't fit 282 * vertically. The available policy settings are listed at 283 * {@link #setVerticalScrollBarPolicy} and 284 * {@link #setHorizontalScrollBarPolicy}. 285 * 286 * @see #setViewportView 287 * 288 * @param view the component to display in the scrollpanes viewport 289 * @param vsbPolicy an integer that specifies the vertical 290 * scrollbar policy 291 * @param hsbPolicy an integer that specifies the horizontal 292 * scrollbar policy 293 */ 294 public JScrollPane(Component view, int vsbPolicy, int hsbPolicy) 295 { 296 setLayout(new ScrollPaneLayout.UIResource()); 297 setVerticalScrollBarPolicy(vsbPolicy); 298 setHorizontalScrollBarPolicy(hsbPolicy); 299 setViewport(createViewport()); 300 setVerticalScrollBar(createVerticalScrollBar()); 301 setHorizontalScrollBar(createHorizontalScrollBar()); 302 if (view != null) { 303 setViewportView(view); 304 } 305 setUIProperty("opaque",true); 306 updateUI(); 307 308 if (!this.getComponentOrientation().isLeftToRight()) { 309 viewport.setViewPosition(new Point(Integer.MAX_VALUE, 0)); 310 } 311 } 312 313 314 /** 315 * Creates a <code>JScrollPane</code> that displays the 316 * contents of the specified 317 * component, where both horizontal and vertical scrollbars appear 318 * whenever the component's contents are larger than the view. 319 * 320 * @see #setViewportView 321 * @param view the component to display in the scrollpane's viewport 322 */ 323 public JScrollPane(Component view) { 324 this(view, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED); 325 } 326 327 328 /** 329 * Creates an empty (no viewport view) <code>JScrollPane</code> 330 * with specified 331 * scrollbar policies. The available policy settings are listed at 332 * {@link #setVerticalScrollBarPolicy} and 333 * {@link #setHorizontalScrollBarPolicy}. 334 * 335 * @see #setViewportView 336 * 337 * @param vsbPolicy an integer that specifies the vertical 338 * scrollbar policy 339 * @param hsbPolicy an integer that specifies the horizontal 340 * scrollbar policy 341 */ 342 public JScrollPane(int vsbPolicy, int hsbPolicy) { 343 this(null, vsbPolicy, hsbPolicy); 344 } 345 346 347 /** 348 * Creates an empty (no viewport view) <code>JScrollPane</code> 349 * where both horizontal and vertical scrollbars appear when needed. 350 */ 351 public JScrollPane() { 352 this(null, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED); 353 } 354 355 356 /** 357 * Returns the look and feel (L&F) object that renders this component. 358 * 359 * @return the <code>ScrollPaneUI</code> object that renders this 360 * component 361 * @see #setUI 362 * @beaninfo 363 * bound: true 364 * hidden: true 365 * attribute: visualUpdate true 366 * description: The UI object that implements the Component's LookAndFeel. 367 */ 368 public ScrollPaneUI getUI() { 369 return (ScrollPaneUI)ui; 370 } 371 372 373 /** 374 * Sets the <code>ScrollPaneUI</code> object that provides the 375 * look and feel (L&F) for this component. 376 * 377 * @param ui the <code>ScrollPaneUI</code> L&F object 378 * @see #getUI 379 */ 380 public void setUI(ScrollPaneUI ui) { 381 super.setUI(ui); 382 } 383 384 385 /** 386 * Replaces the current <code>ScrollPaneUI</code> object with a version 387 * from the current default look and feel. 388 * To be called when the default look and feel changes. 389 * 390 * @see JComponent#updateUI 391 * @see UIManager#getUI 392 */ 393 public void updateUI() { 394 setUI((ScrollPaneUI)UIManager.getUI(this)); 395 } 396 397 398 /** 399 * Returns the suffix used to construct the name of the L&F class used to 400 * render this component. 401 * 402 * @return the string "ScrollPaneUI" 403 * @see JComponent#getUIClassID 404 * @see UIDefaults#getUI 405 * 406 * @beaninfo 407 * hidden: true 408 */ 409 public String getUIClassID() { 410 return uiClassID; 411 } 412 413 414 415 /** 416 * Sets the layout manager for this <code>JScrollPane</code>. 417 * This method overrides <code>setLayout</code> in 418 * <code>java.awt.Container</code> to ensure that only 419 * <code>LayoutManager</code>s which 420 * are subclasses of <code>ScrollPaneLayout</code> can be used in a 421 * <code>JScrollPane</code>. If <code>layout</code> is non-null, this 422 * will invoke <code>syncWithScrollPane</code> on it. 423 * 424 * @param layout the specified layout manager 425 * @exception ClassCastException if layout is not a 426 * <code>ScrollPaneLayout</code> 427 * @see java.awt.Container#getLayout 428 * @see java.awt.Container#setLayout 429 * 430 * @beaninfo 431 * hidden: true 432 */ 433 public void setLayout(LayoutManager layout) { 434 if (layout instanceof ScrollPaneLayout) { 435 super.setLayout(layout); 436 ((ScrollPaneLayout)layout).syncWithScrollPane(this); 437 } 438 else if (layout == null) { 439 super.setLayout(layout); 440 } 441 else { 442 String s = "layout of JScrollPane must be a ScrollPaneLayout"; 443 throw new ClassCastException(s); 444 } 445 } 446 447 /** 448 * Overridden to return true so that any calls to <code>revalidate</code> 449 * on any descendants of this <code>JScrollPane</code> will cause the 450 * entire tree beginning with this <code>JScrollPane</code> to be 451 * validated. 452 * 453 * @return true 454 * @see java.awt.Container#validate 455 * @see JComponent#revalidate 456 * @see JComponent#isValidateRoot 457 * @see java.awt.Container#isValidateRoot 458 * 459 * @beaninfo 460 * hidden: true 461 */ 462 @Override 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™ 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 @SuppressWarnings("serial") // Same-version serialization only 690 protected class ScrollBar extends JScrollBar implements UIResource 691 { 692 /** 693 * Set to true when the unit increment has been explicitly set. 694 * If this is false the viewport's view is obtained and if it 695 * is an instance of <code>Scrollable</code> the unit increment 696 * from it is used. 697 */ 698 private boolean unitIncrementSet; 699 /** 700 * Set to true when the block increment has been explicitly set. 701 * If this is false the viewport's view is obtained and if it 702 * is an instance of <code>Scrollable</code> the block increment 703 * from it is used. 704 */ 705 private boolean blockIncrementSet; 706 707 /** 708 * Creates a scrollbar with the specified orientation. 709 * The options are: 710 * <ul> 711 * <li><code>ScrollPaneConstants.VERTICAL</code> 712 * <li><code>ScrollPaneConstants.HORIZONTAL</code> 713 * </ul> 714 * 715 * @param orientation an integer specifying one of the legal 716 * orientation values shown above 717 * @since 1.4 718 */ 719 public ScrollBar(int orientation) { 720 super(orientation); 721 this.putClientProperty("JScrollBar.fastWheelScrolling", 722 Boolean.TRUE); 723 } 724 725 /** 726 * Messages super to set the value, and resets the 727 * <code>unitIncrementSet</code> instance variable to true. 728 * 729 * @param unitIncrement the new unit increment value, in pixels 730 */ 731 public void setUnitIncrement(int unitIncrement) { 732 unitIncrementSet = true; 733 this.putClientProperty("JScrollBar.fastWheelScrolling", null); 734 super.setUnitIncrement(unitIncrement); 735 } 736 737 /** 738 * Computes the unit increment for scrolling if the viewport's 739 * view is a <code>Scrollable</code> object. 740 * Otherwise return <code>super.getUnitIncrement</code>. 741 * 742 * @param direction less than zero to scroll up/left, 743 * greater than zero for down/right 744 * @return an integer, in pixels, containing the unit increment 745 * @see Scrollable#getScrollableUnitIncrement 746 */ 747 public int getUnitIncrement(int direction) { 748 JViewport vp = getViewport(); 749 if (!unitIncrementSet && (vp != null) && 750 (vp.getView() instanceof Scrollable)) { 751 Scrollable view = (Scrollable)(vp.getView()); 752 Rectangle vr = vp.getViewRect(); 753 return view.getScrollableUnitIncrement(vr, getOrientation(), direction); 754 } 755 else { 756 return super.getUnitIncrement(direction); 757 } 758 } 759 760 /** 761 * Messages super to set the value, and resets the 762 * <code>blockIncrementSet</code> instance variable to true. 763 * 764 * @param blockIncrement the new block increment value, in pixels 765 */ 766 public void setBlockIncrement(int blockIncrement) { 767 blockIncrementSet = true; 768 this.putClientProperty("JScrollBar.fastWheelScrolling", null); 769 super.setBlockIncrement(blockIncrement); 770 } 771 772 /** 773 * Computes the block increment for scrolling if the viewport's 774 * view is a <code>Scrollable</code> object. Otherwise 775 * the <code>blockIncrement</code> equals the viewport's width 776 * or height. If there's no viewport return 777 * <code>super.getBlockIncrement</code>. 778 * 779 * @param direction less than zero to scroll up/left, 780 * greater than zero for down/right 781 * @return an integer, in pixels, containing the block increment 782 * @see Scrollable#getScrollableBlockIncrement 783 */ 784 public int getBlockIncrement(int direction) { 785 JViewport vp = getViewport(); 786 if (blockIncrementSet || vp == null) { 787 return super.getBlockIncrement(direction); 788 } 789 else if (vp.getView() instanceof Scrollable) { 790 Scrollable view = (Scrollable)(vp.getView()); 791 Rectangle vr = vp.getViewRect(); 792 return view.getScrollableBlockIncrement(vr, getOrientation(), direction); 793 } 794 else if (getOrientation() == VERTICAL) { 795 return vp.getExtentSize().height; 796 } 797 else { 798 return vp.getExtentSize().width; 799 } 800 } 801 802 } 803 804 805 /** 806 * Returns a <code>JScrollPane.ScrollBar</code> by default. 807 * Subclasses may override this method to force <code>ScrollPaneUI</code> 808 * implementations to use a <code>JScrollBar</code> subclass. 809 * Used by <code>ScrollPaneUI</code> implementations to 810 * create the horizontal scrollbar. 811 * 812 * @return a <code>JScrollBar</code> with a horizontal orientation 813 * @see JScrollBar 814 */ 815 public JScrollBar createHorizontalScrollBar() { 816 return new ScrollBar(JScrollBar.HORIZONTAL); 817 } 818 819 820 /** 821 * Returns the horizontal scroll bar that controls the viewport's 822 * horizontal view position. 823 * 824 * @return the <code>horizontalScrollBar</code> property 825 * @see #setHorizontalScrollBar 826 */ 827 @Transient 828 public JScrollBar getHorizontalScrollBar() { 829 return horizontalScrollBar; 830 } 831 832 833 /** 834 * Adds the scrollbar that controls the viewport's horizontal view 835 * position to the scrollpane. 836 * This is usually unnecessary, as <code>JScrollPane</code> creates 837 * horizontal and vertical scrollbars by default. 838 * 839 * @param horizontalScrollBar the horizontal scrollbar to be added 840 * @see #createHorizontalScrollBar 841 * @see #getHorizontalScrollBar 842 * 843 * @beaninfo 844 * expert: true 845 * bound: true 846 * description: The horizontal scrollbar. 847 */ 848 public void setHorizontalScrollBar(JScrollBar horizontalScrollBar) { 849 JScrollBar old = getHorizontalScrollBar(); 850 this.horizontalScrollBar = horizontalScrollBar; 851 if (horizontalScrollBar != null) { 852 add(horizontalScrollBar, HORIZONTAL_SCROLLBAR); 853 } 854 else if (old != null) { 855 remove(old); 856 } 857 firePropertyChange("horizontalScrollBar", old, horizontalScrollBar); 858 859 revalidate(); 860 repaint(); 861 } 862 863 864 /** 865 * Returns a <code>JScrollPane.ScrollBar</code> by default. Subclasses 866 * may override this method to force <code>ScrollPaneUI</code> 867 * implementations to use a <code>JScrollBar</code> subclass. 868 * Used by <code>ScrollPaneUI</code> implementations to create the 869 * vertical scrollbar. 870 * 871 * @return a <code>JScrollBar</code> with a vertical orientation 872 * @see JScrollBar 873 */ 874 public JScrollBar createVerticalScrollBar() { 875 return new ScrollBar(JScrollBar.VERTICAL); 876 } 877 878 879 /** 880 * Returns the vertical scroll bar that controls the viewports 881 * vertical view position. 882 * 883 * @return the <code>verticalScrollBar</code> property 884 * @see #setVerticalScrollBar 885 */ 886 @Transient 887 public JScrollBar getVerticalScrollBar() { 888 return verticalScrollBar; 889 } 890 891 892 /** 893 * Adds the scrollbar that controls the viewports vertical view position 894 * to the scrollpane. This is usually unnecessary, 895 * as <code>JScrollPane</code> creates vertical and 896 * horizontal scrollbars by default. 897 * 898 * @param verticalScrollBar the new vertical scrollbar to be added 899 * @see #createVerticalScrollBar 900 * @see #getVerticalScrollBar 901 * 902 * @beaninfo 903 * expert: true 904 * bound: true 905 * description: The vertical scrollbar. 906 */ 907 public void setVerticalScrollBar(JScrollBar verticalScrollBar) { 908 JScrollBar old = getVerticalScrollBar(); 909 this.verticalScrollBar = verticalScrollBar; 910 add(verticalScrollBar, VERTICAL_SCROLLBAR); 911 firePropertyChange("verticalScrollBar", old, verticalScrollBar); 912 913 revalidate(); 914 repaint(); 915 } 916 917 918 /** 919 * Returns a new <code>JViewport</code> by default. 920 * Used to create the 921 * viewport (as needed) in <code>setViewportView</code>, 922 * <code>setRowHeaderView</code>, and <code>setColumnHeaderView</code>. 923 * Subclasses may override this method to return a subclass of 924 * <code>JViewport</code>. 925 * 926 * @return a new <code>JViewport</code> 927 */ 928 protected JViewport createViewport() { 929 return new JViewport(); 930 } 931 932 933 /** 934 * Returns the current <code>JViewport</code>. 935 * 936 * @see #setViewport 937 * @return the <code>viewport</code> property 938 */ 939 public JViewport getViewport() { 940 return viewport; 941 } 942 943 944 /** 945 * Removes the old viewport (if there is one); forces the 946 * viewPosition of the new viewport to be in the +x,+y quadrant; 947 * syncs up the row and column headers (if there are any) with the 948 * new viewport; and finally syncs the scrollbars and 949 * headers with the new viewport. 950 * <p> 951 * Most applications will find it more convenient to use 952 * <code>setViewportView</code> 953 * to add a viewport and a view to the scrollpane. 954 * 955 * @param viewport the new viewport to be used; if viewport is 956 * <code>null</code>, the old viewport is still removed 957 * and the new viewport is set to <code>null</code> 958 * @see #createViewport 959 * @see #getViewport 960 * @see #setViewportView 961 * 962 * @beaninfo 963 * expert: true 964 * bound: true 965 * attribute: visualUpdate true 966 * description: The viewport child for this scrollpane 967 * 968 */ 969 public void setViewport(JViewport viewport) { 970 JViewport old = getViewport(); 971 this.viewport = viewport; 972 if (viewport != null) { 973 add(viewport, VIEWPORT); 974 } 975 else if (old != null) { 976 remove(old); 977 } 978 firePropertyChange("viewport", old, viewport); 979 980 if (accessibleContext != null) { 981 ((AccessibleJScrollPane)accessibleContext).resetViewPort(); 982 } 983 984 revalidate(); 985 repaint(); 986 } 987 988 989 /** 990 * Creates a viewport if necessary and then sets its view. Applications 991 * that don't provide the view directly to the <code>JScrollPane</code> 992 * constructor 993 * should use this method to specify the scrollable child that's going 994 * to be displayed in the scrollpane. For example: 995 * <pre> 996 * JScrollPane scrollpane = new JScrollPane(); 997 * scrollpane.setViewportView(myBigComponentToScroll); 998 * </pre> 999 * Applications should not add children directly to the scrollpane. 1000 * 1001 * @param view the component to add to the viewport 1002 * @see #setViewport 1003 * @see JViewport#setView 1004 */ 1005 public void setViewportView(Component view) { 1006 if (getViewport() == null) { 1007 setViewport(createViewport()); 1008 } 1009 getViewport().setView(view); 1010 } 1011 1012 1013 1014 /** 1015 * Returns the row header. 1016 * @return the <code>rowHeader</code> property 1017 * @see #setRowHeader 1018 */ 1019 @Transient 1020 public JViewport getRowHeader() { 1021 return rowHeader; 1022 } 1023 1024 1025 /** 1026 * Removes the old rowHeader, if it exists; if the new rowHeader 1027 * isn't <code>null</code>, syncs the y coordinate of its 1028 * viewPosition with 1029 * the viewport (if there is one) and then adds it to the scroll pane. 1030 * <p> 1031 * Most applications will find it more convenient to use 1032 * <code>setRowHeaderView</code> 1033 * to add a row header component and its viewport to the scroll pane. 1034 * 1035 * @param rowHeader the new row header to be used; if <code>null</code> 1036 * the old row header is still removed and the new rowHeader 1037 * is set to <code>null</code> 1038 * @see #getRowHeader 1039 * @see #setRowHeaderView 1040 * 1041 * @beaninfo 1042 * bound: true 1043 * expert: true 1044 * description: The row header child for this scrollpane 1045 */ 1046 public void setRowHeader(JViewport rowHeader) { 1047 JViewport old = getRowHeader(); 1048 this.rowHeader = rowHeader; 1049 if (rowHeader != null) { 1050 add(rowHeader, ROW_HEADER); 1051 } 1052 else if (old != null) { 1053 remove(old); 1054 } 1055 firePropertyChange("rowHeader", old, rowHeader); 1056 revalidate(); 1057 repaint(); 1058 } 1059 1060 1061 /** 1062 * Creates a row-header viewport if necessary, sets 1063 * its view and then adds the row-header viewport 1064 * to the scrollpane. For example: 1065 * <pre> 1066 * JScrollPane scrollpane = new JScrollPane(); 1067 * scrollpane.setViewportView(myBigComponentToScroll); 1068 * scrollpane.setRowHeaderView(myBigComponentsRowHeader); 1069 * </pre> 1070 * 1071 * @see #setRowHeader 1072 * @see JViewport#setView 1073 * @param view the component to display as the row header 1074 */ 1075 public void setRowHeaderView(Component view) { 1076 if (getRowHeader() == null) { 1077 setRowHeader(createViewport()); 1078 } 1079 getRowHeader().setView(view); 1080 } 1081 1082 1083 1084 /** 1085 * Returns the column header. 1086 * @return the <code>columnHeader</code> property 1087 * @see #setColumnHeader 1088 */ 1089 @Transient 1090 public JViewport getColumnHeader() { 1091 return columnHeader; 1092 } 1093 1094 1095 /** 1096 * Removes the old columnHeader, if it exists; if the new columnHeader 1097 * isn't <code>null</code>, syncs the x coordinate of its viewPosition 1098 * with the viewport (if there is one) and then adds it to the scroll pane. 1099 * <p> 1100 * Most applications will find it more convenient to use 1101 * <code>setColumnHeaderView</code> 1102 * to add a column header component and its viewport to the scroll pane. 1103 * 1104 * @see #getColumnHeader 1105 * @see #setColumnHeaderView 1106 * 1107 * @beaninfo 1108 * bound: true 1109 * description: The column header child for this scrollpane 1110 * attribute: visualUpdate true 1111 */ 1112 public void setColumnHeader(JViewport columnHeader) { 1113 JViewport old = getColumnHeader(); 1114 this.columnHeader = columnHeader; 1115 if (columnHeader != null) { 1116 add(columnHeader, COLUMN_HEADER); 1117 } 1118 else if (old != null) { 1119 remove(old); 1120 } 1121 firePropertyChange("columnHeader", old, columnHeader); 1122 1123 revalidate(); 1124 repaint(); 1125 } 1126 1127 1128 1129 /** 1130 * Creates a column-header viewport if necessary, sets 1131 * its view, and then adds the column-header viewport 1132 * to the scrollpane. For example: 1133 * <pre> 1134 * JScrollPane scrollpane = new JScrollPane(); 1135 * scrollpane.setViewportView(myBigComponentToScroll); 1136 * scrollpane.setColumnHeaderView(myBigComponentsColumnHeader); 1137 * </pre> 1138 * 1139 * @see #setColumnHeader 1140 * @see JViewport#setView 1141 * 1142 * @param view the component to display as the column header 1143 */ 1144 public void setColumnHeaderView(Component view) { 1145 if (getColumnHeader() == null) { 1146 setColumnHeader(createViewport()); 1147 } 1148 getColumnHeader().setView(view); 1149 } 1150 1151 1152 /** 1153 * Returns the component at the specified corner. The 1154 * <code>key</code> value specifying the corner is one of: 1155 * <ul> 1156 * <li>ScrollPaneConstants.LOWER_LEFT_CORNER 1157 * <li>ScrollPaneConstants.LOWER_RIGHT_CORNER 1158 * <li>ScrollPaneConstants.UPPER_LEFT_CORNER 1159 * <li>ScrollPaneConstants.UPPER_RIGHT_CORNER 1160 * <li>ScrollPaneConstants.LOWER_LEADING_CORNER 1161 * <li>ScrollPaneConstants.LOWER_TRAILING_CORNER 1162 * <li>ScrollPaneConstants.UPPER_LEADING_CORNER 1163 * <li>ScrollPaneConstants.UPPER_TRAILING_CORNER 1164 * </ul> 1165 * 1166 * @param key one of the values as shown above 1167 * @return the corner component (which may be <code>null</code>) 1168 * identified by the given key, or <code>null</code> 1169 * if the key is invalid 1170 * @see #setCorner 1171 */ 1172 public Component getCorner(String key) { 1173 boolean isLeftToRight = getComponentOrientation().isLeftToRight(); 1174 if (key.equals(LOWER_LEADING_CORNER)) { 1175 key = isLeftToRight ? LOWER_LEFT_CORNER : LOWER_RIGHT_CORNER; 1176 } else if (key.equals(LOWER_TRAILING_CORNER)) { 1177 key = isLeftToRight ? LOWER_RIGHT_CORNER : LOWER_LEFT_CORNER; 1178 } else if (key.equals(UPPER_LEADING_CORNER)) { 1179 key = isLeftToRight ? UPPER_LEFT_CORNER : UPPER_RIGHT_CORNER; 1180 } else if (key.equals(UPPER_TRAILING_CORNER)) { 1181 key = isLeftToRight ? UPPER_RIGHT_CORNER : UPPER_LEFT_CORNER; 1182 } 1183 if (key.equals(LOWER_LEFT_CORNER)) { 1184 return lowerLeft; 1185 } 1186 else if (key.equals(LOWER_RIGHT_CORNER)) { 1187 return lowerRight; 1188 } 1189 else if (key.equals(UPPER_LEFT_CORNER)) { 1190 return upperLeft; 1191 } 1192 else if (key.equals(UPPER_RIGHT_CORNER)) { 1193 return upperRight; 1194 } 1195 else { 1196 return null; 1197 } 1198 } 1199 1200 1201 /** 1202 * Adds a child that will appear in one of the scroll panes 1203 * corners, if there's room. For example with both scrollbars 1204 * showing (on the right and bottom edges of the scrollpane) 1205 * the lower left corner component will be shown in the space 1206 * between ends of the two scrollbars. Legal values for 1207 * the <b>key</b> are: 1208 * <ul> 1209 * <li>ScrollPaneConstants.LOWER_LEFT_CORNER 1210 * <li>ScrollPaneConstants.LOWER_RIGHT_CORNER 1211 * <li>ScrollPaneConstants.UPPER_LEFT_CORNER 1212 * <li>ScrollPaneConstants.UPPER_RIGHT_CORNER 1213 * <li>ScrollPaneConstants.LOWER_LEADING_CORNER 1214 * <li>ScrollPaneConstants.LOWER_TRAILING_CORNER 1215 * <li>ScrollPaneConstants.UPPER_LEADING_CORNER 1216 * <li>ScrollPaneConstants.UPPER_TRAILING_CORNER 1217 * </ul> 1218 * <p> 1219 * Although "corner" doesn't match any beans property 1220 * signature, <code>PropertyChange</code> events are generated with the 1221 * property name set to the corner key. 1222 * 1223 * @param key identifies which corner the component will appear in 1224 * @param corner one of the following components: 1225 * <ul> 1226 * <li>lowerLeft 1227 * <li>lowerRight 1228 * <li>upperLeft 1229 * <li>upperRight 1230 * </ul> 1231 * @exception IllegalArgumentException if corner key is invalid 1232 */ 1233 public void setCorner(String key, Component corner) 1234 { 1235 Component old; 1236 boolean isLeftToRight = getComponentOrientation().isLeftToRight(); 1237 if (key.equals(LOWER_LEADING_CORNER)) { 1238 key = isLeftToRight ? LOWER_LEFT_CORNER : LOWER_RIGHT_CORNER; 1239 } else if (key.equals(LOWER_TRAILING_CORNER)) { 1240 key = isLeftToRight ? LOWER_RIGHT_CORNER : LOWER_LEFT_CORNER; 1241 } else if (key.equals(UPPER_LEADING_CORNER)) { 1242 key = isLeftToRight ? UPPER_LEFT_CORNER : UPPER_RIGHT_CORNER; 1243 } else if (key.equals(UPPER_TRAILING_CORNER)) { 1244 key = isLeftToRight ? UPPER_RIGHT_CORNER : UPPER_LEFT_CORNER; 1245 } 1246 if (key.equals(LOWER_LEFT_CORNER)) { 1247 old = lowerLeft; 1248 lowerLeft = corner; 1249 } 1250 else if (key.equals(LOWER_RIGHT_CORNER)) { 1251 old = lowerRight; 1252 lowerRight = corner; 1253 } 1254 else if (key.equals(UPPER_LEFT_CORNER)) { 1255 old = upperLeft; 1256 upperLeft = corner; 1257 } 1258 else if (key.equals(UPPER_RIGHT_CORNER)) { 1259 old = upperRight; 1260 upperRight = corner; 1261 } 1262 else { 1263 throw new IllegalArgumentException("invalid corner key"); 1264 } 1265 if (old != null) { 1266 remove(old); 1267 } 1268 if (corner != null) { 1269 add(corner, key); 1270 } 1271 firePropertyChange(key, old, corner); 1272 revalidate(); 1273 repaint(); 1274 } 1275 1276 /** 1277 * Sets the orientation for the vertical and horizontal 1278 * scrollbars as determined by the 1279 * <code>ComponentOrientation</code> argument. 1280 * 1281 * @param co one of the following values: 1282 * <ul> 1283 * <li>java.awt.ComponentOrientation.LEFT_TO_RIGHT 1284 * <li>java.awt.ComponentOrientation.RIGHT_TO_LEFT 1285 * <li>java.awt.ComponentOrientation.UNKNOWN 1286 * </ul> 1287 * @see java.awt.ComponentOrientation 1288 */ 1289 public void setComponentOrientation( ComponentOrientation co ) { 1290 super.setComponentOrientation( co ); 1291 if( verticalScrollBar != null ) 1292 verticalScrollBar.setComponentOrientation( co ); 1293 if( horizontalScrollBar != null ) 1294 horizontalScrollBar.setComponentOrientation( co ); 1295 } 1296 1297 /** 1298 * Indicates whether or not scrolling will take place in response to the 1299 * mouse wheel. Wheel scrolling is enabled by default. 1300 * 1301 * @see #setWheelScrollingEnabled 1302 * @since 1.4 1303 * @beaninfo 1304 * bound: true 1305 * description: Flag for enabling/disabling mouse wheel scrolling 1306 */ 1307 public boolean isWheelScrollingEnabled() {return wheelScrollState;} 1308 1309 /** 1310 * Enables/disables scrolling in response to movement of the mouse wheel. 1311 * Wheel scrolling is enabled by default. 1312 * 1313 * @param handleWheel <code>true</code> if scrolling should be done 1314 * automatically for a MouseWheelEvent, 1315 * <code>false</code> otherwise. 1316 * @see #isWheelScrollingEnabled 1317 * @see java.awt.event.MouseWheelEvent 1318 * @see java.awt.event.MouseWheelListener 1319 * @since 1.4 1320 * @beaninfo 1321 * bound: true 1322 * description: Flag for enabling/disabling mouse wheel scrolling 1323 */ 1324 public void setWheelScrollingEnabled(boolean handleWheel) { 1325 boolean old = wheelScrollState; 1326 wheelScrollState = handleWheel; 1327 firePropertyChange("wheelScrollingEnabled", old, handleWheel); 1328 } 1329 1330 /** 1331 * See <code>readObject</code> and <code>writeObject</code> in 1332 * <code>JComponent</code> for more 1333 * information about serialization in Swing. 1334 */ 1335 private void writeObject(ObjectOutputStream s) throws IOException { 1336 s.defaultWriteObject(); 1337 if (getUIClassID().equals(uiClassID)) { 1338 byte count = JComponent.getWriteObjCounter(this); 1339 JComponent.setWriteObjCounter(this, --count); 1340 if (count == 0 && ui != null) { 1341 ui.installUI(this); 1342 } 1343 } 1344 } 1345 1346 1347 /** 1348 * Returns a string representation of this <code>JScrollPane</code>. 1349 * This method 1350 * is intended to be used only for debugging purposes, and the 1351 * content and format of the returned string may vary between 1352 * implementations. The returned string may be empty but may not 1353 * be <code>null</code>. 1354 * 1355 * @return a string representation of this <code>JScrollPane</code>. 1356 */ 1357 protected String paramString() { 1358 String viewportBorderString = (viewportBorder != null ? 1359 viewportBorder.toString() : ""); 1360 String viewportString = (viewport != null ? 1361 viewport.toString() : ""); 1362 String verticalScrollBarPolicyString; 1363 if (verticalScrollBarPolicy == VERTICAL_SCROLLBAR_AS_NEEDED) { 1364 verticalScrollBarPolicyString = "VERTICAL_SCROLLBAR_AS_NEEDED"; 1365 } else if (verticalScrollBarPolicy == VERTICAL_SCROLLBAR_NEVER) { 1366 verticalScrollBarPolicyString = "VERTICAL_SCROLLBAR_NEVER"; 1367 } else if (verticalScrollBarPolicy == VERTICAL_SCROLLBAR_ALWAYS) { 1368 verticalScrollBarPolicyString = "VERTICAL_SCROLLBAR_ALWAYS"; 1369 } else verticalScrollBarPolicyString = ""; 1370 String horizontalScrollBarPolicyString; 1371 if (horizontalScrollBarPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED) { 1372 horizontalScrollBarPolicyString = "HORIZONTAL_SCROLLBAR_AS_NEEDED"; 1373 } else if (horizontalScrollBarPolicy == HORIZONTAL_SCROLLBAR_NEVER) { 1374 horizontalScrollBarPolicyString = "HORIZONTAL_SCROLLBAR_NEVER"; 1375 } else if (horizontalScrollBarPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) { 1376 horizontalScrollBarPolicyString = "HORIZONTAL_SCROLLBAR_ALWAYS"; 1377 } else horizontalScrollBarPolicyString = ""; 1378 String horizontalScrollBarString = (horizontalScrollBar != null ? 1379 horizontalScrollBar.toString() 1380 : ""); 1381 String verticalScrollBarString = (verticalScrollBar != null ? 1382 verticalScrollBar.toString() : ""); 1383 String columnHeaderString = (columnHeader != null ? 1384 columnHeader.toString() : ""); 1385 String rowHeaderString = (rowHeader != null ? 1386 rowHeader.toString() : ""); 1387 String lowerLeftString = (lowerLeft != null ? 1388 lowerLeft.toString() : ""); 1389 String lowerRightString = (lowerRight != null ? 1390 lowerRight.toString() : ""); 1391 String upperLeftString = (upperLeft != null ? 1392 upperLeft.toString() : ""); 1393 String upperRightString = (upperRight != null ? 1394 upperRight.toString() : ""); 1395 1396 return super.paramString() + 1397 ",columnHeader=" + columnHeaderString + 1398 ",horizontalScrollBar=" + horizontalScrollBarString + 1399 ",horizontalScrollBarPolicy=" + horizontalScrollBarPolicyString + 1400 ",lowerLeft=" + lowerLeftString + 1401 ",lowerRight=" + lowerRightString + 1402 ",rowHeader=" + rowHeaderString + 1403 ",upperLeft=" + upperLeftString + 1404 ",upperRight=" + upperRightString + 1405 ",verticalScrollBar=" + verticalScrollBarString + 1406 ",verticalScrollBarPolicy=" + verticalScrollBarPolicyString + 1407 ",viewport=" + viewportString + 1408 ",viewportBorder=" + viewportBorderString; 1409 } 1410 1411 ///////////////// 1412 // Accessibility support 1413 //////////////// 1414 1415 /** 1416 * Gets the AccessibleContext associated with this JScrollPane. 1417 * For scroll panes, the AccessibleContext takes the form of an 1418 * AccessibleJScrollPane. 1419 * A new AccessibleJScrollPane instance is created if necessary. 1420 * 1421 * @return an AccessibleJScrollPane that serves as the 1422 * AccessibleContext of this JScrollPane 1423 */ 1424 public AccessibleContext getAccessibleContext() { 1425 if (accessibleContext == null) { 1426 accessibleContext = new AccessibleJScrollPane(); 1427 } 1428 return accessibleContext; 1429 } 1430 1431 /** 1432 * This class implements accessibility support for the 1433 * <code>JScrollPane</code> class. It provides an implementation of the 1434 * Java Accessibility API appropriate to scroll pane user-interface 1435 * elements. 1436 * <p> 1437 * <strong>Warning:</strong> 1438 * Serialized objects of this class will not be compatible with 1439 * future Swing releases. The current serialization support is 1440 * appropriate for short term storage or RMI between applications running 1441 * the same version of Swing. As of 1.4, support for long term storage 1442 * of all JavaBeans™ 1443 * has been added to the <code>java.beans</code> package. 1444 * Please see {@link java.beans.XMLEncoder}. 1445 */ 1446 @SuppressWarnings("serial") // Same-version serialization only 1447 protected class AccessibleJScrollPane extends AccessibleJComponent 1448 implements ChangeListener, PropertyChangeListener { 1449 1450 protected JViewport viewPort = null; 1451 1452 /* 1453 * Resets the viewport ChangeListener and PropertyChangeListener 1454 */ 1455 public void resetViewPort() { 1456 if (viewPort != null) { 1457 viewPort.removeChangeListener(this); 1458 viewPort.removePropertyChangeListener(this); 1459 } 1460 viewPort = JScrollPane.this.getViewport(); 1461 if (viewPort != null) { 1462 viewPort.addChangeListener(this); 1463 viewPort.addPropertyChangeListener(this); 1464 } 1465 } 1466 1467 /** 1468 * AccessibleJScrollPane constructor 1469 */ 1470 public AccessibleJScrollPane() { 1471 super(); 1472 1473 resetViewPort(); 1474 1475 // initialize the AccessibleRelationSets for the JScrollPane 1476 // and JScrollBar(s) 1477 JScrollBar scrollBar = getHorizontalScrollBar(); 1478 if (scrollBar != null) { 1479 setScrollBarRelations(scrollBar); 1480 } 1481 scrollBar = getVerticalScrollBar(); 1482 if (scrollBar != null) { 1483 setScrollBarRelations(scrollBar); 1484 } 1485 } 1486 1487 /** 1488 * Get the role of this object. 1489 * 1490 * @return an instance of AccessibleRole describing the role of the 1491 * object 1492 * @see AccessibleRole 1493 */ 1494 public AccessibleRole getAccessibleRole() { 1495 return AccessibleRole.SCROLL_PANE; 1496 } 1497 1498 /** 1499 * Invoked when the target of the listener has changed its state. 1500 * 1501 * @param e a <code>ChangeEvent</code> object. Must not be null. 1502 * 1503 * @throws NullPointerException if the parameter is null. 1504 */ 1505 public void stateChanged(ChangeEvent e) { 1506 if (e == null) { 1507 throw new NullPointerException(); 1508 } 1509 firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, 1510 Boolean.valueOf(false), 1511 Boolean.valueOf(true)); 1512 } 1513 1514 /** 1515 * This method gets called when a bound property is changed. 1516 * @param e A <code>PropertyChangeEvent</code> object describing 1517 * the event source and the property that has changed. Must not be null. 1518 * 1519 * @throws NullPointerException if the parameter is null. 1520 * @since 1.5 1521 */ 1522 public void propertyChange(PropertyChangeEvent e) { 1523 String propertyName = e.getPropertyName(); 1524 if (propertyName == "horizontalScrollBar" || 1525 propertyName == "verticalScrollBar") { 1526 1527 if (e.getNewValue() instanceof JScrollBar) { 1528 setScrollBarRelations((JScrollBar)e.getNewValue()); 1529 } 1530 } 1531 } 1532 1533 1534 /* 1535 * Sets the CONTROLLER_FOR and CONTROLLED_BY AccessibleRelations for 1536 * the JScrollPane and JScrollBar. JScrollBar must not be null. 1537 */ 1538 void setScrollBarRelations(JScrollBar scrollBar) { 1539 /* 1540 * The JScrollBar is a CONTROLLER_FOR the JScrollPane. 1541 * The JScrollPane is CONTROLLED_BY the JScrollBar. 1542 */ 1543 AccessibleRelation controlledBy = 1544 new AccessibleRelation(AccessibleRelation.CONTROLLED_BY, 1545 scrollBar); 1546 AccessibleRelation controllerFor = 1547 new AccessibleRelation(AccessibleRelation.CONTROLLER_FOR, 1548 JScrollPane.this); 1549 1550 // set the relation set for the scroll bar 1551 AccessibleContext ac = scrollBar.getAccessibleContext(); 1552 ac.getAccessibleRelationSet().add(controllerFor); 1553 1554 // set the relation set for the scroll pane 1555 getAccessibleRelationSet().add(controlledBy); 1556 } 1557 } 1558 }