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