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   
   26   package java.awt;
   27   
   28   import java.util.Hashtable;
   29   import java.util.Vector;
   30   import java.util.Enumeration;
   31   
   32   import java.io.Serializable;
   33   import java.io.ObjectInputStream;
   34   import java.io.ObjectOutputStream;
   35   import java.io.ObjectStreamField;
   36   import java.io.IOException;
   37   
   38   /**
   39    * A <code>CardLayout</code> object is a layout manager for a
   40    * container. It treats each component in the container as a card.
   41    * Only one card is visible at a time, and the container acts as
   42    * a stack of cards. The first component added to a
   43    * <code>CardLayout</code> object is the visible component when the
   44    * container is first displayed.
   45    * <p>
   46    * The ordering of cards is determined by the container's own internal
   47    * ordering of its component objects. <code>CardLayout</code>
   48    * defines a set of methods that allow an application to flip
   49    * through these cards sequentially, or to show a specified card.
   50    * The {@link CardLayout#addLayoutComponent}
   51    * method can be used to associate a string identifier with a given card
   52    * for fast random access.
   53    *
   54    * @author      Arthur van Hoff
   55    * @see         java.awt.Container
   56    * @since       JDK1.0
   57    */
   58   
   59   public class CardLayout implements LayoutManager2,
   60                                      Serializable {
   61   
   62       private static final long serialVersionUID = -4328196481005934313L;
   63   
   64       /*
   65        * This creates a Vector to store associated
   66        * pairs of components and their names.
   67        * @see java.util.Vector
   68        */
   69       Vector vector = new Vector();
   70   
   71       /*
   72        * A pair of Component and String that represents its name.
   73        */
   74       class Card implements Serializable {
   75           static final long serialVersionUID = 6640330810709497518L;
   76           public String name;
   77           public Component comp;
   78           public Card(String cardName, Component cardComponent) {
   79               name = cardName;
   80               comp = cardComponent;
   81           }
   82       }
   83   
   84       /*
   85        * Index of Component currently displayed by CardLayout.
   86        */
   87       int currentCard = 0;
   88   
   89   
   90       /*
   91       * A cards horizontal Layout gap (inset). It specifies
   92       * the space between the left and right edges of a
   93       * container and the current component.
   94       * This should be a non negative Integer.
   95       * @see getHgap()
   96       * @see setHgap()
   97       */
   98       int hgap;
   99   
  100       /*
  101       * A cards vertical Layout gap (inset). It specifies
  102       * the space between the top and bottom edges of a
  103       * container and the current component.
  104       * This should be a non negative Integer.
  105       * @see getVgap()
  106       * @see setVgap()
  107       */
  108       int vgap;
  109   
  110       /**
  111        * @serialField tab         Hashtable
  112        *      deprectated, for forward compatibility only
  113        * @serialField hgap        int
  114        * @serialField vgap        int
  115        * @serialField vector      Vector
  116        * @serialField currentCard int
  117        */
  118       private static final ObjectStreamField[] serialPersistentFields = {
  119           new ObjectStreamField("tab", Hashtable.class),
  120           new ObjectStreamField("hgap", Integer.TYPE),
  121           new ObjectStreamField("vgap", Integer.TYPE),
  122           new ObjectStreamField("vector", Vector.class),
  123           new ObjectStreamField("currentCard", Integer.TYPE)
  124       };
  125   
  126       /**
  127        * Creates a new card layout with gaps of size zero.
  128        */
  129       public CardLayout() {
  130           this(0, 0);
  131       }
  132   
  133       /**
  134        * Creates a new card layout with the specified horizontal and
  135        * vertical gaps. The horizontal gaps are placed at the left and
  136        * right edges. The vertical gaps are placed at the top and bottom
  137        * edges.
  138        * @param     hgap   the horizontal gap.
  139        * @param     vgap   the vertical gap.
  140        */
  141       public CardLayout(int hgap, int vgap) {
  142           this.hgap = hgap;
  143           this.vgap = vgap;
  144       }
  145   
  146       /**
  147        * Gets the horizontal gap between components.
  148        * @return    the horizontal gap between components.
  149        * @see       java.awt.CardLayout#setHgap(int)
  150        * @see       java.awt.CardLayout#getVgap()
  151        * @since     JDK1.1
  152        */
  153       public int getHgap() {
  154           return hgap;
  155       }
  156   
  157       /**
  158        * Sets the horizontal gap between components.
  159        * @param hgap the horizontal gap between components.
  160        * @see       java.awt.CardLayout#getHgap()
  161        * @see       java.awt.CardLayout#setVgap(int)
  162        * @since     JDK1.1
  163        */
  164       public void setHgap(int hgap) {
  165           this.hgap = hgap;
  166       }
  167   
  168       /**
  169        * Gets the vertical gap between components.
  170        * @return the vertical gap between components.
  171        * @see       java.awt.CardLayout#setVgap(int)
  172        * @see       java.awt.CardLayout#getHgap()
  173        */
  174       public int getVgap() {
  175           return vgap;
  176       }
  177   
  178       /**
  179        * Sets the vertical gap between components.
  180        * @param     vgap the vertical gap between components.
  181        * @see       java.awt.CardLayout#getVgap()
  182        * @see       java.awt.CardLayout#setHgap(int)
  183        * @since     JDK1.1
  184        */
  185       public void setVgap(int vgap) {
  186           this.vgap = vgap;
  187       }
  188   
  189       /**
  190        * Adds the specified component to this card layout's internal
  191        * table of names. The object specified by <code>constraints</code>
  192        * must be a string. The card layout stores this string as a key-value
  193        * pair that can be used for random access to a particular card.
  194        * By calling the <code>show</code> method, an application can
  195        * display the component with the specified name.
  196        * @param     comp          the component to be added.
  197        * @param     constraints   a tag that identifies a particular
  198        *                                        card in the layout.
  199        * @see       java.awt.CardLayout#show(java.awt.Container, java.lang.String)
  200        * @exception  IllegalArgumentException  if the constraint is not a string.
  201        */
  202       public void addLayoutComponent(Component comp, Object constraints) {
  203         synchronized (comp.getTreeLock()) {
  204             if (constraints == null){
  205                 constraints = "";
  206             }
  207           if (constraints instanceof String) {
  208               addLayoutComponent((String)constraints, comp);
  209           } else {
  210               throw new IllegalArgumentException("cannot add to layout: constraint must be a string");
  211           }
  212         }
  213       }
  214   
  215       /**
  216        * @deprecated   replaced by
  217        *      <code>addLayoutComponent(Component, Object)</code>.
  218        */
  219       @Deprecated
  220       public void addLayoutComponent(String name, Component comp) {
  221           synchronized (comp.getTreeLock()) {
  222               if (!vector.isEmpty()) {
  223                   comp.setVisible(false);
  224               }
  225               for (int i=0; i < vector.size(); i++) {
  226                   if (((Card)vector.get(i)).name.equals(name)) {
  227                       ((Card)vector.get(i)).comp = comp;
  228                       return;
  229                   }
  230               }
  231               vector.add(new Card(name, comp));
  232           }
  233       }
  234   
  235       /**
  236        * Removes the specified component from the layout.
  237        * If the card was visible on top, the next card underneath it is shown.
  238        * @param   comp   the component to be removed.
  239        * @see     java.awt.Container#remove(java.awt.Component)
  240        * @see     java.awt.Container#removeAll()
  241        */
  242       public void removeLayoutComponent(Component comp) {
  243           synchronized (comp.getTreeLock()) {
  244               for (int i = 0; i < vector.size(); i++) {
  245                   if (((Card)vector.get(i)).comp == comp) {
  246                       // if we remove current component we should show next one
  247                       if (comp.isVisible() && (comp.getParent() != null)) {
  248                           next(comp.getParent());
  249                       }
  250   
  251                       vector.remove(i);
  252   
  253                       // correct currentCard if this is necessary
  254                       if (currentCard > i) {
  255                           currentCard--;
  256                       }
  257                       break;
  258                   }
  259               }
  260           }
  261       }
  262   
  263       /**
  264        * Determines the preferred size of the container argument using
  265        * this card layout.
  266        * @param   parent the parent container in which to do the layout
  267        * @return  the preferred dimensions to lay out the subcomponents
  268        *                of the specified container
  269        * @see     java.awt.Container#getPreferredSize
  270        * @see     java.awt.CardLayout#minimumLayoutSize
  271        */
  272       public Dimension preferredLayoutSize(Container parent) {
  273           synchronized (parent.getTreeLock()) {
  274               Insets insets = parent.getInsets();
  275               int ncomponents = parent.getComponentCount();
  276               int w = 0;
  277               int h = 0;
  278   
  279               for (int i = 0 ; i < ncomponents ; i++) {
  280                   Component comp = parent.getComponent(i);
  281                   Dimension d = comp.getPreferredSize();
  282                   if (d.width > w) {
  283                       w = d.width;
  284                   }
  285                   if (d.height > h) {
  286                       h = d.height;
  287                   }
  288               }
  289               return new Dimension(insets.left + insets.right + w + hgap*2,
  290                                    insets.top + insets.bottom + h + vgap*2);
  291           }
  292       }
  293   
  294       /**
  295        * Calculates the minimum size for the specified panel.
  296        * @param     parent the parent container in which to do the layout
  297        * @return    the minimum dimensions required to lay out the
  298        *                subcomponents of the specified container
  299        * @see       java.awt.Container#doLayout
  300        * @see       java.awt.CardLayout#preferredLayoutSize
  301        */
  302       public Dimension minimumLayoutSize(Container parent) {
  303           synchronized (parent.getTreeLock()) {
  304               Insets insets = parent.getInsets();
  305               int ncomponents = parent.getComponentCount();
  306               int w = 0;
  307               int h = 0;
  308   
  309               for (int i = 0 ; i < ncomponents ; i++) {
  310                   Component comp = parent.getComponent(i);
  311                   Dimension d = comp.getMinimumSize();
  312                   if (d.width > w) {
  313                       w = d.width;
  314                   }
  315                   if (d.height > h) {
  316                       h = d.height;
  317                   }
  318               }
  319               return new Dimension(insets.left + insets.right + w + hgap*2,
  320                                    insets.top + insets.bottom + h + vgap*2);
  321           }
  322       }
  323   
  324       /**
  325        * Returns the maximum dimensions for this layout given the components
  326        * in the specified target container.
  327        * @param target the component which needs to be laid out
  328        * @see Container
  329        * @see #minimumLayoutSize
  330        * @see #preferredLayoutSize
  331        */
  332       public Dimension maximumLayoutSize(Container target) {
  333           return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
  334       }
  335   
  336       /**
  337        * Returns the alignment along the x axis.  This specifies how
  338        * the component would like to be aligned relative to other
  339        * components.  The value should be a number between 0 and 1
  340        * where 0 represents alignment along the origin, 1 is aligned
  341        * the furthest away from the origin, 0.5 is centered, etc.
  342        */
  343       public float getLayoutAlignmentX(Container parent) {
  344           return 0.5f;
  345       }
  346   
  347       /**
  348        * Returns the alignment along the y axis.  This specifies how
  349        * the component would like to be aligned relative to other
  350        * components.  The value should be a number between 0 and 1
  351        * where 0 represents alignment along the origin, 1 is aligned
  352        * the furthest away from the origin, 0.5 is centered, etc.
  353        */
  354       public float getLayoutAlignmentY(Container parent) {
  355           return 0.5f;
  356       }
  357   
  358       /**
  359        * Invalidates the layout, indicating that if the layout manager
  360        * has cached information it should be discarded.
  361        */
  362       public void invalidateLayout(Container target) {
  363       }
  364   
  365       /**
  366        * Lays out the specified container using this card layout.
  367        * <p>
  368        * Each component in the <code>parent</code> container is reshaped
  369        * to be the size of the container, minus space for surrounding
  370        * insets, horizontal gaps, and vertical gaps.
  371        *
  372        * @param     parent the parent container in which to do the layout
  373        * @see       java.awt.Container#doLayout
  374        */
  375       public void layoutContainer(Container parent) {
  376           synchronized (parent.getTreeLock()) {
  377               Insets insets = parent.getInsets();
  378               int ncomponents = parent.getComponentCount();
  379               Component comp = null;
  380               boolean currentFound = false;
  381   
  382               for (int i = 0 ; i < ncomponents ; i++) {
  383                   comp = parent.getComponent(i);
  384                   comp.setBounds(hgap + insets.left, vgap + insets.top,
  385                                  parent.width - (hgap*2 + insets.left + insets.right),
  386                                  parent.height - (vgap*2 + insets.top + insets.bottom));
  387                   if (comp.isVisible()) {
  388                       currentFound = true;
  389                   }
  390               }
  391   
  392               if (!currentFound && ncomponents > 0) {
  393                   parent.getComponent(0).setVisible(true);
  394               }
  395           }
  396       }
  397   
  398       /**
  399        * Make sure that the Container really has a CardLayout installed.
  400        * Otherwise havoc can ensue!
  401        */
  402       void checkLayout(Container parent) {
  403           if (parent.getLayout() != this) {
  404               throw new IllegalArgumentException("wrong parent for CardLayout");
  405           }
  406       }
  407   
  408       /**
  409        * Flips to the first card of the container.
  410        * @param     parent   the parent container in which to do the layout
  411        * @see       java.awt.CardLayout#last
  412        */
  413       public void first(Container parent) {
  414           synchronized (parent.getTreeLock()) {
  415               checkLayout(parent);
  416               int ncomponents = parent.getComponentCount();
  417               for (int i = 0 ; i < ncomponents ; i++) {
  418                   Component comp = parent.getComponent(i);
  419                   if (comp.isVisible()) {
  420                       comp.setVisible(false);
  421                       break;
  422                   }
  423               }
  424               if (ncomponents > 0) {
  425                   currentCard = 0;
  426                   parent.getComponent(0).setVisible(true);
  427                   parent.validate();
  428               }
  429           }
  430       }
  431   
  432       /**
  433        * Flips to the next card of the specified container. If the
  434        * currently visible card is the last one, this method flips to the
  435        * first card in the layout.
  436        * @param     parent   the parent container in which to do the layout
  437        * @see       java.awt.CardLayout#previous
  438        */
  439       public void next(Container parent) {
  440           synchronized (parent.getTreeLock()) {
  441               checkLayout(parent);
  442               int ncomponents = parent.getComponentCount();
  443               for (int i = 0 ; i < ncomponents ; i++) {
  444                   Component comp = parent.getComponent(i);
  445                   if (comp.isVisible()) {
  446                       comp.setVisible(false);
  447                       currentCard = (i + 1) % ncomponents;
  448                       comp = parent.getComponent(currentCard);
  449                       comp.setVisible(true);
  450                       parent.validate();
  451                       return;
  452                   }
  453               }
  454               showDefaultComponent(parent);
  455           }
  456       }
  457   
  458       /**
  459        * Flips to the previous card of the specified container. If the
  460        * currently visible card is the first one, this method flips to the
  461        * last card in the layout.
  462        * @param     parent   the parent container in which to do the layout
  463        * @see       java.awt.CardLayout#next
  464        */
  465       public void previous(Container parent) {
  466           synchronized (parent.getTreeLock()) {
  467               checkLayout(parent);
  468               int ncomponents = parent.getComponentCount();
  469               for (int i = 0 ; i < ncomponents ; i++) {
  470                   Component comp = parent.getComponent(i);
  471                   if (comp.isVisible()) {
  472                       comp.setVisible(false);
  473                       currentCard = ((i > 0) ? i-1 : ncomponents-1);
  474                       comp = parent.getComponent(currentCard);
  475                       comp.setVisible(true);
  476                       parent.validate();
  477                       return;
  478                   }
  479               }
  480               showDefaultComponent(parent);
  481           }
  482       }
  483   
  484       void showDefaultComponent(Container parent) {
  485           if (parent.getComponentCount() > 0) {
  486               currentCard = 0;
  487               parent.getComponent(0).setVisible(true);
  488               parent.validate();
  489           }
  490       }
  491   
  492       /**
  493        * Flips to the last card of the container.
  494        * @param     parent   the parent container in which to do the layout
  495        * @see       java.awt.CardLayout#first
  496        */
  497       public void last(Container parent) {
  498           synchronized (parent.getTreeLock()) {
  499               checkLayout(parent);
  500               int ncomponents = parent.getComponentCount();
  501               for (int i = 0 ; i < ncomponents ; i++) {
  502                   Component comp = parent.getComponent(i);
  503                   if (comp.isVisible()) {
  504                       comp.setVisible(false);
  505                       break;
  506                   }
  507               }
  508               if (ncomponents > 0) {
  509                   currentCard = ncomponents - 1;
  510                   parent.getComponent(currentCard).setVisible(true);
  511                   parent.validate();
  512               }
  513           }
  514       }
  515   
  516       /**
  517        * Flips to the component that was added to this layout with the
  518        * specified <code>name</code>, using <code>addLayoutComponent</code>.
  519        * If no such component exists, then nothing happens.
  520        * @param     parent   the parent container in which to do the layout
  521        * @param     name     the component name
  522        * @see       java.awt.CardLayout#addLayoutComponent(java.awt.Component, java.lang.Object)
  523        */
  524       public void show(Container parent, String name) {
  525           synchronized (parent.getTreeLock()) {
  526               checkLayout(parent);
  527               Component next = null;
  528               int ncomponents = vector.size();
  529               for (int i = 0; i < ncomponents; i++) {
  530                   Card card = (Card)vector.get(i);
  531                   if (card.name.equals(name)) {
  532                       next = card.comp;
  533                       currentCard = i;
  534                       break;
  535                   }
  536               }
  537               if ((next != null) && !next.isVisible()) {
  538                   ncomponents = parent.getComponentCount();
  539                   for (int i = 0; i < ncomponents; i++) {
  540                       Component comp = parent.getComponent(i);
  541                       if (comp.isVisible()) {
  542                           comp.setVisible(false);
  543                           break;
  544                       }
  545                   }
  546                   next.setVisible(true);
  547                   parent.validate();
  548               }
  549           }
  550       }
  551   
  552       /**
  553        * Returns a string representation of the state of this card layout.
  554        * @return    a string representation of this card layout.
  555        */
  556       public String toString() {
  557           return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + "]";
  558       }
  559   
  560       /**
  561        * Reads serializable fields from stream.
  562        */
  563       private void readObject(ObjectInputStream s)
  564           throws ClassNotFoundException, IOException
  565       {
  566           ObjectInputStream.GetField f = s.readFields();
  567   
  568           hgap = f.get("hgap", 0);
  569           vgap = f.get("vgap", 0);
  570   
  571           if (f.defaulted("vector")) {
  572               //  pre-1.4 stream
  573               Hashtable tab = (Hashtable)f.get("tab", null);
  574               vector = new Vector();
  575               if (tab != null && !tab.isEmpty()) {
  576                   for (Enumeration e = tab.keys() ; e.hasMoreElements() ; ) {
  577                       String key = (String)e.nextElement();
  578                       Component comp = (Component)tab.get(key);
  579                       vector.add(new Card(key, comp));
  580                       if (comp.isVisible()) {
  581                           currentCard = vector.size() - 1;
  582                       }
  583                   }
  584               }
  585           } else {
  586               vector = (Vector)f.get("vector", null);
  587               currentCard = f.get("currentCard", 0);
  588           }
  589       }
  590   
  591       /**
  592        * Writes serializable fields to stream.
  593        */
  594       private void writeObject(ObjectOutputStream s)
  595           throws IOException
  596       {
  597           Hashtable tab = new Hashtable();
  598           int ncomponents = vector.size();
  599           for (int i = 0; i < ncomponents; i++) {
  600               Card card = (Card)vector.get(i);
  601               tab.put(card.name, card.comp);
  602           }
  603   
  604           ObjectOutputStream.PutField f = s.putFields();
  605           f.put("hgap", hgap);
  606           f.put("vgap", vgap);
  607           f.put("vector", vector);
  608           f.put("currentCard", currentCard);
  609           f.put("tab", tab);
  610           s.writeFields();
  611       }
  612   }

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