1. /*
  2. * @(#)JScrollPane.java 1.75 00/04/06
  3. *
  4. * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package javax.swing;
  11. import javax.swing.plaf.*;
  12. import javax.swing.border.*;
  13. import javax.swing.event.*;
  14. import javax.accessibility.*;
  15. import java.awt.Component;
  16. import java.awt.ComponentOrientation;
  17. import java.awt.Graphics;
  18. import java.awt.Rectangle;
  19. import java.awt.Insets;
  20. import java.awt.Color;
  21. import java.awt.LayoutManager;
  22. import java.io.ObjectOutputStream;
  23. import java.io.ObjectInputStream;
  24. import java.io.IOException;
  25. /**
  26. * Provides a scrollable view of a component.
  27. * A <code>JScrollPane</code> manages a viewport, optional
  28. * vertical and horizontal scroll bars, and optional row and
  29. * column heading viewports.
  30. * You can find task-oriented documentation of <code>JScrollPane</code> in
  31. * <a
  32. href="http://java.sun.com/docs/books/tutorial/uiswing/components/scrollpane.html">How to Use Scroll Panes</a>,
  33. * a section in <em>The Java Tutorial</em>.
  34. * <p>
  35. * <TABLE ALIGN="RIGHT" BORDER="0">
  36. * <TR>
  37. * <TD ALIGN="CENTER">
  38. * <P ALIGN="CENTER"><IMG SRC="doc-files/JScrollPane-1.gif" WIDTH="256" HEIGHT="248" ALIGN="BOTTOM" BORDER="0">
  39. * </TD>
  40. * </TR>
  41. * </TABLE>
  42. * The <code>JViewport</code> provides a window,
  43. * or "viewport" onto a data
  44. * source -- for example, a text file. That data source is the
  45. * "scrollable client" (aka data model) displayed by the
  46. * <code>JViewport</code> view.
  47. * A <code>JScrollPane</code> basically consists of <code>JScrollBar</code>s,
  48. * a <code>JViewport</code>, and the wiring between them,
  49. * as shown in the diagram at right.
  50. * <p>
  51. * In addition to the scroll bars and viewport,
  52. * a <code>JScrollPane</code> can have a
  53. * column header and a row header. Each of these is a
  54. * <code>JViewport</code> object that
  55. * you specify with <code>setRowHeaderView</code>,
  56. * and <code>setColumnHeaderView</code>.
  57. * The column header viewport automatically scrolls left and right, tracking
  58. * the left-right scrolling of the main viewport.
  59. * (It never scrolls vertically, however.)
  60. * The row header acts in a similar fashion.
  61. * <p>
  62. * By default, the corners are empty.
  63. * You can put a component into a corner using
  64. * <code>setCorner</code>,
  65. * in case you there is some function or decoration you
  66. * would like to add to the scroll pane. The size of corner components is
  67. * entirely determined by the size of the headers and scroll bars that
  68. * surround them.
  69. * <p>
  70. * To add a border around the main viewport,
  71. * you can use <code>setViewportBorder</code>.
  72. * (Of course, you can also add a border around the whole scroll pane using
  73. * <code>setBorder</code>.)
  74. * <p>
  75. * For the keyboard keys used by this component in the standard Look and
  76. * Feel (L&F) renditions, see the
  77. * <a href="doc-files/Key-Index.html#JScrollPane">JScrollPane</a>
  78. * key assignments.
  79. * <p>
  80. * A common operation to want to do is to set the background color that will
  81. * be used if the main viewport view is smaller than the viewport, or is
  82. * not opaque. This can be accomplished by setting the background color
  83. * of the viewport, via <code>scrollPane.getViewport().setBackground()</code>.
  84. * The reason for setting the color of the viewport and not the scrollpane
  85. * is that by default <code>JViewport</code> is opaque
  86. * which, among other things, means it will completely fill
  87. * in its background using its background color. Therefore when
  88. * <code>JScrollPane</code> draws its background the viewport will
  89. * usually draw over it.
  90. * <p>
  91. * <strong>Warning:</strong>
  92. * Serialized objects of this class will not be compatible with
  93. * future Swing releases. The current serialization support is appropriate
  94. * for short term storage or RMI between applications running the same
  95. * version of Swing. A future release of Swing will provide support for
  96. * long term persistence.
  97. *
  98. * @see JScrollBar
  99. * @see JViewport
  100. * @see #setViewportView
  101. * @see #setRowHeaderView
  102. * @see #setColumnHeaderView
  103. * @see #setCorner
  104. * @see #setViewportBorder
  105. *
  106. * @beaninfo
  107. * attribute: isContainer true
  108. * attribute: containerDelegate getViewport
  109. * description: A specialized container that manages a viewport, optional scrollbars and headers
  110. *
  111. * @version 1.75 04/06/00
  112. * @author Hans Muller
  113. */
  114. public class JScrollPane extends JComponent implements ScrollPaneConstants, Accessible
  115. {
  116. private Border viewportBorder;
  117. /**
  118. * @see #getUIClassID
  119. * @see #readObject
  120. */
  121. private static final String uiClassID = "ScrollPaneUI";
  122. /**
  123. * The display policy for the vertical scrollbar.
  124. * The default is <code>JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED</code>.
  125. * @see #setVerticalScrollBarPolicy
  126. */
  127. protected int verticalScrollBarPolicy = VERTICAL_SCROLLBAR_AS_NEEDED;
  128. /**
  129. * The display policy for the horizontal scrollbar.
  130. * The default is <code>JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED</code>.
  131. * @see #setHorizontalScrollBarPolicy
  132. */
  133. protected int horizontalScrollBarPolicy = HORIZONTAL_SCROLLBAR_AS_NEEDED;
  134. /**
  135. * The scrollpane's viewport child. Default is an empty
  136. * <code>JViewport</code>.
  137. * @see #setViewport
  138. */
  139. protected JViewport viewport;
  140. /**
  141. * The scrollpane's vertical scrollbar child.
  142. * Default is a <code>JScrollBar</code>.
  143. * @see #setVerticalScrollBar
  144. */
  145. protected JScrollBar verticalScrollBar;
  146. /**
  147. * The scrollpane's horizontal scrollbar child.
  148. * Default is a <code>JScrollBar</code>.
  149. * @see #setHorizontalScrollBar
  150. */
  151. protected JScrollBar horizontalScrollBar;
  152. /**
  153. * The row header child. Default is <code>null</code>.
  154. * @see #setRowHeader
  155. */
  156. protected JViewport rowHeader;
  157. /**
  158. * The column header child. Default is <code>null</code>.
  159. * @see #setColumnHeader
  160. */
  161. protected JViewport columnHeader;
  162. /**
  163. * The component to display in the lower left corner.
  164. * Default is <code>null</code>.
  165. * @see #setCorner
  166. */
  167. protected Component lowerLeft;
  168. /**
  169. * The component to display in the lower right corner.
  170. * Default is <code>null</code>.
  171. * @see #setCorner
  172. */
  173. protected Component lowerRight;
  174. /**
  175. * The component to display in the upper left corner.
  176. * Default is <code>null</code>.
  177. * @see #setCorner
  178. */
  179. protected Component upperLeft;
  180. /**
  181. * The component to display in the upper right corner.
  182. * Default is <code>null</code>.
  183. * @see #setCorner
  184. */
  185. protected Component upperRight;
  186. /**
  187. * Creates a <code>JScrollPane</code> that displays the view
  188. * component in a viewport
  189. * whose view position can be controlled with a pair of scrollbars.
  190. * The scrollbar policies specify when the scrollbars are displayed,
  191. * For example, if <code>vsbPolicy</code> is
  192. * <code>VERTICAL_SCROLLBAR_AS_NEEDED</code>
  193. * then the vertical scrollbar only appears if the view doesn't fit
  194. * vertically. The available policy settings are listed at
  195. * {@link #setVerticalScrollBarPolicy} and
  196. * {@link #setHorizontalScrollBarPolicy}.
  197. *
  198. * @see #setViewportView
  199. *
  200. * @param view the component to display in the scrollpanes viewport
  201. * @param vsbPolicy an integer that specifies the vertical
  202. * scrollbar policy
  203. * @param hsbPolicy an integer that specifies the horizontal
  204. * scrollbar policy
  205. */
  206. public JScrollPane(Component view, int vsbPolicy, int hsbPolicy)
  207. {
  208. setLayout(new ScrollPaneLayout.UIResource());
  209. setVerticalScrollBarPolicy(vsbPolicy);
  210. setHorizontalScrollBarPolicy(hsbPolicy);
  211. setViewport(createViewport());
  212. setVerticalScrollBar(createVerticalScrollBar());
  213. setHorizontalScrollBar(createHorizontalScrollBar());
  214. if (view != null) {
  215. setViewportView(view);
  216. }
  217. setOpaque(true);
  218. updateUI();
  219. }
  220. /**
  221. * Creates a <code>JScrollPane</code> that displays the
  222. * contents of the specified
  223. * component, where both horizontal and vertical scrollbars appear
  224. * whenever the component's contents are larger than the view.
  225. *
  226. * @see #setViewportView
  227. * @param view the component to display in the scrollpane's viewport
  228. */
  229. public JScrollPane(Component view) {
  230. this(view, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED);
  231. }
  232. /**
  233. * Creates an empty (no viewport view) <code>JScrollPane</code>
  234. * with specified
  235. * scrollbar policies. The available policy settings are listed at
  236. * {@link #setVerticalScrollBarPolicy} and
  237. * {@link #setHorizontalScrollBarPolicy}.
  238. *
  239. * @see #setViewportView
  240. *
  241. * @param vsbPolicy an integer that specifies the vertical
  242. * scrollbar policy
  243. * @param hsbPolicy an integer that specifies the horizontal
  244. * scrollbar policy
  245. */
  246. public JScrollPane(int vsbPolicy, int hsbPolicy) {
  247. this(null, vsbPolicy, hsbPolicy);
  248. }
  249. /**
  250. * Creates an empty (no viewport view) <code>JScrollPane</code>
  251. * where both horizontal and vertical scrollbars appear when needed.
  252. */
  253. public JScrollPane() {
  254. this(null, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED);
  255. }
  256. /**
  257. * Returns the look and feel (L&F) object that renders this component.
  258. *
  259. * @return the <code>ScrollPaneUI</code> object that renders this
  260. * component
  261. * @see #setUI
  262. */
  263. public ScrollPaneUI getUI() {
  264. return (ScrollPaneUI)ui;
  265. }
  266. /**
  267. * Sets the <code>ScrollPaneUI</code> object that provides the
  268. * look and feel (L&F) for this component.
  269. *
  270. * @param ui the <code>ScrollPaneUI</code> L&F object
  271. * @see #getUI
  272. */
  273. public void setUI(ScrollPaneUI ui) {
  274. super.setUI(ui);
  275. }
  276. /**
  277. * Replaces the current <code>ScrollPaneUI</code> object with a version
  278. * from the current default look and feel.
  279. * To be called when the default look and feel changes.
  280. *
  281. * @see JComponent#updateUI
  282. * @see UIManager#getUI
  283. */
  284. public void updateUI() {
  285. setUI((ScrollPaneUI)UIManager.getUI(this));
  286. }
  287. /**
  288. * Returns the suffix used to construct the name of the L&F class used to
  289. * render this component.
  290. *
  291. * @return the string "ScrollPaneUI"
  292. * @see JComponent#getUIClassID
  293. * @see UIDefaults#getUI
  294. *
  295. * @beaninfo
  296. * hidden: true
  297. */
  298. public String getUIClassID() {
  299. return uiClassID;
  300. }
  301. /**
  302. * Sets the layout manager for this <code>JScrollPane</code>.
  303. * This method overrides <code>setLayout</code> in
  304. * <code>java.awt.Container</code> to ensure that only
  305. * <code>LayoutManager</code>s which
  306. * are subclasses of <code>ScrollPaneLayout</code> can be used in a
  307. * <code>JScrollPane</code>.
  308. *
  309. * @param layout the specified layout manager
  310. * @exception ClassCastException if layout is not a
  311. * <code>ScrollPaneLayout</code>
  312. * @see java.awt.Container#getLayout
  313. * @see java.awt.Container#setLayout
  314. *
  315. * @beaninfo
  316. * hidden: true
  317. */
  318. public void setLayout(LayoutManager layout) {
  319. if ((layout == null) || (layout instanceof ScrollPaneLayout)) {
  320. super.setLayout(layout);
  321. }
  322. else {
  323. String s = "layout of JScrollPane must be a ScrollPaneLayout";
  324. throw new ClassCastException(s);
  325. }
  326. }
  327. /**
  328. * Calls <code>revalidate</code> on any descendant of this
  329. * <code>JScrollPane</code>. For example,
  330. * the viewport's view, will cause a request to be queued that
  331. * will validate the <code>JScrollPane</code> and all its descendants.
  332. *
  333. * @return true
  334. * @see JComponent#revalidate
  335. *
  336. * @beaninfo
  337. * hidden: true
  338. */
  339. public boolean isValidateRoot() {
  340. return true;
  341. }
  342. /**
  343. * Returns the vertical scroll bar policy value.
  344. * @return the <code>verticalScrollBarPolicy</code> property
  345. * @see #setVerticalScrollBarPolicy
  346. */
  347. public int getVerticalScrollBarPolicy() {
  348. return verticalScrollBarPolicy;
  349. }
  350. /**
  351. * Determines when the vertical scrollbar appears in the scrollpane.
  352. * Legal values are:
  353. * <ul>
  354. * <li>JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED
  355. * <li>JScrollPane.VERTICAL_SCROLLBAR_NEVER
  356. * <li>JScrollPane.VERTICAL_SCROLLBAR_ALWAYS
  357. * </ul>
  358. *
  359. * @param policy one of the three values listed above
  360. * @exception IllegalArgumentException if <code>policy</code>
  361. * is not one of the legal values shown above
  362. * @see #getVerticalScrollBarPolicy
  363. *
  364. * @beaninfo
  365. * preferred: true
  366. * bound: true
  367. * description: The scrollpane vertical scrollbar policy
  368. * enum: VERTICAL_SCROLLBAR_AS_NEEDED JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED
  369. * VERTICAL_SCROLLBAR_NEVER JScrollPane.VERTICAL_SCROLLBAR_NEVER
  370. * VERTICAL_SCROLLBAR_ALWAYS JScrollPane.VERTICAL_SCROLLBAR_ALWAYS
  371. */
  372. public void setVerticalScrollBarPolicy(int policy) {
  373. switch (policy) {
  374. case VERTICAL_SCROLLBAR_AS_NEEDED:
  375. case VERTICAL_SCROLLBAR_NEVER:
  376. case VERTICAL_SCROLLBAR_ALWAYS:
  377. break;
  378. default:
  379. throw new IllegalArgumentException("invalid verticalScrollBarPolicy");
  380. }
  381. int old = verticalScrollBarPolicy;
  382. verticalScrollBarPolicy = policy;
  383. firePropertyChange("verticalScrollBarPolicy", old, policy);
  384. }
  385. /**
  386. * Returns the horizontal scroll bar policy value.
  387. * @return the <code>horizontalScrollBarPolicy</code> property
  388. * @see #setHorizontalScrollBarPolicy
  389. */
  390. public int getHorizontalScrollBarPolicy() {
  391. return horizontalScrollBarPolicy;
  392. }
  393. /**
  394. * Determines when the horizontal scrollbar appears in the scrollpane.
  395. * The options are:<ul>
  396. * <li>JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED
  397. * <li>JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
  398. * <li>JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS
  399. * </ul>
  400. *
  401. * @param policy one of the three values listed above
  402. * @exception IllegalArgumentException if <code>policy</code>
  403. * is not one of the legal values shown above
  404. * @see #getHorizontalScrollBarPolicy
  405. *
  406. * @beaninfo
  407. * preferred: true
  408. * bound: true
  409. * description: The scrollpane scrollbar policy
  410. * enum: HORIZONTAL_SCROLLBAR_AS_NEEDED JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED
  411. * HORIZONTAL_SCROLLBAR_NEVER JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
  412. * HORIZONTAL_SCROLLBAR_ALWAYS JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS
  413. */
  414. public void setHorizontalScrollBarPolicy(int policy) {
  415. switch (policy) {
  416. case HORIZONTAL_SCROLLBAR_AS_NEEDED:
  417. case HORIZONTAL_SCROLLBAR_NEVER:
  418. case HORIZONTAL_SCROLLBAR_ALWAYS:
  419. break;
  420. default:
  421. throw new IllegalArgumentException("invalid horizontalScrollBarPolicy");
  422. }
  423. int old = horizontalScrollBarPolicy;
  424. horizontalScrollBarPolicy = policy;
  425. firePropertyChange("horizontalScrollBarPolicy", old, policy);
  426. }
  427. /**
  428. * Returns the <code>Border</code> object that surrounds the viewport.
  429. *
  430. * @return the <code>viewportBorder</code> property
  431. * @see #setViewportBorder
  432. */
  433. public Border getViewportBorder() {
  434. return viewportBorder;
  435. }
  436. /**
  437. * Adds a border around the viewport. Note that the border isn't
  438. * set on the viewport directly, <code>JViewport</code> doesn't support
  439. * the <code>JComponent</code> border property.
  440. * Similarly setting the <code>JScrollPane</code>s
  441. * viewport doesn't affect the <code>viewportBorder</code> property.
  442. * <p>
  443. * The default value of this property is computed by the look
  444. * and feel implementation.
  445. *
  446. * @param viewportBorder the border to be added
  447. * @see #getViewportBorder
  448. * @see #setViewport
  449. *
  450. * @beaninfo
  451. * preferred: true
  452. * bound: true
  453. * description: The border around the viewport.
  454. */
  455. public void setViewportBorder(Border viewportBorder) {
  456. Border oldValue = this.viewportBorder;
  457. this.viewportBorder = viewportBorder;
  458. firePropertyChange("viewportBorder", oldValue, viewportBorder);
  459. }
  460. /**
  461. * Returns the bounds of the viewport's border.
  462. *
  463. * @return a <code>Rectangle</code> object specifying the viewport border
  464. */
  465. public Rectangle getViewportBorderBounds()
  466. {
  467. Rectangle borderR = new Rectangle(getSize());
  468. Insets insets = getInsets();
  469. borderR.x = insets.left;
  470. borderR.y = insets.top;
  471. borderR.width -= insets.left + insets.right;
  472. borderR.height -= insets.top + insets.bottom;
  473. boolean leftToRight = SwingUtilities.isLeftToRight(this);
  474. /* If there's a visible column header remove the space it
  475. * needs from the top of borderR.
  476. */
  477. JViewport colHead = getColumnHeader();
  478. if ((colHead != null) && (colHead.isVisible())) {
  479. int colHeadHeight = colHead.getHeight();
  480. borderR.y += colHeadHeight;
  481. borderR.height -= colHeadHeight;
  482. }
  483. /* If there's a visible row header remove the space it needs
  484. * from the left of borderR.
  485. */
  486. JViewport rowHead = getRowHeader();
  487. if ((rowHead != null) && (rowHead.isVisible())) {
  488. int rowHeadWidth = rowHead.getWidth();
  489. if ( leftToRight ) {
  490. borderR.x += rowHeadWidth;
  491. }
  492. borderR.width -= rowHeadWidth;
  493. }
  494. /* If there's a visible vertical scrollbar remove the space it needs
  495. * from the width of borderR.
  496. */
  497. JScrollBar vsb = getVerticalScrollBar();
  498. if ((vsb != null) && (vsb.isVisible())) {
  499. int vsbWidth = vsb.getWidth();
  500. if ( !leftToRight ) {
  501. borderR.x += vsbWidth;
  502. }
  503. borderR.width -= vsbWidth;
  504. }
  505. /* If there's a visible horizontal scrollbar remove the space it needs
  506. * from the height of borderR.
  507. */
  508. JScrollBar hsb = getHorizontalScrollBar();
  509. if ((hsb != null) && (hsb.isVisible())) {
  510. borderR.height -= hsb.getHeight();
  511. }
  512. return borderR;
  513. }
  514. /**
  515. * By default <code>JScrollPane</code> creates scrollbars
  516. * that are instances
  517. * of this class. <code>Scrollbar</code> overrides the
  518. * <code>getUnitIncrement</code> and <code>getBlockIncrement</code>
  519. * methods so that, if the viewport's view is a <code>Scrollable</code>,
  520. * the view is asked to compute these values. Unless
  521. * the unit/block increment have been explicitly set.
  522. * <p>
  523. * <strong>Warning:</strong>
  524. * Serialized objects of this class will not be compatible with
  525. * future Swing releases. The current serialization support is appropriate
  526. * for short term storage or RMI between applications running the same
  527. * version of Swing. A future release of Swing will provide support for
  528. * long term persistence.
  529. *
  530. * @see Scrollable
  531. * @see JScrollPane#createVerticalScrollBar
  532. * @see JScrollPane#createHorizontalScrollBar
  533. */
  534. protected class ScrollBar extends JScrollBar implements UIResource
  535. {
  536. /**
  537. * Set to true when the unit increment has been explicitly set.
  538. * If this is false the viewport's view is obtained and if it
  539. * is an instance of <code>Scrollable</code> the unit increment
  540. * from it is used.
  541. */
  542. private boolean unitIncrementSet;
  543. /**
  544. * Set to true when the block increment has been explicitly set.
  545. * If this is false the viewport's view is obtained and if it
  546. * is an instance of <code>Scrollable</code> the block increment
  547. * from it is used.
  548. */
  549. private boolean blockIncrementSet;
  550. /**
  551. * Creates a scrollbar with the specified orientation,
  552. * where the options are:<ul>
  553. * <li>JScrollPane.VERTICAL
  554. * <li>JScrollPane.HORIZONTAL
  555. * </ul>
  556. *
  557. * @param orientation an integer specifying one of the legal
  558. * orientation values shown above
  559. */
  560. public ScrollBar(int orientation) {
  561. super(orientation);
  562. }
  563. /**
  564. * Messages super to set the value, and resets the
  565. * <code>unitIncrementSet</code> instance variable to true.
  566. *
  567. * @param unitIncrement the new unit increment value, in pixels
  568. */
  569. public void setUnitIncrement(int unitIncrement) {
  570. unitIncrementSet = true;
  571. super.setUnitIncrement(unitIncrement);
  572. }
  573. /**
  574. * Computes the unit increment for scrolling if the viewport's
  575. * view is a <code>Scrollable</code> object.
  576. * Otherwise return <code>super.getUnitIncrement</code>.
  577. *
  578. * @param direction less than zero to scroll up/left,
  579. * greater than zero for down/right
  580. * @return an integer, in pixels, containing the unit increment
  581. * @see Scrollable#getScrollableUnitIncrement
  582. */
  583. public int getUnitIncrement(int direction) {
  584. JViewport vp = getViewport();
  585. if (!unitIncrementSet && (vp != null) &&
  586. (vp.getView() instanceof Scrollable)) {
  587. Scrollable view = (Scrollable)(vp.getView());
  588. Rectangle vr = vp.getViewRect();
  589. return view.getScrollableUnitIncrement(vr, getOrientation(), direction);
  590. }
  591. else {
  592. return super.getUnitIncrement(direction);
  593. }
  594. }
  595. /**
  596. * Messages super to set the value, and resets the
  597. * <code>blockIncrementSet</code> instance variable to true.
  598. *
  599. * @param blockIncrement the new block increment value, in pixels
  600. */
  601. public void setBlockIncrement(int blockIncrement) {
  602. blockIncrementSet = true;
  603. super.setBlockIncrement(blockIncrement);
  604. }
  605. /**
  606. * Computes the block increment for scrolling if the viewport's
  607. * view is a <code>Scrollable</code> object. Otherwise
  608. * the <code>blockIncrement</code> equals the viewport's width
  609. * or height. If there's no viewport return
  610. * <code>super.getBlockIncrement</code>.
  611. *
  612. * @param direction less than zero to scroll up/left,
  613. * greater than zero for down/right
  614. * @return an integer, in pixels, containing the block increment
  615. * @see Scrollable#getScrollableBlockIncrement
  616. */
  617. public int getBlockIncrement(int direction) {
  618. JViewport vp = getViewport();
  619. if (blockIncrementSet || vp == null) {
  620. return super.getBlockIncrement(direction);
  621. }
  622. else if (vp.getView() instanceof Scrollable) {
  623. Scrollable view = (Scrollable)(vp.getView());
  624. Rectangle vr = vp.getViewRect();
  625. return view.getScrollableBlockIncrement(vr, getOrientation(), direction);
  626. }
  627. else if (getOrientation() == VERTICAL) {
  628. return vp.getExtentSize().height;
  629. }
  630. else {
  631. return vp.getExtentSize().width;
  632. }
  633. }
  634. }
  635. /**
  636. * Returns a <code>JScrollPane.ScrollBar</code> by default.
  637. * Subclasses may override this method to force <code>ScrollPaneUI</code>
  638. * implementations to use a <code>JScrollBar</code> subclass.
  639. * Used by <code>ScrollPaneUI</code> implementations to
  640. * create the horizontal scrollbar.
  641. *
  642. * @return a <code>JScrollBar</code> with a horizontal orientation
  643. * @see JScrollBar
  644. */
  645. public JScrollBar createHorizontalScrollBar() {
  646. return new ScrollBar(JScrollBar.HORIZONTAL);
  647. }
  648. /**
  649. * Returns the horizontal scroll bar that controls the viewport's
  650. * horizontal view position.
  651. *
  652. * @return the <code>horizontalScrollBar</code> property
  653. * @see #setHorizontalScrollBar
  654. */
  655. public JScrollBar getHorizontalScrollBar() {
  656. return horizontalScrollBar;
  657. }
  658. /**
  659. * Adds the scrollbar that controls the viewport's horizontal view
  660. * position to the scrollpane.
  661. * This is usually unnecessary, as <code>JScrollPane</code> creates
  662. * horizontal and vertical scrollbars by default.
  663. *
  664. * @param horizontalScrollBar the horizontal scrollbar to be added
  665. * @see #createHorizontalScrollBar
  666. * @see #getHorizontalScrollBar
  667. *
  668. * @beaninfo
  669. * expert: true
  670. * bound: true
  671. * description: The horizontal scrollbar.
  672. */
  673. public void setHorizontalScrollBar(JScrollBar horizontalScrollBar) {
  674. JScrollBar old = getHorizontalScrollBar();
  675. this.horizontalScrollBar = horizontalScrollBar;
  676. add(horizontalScrollBar, HORIZONTAL_SCROLLBAR);
  677. firePropertyChange("horizontalScrollBar", old, horizontalScrollBar);
  678. revalidate();
  679. repaint();
  680. }
  681. /**
  682. * Returns a <code>JScrollPane.ScrollBar</code> by default. Subclasses
  683. * may override this method to force <code>ScrollPaneUI</code>
  684. * implementations to use a <code>JScrollBar</code> subclass.
  685. * Used by <code>ScrollPaneUI</code> implementations to create the
  686. * vertical scrollbar.
  687. *
  688. * @return a <code>JScrollBar</code> with a vertical orientation
  689. * @see JScrollBar
  690. */
  691. public JScrollBar createVerticalScrollBar() {
  692. return new ScrollBar(JScrollBar.VERTICAL);
  693. }
  694. /**
  695. * Returns the vertical scroll bar that controls the viewports
  696. * vertical view position.
  697. *
  698. * @return the <code>verticalScrollBar</code> property
  699. * @see #setVerticalScrollBar
  700. */
  701. public JScrollBar getVerticalScrollBar() {
  702. return verticalScrollBar;
  703. }
  704. /**
  705. * Adds the scrollbar that controls the viewports vertical view position
  706. * to the scrollpane. This is usually unnecessary,
  707. * as <code>JScrollPane</code> creates vertical and
  708. * horizontal scrollbars by default.
  709. *
  710. * @param verticalScrollBar the new vertical scrollbar to be added
  711. * @see #createVerticalScrollBar
  712. * @see #getVerticalScrollBar
  713. *
  714. * @beaninfo
  715. * expert: true
  716. * bound: true
  717. * description: The vertical scrollbar.
  718. */
  719. public void setVerticalScrollBar(JScrollBar verticalScrollBar) {
  720. JScrollBar old = getVerticalScrollBar();
  721. this.verticalScrollBar = verticalScrollBar;
  722. add(verticalScrollBar, VERTICAL_SCROLLBAR);
  723. firePropertyChange("verticalScrollBar", old, verticalScrollBar);
  724. revalidate();
  725. repaint();
  726. }
  727. /**
  728. * Returns a new <code>JViewport</code> by default.
  729. * Used to create the
  730. * viewport (as needed) in <code>setViewportView</code>,
  731. * <code>setRowHeaderView</code>, and <code>setColumnHeaderView</code>.
  732. * Subclasses may override this method to return a subclass of
  733. * <code>JViewport</code>.
  734. *
  735. * @return a new <code>JViewport</code>
  736. */
  737. protected JViewport createViewport() {
  738. return new JViewport();
  739. }
  740. /**
  741. * Returns the current <code>JViewport</code>.
  742. *
  743. * @see #setViewport
  744. * @return the <code>viewport</code> property
  745. */
  746. public JViewport getViewport() {
  747. return viewport;
  748. }
  749. /**
  750. * Removes the old viewport (if there is one); forces the
  751. * viewPosition of the new viewport to be in the +x,+y quadrant;
  752. * syncs up the row and column headers (if there are any) with the
  753. * new viewport; and finally syncs the scrollbars and
  754. * headers with the new viewport.
  755. * <p>
  756. * Most applications will find it more convenient to use
  757. * <code>setViewportView</code>
  758. * to add a viewport and a view to the scrollpane.
  759. *
  760. * @param viewport the new viewport to be used; if viewport is
  761. * <code>null</code>, the old viewport is still removed
  762. * and the new viewport is set to <code>null</code>
  763. * @see #createViewport
  764. * @see #getViewport
  765. * @see #setViewportView
  766. *
  767. * @beaninfo
  768. * expert: true
  769. * bound: true
  770. * attribute: visualUpdate true
  771. * description: The viewport child for this scrollpane
  772. *
  773. */
  774. public void setViewport(JViewport viewport) {
  775. JViewport old = getViewport();
  776. this.viewport = viewport;
  777. if (viewport != null) {
  778. add(viewport, VIEWPORT);
  779. }
  780. else if (old != null) {
  781. remove(old);
  782. }
  783. firePropertyChange("viewport", old, viewport);
  784. if (accessibleContext != null) {
  785. ((AccessibleJScrollPane)accessibleContext).resetViewPort();
  786. }
  787. revalidate();
  788. repaint();
  789. }
  790. /**
  791. * Creates a viewport if necessary and then sets its view. Applications
  792. * that don't provide the view directly to the <code>JScrollPane</code>
  793. * constructor
  794. * should use this method to specify the scrollable child that's going
  795. * to be displayed in the scrollpane. For example:
  796. * <pre>
  797. * JScrollPane scrollpane = new JScrollPane();
  798. * scrollpane.setViewportView(myBigComponentToScroll);
  799. * </pre>
  800. * Applications should not add children directly to the scrollpane.
  801. *
  802. * @param view the component to add to the viewport
  803. * @see #setViewport
  804. * @see JViewport#setView
  805. */
  806. public void setViewportView(Component view) {
  807. if (getViewport() == null) {
  808. setViewport(createViewport());
  809. }
  810. getViewport().setView(view);
  811. }
  812. /**
  813. * Returns the row header.
  814. * @return the <code>rowHeader</code> property
  815. * @see #setRowHeader
  816. */
  817. public JViewport getRowHeader() {
  818. return rowHeader;
  819. }
  820. /**
  821. * Removes the old rowHeader, if it exists. If the new rowHeader
  822. * isn't <code>null</code>, syncs the y coordinate of its
  823. * viewPosition with
  824. * the viewport (if there is one) and then adds it to the scrollpane.
  825. * <p>
  826. * Most applications will find it more convenient to use
  827. * <code>setRowHeaderView</code>
  828. * to add a row header component and its viewport to the scrollpane.
  829. *
  830. * @param rowHeader the new row header to be used; if <code>null</code>
  831. * the old row header is still removed and the new rowHeader
  832. * is set to <code>null</code>
  833. * @see #getRowHeader
  834. * @see #setRowHeaderView
  835. *
  836. * @beaninfo
  837. * bound: true
  838. * expert: true
  839. * description: The row header child for this scrollpane
  840. */
  841. public void setRowHeader(JViewport rowHeader) {
  842. JViewport old = getRowHeader();
  843. this.rowHeader = rowHeader;
  844. if (rowHeader != null) {
  845. add(rowHeader, ROW_HEADER);
  846. }
  847. else if (old != null) {
  848. remove(old);
  849. }
  850. firePropertyChange("rowHeader", old, rowHeader);
  851. }
  852. /**
  853. * Creates a row-header viewport if necessary, sets
  854. * its view and then adds the row-header viewport
  855. * to the scrollpane. For example:
  856. * <pre>
  857. * JScrollPane scrollpane = new JScrollPane();
  858. * scrollpane.setViewportView(myBigComponentToScroll);
  859. * scrollpane.setRowHeaderView(myBigComponentsRowHeader);
  860. * </pre>
  861. *
  862. * @see #setRowHeader
  863. * @see JViewport#setView
  864. * @param view the component to display as the row header
  865. */
  866. public void setRowHeaderView(Component view) {
  867. if (getRowHeader() == null) {
  868. setRowHeader(createViewport());
  869. }
  870. getRowHeader().setView(view);
  871. }
  872. /**
  873. * Returns the column header.
  874. * @return the <code>columnHeader</code> property
  875. * @see #setColumnHeader
  876. */
  877. public JViewport getColumnHeader() {
  878. return columnHeader;
  879. }
  880. /**
  881. * Removes the old columnHeader, if it exists. If the new columnHeader
  882. * isn't <code>null</code>, sync the x coordinate of the its viewPosition
  883. * with the viewport (if there is one) and then add it to the scrollpane.
  884. * <p>
  885. * Most applications will find it more convenient to use
  886. * <code>setRowHeaderView</code>
  887. * to add a row header component and its viewport to the scrollpane.
  888. *
  889. * @see #getColumnHeader
  890. * @see #setColumnHeaderView
  891. *
  892. * @beaninfo
  893. * bound: true
  894. * description: The column header child for this scrollpane
  895. * attribute: visualUpdate true
  896. */
  897. public void setColumnHeader(JViewport columnHeader) {
  898. JViewport old = getColumnHeader();
  899. this.columnHeader = columnHeader;
  900. if (columnHeader != null) {
  901. add(columnHeader, COLUMN_HEADER);
  902. }
  903. else if (old != null) {
  904. remove(old);
  905. }
  906. firePropertyChange("columnHeader", old, columnHeader);
  907. revalidate();
  908. repaint();
  909. }
  910. /**
  911. * Creates a column-header viewport if necessary, sets
  912. * its view, and then adds the column-header viewport
  913. * to the scrollpane. For example:
  914. * <pre>
  915. * JScrollPane scrollpane = new JScrollPane();
  916. * scrollpane.setViewportView(myBigComponentToScroll);
  917. * scrollpane.setColumnHeaderView(myBigComponentsColumnHeader);
  918. * </pre>
  919. *
  920. * @see #setColumnHeader
  921. * @see JViewport#setView
  922. *
  923. * @param view the component to display as the column header
  924. */
  925. public void setColumnHeaderView(Component view) {
  926. if (getColumnHeader() == null) {
  927. setColumnHeader(createViewport());
  928. }
  929. getColumnHeader().setView(view);
  930. }
  931. /**
  932. * Returns the component at the specified corner. The
  933. * <code>key</code> value specifying the corner is one of:
  934. * <ul>
  935. * <li>JScrollPane.LOWER_LEFT_CORNER
  936. * <li>JScrollPane.LOWER_RIGHT_CORNER
  937. * <li>JScrollPane.UPPER_LEFT_CORNER
  938. * <li>JScrollPane.UPPER_RIGHT_CORNER
  939. * <li>JScrollPane.LOWER_LEADING_CORNER
  940. * <li>JScrollPane.LOWER_TRAILING_CORNER
  941. * <li>JScrollPane.UPPER_LEADING_CORNER
  942. * <li>JScrollPane.UPPER_TRAILING_CORNER
  943. * </ul>
  944. *
  945. * @param key one of the values as shown above
  946. * @return one of the components listed below or <code>null</code>
  947. * if <code>key</code> is invalid:
  948. * <ul>
  949. * <li>lowerLeft
  950. * <li>lowerRight
  951. * <li>upperLeft
  952. * <li>upperRight
  953. * </ul>
  954. * @see #setCorner
  955. */
  956. public Component getCorner(String key) {
  957. if (key.equals(LOWER_LEFT_CORNER)) {
  958. return lowerLeft;
  959. }
  960. else if (key.equals(LOWER_RIGHT_CORNER)) {
  961. return lowerRight;
  962. }
  963. else if (key.equals(UPPER_LEFT_CORNER)) {
  964. return upperLeft;
  965. }
  966. else if (key.equals(UPPER_RIGHT_CORNER)) {
  967. return upperRight;
  968. }
  969. else {
  970. return null;
  971. }
  972. }
  973. /**
  974. * Adds a child that will appear in one of the scroll panes
  975. * corners, if there's room. For example with both scrollbars
  976. * showing (on the right and bottom edges of the scrollpane)
  977. * the lower left corner component will be shown in the space
  978. * between ends of the two scrollbars. Legal values for
  979. * the <b>key</b> are:
  980. * <ul>
  981. * <li>JScrollPane.LOWER_LEFT_CORNER
  982. * <li>JScrollPane.LOWER_RIGHT_CORNER
  983. * <li>JScrollPane.UPPER_LEFT_CORNER
  984. * <li>JScrollPane.UPPER_RIGHT_CORNER
  985. * <li>JScrollPane.LOWER_LEADING_CORNER
  986. * <li>JScrollPane.LOWER_TRAILING_CORNER
  987. * <li>JScrollPane.UPPER_LEADING_CORNER
  988. * <li>JScrollPane.UPPER_TRAILING_CORNER
  989. * </ul>
  990. * <p>
  991. * Although "corner" doesn't match any beans property
  992. * signature, <code>PropertyChange</code> events are generated with the
  993. * property name set to the corner key.
  994. *
  995. * @param key identifies which corner the component will appear in
  996. * @param corner one of the following components:
  997. * <ul>
  998. * <li>lowerLeft
  999. * <li>lowerRight
  1000. * <li>upperLeft
  1001. * <li>upperRight
  1002. * </ul>
  1003. * @exception IllegalArgumentException if corner key is invalid
  1004. */
  1005. public void setCorner(String key, Component corner)
  1006. {
  1007. Component old;
  1008. if (key.equals(LOWER_LEFT_CORNER)) {
  1009. old = lowerLeft;
  1010. lowerLeft = corner;
  1011. }
  1012. else if (key.equals(LOWER_RIGHT_CORNER)) {
  1013. old = lowerRight;
  1014. lowerRight = corner;
  1015. }
  1016. else if (key.equals(UPPER_LEFT_CORNER)) {
  1017. old = upperLeft;
  1018. upperLeft = corner;
  1019. }
  1020. else if (key.equals(UPPER_RIGHT_CORNER)) {
  1021. old = upperRight;
  1022. upperRight = corner;
  1023. }
  1024. else {
  1025. throw new IllegalArgumentException("invalid corner key");
  1026. }
  1027. add(corner, key);
  1028. firePropertyChange(key, old, corner);
  1029. }
  1030. /**
  1031. * Sets the orientation for the vertical and horizontal
  1032. * scrollbars as determined by the
  1033. * <code>ComponentOrientation</code> argument.
  1034. *
  1035. * @param co one of the following values:
  1036. * <ul>
  1037. * <li>java.awt.ComponentOrientation.LEFT_TO_RIGHT
  1038. * <li>java.awt.ComponentOrientation.RIGHT_TO_LEFT
  1039. * <li>java.awt.ComponentOrientation.UNKNOWN
  1040. * </ul>
  1041. * @see java.awt.ComponentOrientation
  1042. */
  1043. public void setComponentOrientation( ComponentOrientation co ) {
  1044. super.setComponentOrientation( co );
  1045. verticalScrollBar.setComponentOrientation( co );
  1046. horizontalScrollBar.setComponentOrientation( co );
  1047. }
  1048. /**
  1049. * See <code>readObject</code> and <code>writeObject</code> in
  1050. * <code>JComponent</code> for more
  1051. * information about serialization in Swing.
  1052. */
  1053. private void writeObject(ObjectOutputStream s) throws IOException {
  1054. s.defaultWriteObject();
  1055. if ((ui != null) && (getUIClassID().equals(uiClassID))) {
  1056. ui.installUI(this);
  1057. }
  1058. }
  1059. /**
  1060. * Returns a string representation of this <code>JScrollPane</code>.
  1061. * This method
  1062. * is intended to be used only for debugging purposes, and the
  1063. * content and format of the returned string may vary between
  1064. * implementations. The returned string may be empty but may not
  1065. * be <code>null</code>.
  1066. *
  1067. * @return a string representation of this <code>JScrollPane</code>.
  1068. */
  1069. protected String paramString() {
  1070. String viewportBorderString = (viewportBorder != null ?
  1071. viewportBorder.toString() : "");
  1072. String viewportString = (viewport != null ?
  1073. viewport.toString() : "");
  1074. String verticalScrollBarPolicyString;
  1075. if (verticalScrollBarPolicy == VERTICAL_SCROLLBAR_AS_NEEDED) {
  1076. verticalScrollBarPolicyString = "VERTICAL_SCROLLBAR_AS_NEEDED";
  1077. } else if (verticalScrollBarPolicy == VERTICAL_SCROLLBAR_NEVER) {
  1078. verticalScrollBarPolicyString = "VERTICAL_SCROLLBAR_NEVER";
  1079. } else if (verticalScrollBarPolicy == VERTICAL_SCROLLBAR_ALWAYS) {
  1080. verticalScrollBarPolicyString = "VERTICAL_SCROLLBAR_ALWAYS";
  1081. } else verticalScrollBarPolicyString = "";
  1082. String horizontalScrollBarPolicyString;
  1083. if (horizontalScrollBarPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED) {
  1084. horizontalScrollBarPolicyString = "HORIZONTAL_SCROLLBAR_AS_NEEDED";
  1085. } else if (horizontalScrollBarPolicy == HORIZONTAL_SCROLLBAR_NEVER) {
  1086. horizontalScrollBarPolicyString = "HORIZONTAL_SCROLLBAR_NEVER";
  1087. } else if (horizontalScrollBarPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) {
  1088. horizontalScrollBarPolicyString = "HORIZONTAL_SCROLLBAR_ALWAYS";
  1089. } else horizontalScrollBarPolicyString = "";
  1090. String horizontalScrollBarString = (horizontalScrollBar != null ?
  1091. horizontalScrollBar.toString()
  1092. : "");
  1093. String verticalScrollBarString = (verticalScrollBar != null ?
  1094. verticalScrollBar.toString() : "");
  1095. String columnHeaderString = (columnHeader != null ?
  1096. columnHeader.toString() : "");
  1097. String rowHeaderString = (rowHeader != null ?
  1098. rowHeader.toString() : "");
  1099. String lowerLeftString = (lowerLeft != null ?
  1100. lowerLeft.toString() : "");
  1101. String lowerRightString = (lowerRight != null ?
  1102. lowerRight.toString() : "");
  1103. String upperLeftString = (upperLeft != null ?
  1104. upperLeft.toString() : "");
  1105. String upperRightString = (upperRight != null ?
  1106. upperRight.toString() : "");
  1107. return super.paramString() +
  1108. ",columnHeader=" + columnHeaderString +
  1109. ",horizontalScrollBar=" + horizontalScrollBarString +
  1110. ",horizontalScrollBarPolicy=" + horizontalScrollBarPolicyString +
  1111. ",lowerLeft=" + lowerLeftString +
  1112. ",lowerRight=" + lowerRightString +
  1113. ",rowHeader=" + rowHeaderString +
  1114. ",upperLeft=" + upperLeftString +
  1115. ",upperRight=" + upperRightString +
  1116. ",verticalScrollBar=" + verticalScrollBarString +
  1117. ",verticalScrollBarPolicy=" + verticalScrollBarPolicyString +
  1118. ",viewport=" + viewportString +
  1119. ",viewportBorder=" + viewportBorderString;
  1120. }
  1121. /////////////////
  1122. // Accessibility support
  1123. ////////////////
  1124. /**
  1125. * Gets the AccessibleContext associated with this JScrollPane.
  1126. * For scroll panes, the AccessibleContext takes the form of an
  1127. * AccessibleJScrollPane.
  1128. * A new AccessibleJScrollPane instance is created if necessary.
  1129. *
  1130. * @return an AccessibleJScrollPane that serves as the
  1131. * AccessibleContext of this JScrollPane
  1132. */
  1133. public AccessibleContext getAccessibleContext() {
  1134. if (accessibleContext == null) {
  1135. accessibleContext = new AccessibleJScrollPane();
  1136. }
  1137. return accessibleContext;
  1138. }
  1139. /**
  1140. * This class implements accessibility support for the
  1141. * <code>JScrollPane</code> class. It provides an implementation of the
  1142. * Java Accessibility API appropriate to scroll pane user-interface
  1143. * elements.
  1144. * <p>
  1145. * <strong>Warning:</strong>
  1146. * Serialized objects of this class will not be compatible with
  1147. * future Swing releases. The current serialization support is appropriate
  1148. * for short term storage or RMI between applications running the same
  1149. * version of Swing. A future release of Swing will provide support for
  1150. * long term persistence.
  1151. */
  1152. protected class AccessibleJScrollPane extends AccessibleJComponent
  1153. implements ChangeListener {
  1154. protected JViewport viewPort = null;
  1155. public void resetViewPort() {
  1156. viewPort.removeChangeListener(this);
  1157. viewPort = JScrollPane.this.getViewport();
  1158. viewPort.addChangeListener(this);
  1159. }
  1160. /**
  1161. * Constructor to set up listener on viewport.
  1162. */
  1163. public AccessibleJScrollPane() {
  1164. super();
  1165. if (viewPort == null) {
  1166. viewPort = JScrollPane.this.getViewport();
  1167. }
  1168. viewPort.addChangeListener(this);
  1169. }
  1170. /**
  1171. * Get the role of this object.
  1172. *
  1173. * @return an instance of AccessibleRole describing the role of the
  1174. * object
  1175. * @see AccessibleRole
  1176. */
  1177. public AccessibleRole getAccessibleRole() {
  1178. return AccessibleRole.SCROLL_PANE;
  1179. }
  1180. /**
  1181. * Supports the change listener interface and fires property change
  1182. */
  1183. public void stateChanged(ChangeEvent e) {
  1184. AccessibleContext ac = ((Accessible)JScrollPane.this).getAccessibleContext();
  1185. if (ac != null) {
  1186. ac.firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY, new Boolean(false), new Boolean(true));
  1187. }
  1188. }
  1189. }
  1190. }