KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > awt > CardLayout


1 /*
2  * @(#)CardLayout.java 1.40 04/05/18
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.awt;
9
10 import java.util.Hashtable JavaDoc;
11 import java.util.Vector JavaDoc;
12 import java.util.Enumeration JavaDoc;
13
14 import java.io.Serializable JavaDoc;
15 import java.io.ObjectInputStream JavaDoc;
16 import java.io.ObjectOutputStream JavaDoc;
17 import java.io.ObjectStreamField JavaDoc;
18 import java.io.IOException JavaDoc;
19
20 /**
21  * A <code>CardLayout</code> object is a layout manager for a
22  * container. It treats each component in the container as a card.
23  * Only one card is visible at a time, and the container acts as
24  * a stack of cards. The first component added to a
25  * <code>CardLayout</code> object is the visible component when the
26  * container is first displayed.
27  * <p>
28  * The ordering of cards is determined by the container's own internal
29  * ordering of its component objects. <code>CardLayout</code>
30  * defines a set of methods that allow an application to flip
31  * through these cards sequentially, or to show a specified card.
32  * The {@link CardLayout#addLayoutComponent}
33  * method can be used to associate a string identifier with a given card
34  * for fast random access.
35  *
36  * @version 1.40 05/18/04
37  * @author Arthur van Hoff
38  * @see java.awt.Container
39  * @since JDK1.0
40  */

