Home » openjdk-7 » javax » swing » [javadoc | source]

    1   /*
    2    * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   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<sup><font size="-2">TM</font></sup>
   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    */
   60   public class ScrollPaneLayout
   61       implements LayoutManager, ScrollPaneConstants, Serializable
   62   {
   63   
   64       /**
   65        * The scrollpane's viewport child.
   66        * Default is an empty <code>JViewport</code>.
   67        * @see JScrollPane#setViewport
   68        */
   69       protected JViewport viewport;
   70   
   71   
   72       /**
   73        * The scrollpane's vertical scrollbar child.
   74        * Default is a <code>JScrollBar</code>.
   75        * @see JScrollPane#setVerticalScrollBar
   76        */
   77       protected JScrollBar vsb;
   78   
   79   
   80       /**
   81        * The scrollpane's horizontal scrollbar child.
   82        * Default is a <code>JScrollBar</code>.
   83        * @see JScrollPane#setHorizontalScrollBar
   84        */
   85       protected JScrollBar hsb;
   86   
   87   
   88       /**
   89        * The row header child.  Default is <code>null</code>.
   90        * @see JScrollPane#setRowHeader
   91        */
   92       protected JViewport rowHead;
   93   
   94   
   95       /**
   96        * The column header child.  Default is <code>null</code>.
   97        * @see JScrollPane#setColumnHeader
   98        */
   99       protected JViewport colHead;
  100   
  101   
  102       /**
  103        * The component to display in the lower left corner.
  104        * Default is <code>null</code>.
  105        * @see JScrollPane#setCorner
  106        */
  107       protected Component lowerLeft;
  108   
  109   
  110       /**
  111        * The component to display in the lower right corner.
  112        * Default is <code>null</code>.
  113        * @see JScrollPane#setCorner
  114        */
  115       protected Component lowerRight;
  116   
  117   
  118       /**
  119        * The component to display in the upper left corner.
  120        * Default is <code>null</code>.
  121        * @see JScrollPane#setCorner
  122        */
  123       protected Component upperLeft;
  124   
  125   
  126       /**
  127        * The component to display in the upper right corner.
  128        * Default is <code>null</code>.
  129        * @see JScrollPane#setCorner
  130        */
  131       protected Component upperRight;
  132   
  133   
  134       /**
  135        * The display policy for the vertical scrollbar.
  136        * The default is <code>ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED</code>.
  137        * <p>
  138        * This field is obsolete, please use the <code>JScrollPane</code> field instead.
  139        *
  140        * @see JScrollPane#setVerticalScrollBarPolicy
  141        */
  142       protected int vsbPolicy = VERTICAL_SCROLLBAR_AS_NEEDED;
  143   
  144   
  145       /**
  146        * The display policy for the horizontal scrollbar.
  147        * The default is <code>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED</code>.
  148        * <p>
  149        * This field is obsolete, please use the <code>JScrollPane</code> field instead.
  150        *
  151        * @see JScrollPane#setHorizontalScrollBarPolicy
  152        */
  153       protected int hsbPolicy = HORIZONTAL_SCROLLBAR_AS_NEEDED;
  154   
  155   
  156       /**
  157        * This method is invoked after the ScrollPaneLayout is set as the
  158        * LayoutManager of a <code>JScrollPane</code>.
  159        * It initializes all of the internal fields that
  160        * are ordinarily set by <code>addLayoutComponent</code>.  For example:
  161        * <pre>
  162        * ScrollPaneLayout mySPLayout = new ScrollPanelLayout() {
  163        *     public void layoutContainer(Container p) {
  164        *         super.layoutContainer(p);
  165        *         // do some extra work here ...
  166        *     }
  167        * };
  168        * scrollpane.setLayout(mySPLayout):
  169        * </pre>
  170        */
  171       public void syncWithScrollPane(JScrollPane sp) {
  172           viewport = sp.getViewport();
  173           vsb = sp.getVerticalScrollBar();
  174           hsb = sp.getHorizontalScrollBar();
  175           rowHead = sp.getRowHeader();
  176           colHead = sp.getColumnHeader();
  177           lowerLeft = sp.getCorner(LOWER_LEFT_CORNER);
  178           lowerRight = sp.getCorner(LOWER_RIGHT_CORNER);
  179           upperLeft = sp.getCorner(UPPER_LEFT_CORNER);
  180           upperRight = sp.getCorner(UPPER_RIGHT_CORNER);
  181           vsbPolicy = sp.getVerticalScrollBarPolicy();
  182           hsbPolicy = sp.getHorizontalScrollBarPolicy();
  183       }
  184   
  185   
  186       /**
  187        * Removes an existing component.  When a new component, such as
  188        * the left corner, or vertical scrollbar, is added, the old one,
  189        * if it exists, must be removed.
  190        * <p>
  191        * This method returns <code>newC</code>. If <code>oldC</code> is
  192        * not equal to <code>newC</code> and is non-<code>null</code>,
  193        * it will be removed from its parent.
  194        *
  195        * @param oldC the <code>Component</code> to replace
  196        * @param newC the <code>Component</code> to add
  197        * @return the <code>newC</code>
  198        */
  199       protected Component addSingletonComponent(Component oldC, Component newC)
  200       {
  201           if ((oldC != null) && (oldC != newC)) {
  202               oldC.getParent().remove(oldC);
  203           }
  204           return newC;
  205       }
  206   
  207   
  208       /**
  209        * Adds the specified component to the layout. The layout is
  210        * identified using one of:
  211        * <ul>
  212        * <li>ScrollPaneConstants.VIEWPORT
  213        * <li>ScrollPaneConstants.VERTICAL_SCROLLBAR
  214        * <li>ScrollPaneConstants.HORIZONTAL_SCROLLBAR
  215        * <li>ScrollPaneConstants.ROW_HEADER
  216        * <li>ScrollPaneConstants.COLUMN_HEADER
  217        * <li>ScrollPaneConstants.LOWER_LEFT_CORNER
  218        * <li>ScrollPaneConstants.LOWER_RIGHT_CORNER
  219        * <li>ScrollPaneConstants.UPPER_LEFT_CORNER
  220        * <li>ScrollPaneConstants.UPPER_RIGHT_CORNER
  221        * </ul>
  222        *
  223        * @param s the component identifier
  224        * @param c the the component to be added
  225        * @exception IllegalArgumentException if <code>s</code> is an invalid key
  226        */
  227       public void addLayoutComponent(String s, Component c)
  228       {
  229           if (s.equals(VIEWPORT)) {
  230               viewport = (JViewport)addSingletonComponent(viewport, c);
  231           }
  232           else if (s.equals(VERTICAL_SCROLLBAR)) {
  233               vsb = (JScrollBar)addSingletonComponent(vsb, c);
  234           }
  235           else if (s.equals(HORIZONTAL_SCROLLBAR)) {
  236               hsb = (JScrollBar)addSingletonComponent(hsb, c);
  237           }
  238           else if (s.equals(ROW_HEADER)) {
  239               rowHead = (JViewport)addSingletonComponent(rowHead, c);
  240           }
  241           else if (s.equals(COLUMN_HEADER)) {
  242               colHead = (JViewport)addSingletonComponent(colHead, c);
  243           }
  244           else if (s.equals(LOWER_LEFT_CORNER)) {
  245               lowerLeft = addSingletonComponent(lowerLeft, c);
  246           }
  247           else if (s.equals(LOWER_RIGHT_CORNER)) {
  248               lowerRight = addSingletonComponent(lowerRight, c);
  249           }
  250           else if (s.equals(UPPER_LEFT_CORNER)) {
  251               upperLeft = addSingletonComponent(upperLeft, c);
  252           }
  253           else if (s.equals(UPPER_RIGHT_CORNER)) {
  254               upperRight = addSingletonComponent(upperRight, c);
  255           }
  256           else {
  257               throw new IllegalArgumentException("invalid layout key " + s);
  258           }
  259       }
  260   
  261   
  262       /**
  263        * Removes the specified component from the layout.
  264        *
  265        * @param c the component to remove
  266        */
  267       public void removeLayoutComponent(Component c)
  268       {
  269           if (c == viewport) {
  270               viewport = null;
  271           }
  272           else if (c == vsb) {
  273               vsb = null;
  274           }
  275           else if (c == hsb) {
  276               hsb = null;
  277           }
  278           else if (c == rowHead) {
  279               rowHead = null;
  280           }
  281           else if (c == colHead) {
  282               colHead = null;
  283           }
  284           else if (c == lowerLeft) {
  285               lowerLeft = null;
  286           }
  287           else if (c == lowerRight) {
  288               lowerRight = null;
  289           }
  290           else if (c == upperLeft) {
  291               upperLeft = null;
  292           }
  293           else if (c == upperRight) {
  294               upperRight = null;
  295           }
  296       }
  297   
  298   
  299       /**
  300        * Returns the vertical scrollbar-display policy.
  301        *
  302        * @return an integer giving the display policy
  303        * @see #setVerticalScrollBarPolicy
  304        */
  305       public int getVerticalScrollBarPolicy() {
  306           return vsbPolicy;
  307       }
  308   
  309   
  310       /**
  311        * Sets the vertical scrollbar-display policy. The options
  312        * are:
  313        * <ul>
  314        * <li>ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED
  315        * <li>ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER
  316        * <li>ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS
  317        * </ul>
  318        * Note: Applications should use the <code>JScrollPane</code> version
  319        * of this method.  It only exists for backwards compatibility
  320        * with the Swing 1.0.2 (and earlier) versions of this class.
  321        *
  322        * @param x an integer giving the display policy
  323        * @exception IllegalArgumentException if <code>x</code> is an invalid
  324        *          vertical scroll bar policy, as listed above
  325        */
  326       public void setVerticalScrollBarPolicy(int x) {
  327           switch (x) {
  328           case VERTICAL_SCROLLBAR_AS_NEEDED:
  329           case VERTICAL_SCROLLBAR_NEVER:
  330           case VERTICAL_SCROLLBAR_ALWAYS:
  331                   vsbPolicy = x;
  332                   break;
  333           default:
  334               throw new IllegalArgumentException("invalid verticalScrollBarPolicy");
  335           }
  336       }
  337   
  338   
  339       /**
  340        * Returns the horizontal scrollbar-display policy.
  341        *
  342        * @return an integer giving the display policy
  343        * @see #setHorizontalScrollBarPolicy
  344        */
  345       public int getHorizontalScrollBarPolicy() {
  346           return hsbPolicy;
  347       }
  348   
  349       /**
  350        * Sets the horizontal scrollbar-display policy.
  351        * The options are:<ul>
  352        * <li>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED
  353        * <li>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER
  354        * <li>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS
  355        * </ul>
  356        * Note: Applications should use the <code>JScrollPane</code> version
  357        * of this method.  It only exists for backwards compatibility
  358        * with the Swing 1.0.2 (and earlier) versions of this class.
  359        *
  360        * @param x an int giving the display policy
  361        * @exception IllegalArgumentException if <code>x</code> is not a valid
  362        *          horizontal scrollbar policy, as listed above
  363        */
  364       public void setHorizontalScrollBarPolicy(int x) {
  365           switch (x) {
  366           case HORIZONTAL_SCROLLBAR_AS_NEEDED:
  367           case HORIZONTAL_SCROLLBAR_NEVER:
  368           case HORIZONTAL_SCROLLBAR_ALWAYS:
  369                   hsbPolicy = x;
  370                   break;
  371           default:
  372               throw new IllegalArgumentException("invalid horizontalScrollBarPolicy");
  373           }
  374       }
  375   
  376   
  377       /**
  378        * Returns the <code>JViewport</code> object that displays the
  379        * scrollable contents.
  380        * @return the <code>JViewport</code> object that displays the scrollable contents
  381        * @see JScrollPane#getViewport
  382        */
  383       public JViewport getViewport() {
  384           return viewport;
  385       }
  386   
  387   
  388       /**
  389        * Returns the <code>JScrollBar</code> object that handles horizontal scrolling.
  390        * @return the <code>JScrollBar</code> object that handles horizontal scrolling
  391        * @see JScrollPane#getHorizontalScrollBar
  392        */
  393       public JScrollBar getHorizontalScrollBar() {
  394           return hsb;
  395       }
  396   
  397       /**
  398        * Returns the <code>JScrollBar</code> object that handles vertical scrolling.
  399        * @return the <code>JScrollBar</code> object that handles vertical scrolling
  400        * @see JScrollPane#getVerticalScrollBar
  401        */
  402       public JScrollBar getVerticalScrollBar() {
  403           return vsb;
  404       }
  405   
  406   
  407       /**
  408        * Returns the <code>JViewport</code> object that is the row header.
  409        * @return the <code>JViewport</code> object that is the row header
  410        * @see JScrollPane#getRowHeader
  411        */
  412       public JViewport getRowHeader() {
  413           return rowHead;
  414       }
  415   
  416   
  417       /**
  418        * Returns the <code>JViewport</code> object that is the column header.
  419        * @return the <code>JViewport</code> object that is the column header
  420        * @see JScrollPane#getColumnHeader
  421        */
  422       public JViewport getColumnHeader() {
  423           return colHead;
  424       }
  425   
  426   
  427       /**
  428        * Returns the <code>Component</code> at the specified corner.
  429        * @param key the <code>String</code> specifying the corner
  430        * @return the <code>Component</code> at the specified corner, as defined in
  431        *         {@link ScrollPaneConstants}; if <code>key</code> is not one of the
  432        *          four corners, <code>null</code> is returned
  433        * @see JScrollPane#getCorner
  434        */
  435       public Component getCorner(String key) {
  436           if (key.equals(LOWER_LEFT_CORNER)) {
  437               return lowerLeft;
  438           }
  439           else if (key.equals(LOWER_RIGHT_CORNER)) {
  440               return lowerRight;
  441           }
  442           else if (key.equals(UPPER_LEFT_CORNER)) {
  443               return upperLeft;
  444           }
  445           else if (key.equals(UPPER_RIGHT_CORNER)) {
  446               return upperRight;
  447           }
  448           else {
  449               return null;
  450           }
  451       }
  452   
  453   
  454       /**
  455        * The preferred size of a <code>ScrollPane</code> is the size of the insets,
  456        * plus the preferred size of the viewport, plus the preferred size of
  457        * the visible headers, plus the preferred size of the scrollbars
  458        * that will appear given the current view and the current
  459        * scrollbar displayPolicies.
  460        * <p>Note that the rowHeader is calculated as part of the preferred width
  461        * and the colHeader is calculated as part of the preferred size.
  462        *
  463        * @param parent the <code>Container</code> that will be laid out
  464        * @return a <code>Dimension</code> object specifying the preferred size of the
  465        *         viewport and any scrollbars
  466        * @see ViewportLayout
  467        * @see LayoutManager
  468        */
  469       public Dimension preferredLayoutSize(Container parent)
  470       {
  471           /* Sync the (now obsolete) policy fields with the
  472            * JScrollPane.
  473            */
  474           JScrollPane scrollPane = (JScrollPane)parent;
  475           vsbPolicy = scrollPane.getVerticalScrollBarPolicy();
  476           hsbPolicy = scrollPane.getHorizontalScrollBarPolicy();
  477   
  478           Insets insets = parent.getInsets();
  479           int prefWidth = insets.left + insets.right;
  480           int prefHeight = insets.top + insets.bottom;
  481   
  482           /* Note that viewport.getViewSize() is equivalent to
  483            * viewport.getView().getPreferredSize() modulo a null
  484            * view or a view whose size was explicitly set.
  485            */
  486   
  487           Dimension extentSize = null;
  488           Dimension viewSize = null;
  489           Component view = null;
  490   
  491           if (viewport != null) {
  492               extentSize = viewport.getPreferredSize();
  493               view = viewport.getView();
  494               if (view != null) {
  495                   viewSize = view.getPreferredSize();
  496               } else {
  497                   viewSize = new Dimension(0, 0);
  498               }
  499           }
  500   
  501           /* If there's a viewport add its preferredSize.
  502            */
  503   
  504           if (extentSize != null) {
  505               prefWidth += extentSize.width;
  506               prefHeight += extentSize.height;
  507           }
  508   
  509           /* If there's a JScrollPane.viewportBorder, add its insets.
  510            */
  511   
  512           Border viewportBorder = scrollPane.getViewportBorder();
  513           if (viewportBorder != null) {
  514               Insets vpbInsets = viewportBorder.getBorderInsets(parent);
  515               prefWidth += vpbInsets.left + vpbInsets.right;
  516               prefHeight += vpbInsets.top + vpbInsets.bottom;
  517           }
  518   
  519           /* If a header exists and it's visible, factor its
  520            * preferred size in.
  521            */
  522   
  523           if ((rowHead != null) && rowHead.isVisible()) {
  524               prefWidth += rowHead.getPreferredSize().width;
  525           }
  526   
  527           if ((colHead != null) && colHead.isVisible()) {
  528               prefHeight += colHead.getPreferredSize().height;
  529           }
  530   
  531           /* If a scrollbar is going to appear, factor its preferred size in.
  532            * If the scrollbars policy is AS_NEEDED, this can be a little
  533            * tricky:
  534            *
  535            * - If the view is a Scrollable then scrollableTracksViewportWidth
  536            * and scrollableTracksViewportHeight can be used to effectively
  537            * disable scrolling (if they're true) in their respective dimensions.
  538            *
  539            * - Assuming that a scrollbar hasn't been disabled by the
  540            * previous constraint, we need to decide if the scrollbar is going
  541            * to appear to correctly compute the JScrollPanes preferred size.
  542            * To do this we compare the preferredSize of the viewport (the
  543            * extentSize) to the preferredSize of the view.  Although we're
  544            * not responsible for laying out the view we'll assume that the
  545            * JViewport will always give it its preferredSize.
  546            */
  547   
  548           if ((vsb != null) && (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
  549               if (vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) {
  550                   prefWidth += vsb.getPreferredSize().width;
  551               }
  552               else if ((viewSize != null) && (extentSize != null)) {
  553                   boolean canScroll = true;
  554                   if (view instanceof Scrollable) {
  555                       canScroll = !((Scrollable)view).getScrollableTracksViewportHeight();
  556                   }
  557                   if (canScroll && (viewSize.height > extentSize.height)) {
  558                       prefWidth += vsb.getPreferredSize().width;
  559                   }
  560               }
  561           }
  562   
  563           if ((hsb != null) && (hsbPolicy != HORIZONTAL_SCROLLBAR_NEVER)) {
  564               if (hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) {
  565                   prefHeight += hsb.getPreferredSize().height;
  566               }
  567               else if ((viewSize != null) && (extentSize != null)) {
  568                   boolean canScroll = true;
  569                   if (view instanceof Scrollable) {
  570                       canScroll = !((Scrollable)view).getScrollableTracksViewportWidth();
  571                   }
  572                   if (canScroll && (viewSize.width > extentSize.width)) {
  573                       prefHeight += hsb.getPreferredSize().height;
  574                   }
  575               }
  576           }
  577   
  578           return new Dimension(prefWidth, prefHeight);
  579       }
  580   
  581   
  582       /**
  583        * The minimum size of a <code>ScrollPane</code> is the size of the insets
  584        * plus minimum size of the viewport, plus the scrollpane's
  585        * viewportBorder insets, plus the minimum size
  586        * of the visible headers, plus the minimum size of the
  587        * scrollbars whose displayPolicy isn't NEVER.
  588        *
  589        * @param parent the <code>Container</code> that will be laid out
  590        * @return a <code>Dimension</code> object specifying the minimum size
  591        */
  592       public Dimension minimumLayoutSize(Container parent)
  593       {
  594           /* Sync the (now obsolete) policy fields with the
  595            * JScrollPane.
  596            */
  597           JScrollPane scrollPane = (JScrollPane)parent;
  598           vsbPolicy = scrollPane.getVerticalScrollBarPolicy();
  599           hsbPolicy = scrollPane.getHorizontalScrollBarPolicy();
  600   
  601           Insets insets = parent.getInsets();
  602           int minWidth = insets.left + insets.right;
  603           int minHeight = insets.top + insets.bottom;
  604   
  605           /* If there's a viewport add its minimumSize.
  606            */
  607   
  608           if (viewport != null) {
  609               Dimension size = viewport.getMinimumSize();
  610               minWidth += size.width;
  611               minHeight += size.height;
  612           }
  613   
  614           /* If there's a JScrollPane.viewportBorder, add its insets.
  615            */
  616   
  617           Border viewportBorder = scrollPane.getViewportBorder();
  618           if (viewportBorder != null) {
  619               Insets vpbInsets = viewportBorder.getBorderInsets(parent);
  620               minWidth += vpbInsets.left + vpbInsets.right;
  621               minHeight += vpbInsets.top + vpbInsets.bottom;
  622           }
  623   
  624           /* If a header exists and it's visible, factor its
  625            * minimum size in.
  626            */
  627   
  628           if ((rowHead != null) && rowHead.isVisible()) {
  629               Dimension size = rowHead.getMinimumSize();
  630               minWidth += size.width;
  631               minHeight = Math.max(minHeight, size.height);
  632           }
  633   
  634           if ((colHead != null) && colHead.isVisible()) {
  635               Dimension size = colHead.getMinimumSize();
  636               minWidth = Math.max(minWidth, size.width);
  637               minHeight += size.height;
  638           }
  639   
  640           /* If a scrollbar might appear, factor its minimum
  641            * size in.
  642            */
  643   
  644           if ((vsb != null) && (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
  645               Dimension size = vsb.getMinimumSize();
  646               minWidth += size.width;
  647               minHeight = Math.max(minHeight, size.height);
  648           }
  649   
  650           if ((hsb != null) && (hsbPolicy != HORIZONTAL_SCROLLBAR_NEVER)) {
  651               Dimension size = hsb.getMinimumSize();
  652               minWidth = Math.max(minWidth, size.width);
  653               minHeight += size.height;
  654           }
  655   
  656           return new Dimension(minWidth, minHeight);
  657       }
  658   
  659   
  660       /**
  661        * Lays out the scrollpane. The positioning of components depends on
  662        * the following constraints:
  663        * <ul>
  664        * <li> The row header, if present and visible, gets its preferred
  665        * width and the viewport's height.
  666        *
  667        * <li> The column header, if present and visible, gets its preferred
  668        * height and the viewport's width.
  669        *
  670        * <li> If a vertical scrollbar is needed, i.e. if the viewport's extent
  671        * height is smaller than its view height or if the <code>displayPolicy</code>
  672        * is ALWAYS, it's treated like the row header with respect to its
  673        * dimensions and is made visible.
  674        *
  675        * <li> If a horizontal scrollbar is needed, it is treated like the
  676        * column header (see the paragraph above regarding the vertical scrollbar).
  677        *
  678        * <li> If the scrollpane has a non-<code>null</code>
  679        * <code>viewportBorder</code>, then space is allocated for that.
  680        *
  681        * <li> The viewport gets the space available after accounting for
  682        * the previous constraints.
  683        *
  684        * <li> The corner components, if provided, are aligned with the
  685        * ends of the scrollbars and headers. If there is a vertical
  686        * scrollbar, the right corners appear; if there is a horizontal
  687        * scrollbar, the lower corners appear; a row header gets left
  688        * corners, and a column header gets upper corners.
  689        * </ul>
  690        *
  691        * @param parent the <code>Container</code> to lay out
  692        */
  693       public void layoutContainer(Container parent)
  694       {
  695           /* Sync the (now obsolete) policy fields with the
  696            * JScrollPane.
  697            */
  698           JScrollPane scrollPane = (JScrollPane)parent;
  699           vsbPolicy = scrollPane.getVerticalScrollBarPolicy();
  700           hsbPolicy = scrollPane.getHorizontalScrollBarPolicy();
  701   
  702           Rectangle availR = scrollPane.getBounds();
  703           availR.x = availR.y = 0;
  704   
  705           Insets insets = parent.getInsets();
  706           availR.x = insets.left;
  707           availR.y = insets.top;
  708           availR.width -= insets.left + insets.right;
  709           availR.height -= insets.top + insets.bottom;
  710   
  711           /* Get the scrollPane's orientation.
  712            */
  713           boolean leftToRight = SwingUtilities.isLeftToRight(scrollPane);
  714   
  715           /* If there's a visible column header remove the space it
  716            * needs from the top of availR.  The column header is treated
  717            * as if it were fixed height, arbitrary width.
  718            */
  719   
  720           Rectangle colHeadR = new Rectangle(0, availR.y, 0, 0);
  721   
  722           if ((colHead != null) && (colHead.isVisible())) {
  723               int colHeadHeight = Math.min(availR.height,
  724                                            colHead.getPreferredSize().height);
  725               colHeadR.height = colHeadHeight;
  726               availR.y += colHeadHeight;
  727               availR.height -= colHeadHeight;
  728           }
  729   
  730           /* If there's a visible row header remove the space it needs
  731            * from the left or right of availR.  The row header is treated
  732            * as if it were fixed width, arbitrary height.
  733            */
  734   
  735           Rectangle rowHeadR = new Rectangle(0, 0, 0, 0);
  736   
  737           if ((rowHead != null) && (rowHead.isVisible())) {
  738               int rowHeadWidth = Math.min(availR.width,
  739                                           rowHead.getPreferredSize().width);
  740               rowHeadR.width = rowHeadWidth;
  741               availR.width -= rowHeadWidth;
  742               if ( leftToRight ) {
  743                   rowHeadR.x = availR.x;
  744                   availR.x += rowHeadWidth;
  745               } else {
  746                   rowHeadR.x = availR.x + availR.width;
  747               }
  748           }
  749   
  750           /* If there's a JScrollPane.viewportBorder, remove the
  751            * space it occupies for availR.
  752            */
  753   
  754           Border viewportBorder = scrollPane.getViewportBorder();
  755           Insets vpbInsets;
  756           if (viewportBorder != null) {
  757               vpbInsets = viewportBorder.getBorderInsets(parent);
  758               availR.x += vpbInsets.left;
  759               availR.y += vpbInsets.top;
  760               availR.width -= vpbInsets.left + vpbInsets.right;
  761               availR.height -= vpbInsets.top + vpbInsets.bottom;
  762           }
  763           else {
  764               vpbInsets = new Insets(0,0,0,0);
  765           }
  766   
  767   
  768           /* At this point availR is the space available for the viewport
  769            * and scrollbars. rowHeadR is correct except for its height and y
  770            * and colHeadR is correct except for its width and x.  Once we're
  771            * through computing the dimensions  of these three parts we can
  772            * go back and set the dimensions of rowHeadR.height, rowHeadR.y,
  773            * colHeadR.width, colHeadR.x and the bounds for the corners.
  774            *
  775            * We'll decide about putting up scrollbars by comparing the
  776            * viewport views preferred size with the viewports extent
  777            * size (generally just its size).  Using the preferredSize is
  778            * reasonable because layout proceeds top down - so we expect
  779            * the viewport to be laid out next.  And we assume that the
  780            * viewports layout manager will give the view it's preferred
  781            * size.  One exception to this is when the view implements
  782            * Scrollable and Scrollable.getViewTracksViewport{Width,Height}
  783            * methods return true.  If the view is tracking the viewports
  784            * width we don't bother with a horizontal scrollbar, similarly
  785            * if view.getViewTracksViewport(Height) is true we don't bother
  786            * with a vertical scrollbar.
  787            */
  788   
  789           Component view = (viewport != null) ? viewport.getView() : null;
  790           Dimension viewPrefSize =
  791               (view != null) ? view.getPreferredSize()
  792                              : new Dimension(0,0);
  793   
  794           Dimension extentSize =
  795               (viewport != null) ? viewport.toViewCoordinates(availR.getSize())
  796                                  : new Dimension(0,0);
  797   
  798           boolean viewTracksViewportWidth = false;
  799           boolean viewTracksViewportHeight = false;
  800           boolean isEmpty = (availR.width < 0 || availR.height < 0);
  801           Scrollable sv;
  802           // Don't bother checking the Scrollable methods if there is no room
  803           // for the viewport, we aren't going to show any scrollbars in this
  804           // case anyway.
  805           if (!isEmpty && view instanceof Scrollable) {
  806               sv = (Scrollable)view;
  807               viewTracksViewportWidth = sv.getScrollableTracksViewportWidth();
  808               viewTracksViewportHeight = sv.getScrollableTracksViewportHeight();
  809           }
  810           else {
  811               sv = null;
  812           }
  813   
  814           /* If there's a vertical scrollbar and we need one, allocate
  815            * space for it (we'll make it visible later). A vertical
  816            * scrollbar is considered to be fixed width, arbitrary height.
  817            */
  818   
  819           Rectangle vsbR = new Rectangle(0, availR.y - vpbInsets.top, 0, 0);
  820   
  821           boolean vsbNeeded;
  822           if (isEmpty) {
  823               vsbNeeded = false;
  824           }
  825           else if (vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) {
  826               vsbNeeded = true;
  827           }
  828           else if (vsbPolicy == VERTICAL_SCROLLBAR_NEVER) {
  829               vsbNeeded = false;
  830           }
  831           else {  // vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED
  832               vsbNeeded = !viewTracksViewportHeight && (viewPrefSize.height > extentSize.height);
  833           }
  834   
  835   
  836           if ((vsb != null) && vsbNeeded) {
  837               adjustForVSB(true, availR, vsbR, vpbInsets, leftToRight);
  838               extentSize = viewport.toViewCoordinates(availR.getSize());
  839           }
  840   
  841           /* If there's a horizontal scrollbar and we need one, allocate
  842            * space for it (we'll make it visible later). A horizontal
  843            * scrollbar is considered to be fixed height, arbitrary width.
  844            */
  845   
  846           Rectangle hsbR = new Rectangle(availR.x - vpbInsets.left, 0, 0, 0);
  847           boolean hsbNeeded;
  848           if (isEmpty) {
  849               hsbNeeded = false;
  850           }
  851           else if (hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) {
  852               hsbNeeded = true;
  853           }
  854           else if (hsbPolicy == HORIZONTAL_SCROLLBAR_NEVER) {
  855               hsbNeeded = false;
  856           }
  857           else {  // hsbPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED
  858               hsbNeeded = !viewTracksViewportWidth && (viewPrefSize.width > extentSize.width);
  859           }
  860   
  861           if ((hsb != null) && hsbNeeded) {
  862               adjustForHSB(true, availR, hsbR, vpbInsets);
  863   
  864               /* If we added the horizontal scrollbar then we've implicitly
  865                * reduced  the vertical space available to the viewport.
  866                * As a consequence we may have to add the vertical scrollbar,
  867                * if that hasn't been done so already.  Of course we
  868                * don't bother with any of this if the vsbPolicy is NEVER.
  869                */
  870               if ((vsb != null) && !vsbNeeded &&
  871                   (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
  872   
  873                   extentSize = viewport.toViewCoordinates(availR.getSize());
  874                   vsbNeeded = viewPrefSize.height > extentSize.height;
  875   
  876                   if (vsbNeeded) {
  877                       adjustForVSB(true, availR, vsbR, vpbInsets, leftToRight);
  878                   }
  879               }
  880           }
  881   
  882           /* Set the size of the viewport first, and then recheck the Scrollable
  883            * methods. Some components base their return values for the Scrollable
  884            * methods on the size of the Viewport, so that if we don't
  885            * ask after resetting the bounds we may have gotten the wrong
  886            * answer.
  887            */
  888   
  889           if (viewport != null) {
  890               viewport.setBounds(availR);
  891   
  892               if (sv != null) {
  893                   extentSize = viewport.toViewCoordinates(availR.getSize());
  894   
  895                   boolean oldHSBNeeded = hsbNeeded;
  896                   boolean oldVSBNeeded = vsbNeeded;
  897                   viewTracksViewportWidth = sv.
  898                                             getScrollableTracksViewportWidth();
  899                   viewTracksViewportHeight = sv.
  900                                             getScrollableTracksViewportHeight();
  901                   if (vsb != null && vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED) {
  902                       boolean newVSBNeeded = !viewTracksViewportHeight &&
  903                                        (viewPrefSize.height > extentSize.height);
  904                       if (newVSBNeeded != vsbNeeded) {
  905                           vsbNeeded = newVSBNeeded;
  906                           adjustForVSB(vsbNeeded, availR, vsbR, vpbInsets,
  907                                        leftToRight);
  908                           extentSize = viewport.toViewCoordinates
  909                                                 (availR.getSize());
  910                       }
  911                   }
  912                   if (hsb != null && hsbPolicy ==HORIZONTAL_SCROLLBAR_AS_NEEDED){
  913                       boolean newHSBbNeeded = !viewTracksViewportWidth &&
  914                                          (viewPrefSize.width > extentSize.width);
  915                       if (newHSBbNeeded != hsbNeeded) {
  916                           hsbNeeded = newHSBbNeeded;
  917                           adjustForHSB(hsbNeeded, availR, hsbR, vpbInsets);
  918                           if ((vsb != null) && !vsbNeeded &&
  919                               (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
  920   
  921                               extentSize = viewport.toViewCoordinates
  922                                            (availR.getSize());
  923                               vsbNeeded = viewPrefSize.height >
  924                                           extentSize.height;
  925   
  926                               if (vsbNeeded) {
  927                                   adjustForVSB(true, availR, vsbR, vpbInsets,
  928                                                leftToRight);
  929                               }
  930                           }
  931                       }
  932                   }
  933                   if (oldHSBNeeded != hsbNeeded ||
  934                       oldVSBNeeded != vsbNeeded) {
  935                       viewport.setBounds(availR);
  936                       // You could argue that we should recheck the
  937                       // Scrollable methods again until they stop changing,
  938                       // but they might never stop changing, so we stop here
  939                       // and don't do any additional checks.
  940                   }
  941               }
  942           }
  943   
  944           /* We now have the final size of the viewport: availR.
  945            * Now fixup the header and scrollbar widths/heights.
  946            */
  947           vsbR.height = availR.height + vpbInsets.top + vpbInsets.bottom;
  948           hsbR.width = availR.width + vpbInsets.left + vpbInsets.right;
  949           rowHeadR.height = availR.height + vpbInsets.top + vpbInsets.bottom;
  950           rowHeadR.y = availR.y - vpbInsets.top;
  951           colHeadR.width = availR.width + vpbInsets.left + vpbInsets.right;
  952           colHeadR.x = availR.x - vpbInsets.left;
  953   
  954           /* Set the bounds of the remaining components.  The scrollbars
  955            * are made invisible if they're not needed.
  956            */
  957   
  958           if (rowHead != null) {
  959               rowHead.setBounds(rowHeadR);
  960           }
  961   
  962           if (colHead != null) {
  963               colHead.setBounds(colHeadR);
  964           }
  965   
  966           if (vsb != null) {
  967               if (vsbNeeded) {
  968                   if (colHead != null &&
  969                       UIManager.getBoolean("ScrollPane.fillUpperCorner"))
  970                   {
  971                       if ((leftToRight && upperRight == null) ||
  972                           (!leftToRight && upperLeft == null))
  973                       {
  974                           // This is used primarily for GTK L&F, which needs to
  975                           // extend the vertical scrollbar to fill the upper
  976                           // corner near the column header.  Note that we skip
  977                           // this step (and use the default behavior) if the
  978                           // user has set a custom corner component.
  979                           vsbR.y = colHeadR.y;
  980                           vsbR.height += colHeadR.height;
  981                       }
  982                   }
  983                   vsb.setVisible(true);
  984                   vsb.setBounds(vsbR);
  985               }
  986               else {
  987                   vsb.setVisible(false);
  988               }
  989           }
  990   
  991           if (hsb != null) {
  992               if (hsbNeeded) {
  993                   if (rowHead != null &&
  994                       UIManager.getBoolean("ScrollPane.fillLowerCorner"))
  995                   {
  996                       if ((leftToRight && lowerLeft == null) ||
  997                           (!leftToRight && lowerRight == null))
  998                       {
  999                           // This is used primarily for GTK L&F, which needs to
 1000                           // extend the horizontal scrollbar to fill the lower
 1001                           // corner near the row header.  Note that we skip
 1002                           // this step (and use the default behavior) if the
 1003                           // user has set a custom corner component.
 1004                           if (leftToRight) {
 1005                               hsbR.x = rowHeadR.x;
 1006                           }
 1007                           hsbR.width += rowHeadR.width;
 1008                       }
 1009                   }
 1010                   hsb.setVisible(true);
 1011                   hsb.setBounds(hsbR);
 1012               }
 1013               else {
 1014                   hsb.setVisible(false);
 1015               }
 1016           }
 1017   
 1018           if (lowerLeft != null) {
 1019               lowerLeft.setBounds(leftToRight ? rowHeadR.x : vsbR.x,
 1020                                   hsbR.y,
 1021                                   leftToRight ? rowHeadR.width : vsbR.width,
 1022                                   hsbR.height);
 1023           }
 1024   
 1025           if (lowerRight != null) {
 1026               lowerRight.setBounds(leftToRight ? vsbR.x : rowHeadR.x,
 1027                                    hsbR.y,
 1028                                    leftToRight ? vsbR.width : rowHeadR.width,
 1029                                    hsbR.height);
 1030           }
 1031   
 1032           if (upperLeft != null) {
 1033               upperLeft.setBounds(leftToRight ? rowHeadR.x : vsbR.x,
 1034                                   colHeadR.y,
 1035                                   leftToRight ? rowHeadR.width : vsbR.width,
 1036                                   colHeadR.height);
 1037           }
 1038   
 1039           if (upperRight != null) {
 1040               upperRight.setBounds(leftToRight ? vsbR.x : rowHeadR.x,
 1041                                    colHeadR.y,
 1042                                    leftToRight ? vsbR.width : rowHeadR.width,
 1043                                    colHeadR.height);
 1044           }
 1045       }
 1046   
 1047       /**
 1048        * Adjusts the <code>Rectangle</code> <code>available</code> based on if
 1049        * the vertical scrollbar is needed (<code>wantsVSB</code>).
 1050        * The location of the vsb is updated in <code>vsbR</code>, and
 1051        * the viewport border insets (<code>vpbInsets</code>) are used to offset
 1052        * the vsb. This is only called when <code>wantsVSB</code> has
 1053        * changed, eg you shouldn't invoke adjustForVSB(true) twice.
 1054        */
 1055       private void adjustForVSB(boolean wantsVSB, Rectangle available,
 1056                                 Rectangle vsbR, Insets vpbInsets,
 1057                                 boolean leftToRight) {
 1058           int oldWidth = vsbR.width;
 1059           if (wantsVSB) {
 1060               int vsbWidth = Math.max(0, Math.min(vsb.getPreferredSize().width,
 1061                                                   available.width));
 1062   
 1063               available.width -= vsbWidth;
 1064               vsbR.width = vsbWidth;
 1065   
 1066               if( leftToRight ) {
 1067                   vsbR.x = available.x + available.width + vpbInsets.right;
 1068               } else {
 1069                   vsbR.x = available.x - vpbInsets.left;
 1070                   available.x += vsbWidth;
 1071               }
 1072           }
 1073           else {
 1074               available.width += oldWidth;
 1075           }
 1076       }
 1077   
 1078       /**
 1079        * Adjusts the <code>Rectangle</code> <code>available</code> based on if
 1080        * the horizontal scrollbar is needed (<code>wantsHSB</code>).
 1081        * The location of the hsb is updated in <code>hsbR</code>, and
 1082        * the viewport border insets (<code>vpbInsets</code>) are used to offset
 1083        * the hsb.  This is only called when <code>wantsHSB</code> has
 1084        * changed, eg you shouldn't invoked adjustForHSB(true) twice.
 1085        */
 1086       private void adjustForHSB(boolean wantsHSB, Rectangle available,
 1087                                 Rectangle hsbR, Insets vpbInsets) {
 1088           int oldHeight = hsbR.height;
 1089           if (wantsHSB) {
 1090               int hsbHeight = Math.max(0, Math.min(available.height,
 1091                                                 hsb.getPreferredSize().height));
 1092   
 1093               available.height -= hsbHeight;
 1094               hsbR.y = available.y + available.height + vpbInsets.bottom;
 1095               hsbR.height = hsbHeight;
 1096           }
 1097           else {
 1098               available.height += oldHeight;
 1099           }
 1100       }
 1101   
 1102   
 1103   
 1104       /**
 1105        * Returns the bounds of the border around the specified scroll pane's
 1106        * viewport.
 1107        *
 1108        * @return the size and position of the viewport border
 1109        * @deprecated As of JDK version Swing1.1
 1110        *    replaced by <code>JScrollPane.getViewportBorderBounds()</code>.
 1111        */
 1112       @Deprecated
 1113       public Rectangle getViewportBorderBounds(JScrollPane scrollpane) {
 1114           return scrollpane.getViewportBorderBounds();
 1115       }
 1116   
 1117       /**
 1118        * The UI resource version of <code>ScrollPaneLayout</code>.
 1119        */
 1120       public static class UIResource extends ScrollPaneLayout implements javax.swing.plaf.UIResource {}
 1121   }

Home » openjdk-7 » javax » swing » [javadoc | source]