< prev index next >

src/java.desktop/share/classes/javax/swing/ScrollPaneLayout.java

Print this page




  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 
  26 package javax.swing;
  27 
  28 
  29 import javax.swing.border.*;
  30 
  31 import java.awt.LayoutManager;
  32 import java.awt.Component;
  33 import java.awt.Container;
  34 import java.awt.Rectangle;
  35 import java.awt.Dimension;
  36 import java.awt.Insets;
  37 import java.io.Serializable;
  38 
  39 
  40 /**
  41  * The layout manager used by <code>JScrollPane</code>.
  42  * <code>JScrollPaneLayout</code> is
  43  * responsible for nine components: a viewport, two scrollbars,
  44  * a row header, a column header, and four "corner" components.
  45  * <p>
  46  * <strong>Warning:</strong>
  47  * Serialized objects of this class will not be compatible with
  48  * future Swing releases. The current serialization support is
  49  * appropriate for short term storage or RMI between applications running
  50  * the same version of Swing.  As of 1.4, support for long term storage
  51  * of all JavaBeans&trade;
  52  * has been added to the <code>java.beans</code> package.
  53  * Please see {@link java.beans.XMLEncoder}.
  54  *
  55  * @see JScrollPane
  56  * @see JViewport
  57  *
  58  * @author Hans Muller
  59  * @since 1.2
  60  */
  61 @SuppressWarnings("serial") // Same-version serialization only
  62 public class ScrollPaneLayout
  63     implements LayoutManager, ScrollPaneConstants, Serializable
  64 {
  65 
  66     /**
  67      * The scrollpane's viewport child.
  68      * Default is an empty <code>JViewport</code>.
  69      * @see JScrollPane#setViewport
  70      */
  71     protected JViewport viewport;
  72 
  73 
  74     /**
  75      * The scrollpane's vertical scrollbar child.
  76      * Default is a <code>JScrollBar</code>.
  77      * @see JScrollPane#setVerticalScrollBar
  78      */
  79     protected JScrollBar vsb;
  80 
  81 
  82     /**
  83      * The scrollpane's horizontal scrollbar child.
  84      * Default is a <code>JScrollBar</code>.
  85      * @see JScrollPane#setHorizontalScrollBar
  86      */
  87     protected JScrollBar hsb;
  88 
  89 
  90     /**
  91      * The row header child.  Default is <code>null</code>.
  92      * @see JScrollPane#setRowHeader
  93      */
  94     protected JViewport rowHead;
  95 
  96 
  97     /**
  98      * The column header child.  Default is <code>null</code>.
  99      * @see JScrollPane#setColumnHeader
 100      */
 101     protected JViewport colHead;
 102 
 103 
 104     /**
 105      * The component to display in the lower left corner.
 106      * Default is <code>null</code>.
 107      * @see JScrollPane#setCorner
 108      */
 109     protected Component lowerLeft;
 110 
 111 
 112     /**
 113      * The component to display in the lower right corner.
 114      * Default is <code>null</code>.
 115      * @see JScrollPane#setCorner
 116      */
 117     protected Component lowerRight;
 118 
 119 
 120     /**
 121      * The component to display in the upper left corner.
 122      * Default is <code>null</code>.
 123      * @see JScrollPane#setCorner
 124      */
 125     protected Component upperLeft;
 126 
 127 
 128     /**
 129      * The component to display in the upper right corner.
 130      * Default is <code>null</code>.
 131      * @see JScrollPane#setCorner
 132      */
 133     protected Component upperRight;
 134 
 135 
 136     /**
 137      * The display policy for the vertical scrollbar.
 138      * The default is <code>ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED</code>.
 139      * <p>
 140      * This field is obsolete, please use the <code>JScrollPane</code> field instead.
 141      *
 142      * @see JScrollPane#setVerticalScrollBarPolicy
 143      */
 144     protected int vsbPolicy = VERTICAL_SCROLLBAR_AS_NEEDED;
 145 
 146 
 147     /**
 148      * The display policy for the horizontal scrollbar.
 149      * The default is <code>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED</code>.
 150      * <p>
 151      * This field is obsolete, please use the <code>JScrollPane</code> field instead.
 152      *
 153      * @see JScrollPane#setHorizontalScrollBarPolicy
 154      */
 155     protected int hsbPolicy = HORIZONTAL_SCROLLBAR_AS_NEEDED;
 156 
 157 
 158     /**
 159      * This method is invoked after the ScrollPaneLayout is set as the
 160      * LayoutManager of a <code>JScrollPane</code>.
 161      * It initializes all of the internal fields that
 162      * are ordinarily set by <code>addLayoutComponent</code>.  For example:
 163      * <pre>
 164      * ScrollPaneLayout mySPLayout = new ScrollPanelLayout() {
 165      *     public void layoutContainer(Container p) {
 166      *         super.layoutContainer(p);
 167      *         // do some extra work here ...
 168      *     }
 169      * };
 170      * scrollpane.setLayout(mySPLayout):
 171      * </pre>
 172      *
 173      * @param sp an instance of the {@code JScrollPane}
 174      */
 175     public void syncWithScrollPane(JScrollPane sp) {
 176         viewport = sp.getViewport();
 177         vsb = sp.getVerticalScrollBar();
 178         hsb = sp.getHorizontalScrollBar();
 179         rowHead = sp.getRowHeader();
 180         colHead = sp.getColumnHeader();
 181         lowerLeft = sp.getCorner(LOWER_LEFT_CORNER);
 182         lowerRight = sp.getCorner(LOWER_RIGHT_CORNER);
 183         upperLeft = sp.getCorner(UPPER_LEFT_CORNER);
 184         upperRight = sp.getCorner(UPPER_RIGHT_CORNER);
 185         vsbPolicy = sp.getVerticalScrollBarPolicy();
 186         hsbPolicy = sp.getHorizontalScrollBarPolicy();
 187     }
 188 
 189 
 190     /**
 191      * Removes an existing component.  When a new component, such as
 192      * the left corner, or vertical scrollbar, is added, the old one,
 193      * if it exists, must be removed.
 194      * <p>
 195      * This method returns <code>newC</code>. If <code>oldC</code> is
 196      * not equal to <code>newC</code> and is non-<code>null</code>,
 197      * it will be removed from its parent.
 198      *
 199      * @param oldC the <code>Component</code> to replace
 200      * @param newC the <code>Component</code> to add
 201      * @return the <code>newC</code>
 202      */
 203     protected Component addSingletonComponent(Component oldC, Component newC)
 204     {
 205         if ((oldC != null) && (oldC != newC)) {
 206             oldC.getParent().remove(oldC);
 207         }
 208         return newC;
 209     }
 210 
 211 
 212     /**
 213      * Adds the specified component to the layout. The layout is
 214      * identified using one of:
 215      * <ul>
 216      * <li>ScrollPaneConstants.VIEWPORT
 217      * <li>ScrollPaneConstants.VERTICAL_SCROLLBAR
 218      * <li>ScrollPaneConstants.HORIZONTAL_SCROLLBAR
 219      * <li>ScrollPaneConstants.ROW_HEADER
 220      * <li>ScrollPaneConstants.COLUMN_HEADER
 221      * <li>ScrollPaneConstants.LOWER_LEFT_CORNER
 222      * <li>ScrollPaneConstants.LOWER_RIGHT_CORNER
 223      * <li>ScrollPaneConstants.UPPER_LEFT_CORNER
 224      * <li>ScrollPaneConstants.UPPER_RIGHT_CORNER
 225      * </ul>
 226      *
 227      * @param s the component identifier
 228      * @param c the component to be added
 229      * @exception IllegalArgumentException if <code>s</code> is an invalid key
 230      */
 231     public void addLayoutComponent(String s, Component c)
 232     {
 233         if (s.equals(VIEWPORT)) {
 234             viewport = (JViewport)addSingletonComponent(viewport, c);
 235         }
 236         else if (s.equals(VERTICAL_SCROLLBAR)) {
 237             vsb = (JScrollBar)addSingletonComponent(vsb, c);
 238         }
 239         else if (s.equals(HORIZONTAL_SCROLLBAR)) {
 240             hsb = (JScrollBar)addSingletonComponent(hsb, c);
 241         }
 242         else if (s.equals(ROW_HEADER)) {
 243             rowHead = (JViewport)addSingletonComponent(rowHead, c);
 244         }
 245         else if (s.equals(COLUMN_HEADER)) {
 246             colHead = (JViewport)addSingletonComponent(colHead, c);
 247         }
 248         else if (s.equals(LOWER_LEFT_CORNER)) {
 249             lowerLeft = addSingletonComponent(lowerLeft, c);


 302 
 303     /**
 304      * Returns the vertical scrollbar-display policy.
 305      *
 306      * @return an integer giving the display policy
 307      * @see #setVerticalScrollBarPolicy
 308      */
 309     public int getVerticalScrollBarPolicy() {
 310         return vsbPolicy;
 311     }
 312 
 313 
 314     /**
 315      * Sets the vertical scrollbar-display policy. The options
 316      * are:
 317      * <ul>
 318      * <li>ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED
 319      * <li>ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER
 320      * <li>ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS
 321      * </ul>
 322      * Note: Applications should use the <code>JScrollPane</code> version
 323      * of this method.  It only exists for backwards compatibility
 324      * with the Swing 1.0.2 (and earlier) versions of this class.
 325      *
 326      * @param x an integer giving the display policy
 327      * @exception IllegalArgumentException if <code>x</code> is an invalid
 328      *          vertical scroll bar policy, as listed above
 329      */
 330     public void setVerticalScrollBarPolicy(int x) {
 331         switch (x) {
 332         case VERTICAL_SCROLLBAR_AS_NEEDED:
 333         case VERTICAL_SCROLLBAR_NEVER:
 334         case VERTICAL_SCROLLBAR_ALWAYS:
 335                 vsbPolicy = x;
 336                 break;
 337         default:
 338             throw new IllegalArgumentException("invalid verticalScrollBarPolicy");
 339         }
 340     }
 341 
 342 
 343     /**
 344      * Returns the horizontal scrollbar-display policy.
 345      *
 346      * @return an integer giving the display policy
 347      * @see #setHorizontalScrollBarPolicy
 348      */
 349     public int getHorizontalScrollBarPolicy() {
 350         return hsbPolicy;
 351     }
 352 
 353     /**
 354      * Sets the horizontal scrollbar-display policy.
 355      * The options are:<ul>
 356      * <li>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED
 357      * <li>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER
 358      * <li>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS
 359      * </ul>
 360      * Note: Applications should use the <code>JScrollPane</code> version
 361      * of this method.  It only exists for backwards compatibility
 362      * with the Swing 1.0.2 (and earlier) versions of this class.
 363      *
 364      * @param x an int giving the display policy
 365      * @exception IllegalArgumentException if <code>x</code> is not a valid
 366      *          horizontal scrollbar policy, as listed above
 367      */
 368     public void setHorizontalScrollBarPolicy(int x) {
 369         switch (x) {
 370         case HORIZONTAL_SCROLLBAR_AS_NEEDED:
 371         case HORIZONTAL_SCROLLBAR_NEVER:
 372         case HORIZONTAL_SCROLLBAR_ALWAYS:
 373                 hsbPolicy = x;
 374                 break;
 375         default:
 376             throw new IllegalArgumentException("invalid horizontalScrollBarPolicy");
 377         }
 378     }
 379 
 380 
 381     /**
 382      * Returns the <code>JViewport</code> object that displays the
 383      * scrollable contents.
 384      * @return the <code>JViewport</code> object that displays the scrollable contents
 385      * @see JScrollPane#getViewport
 386      */
 387     public JViewport getViewport() {
 388         return viewport;
 389     }
 390 
 391 
 392     /**
 393      * Returns the <code>JScrollBar</code> object that handles horizontal scrolling.
 394      * @return the <code>JScrollBar</code> object that handles horizontal scrolling
 395      * @see JScrollPane#getHorizontalScrollBar
 396      */
 397     public JScrollBar getHorizontalScrollBar() {
 398         return hsb;
 399     }
 400 
 401     /**
 402      * Returns the <code>JScrollBar</code> object that handles vertical scrolling.
 403      * @return the <code>JScrollBar</code> object that handles vertical scrolling
 404      * @see JScrollPane#getVerticalScrollBar
 405      */
 406     public JScrollBar getVerticalScrollBar() {
 407         return vsb;
 408     }
 409 
 410 
 411     /**
 412      * Returns the <code>JViewport</code> object that is the row header.
 413      * @return the <code>JViewport</code> object that is the row header
 414      * @see JScrollPane#getRowHeader
 415      */
 416     public JViewport getRowHeader() {
 417         return rowHead;
 418     }
 419 
 420 
 421     /**
 422      * Returns the <code>JViewport</code> object that is the column header.
 423      * @return the <code>JViewport</code> object that is the column header
 424      * @see JScrollPane#getColumnHeader
 425      */
 426     public JViewport getColumnHeader() {
 427         return colHead;
 428     }
 429 
 430 
 431     /**
 432      * Returns the <code>Component</code> at the specified corner.
 433      * @param key the <code>String</code> specifying the corner
 434      * @return the <code>Component</code> at the specified corner, as defined in
 435      *         {@link ScrollPaneConstants}; if <code>key</code> is not one of the
 436      *          four corners, <code>null</code> is returned
 437      * @see JScrollPane#getCorner
 438      */
 439     public Component getCorner(String key) {
 440         if (key.equals(LOWER_LEFT_CORNER)) {
 441             return lowerLeft;
 442         }
 443         else if (key.equals(LOWER_RIGHT_CORNER)) {
 444             return lowerRight;
 445         }
 446         else if (key.equals(UPPER_LEFT_CORNER)) {
 447             return upperLeft;
 448         }
 449         else if (key.equals(UPPER_RIGHT_CORNER)) {
 450             return upperRight;
 451         }
 452         else {
 453             return null;
 454         }
 455     }
 456 
 457 
 458     /**
 459      * The preferred size of a <code>ScrollPane</code> is the size of the insets,
 460      * plus the preferred size of the viewport, plus the preferred size of
 461      * the visible headers, plus the preferred size of the scrollbars
 462      * that will appear given the current view and the current
 463      * scrollbar displayPolicies.
 464      * <p>Note that the rowHeader is calculated as part of the preferred width
 465      * and the colHeader is calculated as part of the preferred size.
 466      *
 467      * @param parent the <code>Container</code> that will be laid out
 468      * @return a <code>Dimension</code> object specifying the preferred size of the
 469      *         viewport and any scrollbars
 470      * @see ViewportLayout
 471      * @see LayoutManager
 472      */
 473     public Dimension preferredLayoutSize(Container parent)
 474     {
 475         /* Sync the (now obsolete) policy fields with the
 476          * JScrollPane.
 477          */
 478         JScrollPane scrollPane = (JScrollPane)parent;
 479         vsbPolicy = scrollPane.getVerticalScrollBarPolicy();
 480         hsbPolicy = scrollPane.getHorizontalScrollBarPolicy();
 481 
 482         Insets insets = parent.getInsets();
 483         int prefWidth = insets.left + insets.right;
 484         int prefHeight = insets.top + insets.bottom;
 485 
 486         /* Note that viewport.getViewSize() is equivalent to
 487          * viewport.getView().getPreferredSize() modulo a null
 488          * view or a view whose size was explicitly set.


 567         if ((hsb != null) && (hsbPolicy != HORIZONTAL_SCROLLBAR_NEVER)) {
 568             if (hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) {
 569                 prefHeight += hsb.getPreferredSize().height;
 570             }
 571             else if ((viewSize != null) && (extentSize != null)) {
 572                 boolean canScroll = true;
 573                 if (view instanceof Scrollable) {
 574                     canScroll = !((Scrollable)view).getScrollableTracksViewportWidth();
 575                 }
 576                 if (canScroll && (viewSize.width > extentSize.width)) {
 577                     prefHeight += hsb.getPreferredSize().height;
 578                 }
 579             }
 580         }
 581 
 582         return new Dimension(prefWidth, prefHeight);
 583     }
 584 
 585 
 586     /**
 587      * The minimum size of a <code>ScrollPane</code> is the size of the insets
 588      * plus minimum size of the viewport, plus the scrollpane's
 589      * viewportBorder insets, plus the minimum size
 590      * of the visible headers, plus the minimum size of the
 591      * scrollbars whose displayPolicy isn't NEVER.
 592      *
 593      * @param parent the <code>Container</code> that will be laid out
 594      * @return a <code>Dimension</code> object specifying the minimum size
 595      */
 596     public Dimension minimumLayoutSize(Container parent)
 597     {
 598         /* Sync the (now obsolete) policy fields with the
 599          * JScrollPane.
 600          */
 601         JScrollPane scrollPane = (JScrollPane)parent;
 602         vsbPolicy = scrollPane.getVerticalScrollBarPolicy();
 603         hsbPolicy = scrollPane.getHorizontalScrollBarPolicy();
 604 
 605         Insets insets = parent.getInsets();
 606         int minWidth = insets.left + insets.right;
 607         int minHeight = insets.top + insets.bottom;
 608 
 609         /* If there's a viewport add its minimumSize.
 610          */
 611 
 612         if (viewport != null) {
 613             Dimension size = viewport.getMinimumSize();
 614             minWidth += size.width;


 655             Dimension size = hsb.getMinimumSize();
 656             minWidth = Math.max(minWidth, size.width);
 657             minHeight += size.height;
 658         }
 659 
 660         return new Dimension(minWidth, minHeight);
 661     }
 662 
 663 
 664     /**
 665      * Lays out the scrollpane. The positioning of components depends on
 666      * the following constraints:
 667      * <ul>
 668      * <li> The row header, if present and visible, gets its preferred
 669      * width and the viewport's height.
 670      *
 671      * <li> The column header, if present and visible, gets its preferred
 672      * height and the viewport's width.
 673      *
 674      * <li> If a vertical scrollbar is needed, i.e. if the viewport's extent
 675      * height is smaller than its view height or if the <code>displayPolicy</code>
 676      * is ALWAYS, it's treated like the row header with respect to its
 677      * dimensions and is made visible.
 678      *
 679      * <li> If a horizontal scrollbar is needed, it is treated like the
 680      * column header (see the paragraph above regarding the vertical scrollbar).
 681      *
 682      * <li> If the scrollpane has a non-<code>null</code>
 683      * <code>viewportBorder</code>, then space is allocated for that.
 684      *
 685      * <li> The viewport gets the space available after accounting for
 686      * the previous constraints.
 687      *
 688      * <li> The corner components, if provided, are aligned with the
 689      * ends of the scrollbars and headers. If there is a vertical
 690      * scrollbar, the right corners appear; if there is a horizontal
 691      * scrollbar, the lower corners appear; a row header gets left
 692      * corners, and a column header gets upper corners.
 693      * </ul>
 694      *
 695      * @param parent the <code>Container</code> to lay out
 696      */
 697     public void layoutContainer(Container parent)
 698     {
 699         /* Sync the (now obsolete) policy fields with the
 700          * JScrollPane.
 701          */
 702         JScrollPane scrollPane = (JScrollPane)parent;
 703         vsbPolicy = scrollPane.getVerticalScrollBarPolicy();
 704         hsbPolicy = scrollPane.getHorizontalScrollBarPolicy();
 705 
 706         Rectangle availR = scrollPane.getBounds();
 707         availR.x = availR.y = 0;
 708 
 709         Insets insets = parent.getInsets();
 710         availR.x = insets.left;
 711         availR.y = insets.top;
 712         availR.width -= insets.left + insets.right;
 713         availR.height -= insets.top + insets.bottom;
 714 
 715         /* Get the scrollPane's orientation.


1026                                  leftToRight ? vsbR.width : rowHeadR.width,
1027                                  hsbR.height);
1028         }
1029 
1030         if (upperLeft != null) {
1031             upperLeft.setBounds(leftToRight ? rowHeadR.x : vsbR.x,
1032                                 colHeadR.y,
1033                                 leftToRight ? rowHeadR.width : vsbR.width,
1034                                 colHeadR.height);
1035         }
1036 
1037         if (upperRight != null) {
1038             upperRight.setBounds(leftToRight ? vsbR.x : rowHeadR.x,
1039                                  colHeadR.y,
1040                                  leftToRight ? vsbR.width : rowHeadR.width,
1041                                  colHeadR.height);
1042         }
1043     }
1044 
1045     /**
1046      * Adjusts the <code>Rectangle</code> <code>available</code> based on if
1047      * the vertical scrollbar is needed (<code>wantsVSB</code>).
1048      * The location of the vsb is updated in <code>vsbR</code>, and
1049      * the viewport border insets (<code>vpbInsets</code>) are used to offset
1050      * the vsb. This is only called when <code>wantsVSB</code> has
1051      * changed, eg you shouldn't invoke adjustForVSB(true) twice.
1052      */
1053     private void adjustForVSB(boolean wantsVSB, Rectangle available,
1054                               Rectangle vsbR, Insets vpbInsets,
1055                               boolean leftToRight) {
1056         int oldWidth = vsbR.width;
1057         if (wantsVSB) {
1058             int vsbWidth = Math.max(0, Math.min(vsb.getPreferredSize().width,
1059                                                 available.width));
1060 
1061             available.width -= vsbWidth;
1062             vsbR.width = vsbWidth;
1063 
1064             if( leftToRight ) {
1065                 vsbR.x = available.x + available.width + vpbInsets.right;
1066             } else {
1067                 vsbR.x = available.x - vpbInsets.left;
1068                 available.x += vsbWidth;
1069             }
1070         }
1071         else {
1072             available.width += oldWidth;
1073         }
1074     }
1075 
1076     /**
1077      * Adjusts the <code>Rectangle</code> <code>available</code> based on if
1078      * the horizontal scrollbar is needed (<code>wantsHSB</code>).
1079      * The location of the hsb is updated in <code>hsbR</code>, and
1080      * the viewport border insets (<code>vpbInsets</code>) are used to offset
1081      * the hsb.  This is only called when <code>wantsHSB</code> has
1082      * changed, eg you shouldn't invoked adjustForHSB(true) twice.
1083      */
1084     private void adjustForHSB(boolean wantsHSB, Rectangle available,
1085                               Rectangle hsbR, Insets vpbInsets) {
1086         int oldHeight = hsbR.height;
1087         if (wantsHSB) {
1088             int hsbHeight = Math.max(0, Math.min(available.height,
1089                                               hsb.getPreferredSize().height));
1090 
1091             available.height -= hsbHeight;
1092             hsbR.y = available.y + available.height + vpbInsets.bottom;
1093             hsbR.height = hsbHeight;
1094         }
1095         else {
1096             available.height += oldHeight;
1097         }
1098     }
1099 
1100 
1101 
1102     /**
1103      * Returns the bounds of the border around the specified scroll pane's
1104      * viewport.
1105      *
1106      * @param scrollpane an instance of the {@code JScrollPane}
1107      * @return the size and position of the viewport border
1108      * @deprecated As of JDK version Swing1.1
1109      *    replaced by <code>JScrollPane.getViewportBorderBounds()</code>.
1110      */
1111     @Deprecated
1112     public Rectangle getViewportBorderBounds(JScrollPane scrollpane) {
1113         return scrollpane.getViewportBorderBounds();
1114     }
1115 
1116     /**
1117      * The UI resource version of <code>ScrollPaneLayout</code>.
1118      */
1119     public static class UIResource extends ScrollPaneLayout implements javax.swing.plaf.UIResource {}
1120 }


  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 
  26 package javax.swing;
  27 
  28 
  29 import javax.swing.border.*;
  30 
  31 import java.awt.LayoutManager;
  32 import java.awt.Component;
  33 import java.awt.Container;
  34 import java.awt.Rectangle;
  35 import java.awt.Dimension;
  36 import java.awt.Insets;
  37 import java.io.Serializable;
  38 
  39 
  40 /**
  41  * The layout manager used by {@code JScrollPane}.
  42  * {@code JScrollPaneLayout} is
  43  * responsible for nine components: a viewport, two scrollbars,
  44  * a row header, a column header, and four "corner" components.
  45  * <p>
  46  * <strong>Warning:</strong>
  47  * Serialized objects of this class will not be compatible with
  48  * future Swing releases. The current serialization support is
  49  * appropriate for short term storage or RMI between applications running
  50  * the same version of Swing.  As of 1.4, support for long term storage
  51  * of all JavaBeans&trade;
  52  * has been added to the {@code java.beans} package.
  53  * Please see {@link java.beans.XMLEncoder}.
  54  *
  55  * @see JScrollPane
  56  * @see JViewport
  57  *
  58  * @author Hans Muller
  59  * @since 1.2
  60  */
  61 @SuppressWarnings("serial") // Same-version serialization only
  62 public class ScrollPaneLayout
  63     implements LayoutManager, ScrollPaneConstants, Serializable
  64 {
  65 
  66     /**
  67      * The scrollpane's viewport child.
  68      * Default is an empty {@code JViewport}.
  69      * @see JScrollPane#setViewport
  70      */
  71     protected JViewport viewport;
  72 
  73 
  74     /**
  75      * The scrollpane's vertical scrollbar child.
  76      * Default is a {@code JScrollBar}.
  77      * @see JScrollPane#setVerticalScrollBar
  78      */
  79     protected JScrollBar vsb;
  80 
  81 
  82     /**
  83      * The scrollpane's horizontal scrollbar child.
  84      * Default is a {@code JScrollBar}.
  85      * @see JScrollPane#setHorizontalScrollBar
  86      */
  87     protected JScrollBar hsb;
  88 
  89 
  90     /**
  91      * The row header child.  Default is {@code null}.
  92      * @see JScrollPane#setRowHeader
  93      */
  94     protected JViewport rowHead;
  95 
  96 
  97     /**
  98      * The column header child.  Default is {@code null}.
  99      * @see JScrollPane#setColumnHeader
 100      */
 101     protected JViewport colHead;
 102 
 103 
 104     /**
 105      * The component to display in the lower left corner.
 106      * Default is {@code null}.
 107      * @see JScrollPane#setCorner
 108      */
 109     protected Component lowerLeft;
 110 
 111 
 112     /**
 113      * The component to display in the lower right corner.
 114      * Default is {@code null}.
 115      * @see JScrollPane#setCorner
 116      */
 117     protected Component lowerRight;
 118 
 119 
 120     /**
 121      * The component to display in the upper left corner.
 122      * Default is {@code null}.
 123      * @see JScrollPane#setCorner
 124      */
 125     protected Component upperLeft;
 126 
 127 
 128     /**
 129      * The component to display in the upper right corner.
 130      * Default is {@code null}.
 131      * @see JScrollPane#setCorner
 132      */
 133     protected Component upperRight;
 134 
 135 
 136     /**
 137      * The display policy for the vertical scrollbar.
 138      * The default is {@code ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED}.
 139      * <p>
 140      * This field is obsolete, please use the {@code JScrollPane} field instead.
 141      *
 142      * @see JScrollPane#setVerticalScrollBarPolicy
 143      */
 144     protected int vsbPolicy = VERTICAL_SCROLLBAR_AS_NEEDED;
 145 
 146 
 147     /**
 148      * The display policy for the horizontal scrollbar.
 149      * The default is {@code ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED}.
 150      * <p>
 151      * This field is obsolete, please use the {@code JScrollPane} field instead.
 152      *
 153      * @see JScrollPane#setHorizontalScrollBarPolicy
 154      */
 155     protected int hsbPolicy = HORIZONTAL_SCROLLBAR_AS_NEEDED;
 156 
 157 
 158     /**
 159      * This method is invoked after the ScrollPaneLayout is set as the
 160      * LayoutManager of a {@code JScrollPane}.
 161      * It initializes all of the internal fields that
 162      * are ordinarily set by {@code addLayoutComponent}.  For example:
 163      * <pre>
 164      * ScrollPaneLayout mySPLayout = new ScrollPanelLayout() {
 165      *     public void layoutContainer(Container p) {
 166      *         super.layoutContainer(p);
 167      *         // do some extra work here ...
 168      *     }
 169      * };
 170      * scrollpane.setLayout(mySPLayout):
 171      * </pre>
 172      *
 173      * @param sp an instance of the {@code JScrollPane}
 174      */
 175     public void syncWithScrollPane(JScrollPane sp) {
 176         viewport = sp.getViewport();
 177         vsb = sp.getVerticalScrollBar();
 178         hsb = sp.getHorizontalScrollBar();
 179         rowHead = sp.getRowHeader();
 180         colHead = sp.getColumnHeader();
 181         lowerLeft = sp.getCorner(LOWER_LEFT_CORNER);
 182         lowerRight = sp.getCorner(LOWER_RIGHT_CORNER);
 183         upperLeft = sp.getCorner(UPPER_LEFT_CORNER);
 184         upperRight = sp.getCorner(UPPER_RIGHT_CORNER);
 185         vsbPolicy = sp.getVerticalScrollBarPolicy();
 186         hsbPolicy = sp.getHorizontalScrollBarPolicy();
 187     }
 188 
 189 
 190     /**
 191      * Removes an existing component.  When a new component, such as
 192      * the left corner, or vertical scrollbar, is added, the old one,
 193      * if it exists, must be removed.
 194      * <p>
 195      * This method returns {@code newC}. If {@code oldC} is
 196      * not equal to {@code newC} and is non-{@code null},
 197      * it will be removed from its parent.
 198      *
 199      * @param oldC the {@code Component} to replace
 200      * @param newC the {@code Component} to add
 201      * @return the {@code newC}
 202      */
 203     protected Component addSingletonComponent(Component oldC, Component newC)
 204     {
 205         if ((oldC != null) && (oldC != newC)) {
 206             oldC.getParent().remove(oldC);
 207         }
 208         return newC;
 209     }
 210 
 211 
 212     /**
 213      * Adds the specified component to the layout. The layout is
 214      * identified using one of:
 215      * <ul>
 216      * <li>ScrollPaneConstants.VIEWPORT
 217      * <li>ScrollPaneConstants.VERTICAL_SCROLLBAR
 218      * <li>ScrollPaneConstants.HORIZONTAL_SCROLLBAR
 219      * <li>ScrollPaneConstants.ROW_HEADER
 220      * <li>ScrollPaneConstants.COLUMN_HEADER
 221      * <li>ScrollPaneConstants.LOWER_LEFT_CORNER
 222      * <li>ScrollPaneConstants.LOWER_RIGHT_CORNER
 223      * <li>ScrollPaneConstants.UPPER_LEFT_CORNER
 224      * <li>ScrollPaneConstants.UPPER_RIGHT_CORNER
 225      * </ul>
 226      *
 227      * @param s the component identifier
 228      * @param c the component to be added
 229      * @exception IllegalArgumentException if {@code s} is an invalid key
 230      */
 231     public void addLayoutComponent(String s, Component c)
 232     {
 233         if (s.equals(VIEWPORT)) {
 234             viewport = (JViewport)addSingletonComponent(viewport, c);
 235         }
 236         else if (s.equals(VERTICAL_SCROLLBAR)) {
 237             vsb = (JScrollBar)addSingletonComponent(vsb, c);
 238         }
 239         else if (s.equals(HORIZONTAL_SCROLLBAR)) {
 240             hsb = (JScrollBar)addSingletonComponent(hsb, c);
 241         }
 242         else if (s.equals(ROW_HEADER)) {
 243             rowHead = (JViewport)addSingletonComponent(rowHead, c);
 244         }
 245         else if (s.equals(COLUMN_HEADER)) {
 246             colHead = (JViewport)addSingletonComponent(colHead, c);
 247         }
 248         else if (s.equals(LOWER_LEFT_CORNER)) {
 249             lowerLeft = addSingletonComponent(lowerLeft, c);


 302 
 303     /**
 304      * Returns the vertical scrollbar-display policy.
 305      *
 306      * @return an integer giving the display policy
 307      * @see #setVerticalScrollBarPolicy
 308      */
 309     public int getVerticalScrollBarPolicy() {
 310         return vsbPolicy;
 311     }
 312 
 313 
 314     /**
 315      * Sets the vertical scrollbar-display policy. The options
 316      * are:
 317      * <ul>
 318      * <li>ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED
 319      * <li>ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER
 320      * <li>ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS
 321      * </ul>
 322      * Note: Applications should use the {@code JScrollPane} version
 323      * of this method.  It only exists for backwards compatibility
 324      * with the Swing 1.0.2 (and earlier) versions of this class.
 325      *
 326      * @param x an integer giving the display policy
 327      * @exception IllegalArgumentException if {@code x} is an invalid
 328      *          vertical scroll bar policy, as listed above
 329      */
 330     public void setVerticalScrollBarPolicy(int x) {
 331         switch (x) {
 332         case VERTICAL_SCROLLBAR_AS_NEEDED:
 333         case VERTICAL_SCROLLBAR_NEVER:
 334         case VERTICAL_SCROLLBAR_ALWAYS:
 335                 vsbPolicy = x;
 336                 break;
 337         default:
 338             throw new IllegalArgumentException("invalid verticalScrollBarPolicy");
 339         }
 340     }
 341 
 342 
 343     /**
 344      * Returns the horizontal scrollbar-display policy.
 345      *
 346      * @return an integer giving the display policy
 347      * @see #setHorizontalScrollBarPolicy
 348      */
 349     public int getHorizontalScrollBarPolicy() {
 350         return hsbPolicy;
 351     }
 352 
 353     /**
 354      * Sets the horizontal scrollbar-display policy.
 355      * The options are:<ul>
 356      * <li>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED
 357      * <li>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER
 358      * <li>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS
 359      * </ul>
 360      * Note: Applications should use the {@code JScrollPane} version
 361      * of this method.  It only exists for backwards compatibility
 362      * with the Swing 1.0.2 (and earlier) versions of this class.
 363      *
 364      * @param x an int giving the display policy
 365      * @exception IllegalArgumentException if {@code x} is not a valid
 366      *          horizontal scrollbar policy, as listed above
 367      */
 368     public void setHorizontalScrollBarPolicy(int x) {
 369         switch (x) {
 370         case HORIZONTAL_SCROLLBAR_AS_NEEDED:
 371         case HORIZONTAL_SCROLLBAR_NEVER:
 372         case HORIZONTAL_SCROLLBAR_ALWAYS:
 373                 hsbPolicy = x;
 374                 break;
 375         default:
 376             throw new IllegalArgumentException("invalid horizontalScrollBarPolicy");
 377         }
 378     }
 379 
 380 
 381     /**
 382      * Returns the {@code JViewport} object that displays the
 383      * scrollable contents.
 384      * @return the {@code JViewport} object that displays the scrollable contents
 385      * @see JScrollPane#getViewport
 386      */
 387     public JViewport getViewport() {
 388         return viewport;
 389     }
 390 
 391 
 392     /**
 393      * Returns the {@code JScrollBar} object that handles horizontal scrolling.
 394      * @return the {@code JScrollBar} object that handles horizontal scrolling
 395      * @see JScrollPane#getHorizontalScrollBar
 396      */
 397     public JScrollBar getHorizontalScrollBar() {
 398         return hsb;
 399     }
 400 
 401     /**
 402      * Returns the {@code JScrollBar} object that handles vertical scrolling.
 403      * @return the {@code JScrollBar} object that handles vertical scrolling
 404      * @see JScrollPane#getVerticalScrollBar
 405      */
 406     public JScrollBar getVerticalScrollBar() {
 407         return vsb;
 408     }
 409 
 410 
 411     /**
 412      * Returns the {@code JViewport} object that is the row header.
 413      * @return the {@code JViewport} object that is the row header
 414      * @see JScrollPane#getRowHeader
 415      */
 416     public JViewport getRowHeader() {
 417         return rowHead;
 418     }
 419 
 420 
 421     /**
 422      * Returns the {@code JViewport} object that is the column header.
 423      * @return the {@code JViewport} object that is the column header
 424      * @see JScrollPane#getColumnHeader
 425      */
 426     public JViewport getColumnHeader() {
 427         return colHead;
 428     }
 429 
 430 
 431     /**
 432      * Returns the {@code Component} at the specified corner.
 433      * @param key the {@code String} specifying the corner
 434      * @return the {@code Component} at the specified corner, as defined in
 435      *         {@link ScrollPaneConstants}; if {@code key} is not one of the
 436      *          four corners, {@code null} is returned
 437      * @see JScrollPane#getCorner
 438      */
 439     public Component getCorner(String key) {
 440         if (key.equals(LOWER_LEFT_CORNER)) {
 441             return lowerLeft;
 442         }
 443         else if (key.equals(LOWER_RIGHT_CORNER)) {
 444             return lowerRight;
 445         }
 446         else if (key.equals(UPPER_LEFT_CORNER)) {
 447             return upperLeft;
 448         }
 449         else if (key.equals(UPPER_RIGHT_CORNER)) {
 450             return upperRight;
 451         }
 452         else {
 453             return null;
 454         }
 455     }
 456 
 457 
 458     /**
 459      * The preferred size of a {@code ScrollPane} is the size of the insets,
 460      * plus the preferred size of the viewport, plus the preferred size of
 461      * the visible headers, plus the preferred size of the scrollbars
 462      * that will appear given the current view and the current
 463      * scrollbar displayPolicies.
 464      * <p>Note that the rowHeader is calculated as part of the preferred width
 465      * and the colHeader is calculated as part of the preferred size.
 466      *
 467      * @param parent the {@code Container} that will be laid out
 468      * @return a {@code Dimension} object specifying the preferred size of the
 469      *         viewport and any scrollbars
 470      * @see ViewportLayout
 471      * @see LayoutManager
 472      */
 473     public Dimension preferredLayoutSize(Container parent)
 474     {
 475         /* Sync the (now obsolete) policy fields with the
 476          * JScrollPane.
 477          */
 478         JScrollPane scrollPane = (JScrollPane)parent;
 479         vsbPolicy = scrollPane.getVerticalScrollBarPolicy();
 480         hsbPolicy = scrollPane.getHorizontalScrollBarPolicy();
 481 
 482         Insets insets = parent.getInsets();
 483         int prefWidth = insets.left + insets.right;
 484         int prefHeight = insets.top + insets.bottom;
 485 
 486         /* Note that viewport.getViewSize() is equivalent to
 487          * viewport.getView().getPreferredSize() modulo a null
 488          * view or a view whose size was explicitly set.


 567         if ((hsb != null) && (hsbPolicy != HORIZONTAL_SCROLLBAR_NEVER)) {
 568             if (hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) {
 569                 prefHeight += hsb.getPreferredSize().height;
 570             }
 571             else if ((viewSize != null) && (extentSize != null)) {
 572                 boolean canScroll = true;
 573                 if (view instanceof Scrollable) {
 574                     canScroll = !((Scrollable)view).getScrollableTracksViewportWidth();
 575                 }
 576                 if (canScroll && (viewSize.width > extentSize.width)) {
 577                     prefHeight += hsb.getPreferredSize().height;
 578                 }
 579             }
 580         }
 581 
 582         return new Dimension(prefWidth, prefHeight);
 583     }
 584 
 585 
 586     /**
 587      * The minimum size of a {@code ScrollPane} is the size of the insets
 588      * plus minimum size of the viewport, plus the scrollpane's
 589      * viewportBorder insets, plus the minimum size
 590      * of the visible headers, plus the minimum size of the
 591      * scrollbars whose displayPolicy isn't NEVER.
 592      *
 593      * @param parent the {@code Container} that will be laid out
 594      * @return a {@code Dimension} object specifying the minimum size
 595      */
 596     public Dimension minimumLayoutSize(Container parent)
 597     {
 598         /* Sync the (now obsolete) policy fields with the
 599          * JScrollPane.
 600          */
 601         JScrollPane scrollPane = (JScrollPane)parent;
 602         vsbPolicy = scrollPane.getVerticalScrollBarPolicy();
 603         hsbPolicy = scrollPane.getHorizontalScrollBarPolicy();
 604 
 605         Insets insets = parent.getInsets();
 606         int minWidth = insets.left + insets.right;
 607         int minHeight = insets.top + insets.bottom;
 608 
 609         /* If there's a viewport add its minimumSize.
 610          */
 611 
 612         if (viewport != null) {
 613             Dimension size = viewport.getMinimumSize();
 614             minWidth += size.width;


 655             Dimension size = hsb.getMinimumSize();
 656             minWidth = Math.max(minWidth, size.width);
 657             minHeight += size.height;
 658         }
 659 
 660         return new Dimension(minWidth, minHeight);
 661     }
 662 
 663 
 664     /**
 665      * Lays out the scrollpane. The positioning of components depends on
 666      * the following constraints:
 667      * <ul>
 668      * <li> The row header, if present and visible, gets its preferred
 669      * width and the viewport's height.
 670      *
 671      * <li> The column header, if present and visible, gets its preferred
 672      * height and the viewport's width.
 673      *
 674      * <li> If a vertical scrollbar is needed, i.e. if the viewport's extent
 675      * height is smaller than its view height or if the {@code displayPolicy}
 676      * is ALWAYS, it's treated like the row header with respect to its
 677      * dimensions and is made visible.
 678      *
 679      * <li> If a horizontal scrollbar is needed, it is treated like the
 680      * column header (see the paragraph above regarding the vertical scrollbar).
 681      *
 682      * <li> If the scrollpane has a non-{@code null}
 683      * {@code viewportBorder}, then space is allocated for that.
 684      *
 685      * <li> The viewport gets the space available after accounting for
 686      * the previous constraints.
 687      *
 688      * <li> The corner components, if provided, are aligned with the
 689      * ends of the scrollbars and headers. If there is a vertical
 690      * scrollbar, the right corners appear; if there is a horizontal
 691      * scrollbar, the lower corners appear; a row header gets left
 692      * corners, and a column header gets upper corners.
 693      * </ul>
 694      *
 695      * @param parent the {@code Container} to lay out
 696      */
 697     public void layoutContainer(Container parent)
 698     {
 699         /* Sync the (now obsolete) policy fields with the
 700          * JScrollPane.
 701          */
 702         JScrollPane scrollPane = (JScrollPane)parent;
 703         vsbPolicy = scrollPane.getVerticalScrollBarPolicy();
 704         hsbPolicy = scrollPane.getHorizontalScrollBarPolicy();
 705 
 706         Rectangle availR = scrollPane.getBounds();
 707         availR.x = availR.y = 0;
 708 
 709         Insets insets = parent.getInsets();
 710         availR.x = insets.left;
 711         availR.y = insets.top;
 712         availR.width -= insets.left + insets.right;
 713         availR.height -= insets.top + insets.bottom;
 714 
 715         /* Get the scrollPane's orientation.


1026                                  leftToRight ? vsbR.width : rowHeadR.width,
1027                                  hsbR.height);
1028         }
1029 
1030         if (upperLeft != null) {
1031             upperLeft.setBounds(leftToRight ? rowHeadR.x : vsbR.x,
1032                                 colHeadR.y,
1033                                 leftToRight ? rowHeadR.width : vsbR.width,
1034                                 colHeadR.height);
1035         }
1036 
1037         if (upperRight != null) {
1038             upperRight.setBounds(leftToRight ? vsbR.x : rowHeadR.x,
1039                                  colHeadR.y,
1040                                  leftToRight ? vsbR.width : rowHeadR.width,
1041                                  colHeadR.height);
1042         }
1043     }
1044 
1045     /**
1046      * Adjusts the {@code Rectangle available} based on if
1047      * the vertical scrollbar is needed ({@code wantsVSB}).
1048      * The location of the vsb is updated in {@code vsbR}, and
1049      * the viewport border insets ({@code vpbInsets}) are used to offset
1050      * the vsb. This is only called when {@code wantsVSB} has
1051      * changed, eg you shouldn't invoke adjustForVSB(true) twice.
1052      */
1053     private void adjustForVSB(boolean wantsVSB, Rectangle available,
1054                               Rectangle vsbR, Insets vpbInsets,
1055                               boolean leftToRight) {
1056         int oldWidth = vsbR.width;
1057         if (wantsVSB) {
1058             int vsbWidth = Math.max(0, Math.min(vsb.getPreferredSize().width,
1059                                                 available.width));
1060 
1061             available.width -= vsbWidth;
1062             vsbR.width = vsbWidth;
1063 
1064             if( leftToRight ) {
1065                 vsbR.x = available.x + available.width + vpbInsets.right;
1066             } else {
1067                 vsbR.x = available.x - vpbInsets.left;
1068                 available.x += vsbWidth;
1069             }
1070         }
1071         else {
1072             available.width += oldWidth;
1073         }
1074     }
1075 
1076     /**
1077      * Adjusts the {@code Rectangle available} based on if
1078      * the horizontal scrollbar is needed ({@code wantsHSB}).
1079      * The location of the hsb is updated in {@code hsbR}, and
1080      * the viewport border insets ({@code vpbInsets}) are used to offset
1081      * the hsb.  This is only called when {@code wantsHSB} has
1082      * changed, eg you shouldn't invoked adjustForHSB(true) twice.
1083      */
1084     private void adjustForHSB(boolean wantsHSB, Rectangle available,
1085                               Rectangle hsbR, Insets vpbInsets) {
1086         int oldHeight = hsbR.height;
1087         if (wantsHSB) {
1088             int hsbHeight = Math.max(0, Math.min(available.height,
1089                                               hsb.getPreferredSize().height));
1090 
1091             available.height -= hsbHeight;
1092             hsbR.y = available.y + available.height + vpbInsets.bottom;
1093             hsbR.height = hsbHeight;
1094         }
1095         else {
1096             available.height += oldHeight;
1097         }
1098     }
1099 
1100 
1101 
1102     /**
1103      * Returns the bounds of the border around the specified scroll pane's
1104      * viewport.
1105      *
1106      * @param scrollpane an instance of the {@code JScrollPane}
1107      * @return the size and position of the viewport border
1108      * @deprecated As of JDK version Swing1.1
1109      *    replaced by {@code JScrollPane.getViewportBorderBounds()}.
1110      */
1111     @Deprecated
1112     public Rectangle getViewportBorderBounds(JScrollPane scrollpane) {
1113         return scrollpane.getViewportBorderBounds();
1114     }
1115 
1116     /**
1117      * The UI resource version of {@code ScrollPaneLayout}.
1118      */
1119     public static class UIResource extends ScrollPaneLayout implements javax.swing.plaf.UIResource {}
1120 }
< prev index next >