41
42 public class CardLayout implements LayoutManager2 JavaDoc,
43                    Serializable JavaDoc {
44
45     private static final long serialVersionUID = -4328196481005934313L;
46
47     /*
48      * This creates a Vector to store associated
49      * pairs of components and their names.
50      * @see java.util.Vector
51      */

52     Vector JavaDoc vector = new Vector JavaDoc();
53
54     /*
55      * A pair of Component and String that represents its name.
56      */

57     class Card implements Serializable JavaDoc {
58         static final long serialVersionUID = 6640330810709497518L;
59         public String JavaDoc name;
60         public Component JavaDoc comp;
61         public Card(String JavaDoc cardName, Component JavaDoc cardComponent) {
62             name = cardName;
63             comp = cardComponent;
64         }
65     }
66
67     /*
68      * Index of Component currently displayed by CardLayout.
69      */

70     int currentCard = 0;
71
72
73     /*
74     * A cards horizontal Layout gap (inset). It specifies
75     * the space between the left and right edges of a
76     * container and the current component.
77     * This should be a non negative Integer.
78     * @see getHgap()
79     * @see setHgap()
80     */

81     int hgap;
82
83     /*
84     * A cards vertical Layout gap (inset). It specifies
85     * the space between the top and bottom edges of a
86     * container and the current component.
87     * This should be a non negative Integer.
88     * @see getVgap()
89     * @see setVgap()
90     */

91     int vgap;
92
93     /**
94      * @serialField tab Hashtable
95      * deprectated, for forward compatibility only
96      * @serialField hgap int
97      * @serialField vgap int
98      * @serialField vector Vector
99      * @serialField currentCard int
100      */

101     private static final ObjectStreamField JavaDoc[] serialPersistentFields = {
102     new ObjectStreamField JavaDoc("tab", Hashtable JavaDoc.class),
103         new ObjectStreamField JavaDoc("hgap", Integer.TYPE),
104         new ObjectStreamField JavaDoc("vgap", Integer.TYPE),
105         new ObjectStreamField JavaDoc("vector", Vector JavaDoc.class),
106         new ObjectStreamField JavaDoc("currentCard", Integer.TYPE)
107     };
108
109     /**
110      * Creates a new card layout with gaps of size zero.
111      */

112     public CardLayout() {
113     this(0, 0);
114     }
115
116     /**
117      * Creates a new card layout with the specified horizontal and
118      * vertical gaps. The horizontal gaps are placed at the left and
119      * right edges. The vertical gaps are placed at the top and bottom
120      * edges.
121      * @param hgap the horizontal gap.
122      * @param vgap the vertical gap.
123      */

124     public CardLayout(int hgap, int vgap) {
125     this.hgap = hgap;
126     this.vgap = vgap;
127     }
128
129     /**
130      * Gets the horizontal gap between components.
131      * @return the horizontal gap between components.
132      * @see java.awt.CardLayout#setHgap(int)
133      * @see java.awt.CardLayout#getVgap()
134      * @since JDK1.1
135      */

136     public int getHgap() {
137     return hgap;
138     }
139
140     /**
141      * Sets the horizontal gap between components.
142      * @param hgap the horizontal gap between components.
143      * @see java.awt.CardLayout#getHgap()
144      * @see java.awt.CardLayout#setVgap(int)
145      * @since JDK1.1
146      */

147     public void setHgap(int hgap) {
148     this.hgap = hgap;
149     }
150
151     /**
152      * Gets the vertical gap between components.
153      * @return the vertical gap between components.
154      * @see java.awt.CardLayout#setVgap(int)
155      * @see java.awt.CardLayout#getHgap()
156      */

157     public int getVgap() {
158     return vgap;
159     }
160
161     /**
162      * Sets the vertical gap between components.
163      * @param vgap the vertical gap between components.
164      * @see java.awt.CardLayout#getVgap()
165      * @see java.awt.CardLayout#setHgap(int)
166      * @since JDK1.1
167      */

168     public void setVgap(int vgap) {
169     this.vgap = vgap;
170     }
171
172     /**
173      * Adds the specified component to this card layout's internal
174      * table of names. The object specified by <code>constraints</code>
175      * must be a string. The card layout stores this string as a key-value
176      * pair that can be used for random access to a particular card.
177      * By calling the <code>show</code> method, an application can
178      * display the component with the specified name.
179      * @param comp the component to be added.
180      * @param constraints a tag that identifies a particular
181      * card in the layout.
182      * @see java.awt.CardLayout#show(java.awt.Container, java.lang.String)
183      * @exception IllegalArgumentException if the constraint is not a string.
184      */

185     public void addLayoutComponent(Component JavaDoc comp, Object JavaDoc constraints) {
186       synchronized (comp.getTreeLock()) {
187     if (constraints instanceof String JavaDoc) {
188         addLayoutComponent((String JavaDoc)constraints, comp);
189     } else {
190         throw new IllegalArgumentException JavaDoc("cannot add to layout: constraint must be a string");
191     }
192       }
193     }
194
195     /**
196      * @deprecated replaced by
197      * <code>addLayoutComponent(Component, Object)</code>.
198      */

199     @Deprecated JavaDoc
200     public void addLayoutComponent(String JavaDoc name, Component JavaDoc comp) {
201         synchronized (comp.getTreeLock()) {
202             if (!vector.isEmpty()) {
203                 comp.setVisible(false);
204             }
205             for (int i=0; i < vector.size(); i++) {
206                 if (((Card)vector.get(i)).name.equals(name)) {
207                     ((Card)vector.get(i)).comp = comp;
208                     return;
209                 }
210             }
211             vector.add(new Card(name, comp));
212         }
213     }
214
215     /**
216      * Removes the specified component from the layout.
217      * @param comp the component to be removed.
218      * @see java.awt.Container#remove(java.awt.Component)
219      * @see java.awt.Container#removeAll()
220      */

221     public void removeLayoutComponent(Component JavaDoc comp) {
222         synchronized (comp.getTreeLock()) {
223             for (int i = 0; i < vector.size(); i++) {
224                 if (((Card)vector.get(i)).comp == comp) {
225                     // if we remove current component we should show next one
226
if (comp.isVisible() && (comp.getParent() != null)) {
227                         next(comp.getParent());
228                     }
229
230                     vector.remove(i);
231
232                     // correct currentCard if this is necessary
233
if (currentCard > i) {
234                         currentCard--;
235                     }
236                     break;
237                 }
238             }
239         }
240     }
241
242     /**
243      * Determines the preferred size of the container argument using
244      * this card layout.
245      * @param parent the parent container in which to do the layout
246      * @return the preferred dimensions to lay out the subcomponents
247      * of the specified container
248      * @see java.awt.Container#getPreferredSize
249      * @see java.awt.CardLayout#minimumLayoutSize
250      */

251     public Dimension JavaDoc preferredLayoutSize(Container JavaDoc parent) {
252         synchronized (parent.getTreeLock()) {
253             Insets JavaDoc insets = parent.getInsets();
254             int ncomponents = parent.getComponentCount();
255             int w = 0;
256             int h = 0;
257
258             for (int i = 0 ; i < ncomponents ; i++) {
259                 Component JavaDoc comp = parent.getComponent(i);
260                 Dimension JavaDoc d = comp.getPreferredSize();
261                 if (d.width > w) {
262                     w = d.width;
263                 }
264                 if (d.height > h) {
265                     h = d.height;
266                 }
267             }
268             return new Dimension JavaDoc(insets.left + insets.right + w + hgap*2,
269                                  insets.top + insets.bottom + h + vgap*2);
270         }
271     }
272
273     /**
274      * Calculates the minimum size for the specified panel.
275      * @param parent the parent container in which to do the layout
276      * @return the minimum dimensions required to lay out the
277      * subcomponents of the specified container
278      * @see java.awt.Container#doLayout
279      * @see java.awt.CardLayout#preferredLayoutSize
280      */

281     public Dimension JavaDoc minimumLayoutSize(Container JavaDoc parent) {
282         synchronized (parent.getTreeLock()) {
283             Insets JavaDoc insets = parent.getInsets();
284             int ncomponents = parent.getComponentCount();
285             int w = 0;
286             int h = 0;
287
288             for (int i = 0 ; i < ncomponents ; i++) {
289                 Component JavaDoc comp = parent.getComponent(i);
290                 Dimension JavaDoc d = comp.getMinimumSize();
291                 if (d.width > w) {
292                     w = d.width;
293                 }
294                 if (d.height > h) {
295                     h = d.height;
296                 }
297             }
298             return new Dimension JavaDoc(insets.left + insets.right + w + hgap*2,
299                                  insets.top + insets.bottom + h + vgap*2);
300         }
301     }
302
303     /**
304      * Returns the maximum dimensions for this layout given the components
305      * in the specified target container.
306      * @param target the component which needs to be laid out
307      * @see Container
308      * @see #minimumLayoutSize
309      * @see #preferredLayoutSize
310      */

311     public Dimension JavaDoc maximumLayoutSize(Container JavaDoc target) {
312     return new Dimension JavaDoc(Integer.MAX_VALUE, Integer.MAX_VALUE);
313     }
314
315     /**
316      * Returns the alignment along the x axis. This specifies how
317      * the component would like to be aligned relative to other
318      * components. The value should be a number between 0 and 1
319      * where 0 represents alignment along the origin, 1 is aligned
320      * the furthest away from the origin, 0.5 is centered, etc.
321      */

322     public float getLayoutAlignmentX(Container JavaDoc parent) {
323     return 0.5f;
324     }
325
326     /**
327      * Returns the alignment along the y axis. This specifies how
328      * the component would like to be aligned relative to other
329      * components. The value should be a number between 0 and 1
330      * where 0 represents alignment along the origin, 1 is aligned
331      * the furthest away from the origin, 0.5 is centered, etc.
332      */

333     public float getLayoutAlignmentY(Container JavaDoc parent) {
334     return 0.5f;
335     }
336
337     /**
338      * Invalidates the layout, indicating that if the layout manager
339      * has cached information it should be discarded.
340      */

341     public void invalidateLayout(Container JavaDoc target) {
342     }
343
344     /**
345      * Lays out the specified container using this card layout.
346      * <p>
347      * Each component in the <code>parent</code> container is reshaped
348      * to be the size of the container, minus space for surrounding
349      * insets, horizontal gaps, and vertical gaps.
350      *
351      * @param parent the parent container in which to do the layout
352      * @see java.awt.Container#doLayout
353      */

354     public void layoutContainer(Container JavaDoc parent) {
355         synchronized (parent.getTreeLock()) {
356             Insets JavaDoc insets = parent.getInsets();
357             int ncomponents = parent.getComponentCount();
358             Component JavaDoc comp = null;
359             boolean currentFound = false;
360
361             for (int i = 0 ; i < ncomponents ; i++) {
362                 comp = parent.getComponent(i);
363                 comp.setBounds(hgap + insets.left, vgap + insets.top,
364                                parent.width - (hgap*2 + insets.left + insets.right),
365                                parent.height - (vgap*2 + insets.top + insets.bottom));
366                 if (comp.isVisible()) {
367                     currentFound = true;
368                 }
369             }
370
371             if (!currentFound && ncomponents > 0) {
372                 parent.getComponent(0).setVisible(true);
373             }
374         }
375     }
376
377     /**
378      * Make sure that the Container really has a CardLayout installed.
379      * Otherwise havoc can ensue!
380      */

381     void checkLayout(Container JavaDoc parent) {
382     if (parent.getLayout() != this) {
383         throw new IllegalArgumentException JavaDoc("wrong parent for CardLayout");
384     }
385     }
386
387     /**
388      * Flips to the first card of the container.
389      * @param parent the parent container in which to do the layout
390      * @see java.awt.CardLayout#last
391      */

392     public void first(Container JavaDoc parent) {
393     synchronized (parent.getTreeLock()) {
394         checkLayout(parent);
395             int ncomponents = parent.getComponentCount();
396             for (int i = 0 ; i < ncomponents ; i++) {
397                 Component JavaDoc comp = parent.getComponent(i);
398                 if (comp.isVisible()) {
399                     comp.setVisible(false);
400                     break;
401                 }
402             }
403             if (ncomponents > 0) {
404                 currentCard = 0;
405                 parent.getComponent(0).setVisible(true);
406                 parent.validate();
407             }
408     }
409     }
410
411     /**
412      * Flips to the next card of the specified container. If the
413      * currently visible card is the last one, this method flips to the
414      * first card in the layout.
415      * @param parent the parent container in which to do the layout
416      * @see java.awt.CardLayout#previous
417      */

418     public void next(Container JavaDoc parent) {
419     synchronized (parent.getTreeLock()) {
420         checkLayout(parent);
421             int ncomponents = parent.getComponentCount();
422             for (int i = 0 ; i < ncomponents ; i++) {
423                 Component JavaDoc comp = parent.getComponent(i);
424                 if (comp.isVisible()) {
425                     comp.setVisible(false);
426                     currentCard = (i + 1) % ncomponents;
427                     comp = parent.getComponent(currentCard);
428                     comp.setVisible(true);
429                     parent.validate();
430                     return;
431                 }
432             }
433             showDefaultComponent(parent);
434     }
435     }
436
437     /**
438      * Flips to the previous card of the specified container. If the
439      * currently visible card is the first one, this method flips to the
440      * last card in the layout.
441      * @param parent the parent container in which to do the layout
442      * @see java.awt.CardLayout#next
443      */

444     public void previous(Container JavaDoc parent) {
445     synchronized (parent.getTreeLock()) {
446         checkLayout(parent);
447             int ncomponents = parent.getComponentCount();
448             for (int i = 0 ; i < ncomponents ; i++) {
449                 Component JavaDoc comp = parent.getComponent(i);
450                 if (comp.isVisible()) {
451                     comp.setVisible(false);
452                     currentCard = ((i > 0) ? i-1 : ncomponents-1);
453                     comp = parent.getComponent(currentCard);
454                     comp.setVisible(true);
455                     parent.validate();
456                     return;
457                 }
458             }
459             showDefaultComponent(parent);
460     }
461     }
462
463     void showDefaultComponent(Container JavaDoc parent) {
464         if (parent.getComponentCount() > 0) {
465             currentCard = 0;
466             parent.getComponent(0).setVisible(true);
467             parent.validate();
468         }
469     }
470
471     /**
472      * Flips to the last card of the container.
473      * @param parent the parent container in which to do the layout
474      * @see java.awt.CardLayout#first
475      */

476     public void last(Container JavaDoc parent) {
477     synchronized (parent.getTreeLock()) {
478         checkLayout(parent);
479             int ncomponents = parent.getComponentCount();
480             for (int i = 0 ; i < ncomponents ; i++) {
481                 Component JavaDoc comp = parent.getComponent(i);
482                 if (comp.isVisible()) {
483                     comp.setVisible(false);
484                     break;
485                 }
486             }
487             if (ncomponents > 0) {
488                 currentCard = ncomponents - 1;
489                 parent.getComponent(currentCard).setVisible(true);
490                 parent.validate();
491             }
492     }
493     }
494
495     /**
496      * Flips to the component that was added to this layout with the
497      * specified <code>name</code>, using <code>addLayoutComponent</code>.
498      * If no such component exists, then nothing happens.
499      * @param parent the parent container in which to do the layout
500      * @param name the component name
501      * @see java.awt.CardLayout#addLayoutComponent(java.awt.Component, java.lang.Object)
502      */

503     public void show(Container JavaDoc parent, String JavaDoc name) {
504     synchronized (parent.getTreeLock()) {
505         checkLayout(parent);
506             Component JavaDoc next = null;
507             int ncomponents = vector.size();
508             for (int i = 0; i < ncomponents; i++) {
509                 Card card = (Card)vector.get(i);
510                 if (card.name.equals(name)) {
511                     next = card.comp;
512                     currentCard = i;
513                     break;
514                 }
515             }
516             if ((next != null) && !next.isVisible()) {
517                 ncomponents = parent.getComponentCount();
518                 for (int i = 0; i < ncomponents; i++) {
519                     Component JavaDoc comp = parent.getComponent(i);
520                     if (comp.isVisible()) {
521                         comp.setVisible(false);
522                         break;
523                     }
524                 }
525                 next.setVisible(true);
526                 parent.validate();
527             }
528     }
529     }
530
531     /**
532      * Returns a string representation of the state of this card layout.
533      * @return a string representation of this card layout.
534      */

535     public String JavaDoc toString() {
536     return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + "]";
537     }
538
539     /**
540      * Reads serializable fields from stream.
541      */

542     private void readObject(ObjectInputStream JavaDoc s)
543     throws ClassNotFoundException JavaDoc, IOException JavaDoc
544     {
545         ObjectInputStream.GetField JavaDoc f = s.readFields();
546
547         hgap = f.get("hgap", 0);
548         vgap = f.get("vgap", 0);
549
550         if (f.defaulted("vector")) {
551             // pre-1.4 stream
552
Hashtable JavaDoc tab = (Hashtable JavaDoc)f.get("tab", null);
553             vector = new Vector JavaDoc();
554             if (tab != null && !tab.isEmpty()) {
555                 for (Enumeration JavaDoc e = tab.keys() ; e.hasMoreElements() ; ) {
556                     String JavaDoc key = (String JavaDoc)e.nextElement();
557                     Component JavaDoc comp = (Component JavaDoc)tab.get(key);
558                     vector.add(new Card(key, comp));
559                     if (comp.isVisible()) {
560                         currentCard = vector.size() - 1;
561                     }
562                 }
563             }
564         } else {
565             vector = (Vector JavaDoc)f.get("vector", null);
566             currentCard = f.get("currentCard", 0);
567         }
568     }
569
570     /**
571      * Writes serializable fields to stream.
572      */

573     private void writeObject(ObjectOutputStream JavaDoc s)
574         throws IOException JavaDoc
575     {
576         Hashtable JavaDoc tab = new Hashtable JavaDoc();
577         int ncomponents = vector.size();
578         for (int i = 0; i < ncomponents; i++) {
579             Card card = (Card)vector.get(i);
580             tab.put(card.name, card.comp);
581         }
582
583         ObjectOutputStream.PutField JavaDoc f = s.putFields();
584         f.put("hgap", hgap);
585         f.put("vgap", vgap);
586         f.put("vector", vector);
587         f.put("currentCard", currentCard);
588         f.put("tab", tab);
589         s.writeFields();
590     }
591 }
592
Popular Tags