jdk/src/share/classes/java/awt/CardLayout.java
changeset 2 90ce3da70b43
child 5506 202f599c92aa
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/awt/CardLayout.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,612 @@
+/*
+ * Copyright 1995-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.awt;
+
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.Enumeration;
+
+import java.io.Serializable;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.io.IOException;
+
+/**
+ * A <code>CardLayout</code> object is a layout manager for a
+ * container. It treats each component in the container as a card.
+ * Only one card is visible at a time, and the container acts as
+ * a stack of cards. The first component added to a
+ * <code>CardLayout</code> object is the visible component when the
+ * container is first displayed.
+ * <p>
+ * The ordering of cards is determined by the container's own internal
+ * ordering of its component objects. <code>CardLayout</code>
+ * defines a set of methods that allow an application to flip
+ * through these cards sequentially, or to show a specified card.
+ * The {@link CardLayout#addLayoutComponent}
+ * method can be used to associate a string identifier with a given card
+ * for fast random access.
+ *
+ * @author      Arthur van Hoff
+ * @see         java.awt.Container
+ * @since       JDK1.0
+ */
+
+public class CardLayout implements LayoutManager2,
+                                   Serializable {
+
+    private static final long serialVersionUID = -4328196481005934313L;
+
+    /*
+     * This creates a Vector to store associated
+     * pairs of components and their names.
+     * @see java.util.Vector
+     */
+    Vector vector = new Vector();
+
+    /*
+     * A pair of Component and String that represents its name.
+     */
+    class Card implements Serializable {
+        static final long serialVersionUID = 6640330810709497518L;
+        public String name;
+        public Component comp;
+        public Card(String cardName, Component cardComponent) {
+            name = cardName;
+            comp = cardComponent;
+        }
+    }
+
+    /*
+     * Index of Component currently displayed by CardLayout.
+     */
+    int currentCard = 0;
+
+
+    /*
+    * A cards horizontal Layout gap (inset). It specifies
+    * the space between the left and right edges of a
+    * container and the current component.
+    * This should be a non negative Integer.
+    * @see getHgap()
+    * @see setHgap()
+    */
+    int hgap;
+
+    /*
+    * A cards vertical Layout gap (inset). It specifies
+    * the space between the top and bottom edges of a
+    * container and the current component.
+    * This should be a non negative Integer.
+    * @see getVgap()
+    * @see setVgap()
+    */
+    int vgap;
+
+    /**
+     * @serialField tab         Hashtable
+     *      deprectated, for forward compatibility only
+     * @serialField hgap        int
+     * @serialField vgap        int
+     * @serialField vector      Vector
+     * @serialField currentCard int
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("tab", Hashtable.class),
+        new ObjectStreamField("hgap", Integer.TYPE),
+        new ObjectStreamField("vgap", Integer.TYPE),
+        new ObjectStreamField("vector", Vector.class),
+        new ObjectStreamField("currentCard", Integer.TYPE)
+    };
+
+    /**
+     * Creates a new card layout with gaps of size zero.
+     */
+    public CardLayout() {
+        this(0, 0);
+    }
+
+    /**
+     * Creates a new card layout with the specified horizontal and
+     * vertical gaps. The horizontal gaps are placed at the left and
+     * right edges. The vertical gaps are placed at the top and bottom
+     * edges.
+     * @param     hgap   the horizontal gap.
+     * @param     vgap   the vertical gap.
+     */
+    public CardLayout(int hgap, int vgap) {
+        this.hgap = hgap;
+        this.vgap = vgap;
+    }
+
+    /**
+     * Gets the horizontal gap between components.
+     * @return    the horizontal gap between components.
+     * @see       java.awt.CardLayout#setHgap(int)
+     * @see       java.awt.CardLayout#getVgap()
+     * @since     JDK1.1
+     */
+    public int getHgap() {
+        return hgap;
+    }
+
+    /**
+     * Sets the horizontal gap between components.
+     * @param hgap the horizontal gap between components.
+     * @see       java.awt.CardLayout#getHgap()
+     * @see       java.awt.CardLayout#setVgap(int)
+     * @since     JDK1.1
+     */
+    public void setHgap(int hgap) {
+        this.hgap = hgap;
+    }
+
+    /**
+     * Gets the vertical gap between components.
+     * @return the vertical gap between components.
+     * @see       java.awt.CardLayout#setVgap(int)
+     * @see       java.awt.CardLayout#getHgap()
+     */
+    public int getVgap() {
+        return vgap;
+    }
+
+    /**
+     * Sets the vertical gap between components.
+     * @param     vgap the vertical gap between components.
+     * @see       java.awt.CardLayout#getVgap()
+     * @see       java.awt.CardLayout#setHgap(int)
+     * @since     JDK1.1
+     */
+    public void setVgap(int vgap) {
+        this.vgap = vgap;
+    }
+
+    /**
+     * Adds the specified component to this card layout's internal
+     * table of names. The object specified by <code>constraints</code>
+     * must be a string. The card layout stores this string as a key-value
+     * pair that can be used for random access to a particular card.
+     * By calling the <code>show</code> method, an application can
+     * display the component with the specified name.
+     * @param     comp          the component to be added.
+     * @param     constraints   a tag that identifies a particular
+     *                                        card in the layout.
+     * @see       java.awt.CardLayout#show(java.awt.Container, java.lang.String)
+     * @exception  IllegalArgumentException  if the constraint is not a string.
+     */
+    public void addLayoutComponent(Component comp, Object constraints) {
+      synchronized (comp.getTreeLock()) {
+          if (constraints == null){
+              constraints = "";
+          }
+        if (constraints instanceof String) {
+            addLayoutComponent((String)constraints, comp);
+        } else {
+            throw new IllegalArgumentException("cannot add to layout: constraint must be a string");
+        }
+      }
+    }
+
+    /**
+     * @deprecated   replaced by
+     *      <code>addLayoutComponent(Component, Object)</code>.
+     */
+    @Deprecated
+    public void addLayoutComponent(String name, Component comp) {
+        synchronized (comp.getTreeLock()) {
+            if (!vector.isEmpty()) {
+                comp.setVisible(false);
+            }
+            for (int i=0; i < vector.size(); i++) {
+                if (((Card)vector.get(i)).name.equals(name)) {
+                    ((Card)vector.get(i)).comp = comp;
+                    return;
+                }
+            }
+            vector.add(new Card(name, comp));
+        }
+    }
+
+    /**
+     * Removes the specified component from the layout.
+     * If the card was visible on top, the next card underneath it is shown.
+     * @param   comp   the component to be removed.
+     * @see     java.awt.Container#remove(java.awt.Component)
+     * @see     java.awt.Container#removeAll()
+     */
+    public void removeLayoutComponent(Component comp) {
+        synchronized (comp.getTreeLock()) {
+            for (int i = 0; i < vector.size(); i++) {
+                if (((Card)vector.get(i)).comp == comp) {
+                    // if we remove current component we should show next one
+                    if (comp.isVisible() && (comp.getParent() != null)) {
+                        next(comp.getParent());
+                    }
+
+                    vector.remove(i);
+
+                    // correct currentCard if this is necessary
+                    if (currentCard > i) {
+                        currentCard--;
+                    }
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Determines the preferred size of the container argument using
+     * this card layout.
+     * @param   parent the parent container in which to do the layout
+     * @return  the preferred dimensions to lay out the subcomponents
+     *                of the specified container
+     * @see     java.awt.Container#getPreferredSize
+     * @see     java.awt.CardLayout#minimumLayoutSize
+     */
+    public Dimension preferredLayoutSize(Container parent) {
+        synchronized (parent.getTreeLock()) {
+            Insets insets = parent.getInsets();
+            int ncomponents = parent.getComponentCount();
+            int w = 0;
+            int h = 0;
+
+            for (int i = 0 ; i < ncomponents ; i++) {
+                Component comp = parent.getComponent(i);
+                Dimension d = comp.getPreferredSize();
+                if (d.width > w) {
+                    w = d.width;
+                }
+                if (d.height > h) {
+                    h = d.height;
+                }
+            }
+            return new Dimension(insets.left + insets.right + w + hgap*2,
+                                 insets.top + insets.bottom + h + vgap*2);
+        }
+    }
+
+    /**
+     * Calculates the minimum size for the specified panel.
+     * @param     parent the parent container in which to do the layout
+     * @return    the minimum dimensions required to lay out the
+     *                subcomponents of the specified container
+     * @see       java.awt.Container#doLayout
+     * @see       java.awt.CardLayout#preferredLayoutSize
+     */
+    public Dimension minimumLayoutSize(Container parent) {
+        synchronized (parent.getTreeLock()) {
+            Insets insets = parent.getInsets();
+            int ncomponents = parent.getComponentCount();
+            int w = 0;
+            int h = 0;
+
+            for (int i = 0 ; i < ncomponents ; i++) {
+                Component comp = parent.getComponent(i);
+                Dimension d = comp.getMinimumSize();
+                if (d.width > w) {
+                    w = d.width;
+                }
+                if (d.height > h) {
+                    h = d.height;
+                }
+            }
+            return new Dimension(insets.left + insets.right + w + hgap*2,
+                                 insets.top + insets.bottom + h + vgap*2);
+        }
+    }
+
+    /**
+     * Returns the maximum dimensions for this layout given the components
+     * in the specified target container.
+     * @param target the component which needs to be laid out
+     * @see Container
+     * @see #minimumLayoutSize
+     * @see #preferredLayoutSize
+     */
+    public Dimension maximumLayoutSize(Container target) {
+        return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
+    }
+
+    /**
+     * Returns the alignment along the x axis.  This specifies how
+     * the component would like to be aligned relative to other
+     * components.  The value should be a number between 0 and 1
+     * where 0 represents alignment along the origin, 1 is aligned
+     * the furthest away from the origin, 0.5 is centered, etc.
+     */
+    public float getLayoutAlignmentX(Container parent) {
+        return 0.5f;
+    }
+
+    /**
+     * Returns the alignment along the y axis.  This specifies how
+     * the component would like to be aligned relative to other
+     * components.  The value should be a number between 0 and 1
+     * where 0 represents alignment along the origin, 1 is aligned
+     * the furthest away from the origin, 0.5 is centered, etc.
+     */
+    public float getLayoutAlignmentY(Container parent) {
+        return 0.5f;
+    }
+
+    /**
+     * Invalidates the layout, indicating that if the layout manager
+     * has cached information it should be discarded.
+     */
+    public void invalidateLayout(Container target) {
+    }
+
+    /**
+     * Lays out the specified container using this card layout.
+     * <p>
+     * Each component in the <code>parent</code> container is reshaped
+     * to be the size of the container, minus space for surrounding
+     * insets, horizontal gaps, and vertical gaps.
+     *
+     * @param     parent the parent container in which to do the layout
+     * @see       java.awt.Container#doLayout
+     */
+    public void layoutContainer(Container parent) {
+        synchronized (parent.getTreeLock()) {
+            Insets insets = parent.getInsets();
+            int ncomponents = parent.getComponentCount();
+            Component comp = null;
+            boolean currentFound = false;
+
+            for (int i = 0 ; i < ncomponents ; i++) {
+                comp = parent.getComponent(i);
+                comp.setBounds(hgap + insets.left, vgap + insets.top,
+                               parent.width - (hgap*2 + insets.left + insets.right),
+                               parent.height - (vgap*2 + insets.top + insets.bottom));
+                if (comp.isVisible()) {
+                    currentFound = true;
+                }
+            }
+
+            if (!currentFound && ncomponents > 0) {
+                parent.getComponent(0).setVisible(true);
+            }
+        }
+    }
+
+    /**
+     * Make sure that the Container really has a CardLayout installed.
+     * Otherwise havoc can ensue!
+     */
+    void checkLayout(Container parent) {
+        if (parent.getLayout() != this) {
+            throw new IllegalArgumentException("wrong parent for CardLayout");
+        }
+    }
+
+    /**
+     * Flips to the first card of the container.
+     * @param     parent   the parent container in which to do the layout
+     * @see       java.awt.CardLayout#last
+     */
+    public void first(Container parent) {
+        synchronized (parent.getTreeLock()) {
+            checkLayout(parent);
+            int ncomponents = parent.getComponentCount();
+            for (int i = 0 ; i < ncomponents ; i++) {
+                Component comp = parent.getComponent(i);
+                if (comp.isVisible()) {
+                    comp.setVisible(false);
+                    break;
+                }
+            }
+            if (ncomponents > 0) {
+                currentCard = 0;
+                parent.getComponent(0).setVisible(true);
+                parent.validate();
+            }
+        }
+    }
+
+    /**
+     * Flips to the next card of the specified container. If the
+     * currently visible card is the last one, this method flips to the
+     * first card in the layout.
+     * @param     parent   the parent container in which to do the layout
+     * @see       java.awt.CardLayout#previous
+     */
+    public void next(Container parent) {
+        synchronized (parent.getTreeLock()) {
+            checkLayout(parent);
+            int ncomponents = parent.getComponentCount();
+            for (int i = 0 ; i < ncomponents ; i++) {
+                Component comp = parent.getComponent(i);
+                if (comp.isVisible()) {
+                    comp.setVisible(false);
+                    currentCard = (i + 1) % ncomponents;
+                    comp = parent.getComponent(currentCard);
+                    comp.setVisible(true);
+                    parent.validate();
+                    return;
+                }
+            }
+            showDefaultComponent(parent);
+        }
+    }
+
+    /**
+     * Flips to the previous card of the specified container. If the
+     * currently visible card is the first one, this method flips to the
+     * last card in the layout.
+     * @param     parent   the parent container in which to do the layout
+     * @see       java.awt.CardLayout#next
+     */
+    public void previous(Container parent) {
+        synchronized (parent.getTreeLock()) {
+            checkLayout(parent);
+            int ncomponents = parent.getComponentCount();
+            for (int i = 0 ; i < ncomponents ; i++) {
+                Component comp = parent.getComponent(i);
+                if (comp.isVisible()) {
+                    comp.setVisible(false);
+                    currentCard = ((i > 0) ? i-1 : ncomponents-1);
+                    comp = parent.getComponent(currentCard);
+                    comp.setVisible(true);
+                    parent.validate();
+                    return;
+                }
+            }
+            showDefaultComponent(parent);
+        }
+    }
+
+    void showDefaultComponent(Container parent) {
+        if (parent.getComponentCount() > 0) {
+            currentCard = 0;
+            parent.getComponent(0).setVisible(true);
+            parent.validate();
+        }
+    }
+
+    /**
+     * Flips to the last card of the container.
+     * @param     parent   the parent container in which to do the layout
+     * @see       java.awt.CardLayout#first
+     */
+    public void last(Container parent) {
+        synchronized (parent.getTreeLock()) {
+            checkLayout(parent);
+            int ncomponents = parent.getComponentCount();
+            for (int i = 0 ; i < ncomponents ; i++) {
+                Component comp = parent.getComponent(i);
+                if (comp.isVisible()) {
+                    comp.setVisible(false);
+                    break;
+                }
+            }
+            if (ncomponents > 0) {
+                currentCard = ncomponents - 1;
+                parent.getComponent(currentCard).setVisible(true);
+                parent.validate();
+            }
+        }
+    }
+
+    /**
+     * Flips to the component that was added to this layout with the
+     * specified <code>name</code>, using <code>addLayoutComponent</code>.
+     * If no such component exists, then nothing happens.
+     * @param     parent   the parent container in which to do the layout
+     * @param     name     the component name
+     * @see       java.awt.CardLayout#addLayoutComponent(java.awt.Component, java.lang.Object)
+     */
+    public void show(Container parent, String name) {
+        synchronized (parent.getTreeLock()) {
+            checkLayout(parent);
+            Component next = null;
+            int ncomponents = vector.size();
+            for (int i = 0; i < ncomponents; i++) {
+                Card card = (Card)vector.get(i);
+                if (card.name.equals(name)) {
+                    next = card.comp;
+                    currentCard = i;
+                    break;
+                }
+            }
+            if ((next != null) && !next.isVisible()) {
+                ncomponents = parent.getComponentCount();
+                for (int i = 0; i < ncomponents; i++) {
+                    Component comp = parent.getComponent(i);
+                    if (comp.isVisible()) {
+                        comp.setVisible(false);
+                        break;
+                    }
+                }
+                next.setVisible(true);
+                parent.validate();
+            }
+        }
+    }
+
+    /**
+     * Returns a string representation of the state of this card layout.
+     * @return    a string representation of this card layout.
+     */
+    public String toString() {
+        return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + "]";
+    }
+
+    /**
+     * Reads serializable fields from stream.
+     */
+    private void readObject(ObjectInputStream s)
+        throws ClassNotFoundException, IOException
+    {
+        ObjectInputStream.GetField f = s.readFields();
+
+        hgap = f.get("hgap", 0);
+        vgap = f.get("vgap", 0);
+
+        if (f.defaulted("vector")) {
+            //  pre-1.4 stream
+            Hashtable tab = (Hashtable)f.get("tab", null);
+            vector = new Vector();
+            if (tab != null && !tab.isEmpty()) {
+                for (Enumeration e = tab.keys() ; e.hasMoreElements() ; ) {
+                    String key = (String)e.nextElement();
+                    Component comp = (Component)tab.get(key);
+                    vector.add(new Card(key, comp));
+                    if (comp.isVisible()) {
+                        currentCard = vector.size() - 1;
+                    }
+                }
+            }
+        } else {
+            vector = (Vector)f.get("vector", null);
+            currentCard = f.get("currentCard", 0);
+        }
+    }
+
+    /**
+     * Writes serializable fields to stream.
+     */
+    private void writeObject(ObjectOutputStream s)
+        throws IOException
+    {
+        Hashtable tab = new Hashtable();
+        int ncomponents = vector.size();
+        for (int i = 0; i < ncomponents; i++) {
+            Card card = (Card)vector.get(i);
+            tab.put(card.name, card.comp);
+        }
+
+        ObjectOutputStream.PutField f = s.putFields();
+        f.put("hgap", hgap);
+        f.put("vgap", vgap);
+        f.put("vector", vector);
+        f.put("currentCard", currentCard);
+        f.put("tab", tab);
+        s.writeFields();
+    }
+}