Home » openjdk-7 » java » awt » [javadoc | source]

    1   /*
    2    * Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   package java.awt;
   26   
   27   import java.io.ObjectInputStream;
   28   import java.io.IOException;
   29   
   30   /**
   31    * A flow layout arranges components in a directional flow, much
   32    * like lines of text in a paragraph. The flow direction is
   33    * determined by the container's <code>componentOrientation</code>
   34    * property and may be one of two values:
   35    * <ul>
   36    * <li><code>ComponentOrientation.LEFT_TO_RIGHT</code>
   37    * <li><code>ComponentOrientation.RIGHT_TO_LEFT</code>
   38    * </ul>
   39    * Flow layouts are typically used
   40    * to arrange buttons in a panel. It arranges buttons
   41    * horizontally until no more buttons fit on the same line.
   42    * The line alignment is determined by the <code>align</code>
   43    * property. The possible values are:
   44    * <ul>
   45    * <li>{@link #LEFT LEFT}
   46    * <li>{@link #RIGHT RIGHT}
   47    * <li>{@link #CENTER CENTER}
   48    * <li>{@link #LEADING LEADING}
   49    * <li>{@link #TRAILING TRAILING}
   50    * </ul>
   51    * <p>
   52    * For example, the following picture shows an applet using the flow
   53    * layout manager (its default layout manager) to position three buttons:
   54    * <p>
   55    * <img src="doc-files/FlowLayout-1.gif"
   56    * ALT="Graphic of Layout for Three Buttons"
   57    * ALIGN=center HSPACE=10 VSPACE=7>
   58    * <p>
   59    * Here is the code for this applet:
   60    * <p>
   61    * <hr><blockquote><pre>
   62    * import java.awt.*;
   63    * import java.applet.Applet;
   64    *
   65    * public class myButtons extends Applet {
   66    *     Button button1, button2, button3;
   67    *     public void init() {
   68    *         button1 = new Button("Ok");
   69    *         button2 = new Button("Open");
   70    *         button3 = new Button("Close");
   71    *         add(button1);
   72    *         add(button2);
   73    *         add(button3);
   74    *     }
   75    * }
   76    * </pre></blockquote><hr>
   77    * <p>
   78    * A flow layout lets each component assume its natural (preferred) size.
   79    *
   80    * @author      Arthur van Hoff
   81    * @author      Sami Shaio
   82    * @since       JDK1.0
   83    * @see ComponentOrientation
   84    */
   85   public class FlowLayout implements LayoutManager, java.io.Serializable {
   86   
   87       /**
   88        * This value indicates that each row of components
   89        * should be left-justified.
   90        */
   91       public static final int LEFT        = 0;
   92   
   93       /**
   94        * This value indicates that each row of components
   95        * should be centered.
   96        */
   97       public static final int CENTER      = 1;
   98   
   99       /**
  100        * This value indicates that each row of components
  101        * should be right-justified.
  102        */
  103       public static final int RIGHT       = 2;
  104   
  105       /**
  106        * This value indicates that each row of components
  107        * should be justified to the leading edge of the container's
  108        * orientation, for example, to the left in left-to-right orientations.
  109        *
  110        * @see     java.awt.Component#getComponentOrientation
  111        * @see     java.awt.ComponentOrientation
  112        * @since   1.2
  113        */
  114       public static final int LEADING     = 3;
  115   
  116       /**
  117        * This value indicates that each row of components
  118        * should be justified to the trailing edge of the container's
  119        * orientation, for example, to the right in left-to-right orientations.
  120        *
  121        * @see     java.awt.Component#getComponentOrientation
  122        * @see     java.awt.ComponentOrientation
  123        * @since   1.2
  124        */
  125       public static final int TRAILING = 4;
  126   
  127       /**
  128        * <code>align</code> is the property that determines
  129        * how each row distributes empty space.
  130        * It can be one of the following values:
  131        * <ul>
  132        * <code>LEFT</code>
  133        * <code>RIGHT</code>
  134        * <code>CENTER</code>
  135        * </ul>
  136        *
  137        * @serial
  138        * @see #getAlignment
  139        * @see #setAlignment
  140        */
  141       int align;          // This is for 1.1 serialization compatibility
  142   
  143       /**
  144        * <code>newAlign</code> is the property that determines
  145        * how each row distributes empty space for the Java 2 platform,
  146        * v1.2 and greater.
  147        * It can be one of the following three values:
  148        * <ul>
  149        * <code>LEFT</code>
  150        * <code>RIGHT</code>
  151        * <code>CENTER</code>
  152        * <code>LEADING</code>
  153        * <code>TRAILING</code>
  154        * </ul>
  155        *
  156        * @serial
  157        * @since 1.2
  158        * @see #getAlignment
  159        * @see #setAlignment
  160        */
  161       int newAlign;       // This is the one we actually use
  162   
  163       /**
  164        * The flow layout manager allows a seperation of
  165        * components with gaps.  The horizontal gap will
  166        * specify the space between components and between
  167        * the components and the borders of the
  168        * <code>Container</code>.
  169        *
  170        * @serial
  171        * @see #getHgap()
  172        * @see #setHgap(int)
  173        */
  174       int hgap;
  175   
  176       /**
  177        * The flow layout manager allows a seperation of
  178        * components with gaps.  The vertical gap will
  179        * specify the space between rows and between the
  180        * the rows and the borders of the <code>Container</code>.
  181        *
  182        * @serial
  183        * @see #getHgap()
  184        * @see #setHgap(int)
  185        */
  186       int vgap;
  187   
  188       /**
  189        * If true, components will be aligned on their baseline.
  190        */
  191       private boolean alignOnBaseline;
  192   
  193       /*
  194        * JDK 1.1 serialVersionUID
  195        */
  196        private static final long serialVersionUID = -7262534875583282631L;
  197   
  198       /**
  199        * Constructs a new <code>FlowLayout</code> with a centered alignment and a
  200        * default 5-unit horizontal and vertical gap.
  201        */
  202       public FlowLayout() {
  203           this(CENTER, 5, 5);
  204       }
  205   
  206       /**
  207        * Constructs a new <code>FlowLayout</code> with the specified
  208        * alignment and a default 5-unit horizontal and vertical gap.
  209        * The value of the alignment argument must be one of
  210        * <code>FlowLayout.LEFT</code>, <code>FlowLayout.RIGHT</code>,
  211        * <code>FlowLayout.CENTER</code>, <code>FlowLayout.LEADING</code>,
  212        * or <code>FlowLayout.TRAILING</code>.
  213        * @param align the alignment value
  214        */
  215       public FlowLayout(int align) {
  216           this(align, 5, 5);
  217       }
  218   
  219       /**
  220        * Creates a new flow layout manager with the indicated alignment
  221        * and the indicated horizontal and vertical gaps.
  222        * <p>
  223        * The value of the alignment argument must be one of
  224        * <code>FlowLayout.LEFT</code>, <code>FlowLayout.RIGHT</code>,
  225        * <code>FlowLayout.CENTER</code>, <code>FlowLayout.LEADING</code>,
  226        * or <code>FlowLayout.TRAILING</code>.
  227        * @param      align   the alignment value
  228        * @param      hgap    the horizontal gap between components
  229        *                     and between the components and the
  230        *                     borders of the <code>Container</code>
  231        * @param      vgap    the vertical gap between components
  232        *                     and between the components and the
  233        *                     borders of the <code>Container</code>
  234        */
  235       public FlowLayout(int align, int hgap, int vgap) {
  236           this.hgap = hgap;
  237           this.vgap = vgap;
  238           setAlignment(align);
  239       }
  240   
  241       /**
  242        * Gets the alignment for this layout.
  243        * Possible values are <code>FlowLayout.LEFT</code>,
  244        * <code>FlowLayout.RIGHT</code>, <code>FlowLayout.CENTER</code>,
  245        * <code>FlowLayout.LEADING</code>,
  246        * or <code>FlowLayout.TRAILING</code>.
  247        * @return     the alignment value for this layout
  248        * @see        java.awt.FlowLayout#setAlignment
  249        * @since      JDK1.1
  250        */
  251       public int getAlignment() {
  252           return newAlign;
  253       }
  254   
  255       /**
  256        * Sets the alignment for this layout.
  257        * Possible values are
  258        * <ul>
  259        * <li><code>FlowLayout.LEFT</code>
  260        * <li><code>FlowLayout.RIGHT</code>
  261        * <li><code>FlowLayout.CENTER</code>
  262        * <li><code>FlowLayout.LEADING</code>
  263        * <li><code>FlowLayout.TRAILING</code>
  264        * </ul>
  265        * @param      align one of the alignment values shown above
  266        * @see        #getAlignment()
  267        * @since      JDK1.1
  268        */
  269       public void setAlignment(int align) {
  270           this.newAlign = align;
  271   
  272           // this.align is used only for serialization compatibility,
  273           // so set it to a value compatible with the 1.1 version
  274           // of the class
  275   
  276           switch (align) {
  277           case LEADING:
  278               this.align = LEFT;
  279               break;
  280           case TRAILING:
  281               this.align = RIGHT;
  282               break;
  283           default:
  284               this.align = align;
  285               break;
  286           }
  287       }
  288   
  289       /**
  290        * Gets the horizontal gap between components
  291        * and between the components and the borders
  292        * of the <code>Container</code>
  293        *
  294        * @return     the horizontal gap between components
  295        *             and between the components and the borders
  296        *             of the <code>Container</code>
  297        * @see        java.awt.FlowLayout#setHgap
  298        * @since      JDK1.1
  299        */
  300       public int getHgap() {
  301           return hgap;
  302       }
  303   
  304       /**
  305        * Sets the horizontal gap between components and
  306        * between the components and the borders of the
  307        * <code>Container</code>.
  308        *
  309        * @param hgap the horizontal gap between components
  310        *             and between the components and the borders
  311        *             of the <code>Container</code>
  312        * @see        java.awt.FlowLayout#getHgap
  313        * @since      JDK1.1
  314        */
  315       public void setHgap(int hgap) {
  316           this.hgap = hgap;
  317       }
  318   
  319       /**
  320        * Gets the vertical gap between components and
  321        * between the components and the borders of the
  322        * <code>Container</code>.
  323        *
  324        * @return     the vertical gap between components
  325        *             and between the components and the borders
  326        *             of the <code>Container</code>
  327        * @see        java.awt.FlowLayout#setVgap
  328        * @since      JDK1.1
  329        */
  330       public int getVgap() {
  331           return vgap;
  332       }
  333   
  334       /**
  335        * Sets the vertical gap between components and between
  336        * the components and the borders of the <code>Container</code>.
  337        *
  338        * @param vgap the vertical gap between components
  339        *             and between the components and the borders
  340        *             of the <code>Container</code>
  341        * @see        java.awt.FlowLayout#getVgap
  342        * @since      JDK1.1
  343        */
  344       public void setVgap(int vgap) {
  345           this.vgap = vgap;
  346       }
  347   
  348       /**
  349        * Sets whether or not components should be vertically aligned along their
  350        * baseline.  Components that do not have a baseline will be centered.
  351        * The default is false.
  352        *
  353        * @param alignOnBaseline whether or not components should be
  354        *                        vertically aligned on their baseline
  355        * @since 1.6
  356        */
  357       public void setAlignOnBaseline(boolean alignOnBaseline) {
  358           this.alignOnBaseline = alignOnBaseline;
  359       }
  360   
  361       /**
  362        * Returns true if components are to be vertically aligned along
  363        * their baseline.  The default is false.
  364        *
  365        * @return true if components are to be vertically aligned along
  366        *              their baseline
  367        * @since 1.6
  368        */
  369       public boolean getAlignOnBaseline() {
  370           return alignOnBaseline;
  371       }
  372   
  373       /**
  374        * Adds the specified component to the layout.
  375        * Not used by this class.
  376        * @param name the name of the component
  377        * @param comp the component to be added
  378        */
  379       public void addLayoutComponent(String name, Component comp) {
  380       }
  381   
  382       /**
  383        * Removes the specified component from the layout.
  384        * Not used by this class.
  385        * @param comp the component to remove
  386        * @see       java.awt.Container#removeAll
  387        */
  388       public void removeLayoutComponent(Component comp) {
  389       }
  390   
  391       /**
  392        * Returns the preferred dimensions for this layout given the
  393        * <i>visible</i> components in the specified target container.
  394        *
  395        * @param target the container that needs to be laid out
  396        * @return    the preferred dimensions to lay out the
  397        *            subcomponents of the specified container
  398        * @see Container
  399        * @see #minimumLayoutSize
  400        * @see       java.awt.Container#getPreferredSize
  401        */
  402       public Dimension preferredLayoutSize(Container target) {
  403         synchronized (target.getTreeLock()) {
  404           Dimension dim = new Dimension(0, 0);
  405           int nmembers = target.getComponentCount();
  406           boolean firstVisibleComponent = true;
  407           boolean useBaseline = getAlignOnBaseline();
  408           int maxAscent = 0;
  409           int maxDescent = 0;
  410   
  411           for (int i = 0 ; i < nmembers ; i++) {
  412               Component m = target.getComponent(i);
  413               if (m.isVisible()) {
  414                   Dimension d = m.getPreferredSize();
  415                   dim.height = Math.max(dim.height, d.height);
  416                   if (firstVisibleComponent) {
  417                       firstVisibleComponent = false;
  418                   } else {
  419                       dim.width += hgap;
  420                   }
  421                   dim.width += d.width;
  422                   if (useBaseline) {
  423                       int baseline = m.getBaseline(d.width, d.height);
  424                       if (baseline >= 0) {
  425                           maxAscent = Math.max(maxAscent, baseline);
  426                           maxDescent = Math.max(maxDescent, d.height - baseline);
  427                       }
  428                   }
  429               }
  430           }
  431           if (useBaseline) {
  432               dim.height = Math.max(maxAscent + maxDescent, dim.height);
  433           }
  434           Insets insets = target.getInsets();
  435           dim.width += insets.left + insets.right + hgap*2;
  436           dim.height += insets.top + insets.bottom + vgap*2;
  437           return dim;
  438         }
  439       }
  440   
  441       /**
  442        * Returns the minimum dimensions needed to layout the <i>visible</i>
  443        * components contained in the specified target container.
  444        * @param target the container that needs to be laid out
  445        * @return    the minimum dimensions to lay out the
  446        *            subcomponents of the specified container
  447        * @see #preferredLayoutSize
  448        * @see       java.awt.Container
  449        * @see       java.awt.Container#doLayout
  450        */
  451       public Dimension minimumLayoutSize(Container target) {
  452         synchronized (target.getTreeLock()) {
  453           boolean useBaseline = getAlignOnBaseline();
  454           Dimension dim = new Dimension(0, 0);
  455           int nmembers = target.getComponentCount();
  456           int maxAscent = 0;
  457           int maxDescent = 0;
  458           boolean firstVisibleComponent = true;
  459   
  460           for (int i = 0 ; i < nmembers ; i++) {
  461               Component m = target.getComponent(i);
  462               if (m.visible) {
  463                   Dimension d = m.getMinimumSize();
  464                   dim.height = Math.max(dim.height, d.height);
  465                   if (firstVisibleComponent) {
  466                       firstVisibleComponent = false;
  467                   } else {
  468                       dim.width += hgap;
  469                   }
  470                   dim.width += d.width;
  471                   if (useBaseline) {
  472                       int baseline = m.getBaseline(d.width, d.height);
  473                       if (baseline >= 0) {
  474                           maxAscent = Math.max(maxAscent, baseline);
  475                           maxDescent = Math.max(maxDescent,
  476                                                 dim.height - baseline);
  477                       }
  478                   }
  479   }
  480   }
  481   
  482           if (useBaseline) {
  483               dim.height = Math.max(maxAscent + maxDescent, dim.height);
  484           }
  485   
  486           Insets insets = target.getInsets();
  487           dim.width += insets.left + insets.right + hgap*2;
  488           dim.height += insets.top + insets.bottom + vgap*2;
  489           return dim;
  490   
  491   
  492   
  493   
  494   
  495         }
  496       }
  497   
  498       /**
  499        * Centers the elements in the specified row, if there is any slack.
  500        * @param target the component which needs to be moved
  501        * @param x the x coordinate
  502        * @param y the y coordinate
  503        * @param width the width dimensions
  504        * @param height the height dimensions
  505        * @param rowStart the beginning of the row
  506        * @param rowEnd the the ending of the row
  507        * @param useBaseline Whether or not to align on baseline.
  508        * @param ascent Ascent for the components. This is only valid if
  509        *               useBaseline is true.
  510        * @param descent Ascent for the components. This is only valid if
  511        *               useBaseline is true.
  512        * @return actual row height
  513        */
  514       private int moveComponents(Container target, int x, int y, int width, int height,
  515                                   int rowStart, int rowEnd, boolean ltr,
  516                                   boolean useBaseline, int[] ascent,
  517                                   int[] descent) {
  518           switch (newAlign) {
  519           case LEFT:
  520               x += ltr ? 0 : width;
  521               break;
  522           case CENTER:
  523               x += width / 2;
  524               break;
  525           case RIGHT:
  526               x += ltr ? width : 0;
  527               break;
  528           case LEADING:
  529               break;
  530           case TRAILING:
  531               x += width;
  532               break;
  533           }
  534           int maxAscent = 0;
  535           int nonbaselineHeight = 0;
  536           int baselineOffset = 0;
  537           if (useBaseline) {
  538               int maxDescent = 0;
  539               for (int i = rowStart ; i < rowEnd ; i++) {
  540                   Component m = target.getComponent(i);
  541                   if (m.visible) {
  542                       if (ascent[i] >= 0) {
  543                           maxAscent = Math.max(maxAscent, ascent[i]);
  544                           maxDescent = Math.max(maxDescent, descent[i]);
  545                       }
  546                       else {
  547                           nonbaselineHeight = Math.max(m.getHeight(),
  548                                                        nonbaselineHeight);
  549                       }
  550                   }
  551               }
  552               height = Math.max(maxAscent + maxDescent, nonbaselineHeight);
  553               baselineOffset = (height - maxAscent - maxDescent) / 2;
  554           }
  555           for (int i = rowStart ; i < rowEnd ; i++) {
  556               Component m = target.getComponent(i);
  557               if (m.isVisible()) {
  558                   int cy;
  559                   if (useBaseline && ascent[i] >= 0) {
  560                       cy = y + baselineOffset + maxAscent - ascent[i];
  561                   }
  562                   else {
  563                       cy = y + (height - m.height) / 2;
  564                   }
  565                   if (ltr) {
  566                       m.setLocation(x, cy);
  567                   } else {
  568                       m.setLocation(target.width - x - m.width, cy);
  569                   }
  570                   x += m.width + hgap;
  571               }
  572           }
  573           return height;
  574       }
  575   
  576       /**
  577        * Lays out the container. This method lets each
  578        * <i>visible</i> component take
  579        * its preferred size by reshaping the components in the
  580        * target container in order to satisfy the alignment of
  581        * this <code>FlowLayout</code> object.
  582        *
  583        * @param target the specified component being laid out
  584        * @see Container
  585        * @see       java.awt.Container#doLayout
  586        */
  587       public void layoutContainer(Container target) {
  588         synchronized (target.getTreeLock()) {
  589           Insets insets = target.getInsets();
  590           int maxwidth = target.width - (insets.left + insets.right + hgap*2);
  591           int nmembers = target.getComponentCount();
  592           int x = 0, y = insets.top + vgap;
  593           int rowh = 0, start = 0;
  594   
  595           boolean ltr = target.getComponentOrientation().isLeftToRight();
  596   
  597           boolean useBaseline = getAlignOnBaseline();
  598           int[] ascent = null;
  599           int[] descent = null;
  600   
  601           if (useBaseline) {
  602               ascent = new int[nmembers];
  603               descent = new int[nmembers];
  604           }
  605   
  606           for (int i = 0 ; i < nmembers ; i++) {
  607               Component m = target.getComponent(i);
  608               if (m.isVisible()) {
  609                   Dimension d = m.getPreferredSize();
  610                   m.setSize(d.width, d.height);
  611   
  612                   if (useBaseline) {
  613                       int baseline = m.getBaseline(d.width, d.height);
  614                       if (baseline >= 0) {
  615                           ascent[i] = baseline;
  616                           descent[i] = d.height - baseline;
  617                       }
  618                       else {
  619                           ascent[i] = -1;
  620                       }
  621                   }
  622                   if ((x == 0) || ((x + d.width) <= maxwidth)) {
  623                       if (x > 0) {
  624                           x += hgap;
  625                       }
  626                       x += d.width;
  627                       rowh = Math.max(rowh, d.height);
  628                   } else {
  629                       rowh = moveComponents(target, insets.left + hgap, y,
  630                                      maxwidth - x, rowh, start, i, ltr,
  631                                      useBaseline, ascent, descent);
  632                       x = d.width;
  633                       y += vgap + rowh;
  634                       rowh = d.height;
  635                       start = i;
  636                   }
  637               }
  638           }
  639           moveComponents(target, insets.left + hgap, y, maxwidth - x, rowh,
  640                          start, nmembers, ltr, useBaseline, ascent, descent);
  641         }
  642       }
  643   
  644       //
  645       // the internal serial version which says which version was written
  646       // - 0 (default) for versions before the Java 2 platform, v1.2
  647       // - 1 for version >= Java 2 platform v1.2, which includes "newAlign" field
  648       //
  649       private static final int currentSerialVersion = 1;
  650       /**
  651        * This represent the <code>currentSerialVersion</code>
  652        * which is bein used.  It will be one of two values :
  653        * <code>0</code> versions before Java 2 platform v1.2..
  654        * <code>1</code> versions after  Java 2 platform v1.2..
  655        *
  656        * @serial
  657        * @since 1.2
  658        */
  659       private int serialVersionOnStream = currentSerialVersion;
  660   
  661       /**
  662        * Reads this object out of a serialization stream, handling
  663        * objects written by older versions of the class that didn't contain all
  664        * of the fields we use now..
  665        */
  666       private void readObject(ObjectInputStream stream)
  667            throws IOException, ClassNotFoundException
  668       {
  669           stream.defaultReadObject();
  670   
  671           if (serialVersionOnStream < 1) {
  672               // "newAlign" field wasn't present, so use the old "align" field.
  673               setAlignment(this.align);
  674           }
  675           serialVersionOnStream = currentSerialVersion;
  676       }
  677   
  678       /**
  679        * Returns a string representation of this <code>FlowLayout</code>
  680        * object and its values.
  681        * @return     a string representation of this layout
  682        */
  683       public String toString() {
  684           String str = "";
  685           switch (align) {
  686             case LEFT:        str = ",align=left"; break;
  687             case CENTER:      str = ",align=center"; break;
  688             case RIGHT:       str = ",align=right"; break;
  689             case LEADING:     str = ",align=leading"; break;
  690             case TRAILING:    str = ",align=trailing"; break;
  691           }
  692           return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + str + "]";
  693       }
  694   
  695   
  696   }

Home » openjdk-7 » java » awt » [javadoc | source]