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