1. /*
  2. * @(#)ScrollPaneLayout.java 1.35 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import javax.swing.border.*;
  9. import java.awt.LayoutManager;
  10. import java.awt.Component;
  11. import java.awt.Container;
  12. import java.awt.Rectangle;
  13. import java.awt.Dimension;
  14. import java.awt.Insets;
  15. import java.io.Serializable;
  16. /**
  17. * The layout manager used by JScrollPane. JScrollPaneLayout is
  18. * responsible for nine components: a viewport, two scrollbars,
  19. * a row header, a column header, and four "corner" components.
  20. * <p>
  21. * <strong>Warning:</strong>
  22. * Serialized objects of this class will not be compatible with
  23. * future Swing releases. The current serialization support is appropriate
  24. * for short term storage or RMI between applications running the same
  25. * version of Swing. A future release of Swing will provide support for
  26. * long term persistence.
  27. *
  28. * @see JScrollPane
  29. * @see JViewport
  30. *
  31. * @version 1.35 11/29/01
  32. * @author Hans Muller
  33. */
  34. public class ScrollPaneLayout
  35. implements LayoutManager, ScrollPaneConstants, Serializable
  36. {
  37. /**
  38. * The scrollpanes viewport child. Default is an empty JViewport.
  39. * @see JScrollPane#setViewport
  40. */
  41. protected JViewport viewport;
  42. /**
  43. * The scrollpanes vertical scrollbar child. Default is a JScrollBar.
  44. * @see JScrollPane#setVerticalScrollbar
  45. */
  46. protected JScrollBar vsb;
  47. /**
  48. * The scrollpanes horizontal scrollbar child. Default is a JScrollBar.
  49. * @see JScrollPane#setHorizontalScrollbar
  50. */
  51. protected JScrollBar hsb;
  52. /**
  53. * The row header child. Default is null.
  54. * @see JScrollPane#setRowHeader
  55. */
  56. protected JViewport rowHead;
  57. /**
  58. * The column header child. Default is null.
  59. * @see JScrollPane#setColumnHeader
  60. */
  61. protected JViewport colHead;
  62. /**
  63. * The component to display in the lower left corner. Default is null.
  64. * @see JScrollPane#setCorner
  65. */
  66. protected Component lowerLeft;
  67. /**
  68. * The component to display in the lower right corner. Default is null.
  69. * @see JScrollPane#setCorner
  70. */
  71. protected Component lowerRight;
  72. /**
  73. * The component to display in the upper left corner. Default is null.
  74. * @see JScrollPane#setCorner
  75. */
  76. protected Component upperLeft;
  77. /**
  78. * The component to display in the upper right corner. Default is null.
  79. * @see JScrollPane#setCorner
  80. */
  81. protected Component upperRight;
  82. /**
  83. * The display policy for the vertical scrollbar.
  84. * The default is JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED.
  85. * <p>
  86. * This field is obsolete, please use the JScrollPane field instead.
  87. *
  88. * @see JScrollPane#setVerticalScrollBarPolicy
  89. */
  90. protected int vsbPolicy = VERTICAL_SCROLLBAR_AS_NEEDED;
  91. /**
  92. * The display policy for the horizontal scrollbar.
  93. * The default is JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED.
  94. * <p>
  95. * This field is obsolete, please use the JScrollPane field instead.
  96. *
  97. * @see JScrollPane#setHorizontalScrollBarPolicy
  98. */
  99. protected int hsbPolicy = HORIZONTAL_SCROLLBAR_AS_NEEDED;
  100. /**
  101. * This method must be called after setting a JScrollPanes
  102. * layout manager. It initializes all of the internal fields that
  103. * are ordinarily set by addLayoutComponent(). For example:
  104. * <pre>
  105. * ScrollPaneLayout mySPLayout = new ScrollPanelLayout() {
  106. * public void layoutContainer(Container p) {
  107. * super.layoutContainer(p);
  108. * // do some extra work here ...
  109. * }
  110. * };
  111. * scrollpane.setLayout(mySPLayout):
  112. * mySPLayout.syncWithScrollPane(scrollpane);
  113. * </pre>
  114. */
  115. public void syncWithScrollPane(JScrollPane sp) {
  116. viewport = sp.getViewport();
  117. vsb = sp.getVerticalScrollBar();
  118. hsb = sp.getHorizontalScrollBar();
  119. rowHead = sp.getRowHeader();
  120. colHead = sp.getColumnHeader();
  121. lowerLeft = sp.getCorner(LOWER_LEFT_CORNER);
  122. lowerRight = sp.getCorner(LOWER_RIGHT_CORNER);
  123. upperLeft = sp.getCorner(UPPER_LEFT_CORNER);
  124. upperRight = sp.getCorner(UPPER_RIGHT_CORNER);
  125. vsbPolicy = sp.getVerticalScrollBarPolicy();
  126. hsbPolicy = sp.getHorizontalScrollBarPolicy();
  127. }
  128. /**
  129. * The method used to replace an existing component (if any) with a
  130. * new one. Used to add each different kind of component to a JScrollPane,
  131. * since there can be one and only one left corner, vertical scrollbar,
  132. * and so on. So only one of each subcomponent is allowed, the old one
  133. * is removed (if it exists) when a new one is added.
  134. *
  135. * @param oldC the Component to replace
  136. * @param newC the Component to add
  137. */
  138. protected Component addSingletonComponent(Component oldC, Component newC)
  139. {
  140. if ((oldC != null) && (oldC != newC)) {
  141. oldC.getParent().remove(oldC);
  142. }
  143. return newC;
  144. }
  145. /**
  146. * Adds the specified component to the layout. The layout is
  147. * identified using one of:<ul>
  148. * <li>JScrollPane.VIEWPORT
  149. * <li>JScrollPane.VERTICAL_SCROLLBAR
  150. * <li>JScrollPane.HORIZONTAL_SCROLLBAR
  151. * <li>JScrollPane.ROW_HEADER
  152. * <li>JScrollPane.COLUMN_HEADER
  153. * <li>JScrollPane.LOWER_LEFT_CORNER
  154. * <li>JScrollPane.LOWER_RIGHT_CORNER
  155. * <li>JScrollPane.UPPER_LEFT_CORNER
  156. * <li>JScrollPane.UPPER_RIGHT_CORNER
  157. * </ul>
  158. *
  159. * @param s the component identifier
  160. * @param comp the the component to be added
  161. */
  162. public void addLayoutComponent(String s, Component c)
  163. {
  164. if (s.equals(VIEWPORT)) {
  165. viewport = (JViewport)addSingletonComponent(viewport, c);
  166. }
  167. else if (s.equals(VERTICAL_SCROLLBAR)) {
  168. vsb = (JScrollBar)addSingletonComponent(vsb, c);
  169. }
  170. else if (s.equals(HORIZONTAL_SCROLLBAR)) {
  171. hsb = (JScrollBar)addSingletonComponent(hsb, c);
  172. }
  173. else if (s.equals(ROW_HEADER)) {
  174. rowHead = (JViewport)addSingletonComponent(rowHead, c);
  175. }
  176. else if (s.equals(COLUMN_HEADER)) {
  177. colHead = (JViewport)addSingletonComponent(colHead, c);
  178. }
  179. else if (s.equals(LOWER_LEFT_CORNER)) {
  180. lowerLeft = addSingletonComponent(lowerLeft, c);
  181. }
  182. else if (s.equals(LOWER_RIGHT_CORNER)) {
  183. lowerRight = addSingletonComponent(lowerRight, c);
  184. }
  185. else if (s.equals(UPPER_LEFT_CORNER)) {
  186. upperLeft = addSingletonComponent(upperLeft, c);
  187. }
  188. else if (s.equals(UPPER_RIGHT_CORNER)) {
  189. upperRight = addSingletonComponent(upperRight, c);
  190. }
  191. else {
  192. throw new IllegalArgumentException("invalid layout key " + s);
  193. }
  194. }
  195. /**
  196. * Removes the specified component from the layout.
  197. *
  198. * @param c the component to remove
  199. */
  200. public void removeLayoutComponent(Component c)
  201. {
  202. if (c == viewport) {
  203. viewport = null;
  204. }
  205. else if (c == vsb) {
  206. vsb = null;
  207. }
  208. else if (c == hsb) {
  209. hsb = null;
  210. }
  211. else if (c == rowHead) {
  212. rowHead = null;
  213. }
  214. else if (c == colHead) {
  215. colHead = null;
  216. }
  217. else if (c == lowerLeft) {
  218. lowerLeft = null;
  219. }
  220. else if (c == lowerRight) {
  221. lowerRight = null;
  222. }
  223. else if (c == upperLeft) {
  224. upperLeft = null;
  225. }
  226. else if (c == upperRight) {
  227. upperRight = null;
  228. }
  229. }
  230. /**
  231. * Returns the vertical scrollbar-display policy.
  232. *
  233. * @return an int giving the display policy
  234. * @see #setVerticalScrollBarPolicy
  235. */
  236. public int getVerticalScrollBarPolicy() {
  237. return vsbPolicy;
  238. }
  239. /**
  240. * Sets the vertical scrollbar-display policy. The options
  241. * are:
  242. * <ul>
  243. * <li>JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED
  244. * <li>JScrollPane.VERTICAL_SCROLLBAR_NEVER
  245. * <li>JScrollPane.VERTICAL_SCROLLBAR_ALWAYS
  246. * </ul>
  247. * Note: Applications should use the JScrollPane version
  248. * of this method. It only exists for backwards compatibility
  249. * with the Swing 1.0.2 (and earlier) versions of this class.
  250. *
  251. * @param x an int giving the display policy
  252. */
  253. public void setVerticalScrollBarPolicy(int x) {
  254. switch (x) {
  255. case VERTICAL_SCROLLBAR_AS_NEEDED:
  256. case VERTICAL_SCROLLBAR_NEVER:
  257. case VERTICAL_SCROLLBAR_ALWAYS:
  258. vsbPolicy = x;
  259. break;
  260. default:
  261. throw new IllegalArgumentException("invalid verticalScrollBarPolicy");
  262. }
  263. }
  264. /**
  265. * Returns the horizontal scrollbar-display policy.
  266. *
  267. * @return an int giving the display policy
  268. * @see #setHorizontalScrollBarPolicy
  269. */
  270. public int getHorizontalScrollBarPolicy() {
  271. return hsbPolicy;
  272. }
  273. /**
  274. * Sets the horizontal scrollbar-display policy.
  275. * The options are:<ul>
  276. * <li>JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED
  277. * <li>JScrollPane.HOTRIZONTAL_SCROLLBAR_NEVER
  278. * <li>JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS
  279. * </ul>
  280. * Note: Applications should use the JScrollPane version
  281. * of this method. It only exists for backwards compatibility
  282. * with the Swing 1.0.2 (and earlier) versions of this class.
  283. *
  284. * @param x an int giving the display policy
  285. */
  286. public void setHorizontalScrollBarPolicy(int x) {
  287. switch (x) {
  288. case HORIZONTAL_SCROLLBAR_AS_NEEDED:
  289. case HORIZONTAL_SCROLLBAR_NEVER:
  290. case HORIZONTAL_SCROLLBAR_ALWAYS:
  291. hsbPolicy = x;
  292. break;
  293. default:
  294. throw new IllegalArgumentException("invalid horizontalScrollBarPolicy");
  295. }
  296. }
  297. /**
  298. * Returns the JViewport object that displays the scrollable contents.
  299. * @return the JViewport object that displays the scrollable contents
  300. * @see JScrollPane#getViewport
  301. */
  302. public JViewport getViewport() {
  303. return viewport;
  304. }
  305. /**
  306. * Returns the JScrollbar object that handles horizontal scrolling.
  307. * @return the JScrollbar object that handles horizontal scrolling
  308. * @see JScrollPane#getHorizontalScrollBar
  309. */
  310. public JScrollBar getHorizontalScrollBar() {
  311. return hsb;
  312. }
  313. /**
  314. * Returns the JScrollbar object that handles vertical scrolling.
  315. * @return the JScrollbar object that handles vertical scrolling
  316. * @see JScrollPane#getVerticalScrollBar
  317. */
  318. public JScrollBar getVerticalScrollBar() {
  319. return vsb;
  320. }
  321. /**
  322. * Returns the JViewport object that is the row header.
  323. * @return the JViewport object that is the row header
  324. * @see JScrollPane#getRowHeader
  325. */
  326. public JViewport getRowHeader() {
  327. return rowHead;
  328. }
  329. /**
  330. * Returns the JViewport object that is the column header.
  331. * @return the JViewport object that is the column header
  332. * @see JScrollPane#getColumnHeader
  333. */
  334. public JViewport getColumnHeader() {
  335. return colHead;
  336. }
  337. /**
  338. * Returns the Component at the specified corner.
  339. * @param key the String specifying the corner
  340. * @return the Component at the specified corner, as defined in
  341. * {@link ScrollPaneConstants}
  342. * @see JScrollPane#getCorner
  343. */
  344. public Component getCorner(String key) {
  345. if (key.equals(LOWER_LEFT_CORNER)) {
  346. return lowerLeft;
  347. }
  348. else if (key.equals(LOWER_RIGHT_CORNER)) {
  349. return lowerRight;
  350. }
  351. else if (key.equals(UPPER_LEFT_CORNER)) {
  352. return upperLeft;
  353. }
  354. else if (key.equals(UPPER_RIGHT_CORNER)) {
  355. return upperRight;
  356. }
  357. else {
  358. return null;
  359. }
  360. }
  361. /**
  362. * The preferred size of a ScrollPane is the size of the insets,
  363. * plus the preferred size of the viewport, plus the preferred size of
  364. * the visible headers, plus the preferred size of the scrollbars
  365. * that will appear given the current view and the current
  366. * scrollbar displayPolicies.
  367. *
  368. * @param parent the Container that will be laid out
  369. * @return a Dimension object specifying the preferred size of the
  370. * viewport and any scrollbars.
  371. * @see ViewportLayout
  372. * @see LayoutManager
  373. */
  374. public Dimension preferredLayoutSize(Container parent)
  375. {
  376. /* Sync the (now obsolete) policy fields with the
  377. * JScrollPane.
  378. */
  379. JScrollPane scrollPane = (JScrollPane)parent;
  380. vsbPolicy = scrollPane.getVerticalScrollBarPolicy();
  381. hsbPolicy = scrollPane.getHorizontalScrollBarPolicy();
  382. Insets insets = parent.getInsets();
  383. int prefWidth = insets.left + insets.right;
  384. int prefHeight = insets.top + insets.bottom;
  385. /* Note that viewport.getViewSize() is equivalent to
  386. * viewport.getView().getPreferredSize() modulo a null
  387. * view or a view whose size was explicitly set.
  388. */
  389. Dimension extentSize = null;
  390. Dimension viewSize = null;
  391. Component view = null;
  392. if (viewport != null) {
  393. extentSize = viewport.getPreferredSize();
  394. viewSize = viewport.getViewSize();
  395. view = viewport.getView();
  396. }
  397. /* If there's a viewport add its preferredSize.
  398. */
  399. if (extentSize != null) {
  400. prefWidth += extentSize.width;
  401. prefHeight += extentSize.height;
  402. }
  403. /* If there's a JScrollPane.viewportBorder, add its insets.
  404. */
  405. Border viewportBorder = scrollPane.getViewportBorder();
  406. if (viewportBorder != null) {
  407. Insets vpbInsets = viewportBorder.getBorderInsets(parent);
  408. prefWidth += vpbInsets.left + vpbInsets.right;
  409. prefHeight += vpbInsets.top + vpbInsets.bottom;
  410. }
  411. /* If a header exists and it's visible, factor its
  412. * preferred size in.
  413. */
  414. if ((rowHead != null) && rowHead.isVisible()) {
  415. prefWidth += rowHead.getPreferredSize().width;
  416. }
  417. if ((colHead != null) && colHead.isVisible()) {
  418. prefHeight += colHead.getPreferredSize().height;
  419. }
  420. /* If a scrollbar is going to appear, factor its preferred size in.
  421. * If the scrollbars policy is AS_NEEDED, this can be a little
  422. * tricky:
  423. *
  424. * - If the view is a Scrollable then scrollableTracksViewportWidth
  425. * and scrollableTracksViewportHeight can be used to effectively
  426. * disable scrolling (if they're true) in their respective dimensions.
  427. *
  428. * - Assuming that a scrollbar hasn't been disabled by the
  429. * previous constraint, we need to decide if the scrollbar is going
  430. * to appear to correctly compute the JScrollPanes preferred size.
  431. * To do this we compare the preferredSize of the viewport (the
  432. * extentSize) to the preferredSize of the view. Although we're
  433. * not responsible for laying out the view we'll assume that the
  434. * JViewport will always give it its preferredSize.
  435. */
  436. if ((vsb != null) && (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
  437. if (vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) {
  438. prefWidth += vsb.getPreferredSize().width;
  439. }
  440. else if ((viewSize != null) && (extentSize != null)) {
  441. boolean canScroll = true;
  442. if (view instanceof Scrollable) {
  443. canScroll = !((Scrollable)view).getScrollableTracksViewportHeight();
  444. }
  445. if (canScroll && (viewSize.height > extentSize.height)) {
  446. prefWidth += vsb.getPreferredSize().width;
  447. }
  448. }
  449. }
  450. if ((hsb != null) && (hsbPolicy != HORIZONTAL_SCROLLBAR_NEVER)) {
  451. if (hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) {
  452. prefHeight += hsb.getPreferredSize().height;
  453. }
  454. else if ((viewSize != null) && (extentSize != null)) {
  455. boolean canScroll = true;
  456. if (view instanceof Scrollable) {
  457. canScroll = !((Scrollable)view).getScrollableTracksViewportWidth();
  458. }
  459. if (canScroll && (viewSize.width > extentSize.width)) {
  460. prefHeight += hsb.getPreferredSize().height;
  461. }
  462. }
  463. }
  464. return new Dimension(prefWidth, prefHeight);
  465. }
  466. /**
  467. * The minimum size of a ScrollPane is the size of the insets
  468. * plus minimum size of the viewport, plus the scrollpane's
  469. * viewportBorder insets, plus the minimum size
  470. * of the visible headers, plus the minimum size of the
  471. * scrollbars whose displayPolicy isn't NEVER.
  472. *
  473. * @param parent the Container that will be laid out
  474. * @return a Dimension object specifying the minimum size
  475. */
  476. public Dimension minimumLayoutSize(Container parent)
  477. {
  478. /* Sync the (now obsolete) policy fields with the
  479. * JScrollPane.
  480. */
  481. JScrollPane scrollPane = (JScrollPane)parent;
  482. vsbPolicy = scrollPane.getVerticalScrollBarPolicy();
  483. hsbPolicy = scrollPane.getHorizontalScrollBarPolicy();
  484. Insets insets = parent.getInsets();
  485. int minWidth = insets.left + insets.right;
  486. int minHeight = insets.top + insets.bottom;
  487. /* If there's a viewport add its minimumSize.
  488. */
  489. if (viewport != null) {
  490. Dimension size = viewport.getMinimumSize();
  491. minWidth += size.width;
  492. minHeight += size.height;
  493. }
  494. /* If there's a JScrollPane.viewportBorder, add its insets.
  495. */
  496. Border viewportBorder = scrollPane.getViewportBorder();
  497. if (viewportBorder != null) {
  498. Insets vpbInsets = viewportBorder.getBorderInsets(parent);
  499. minWidth += vpbInsets.left + vpbInsets.right;
  500. minHeight += vpbInsets.top + vpbInsets.bottom;
  501. }
  502. /* If a header exists and it's visible, factor its
  503. * minimum size in.
  504. */
  505. if ((rowHead != null) && rowHead.isVisible()) {
  506. Dimension size = rowHead.getMinimumSize();
  507. minWidth += size.width;
  508. minHeight = Math.max(minHeight, size.height);
  509. }
  510. if ((colHead != null) && colHead.isVisible()) {
  511. Dimension size = colHead.getMinimumSize();
  512. minWidth = Math.max(minWidth, size.width);
  513. minHeight += size.height;
  514. }
  515. /* If a scrollbar might appear, factor its minimum
  516. * size in.
  517. */
  518. if ((vsb != null) && (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
  519. Dimension size = vsb.getMinimumSize();
  520. minWidth += size.width;
  521. minHeight = Math.max(minHeight, size.height);
  522. }
  523. if ((hsb != null) && (hsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
  524. Dimension size = hsb.getMinimumSize();
  525. minWidth = Math.max(minWidth, size.width);
  526. minHeight += size.height;
  527. }
  528. return new Dimension(minWidth, minHeight);
  529. }
  530. /**
  531. * Lay out the scrollpane. The positioning of components depends on
  532. * the following constraints:
  533. * <ul>
  534. * <li> The row header, if present and visible, gets its preferred
  535. * height and the viewports width.
  536. *
  537. * <li> The column header, if present and visible, gets its preferred
  538. * width and the viewports height.
  539. *
  540. * <li> If a vertical scrollbar is needed, i.e. if the viewports extent
  541. * height is smaller than its view height or if the displayPolicy
  542. * is ALWAYS, it's treated like the row header wrt it's dimensions and
  543. * it's made visible.
  544. *
  545. * <li> If a horizontal scrollbar is needed it's treated like the
  546. * column header (and see the vertical scrollbar item).
  547. *
  548. * <li> If the scrollpane has a non-null viewportBorder, then space
  549. * is allocated for that.
  550. *
  551. * <li> The viewport gets the space available after accounting for
  552. * the previous constraints.
  553. *
  554. * <li> The corner components, if provided, are aligned with the
  555. * ends of the scrollbars and headers. If there's a vertical
  556. * scrollbar the right corners appear, if there's a horizontal
  557. * scrollbar the lower corners appear, a row header gets left
  558. * corners and a column header gets upper corners.
  559. * </ul>
  560. *
  561. * @param parent the Container to lay out
  562. */
  563. public void layoutContainer(Container parent)
  564. {
  565. /* Sync the (now obsolete) policy fields with the
  566. * JScrollPane.
  567. */
  568. JScrollPane scrollPane = (JScrollPane)parent;
  569. vsbPolicy = scrollPane.getVerticalScrollBarPolicy();
  570. hsbPolicy = scrollPane.getHorizontalScrollBarPolicy();
  571. Rectangle availR = new Rectangle(scrollPane.getSize());
  572. Insets insets = parent.getInsets();
  573. availR.x = insets.left;
  574. availR.y = insets.top;
  575. availR.width -= insets.left + insets.right;
  576. availR.height -= insets.top + insets.bottom;
  577. /* If there's a visible column header remove the space it
  578. * needs from the top of availR. The column header is treated
  579. * as if it were fixed height, arbitrary width.
  580. */
  581. Rectangle colHeadR = new Rectangle(0, availR.y, 0, 0);
  582. if ((colHead != null) && (colHead.isVisible())) {
  583. int colHeadHeight = colHead.getPreferredSize().height;
  584. colHeadR.height = colHeadHeight;
  585. availR.y += colHeadHeight;
  586. availR.height -= colHeadHeight;
  587. }
  588. /* If there's a visible row header remove the space it needs
  589. * from the left of availR. The row header is treated
  590. * as if it were fixed width, arbitrary height.
  591. */
  592. Rectangle rowHeadR = new Rectangle(availR.x, 0, 0, 0);
  593. if ((rowHead != null) && (rowHead.isVisible())) {
  594. int rowHeadWidth = rowHead.getPreferredSize().width;
  595. rowHeadR.width = rowHeadWidth;
  596. availR.x += rowHeadWidth;
  597. availR.width -= rowHeadWidth;
  598. }
  599. /* If there's a JScrollPane.viewportBorder, remove the
  600. * space it occupies for availR.
  601. */
  602. Border viewportBorder = scrollPane.getViewportBorder();
  603. Insets vpbInsets;
  604. if (viewportBorder != null) {
  605. vpbInsets = viewportBorder.getBorderInsets(parent);
  606. availR.x += vpbInsets.left;
  607. availR.y += vpbInsets.top;
  608. availR.width -= vpbInsets.left + vpbInsets.right;
  609. availR.height -= vpbInsets.top + vpbInsets.bottom;
  610. }
  611. else {
  612. vpbInsets = new Insets(0,0,0,0);
  613. }
  614. colHeadR.x = availR.x;
  615. rowHeadR.y = availR.y;
  616. /* At this point availR is the space available for the viewport
  617. * and scrollbars, and the rowHeadR colHeadR rectangles are correct
  618. * except for their width and height respectively. Once we're
  619. * through computing the dimensions of these three parts we can
  620. * go back and set the dimensions of rowHeadR.width, colHeadR.height,
  621. * and the bounds for the corners.
  622. *
  623. * We'll decide about putting up scrollbars by comparing the
  624. * viewport views preferred size with the viewports extent
  625. * size (generally just its size). Using the preferredSize is
  626. * reasonable because layout proceeds top down - so we expect
  627. * the viewport to be layed out next. And we assume that the
  628. * viewports layout manager will give the view it's preferred
  629. * size. One exception to this is when the view implements
  630. * Scrollable and Scrollable.getViewTracksViewport{Width,Height}
  631. * methods return true. If the view is tracking the viewports
  632. * width we don't bother with a horizontal scrollbar, similarly
  633. * if view.getViewTracksViewport(Height) is true we don't bother
  634. * with a vertical scrollbar.
  635. */
  636. Component view = (viewport != null) ? viewport.getView() : null;
  637. Dimension viewPrefSize =
  638. (view != null) ? view.getPreferredSize()
  639. : new Dimension(0,0);
  640. Dimension extentSize =
  641. (viewport != null) ? viewport.toViewCoordinates(availR.getSize())
  642. : new Dimension(0,0);
  643. boolean viewTracksViewportWidth = false;
  644. boolean viewTracksViewportHeight = false;
  645. if (view instanceof Scrollable) {
  646. Scrollable sv = ((Scrollable)view);
  647. viewTracksViewportWidth = sv.getScrollableTracksViewportWidth();
  648. viewTracksViewportHeight = sv.getScrollableTracksViewportHeight();
  649. }
  650. /* If there's a vertical scrollbar and we need one, allocate
  651. * space for it (we'll make it visible later). A vertical
  652. * scrollbar is considered to be fixed width, arbitrary height.
  653. */
  654. Rectangle vsbR = new Rectangle(0, availR.y - vpbInsets.top, 0, 0);
  655. boolean vsbNeeded;
  656. if (vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) {
  657. vsbNeeded = true;
  658. }
  659. else if (vsbPolicy == VERTICAL_SCROLLBAR_NEVER) {
  660. vsbNeeded = false;
  661. }
  662. else { // vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED
  663. vsbNeeded = !viewTracksViewportHeight && (viewPrefSize.height > extentSize.height);
  664. }
  665. if ((vsb != null) && vsbNeeded) {
  666. int vsbWidth = vsb.getPreferredSize().width;
  667. availR.width -= vsbWidth;
  668. vsbR.x = availR.x + availR.width + vpbInsets.right;
  669. vsbR.width = vsbWidth;
  670. }
  671. /* If there's a horizontal scrollbar and we need one, allocate
  672. * space for it (we'll make it visible later). A horizontal
  673. * scrollbar is considered to be fixed height, arbitrary width.
  674. */
  675. Rectangle hsbR = new Rectangle(availR.x - vpbInsets.left, 0, 0, 0);
  676. boolean hsbNeeded;
  677. if (hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) {
  678. hsbNeeded = true;
  679. }
  680. else if (hsbPolicy == HORIZONTAL_SCROLLBAR_NEVER) {
  681. hsbNeeded = false;
  682. }
  683. else { // hsbPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED
  684. hsbNeeded = !viewTracksViewportWidth && (viewPrefSize.width > extentSize.width);
  685. }
  686. if ((hsb != null) && hsbNeeded) {
  687. int hsbHeight = hsb.getPreferredSize().height;
  688. availR.height -= hsbHeight;
  689. hsbR.y = availR.y + availR.height + vpbInsets.bottom;
  690. hsbR.height = hsbHeight;
  691. /* If we added the horizontal scrollbar then we've implicitly
  692. * reduced the vertical space available to the viewport.
  693. * As a consequence we may have to add the vertical scrollbar,
  694. * if that hasn't been done so already. Ofcourse we
  695. * don't bother with any of this if the vsbPolicy is NEVER.
  696. */
  697. if ((vsb != null) && !vsbNeeded && (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
  698. extentSize = viewport.toViewCoordinates(availR.getSize());
  699. vsbNeeded = viewPrefSize.height > extentSize.height;
  700. if (vsbNeeded) {
  701. int vsbWidth = vsb.getPreferredSize().width;
  702. availR.width -= vsbWidth;
  703. vsbR.x = availR.x + availR.width + vpbInsets.right;
  704. vsbR.width = vsbWidth;
  705. }
  706. }
  707. }
  708. /* We now have the final size of the viewport: availR.
  709. * Now fixup the header and scrollbar widths/heights.
  710. */
  711. vsbR.height = availR.height + vpbInsets.top + vpbInsets.bottom;
  712. hsbR.width = availR.width + vpbInsets.left + vpbInsets.right;
  713. rowHeadR.height = availR.height;
  714. colHeadR.width = availR.width;
  715. /* Set the bounds of all nine components. The scrollbars
  716. * are made invisible if they're not needed.
  717. */
  718. if (viewport != null) {
  719. viewport.setBounds(availR);
  720. }
  721. if (rowHead != null) {
  722. rowHead.setBounds(rowHeadR);
  723. }
  724. if (colHead != null) {
  725. colHead.setBounds(colHeadR);
  726. }
  727. if (vsb != null) {
  728. if (vsbNeeded) {
  729. vsb.setVisible(true);
  730. vsb.setBounds(vsbR);
  731. }
  732. else {
  733. vsb.setVisible(false);
  734. }
  735. }
  736. if (hsb != null) {
  737. if (hsbNeeded) {
  738. hsb.setVisible(true);
  739. hsb.setBounds(hsbR);
  740. }
  741. else {
  742. hsb.setVisible(false);
  743. }
  744. }
  745. if (lowerLeft != null) {
  746. lowerLeft.setBounds(rowHeadR.x, hsbR.y, rowHeadR.width, hsbR.height);
  747. }
  748. if (lowerRight != null) {
  749. lowerRight.setBounds(vsbR.x, hsbR.y, vsbR.width, hsbR.height);
  750. }
  751. if (upperLeft != null) {
  752. upperLeft.setBounds(rowHeadR.x, colHeadR.y, rowHeadR.width, colHeadR.height);
  753. }
  754. if (upperRight != null) {
  755. upperRight.setBounds(vsbR.x, colHeadR.y, vsbR.width, colHeadR.height);
  756. }
  757. }
  758. /**
  759. * Returns the bounds of the border around the specified scroll pane's
  760. * viewport.
  761. *
  762. * @return the size and position of the viewport border
  763. * @deprecated As of JDK version Swing1.1
  764. * replaced by <code>JScrollPane.getViewportBorderBounds()</code>.
  765. */
  766. public Rectangle getViewportBorderBounds(JScrollPane scrollpane) {
  767. return scrollpane.getViewportBorderBounds();
  768. }
  769. /**
  770. * The UI resource version of ScrollPaneLayout.
  771. */
  772. public static class UIResource extends ScrollPaneLayout implements javax.swing.plaf.UIResource {}
  773. }