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