2
* Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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.
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
28
import java.io.IOException;
29
import java.io.ObjectInputStream;
30
import java.io.ObjectOutputStream;
31
import java.io.ObjectStreamField;
33
import java.io.Serializable;
34
import java.util.Enumeration;
35
import java.util.Hashtable;
36
import java.util.Vector;
39
* A {@code CardLayout} 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} object is the visible component when the
44
* container is first displayed.
46
* The ordering of cards is determined by the container's own internal
47
* ordering of its component objects. {@code CardLayout}
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.
54
* @author Arthur van Hoff
55
* @see java.awt.Container
59
public class CardLayout implements LayoutManager2,
62
* Use serialVersionUID from JDK 1.4 for interoperability.
65
private static final long serialVersionUID = -4328196481005934313L;
68
* This creates a Vector to store associated
69
* pairs of components and their names.
70
* @see java.util.Vector
72
Vector<Card> vector = new Vector<>();
75
* A pair of component and string that represents its name.
77
static class Card implements Serializable {
80
* Use serialVersionUID from JDK 1.4 for interoperability.
83
private static final long serialVersionUID = 6640330810709497518L;
85
public Component comp;
86
public Card(String cardName, Component cardComponent) {
93
* Index of Component currently displayed by CardLayout.
99
* A cards horizontal Layout gap (inset). It specifies
100
* the space between the left and right edges of a
101
* container and the current component.
102
* This should be a non negative Integer.
109
* A cards vertical Layout gap (inset). It specifies
110
* the space between the top and bottom edges of a
111
* container and the current component.
112
* This should be a non negative Integer.
119
* @serialField tab Hashtable
120
* deprecated, for forward compatibility only
121
* @serialField hgap int the horizontal Layout gap
122
* @serialField vgap int the vertical Layout gap
123
* @serialField vector Vector the pairs of components and their names
124
* @serialField currentCard int the index of Component currently displayed
127
private static final ObjectStreamField[] serialPersistentFields = {
128
new ObjectStreamField("tab", Hashtable.class),
129
new ObjectStreamField("hgap", Integer.TYPE),
130
new ObjectStreamField("vgap", Integer.TYPE),
131
new ObjectStreamField("vector", Vector.class),
132
new ObjectStreamField("currentCard", Integer.TYPE)
136
* Creates a new card layout with gaps of size zero.
138
public CardLayout() {
143
* Creates a new card layout with the specified horizontal and
144
* vertical gaps. The horizontal gaps are placed at the left and
145
* right edges. The vertical gaps are placed at the top and bottom
147
* @param hgap the horizontal gap.
148
* @param vgap the vertical gap.
150
public CardLayout(int hgap, int vgap) {
156
* Gets the horizontal gap between components.
157
* @return the horizontal gap between components.
158
* @see java.awt.CardLayout#setHgap(int)
159
* @see java.awt.CardLayout#getVgap()
162
public int getHgap() {
167
* Sets the horizontal gap between components.
168
* @param hgap the horizontal gap between components.
169
* @see java.awt.CardLayout#getHgap()
170
* @see java.awt.CardLayout#setVgap(int)
173
public void setHgap(int hgap) {
178
* Gets the vertical gap between components.
179
* @return the vertical gap between components.
180
* @see java.awt.CardLayout#setVgap(int)
181
* @see java.awt.CardLayout#getHgap()
183
public int getVgap() {
188
* Sets the vertical gap between components.
189
* @param vgap the vertical gap between components.
190
* @see java.awt.CardLayout#getVgap()
191
* @see java.awt.CardLayout#setHgap(int)
194
public void setVgap(int vgap) {
199
* Adds the specified component to this card layout's internal
200
* table of names. The object specified by {@code constraints}
201
* must be a string. The card layout stores this string as a key-value
202
* pair that can be used for random access to a particular card.
203
* By calling the {@code show} method, an application can
204
* display the component with the specified name.
205
* @param comp the component to be added.
206
* @param constraints a tag that identifies a particular
207
* card in the layout.
208
* @see java.awt.CardLayout#show(java.awt.Container, java.lang.String)
209
* @throws IllegalArgumentException if the constraint is not a string.
211
public void addLayoutComponent(Component comp, Object constraints) {
212
synchronized (comp.getTreeLock()) {
213
if (constraints == null){
216
if (constraints instanceof String) {
217
addLayoutComponent((String)constraints, comp);
219
throw new IllegalArgumentException("cannot add to layout: constraint must be a string");
225
* @deprecated replaced by
226
* {@code addLayoutComponent(Component, Object)}.
229
public void addLayoutComponent(String name, Component comp) {
230
synchronized (comp.getTreeLock()) {
231
if (!vector.isEmpty()) {
232
comp.setVisible(false);
234
for (int i=0; i < vector.size(); i++) {
235
if ((vector.get(i)).name.equals(name)) {
236
(vector.get(i)).comp = comp;
240
vector.add(new Card(name, comp));
245
* Removes the specified component from the layout.
246
* If the card was visible on top, the next card underneath it is shown.
247
* @param comp the component to be removed.
248
* @see java.awt.Container#remove(java.awt.Component)
249
* @see java.awt.Container#removeAll()
251
public void removeLayoutComponent(Component comp) {
252
synchronized (comp.getTreeLock()) {
253
for (int i = 0; i < vector.size(); i++) {
254
if ((vector.get(i)).comp == comp) {
255
// if we remove current component we should show next one
256
if (comp.isVisible() && (comp.getParent() != null)) {
257
next(comp.getParent());
262
// correct currentCard if this is necessary
263
if (currentCard > i) {
273
* Determines the preferred size of the container argument using
275
* @param parent the parent container in which to do the layout
276
* @return the preferred dimensions to lay out the subcomponents
277
* of the specified container
278
* @see java.awt.Container#getPreferredSize
279
* @see java.awt.CardLayout#minimumLayoutSize
281
public Dimension preferredLayoutSize(Container parent) {
282
synchronized (parent.getTreeLock()) {
283
Insets insets = parent.getInsets();
284
int ncomponents = parent.getComponentCount();
288
for (int i = 0 ; i < ncomponents ; i++) {
289
Component comp = parent.getComponent(i);
290
Dimension d = comp.getPreferredSize();
298
return new Dimension(insets.left + insets.right + w + hgap*2,
299
insets.top + insets.bottom + h + vgap*2);
304
* Calculates the minimum size for the specified panel.
305
* @param parent the parent container in which to do the layout
306
* @return the minimum dimensions required to lay out the
307
* subcomponents of the specified container
308
* @see java.awt.Container#doLayout
309
* @see java.awt.CardLayout#preferredLayoutSize
311
public Dimension minimumLayoutSize(Container parent) {
312
synchronized (parent.getTreeLock()) {
313
Insets insets = parent.getInsets();
314
int ncomponents = parent.getComponentCount();
318
for (int i = 0 ; i < ncomponents ; i++) {
319
Component comp = parent.getComponent(i);
320
Dimension d = comp.getMinimumSize();
328
return new Dimension(insets.left + insets.right + w + hgap*2,
329
insets.top + insets.bottom + h + vgap*2);
334
* Returns the maximum dimensions for this layout given the components
335
* in the specified target container.
336
* @param target the component which needs to be laid out
338
* @see #minimumLayoutSize
339
* @see #preferredLayoutSize
341
public Dimension maximumLayoutSize(Container target) {
342
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
346
* Returns the alignment along the x axis. This specifies how
347
* the component would like to be aligned relative to other
348
* components. The value should be a number between 0 and 1
349
* where 0 represents alignment along the origin, 1 is aligned
350
* the furthest away from the origin, 0.5 is centered, etc.
352
public float getLayoutAlignmentX(Container parent) {
357
* Returns the alignment along the y axis. This specifies how
358
* the component would like to be aligned relative to other
359
* components. The value should be a number between 0 and 1
360
* where 0 represents alignment along the origin, 1 is aligned
361
* the furthest away from the origin, 0.5 is centered, etc.
363
public float getLayoutAlignmentY(Container parent) {
368
* Invalidates the layout, indicating that if the layout manager
369
* has cached information it should be discarded.
371
public void invalidateLayout(Container target) {
375
* Lays out the specified container using this card layout.
377
* Each component in the {@code parent} container is reshaped
378
* to be the size of the container, minus space for surrounding
379
* insets, horizontal gaps, and vertical gaps.
381
* @param parent the parent container in which to do the layout
382
* @see java.awt.Container#doLayout
384
public void layoutContainer(Container parent) {
385
synchronized (parent.getTreeLock()) {
386
Insets insets = parent.getInsets();
387
int ncomponents = parent.getComponentCount();
388
Component comp = null;
389
boolean currentFound = false;
391
for (int i = 0 ; i < ncomponents ; i++) {
392
comp = parent.getComponent(i);
393
comp.setBounds(hgap + insets.left, vgap + insets.top,
394
parent.width - (hgap*2 + insets.left + insets.right),
395
parent.height - (vgap*2 + insets.top + insets.bottom));
396
if (comp.isVisible()) {
401
if (!currentFound && ncomponents > 0) {
402
parent.getComponent(0).setVisible(true);
408
* Make sure that the Container really has a CardLayout installed.
409
* Otherwise havoc can ensue!
411
void checkLayout(Container parent) {
412
if (parent.getLayout() != this) {
413
throw new IllegalArgumentException("wrong parent for CardLayout");
418
* Flips to the first card of the container.
419
* @param parent the parent container in which to do the layout
420
* @see java.awt.CardLayout#last
422
public void first(Container parent) {
423
synchronized (parent.getTreeLock()) {
425
int ncomponents = parent.getComponentCount();
426
for (int i = 0 ; i < ncomponents ; i++) {
427
Component comp = parent.getComponent(i);
428
if (comp.isVisible()) {
429
comp.setVisible(false);
433
if (ncomponents > 0) {
435
parent.getComponent(0).setVisible(true);
442
* Flips to the next card of the specified container. If the
443
* currently visible card is the last one, this method flips to the
444
* first card in the layout.
445
* @param parent the parent container in which to do the layout
446
* @see java.awt.CardLayout#previous
448
public void next(Container parent) {
449
synchronized (parent.getTreeLock()) {
451
int ncomponents = parent.getComponentCount();
452
for (int i = 0 ; i < ncomponents ; i++) {
453
Component comp = parent.getComponent(i);
454
if (comp.isVisible()) {
455
comp.setVisible(false);
456
currentCard = (i + 1) % ncomponents;
457
comp = parent.getComponent(currentCard);
458
comp.setVisible(true);
463
showDefaultComponent(parent);
468
* Flips to the previous card of the specified container. If the
469
* currently visible card is the first one, this method flips to the
470
* last card in the layout.
471
* @param parent the parent container in which to do the layout
472
* @see java.awt.CardLayout#next
474
public void previous(Container parent) {
475
synchronized (parent.getTreeLock()) {
477
int ncomponents = parent.getComponentCount();
478
for (int i = 0 ; i < ncomponents ; i++) {
479
Component comp = parent.getComponent(i);
480
if (comp.isVisible()) {
481
comp.setVisible(false);
482
currentCard = ((i > 0) ? i-1 : ncomponents-1);
483
comp = parent.getComponent(currentCard);
484
comp.setVisible(true);
489
showDefaultComponent(parent);
493
void showDefaultComponent(Container parent) {
494
if (parent.getComponentCount() > 0) {
496
parent.getComponent(0).setVisible(true);
502
* Flips to the last card of the container.
503
* @param parent the parent container in which to do the layout
504
* @see java.awt.CardLayout#first
506
public void last(Container parent) {
507
synchronized (parent.getTreeLock()) {
509
int ncomponents = parent.getComponentCount();
510
for (int i = 0 ; i < ncomponents ; i++) {
511
Component comp = parent.getComponent(i);
512
if (comp.isVisible()) {
513
comp.setVisible(false);
517
if (ncomponents > 0) {
518
currentCard = ncomponents - 1;
519
parent.getComponent(currentCard).setVisible(true);
526
* Flips to the component that was added to this layout with the
527
* specified {@code name}, using {@code addLayoutComponent}.
528
* If no such component exists, then nothing happens.
529
* @param parent the parent container in which to do the layout
530
* @param name the component name
531
* @see java.awt.CardLayout#addLayoutComponent(java.awt.Component, java.lang.Object)
533
public void show(Container parent, String name) {
534
synchronized (parent.getTreeLock()) {
536
Component next = null;
537
int ncomponents = vector.size();
538
for (int i = 0; i < ncomponents; i++) {
539
Card card = vector.get(i);
540
if (card.name.equals(name)) {
546
if ((next != null) && !next.isVisible()) {
547
ncomponents = parent.getComponentCount();
548
for (int i = 0; i < ncomponents; i++) {
549
Component comp = parent.getComponent(i);
550
if (comp.isVisible()) {
551
comp.setVisible(false);
555
next.setVisible(true);
562
* Returns a string representation of the state of this card layout.
563
* @return a string representation of this card layout.
565
public String toString() {
566
return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + "]";
570
* Reads serializable fields from stream.
572
* @param s the {@code ObjectInputStream} to read
573
* @throws ClassNotFoundException if the class of a serialized object could
575
* @throws IOException if an I/O error occurs
578
@SuppressWarnings("unchecked")
579
private void readObject(ObjectInputStream s)
580
throws ClassNotFoundException, IOException
582
ObjectInputStream.GetField f = s.readFields();
584
hgap = f.get("hgap", 0);
585
vgap = f.get("vgap", 0);
587
if (f.defaulted("vector")) {
589
Hashtable<String, Component> tab = (Hashtable)f.get("tab", null);
590
vector = new Vector<>();
591
if (tab != null && !tab.isEmpty()) {
592
for (Enumeration<String> e = tab.keys() ; e.hasMoreElements() ; ) {
593
String key = e.nextElement();
594
Component comp = tab.get(key);
595
vector.add(new Card(key, comp));
596
if (comp.isVisible()) {
597
currentCard = vector.size() - 1;
602
vector = (Vector)f.get("vector", null);
603
currentCard = f.get("currentCard", 0);
608
* Writes serializable fields to stream.
610
* @param s the {@code ObjectOutputStream} to write
611
* @throws IOException if an I/O error occurs
614
private void writeObject(ObjectOutputStream s)
617
Hashtable<String, Component> tab = new Hashtable<>();
618
int ncomponents = vector.size();
619
for (int i = 0; i < ncomponents; i++) {
620
Card card = vector.get(i);
621
tab.put(card.name, card.comp);
624
ObjectOutputStream.PutField f = s.putFields();
627
f.put("vector", vector);
628
f.put("currentCard", currentCard);