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