1 /* CardLayout.java -- Card-based layout engine
2 Copyright (C) 1999, 2000, 2002, 2003, 2004 Free Software Foundation
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
41 import java.io.Serializable;
42 import java.util.Enumeration;
43 import java.util.Hashtable;
46 * This class implements a card-based layout scheme. Each included
47 * component is treated as a card. Only one card can be shown at a
48 * time. This class includes methods for changing which card is
51 * @author Tom Tromey (tromey@redhat.com)
52 * @author Aaron M. Renn (arenn@urbanophile.com)
54 public class CardLayout implements LayoutManager2, Serializable
56 private static final long serialVersionUID = -4328196481005934313L;
59 * Initializes a new instance of <code>CardLayout</code> with horizontal
60 * and vertical gaps of 0.
68 * Create a new <code>CardLayout</code> object with the specified
69 * horizontal and vertical gaps.
71 * @param hgap The horizontal gap
72 * @param vgap The vertical gap
74 public CardLayout (int hgap, int vgap)
78 this.tab = new Hashtable ();
82 * Add a new component to the layout. The constraint must be a
83 * string which is used to name the component. This string can
84 * later be used to refer to the particular component.
86 * @param comp The component to add
87 * @param constraints The name by which the component can later be called
89 * @exception IllegalArgumentException If `constraints' is not a
92 public void addLayoutComponent (Component comp, Object constraints)
94 if (! (constraints instanceof String))
95 throw new IllegalArgumentException ("Object " + constraints
96 + " is not a string");
97 addLayoutComponent ((String) constraints, comp);
101 * Add a new component to the layout. The name can be used later
102 * to refer to the component.
104 * @param name The name by which the component can later be called
105 * @param comp The component to add
107 * @deprecated This method is deprecated in favor of
108 * <code>addLayoutComponent(Component, Object)</code>.
110 public void addLayoutComponent (String name, Component comp)
112 tab.put (name, comp);
113 // First component added is the default component.
114 comp.setVisible(tab.size() == 1);
118 * Cause the first component in the container to be displayed.
120 * @param parent The parent container, not <code>null</code>.
122 public void first (Container parent)
124 gotoComponent (parent, FIRST);
128 * Return this layout manager's horizontal gap.
130 * @return the horizontal gap
132 public int getHgap ()
138 * Return this layout manager's x alignment. This method always
139 * returns Component.CENTER_ALIGNMENT.
141 * @param parent Container using this layout manager instance
143 * @return the x-axis alignment
145 public float getLayoutAlignmentX (Container parent)
147 return Component.CENTER_ALIGNMENT;
151 * Returns this layout manager's y alignment. This method always
152 * returns Component.CENTER_ALIGNMENT.
154 * @param parent Container using this layout manager instance
156 * @return the y-axis alignment
158 public float getLayoutAlignmentY (Container parent)
160 return Component.CENTER_ALIGNMENT;
164 * Return this layout manager's vertical gap.
166 * @return the vertical gap
168 public int getVgap ()
174 * Invalidate this layout manager's state.
176 public void invalidateLayout (Container target)
182 * Cause the last component in the container to be displayed.
184 * @param parent The parent container, not <code>null</code>.
186 public void last (Container parent)
188 gotoComponent (parent, LAST);
192 * Lays out the container. This is done by resizing the child components
193 * to be the same size as the parent, less insets and gaps.
195 * @param parent The parent container.
197 public void layoutContainer (Container parent)
199 synchronized (parent.getTreeLock ())
201 int width = parent.width;
202 int height = parent.height;
204 Insets ins = parent.getInsets ();
206 int num = parent.ncomponents;
207 Component[] comps = parent.component;
209 int x = ins.left + hgap;
210 int y = ins.top + vgap;
211 width = width - 2 * hgap - ins.left - ins.right;
212 height = height - 2 * vgap - ins.top - ins.bottom;
214 for (int i = 0; i < num; ++i)
215 comps[i].setBounds (x, y, width, height);
220 * Get the maximum layout size of the container.
222 * @param target The parent container
224 * @return the maximum layout size
226 public Dimension maximumLayoutSize (Container target)
229 return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
230 // The JCL says that this returns Integer.MAX_VALUE for both
231 // dimensions. But that just seems wrong to me.
232 return getSize (target, MAX);
236 * Get the minimum layout size of the container.
238 * @param target The parent container
240 * @return the minimum layout size
242 public Dimension minimumLayoutSize (Container target)
244 return getSize (target, MIN);
248 * Cause the next component in the container to be displayed. If
249 * this current card is the last one in the deck, the first
250 * component is displayed.
252 * @param parent The parent container, not <code>null</code>.
254 public void next (Container parent)
256 gotoComponent (parent, NEXT);
260 * Get the preferred layout size of the container.
262 * @param parent The parent container
264 * @return the preferred layout size
266 public Dimension preferredLayoutSize (Container parent)
268 return getSize (parent, PREF);
272 * Cause the previous component in the container to be displayed.
273 * If this current card is the first one in the deck, the last
274 * component is displayed.
276 * @param parent The parent container, not <code>null</code>.
278 public void previous (Container parent)
280 gotoComponent (parent, PREV);
284 * Remove the indicated component from this layout manager.
286 * @param comp The component to remove
288 public void removeLayoutComponent (Component comp)
290 Enumeration e = tab.keys ();
291 while (e.hasMoreElements ())
293 Object key = e.nextElement ();
294 if (tab.get (key) == comp)
297 Container parent = comp.getParent();
305 * Set this layout manager's horizontal gap.
307 * @param hgap The new gap
309 public void setHgap (int hgap)
315 * Set this layout manager's vertical gap.
317 * @param vgap The new gap
319 public void setVgap (int vgap)
325 * Cause the named component to be shown. If the component name is
326 * unknown or <code>null</code>, this method does nothing.
328 * @param parent The parent container, not <code>null</code>.
329 * @param name The name of the component to show
331 public void show (Container parent, String name)
336 if (parent.getLayout() != this)
337 throw new IllegalArgumentException("parent's layout is not this CardLayout");
339 Object target = tab.get (name);
342 int num = parent.ncomponents;
343 // This is more efficient than calling getComponents().
344 Component[] comps = parent.component;
345 for (int i = 0; i < num; ++i)
347 if (comps[i].isVisible())
349 if (target == comps[i])
351 comps[i].setVisible (false);
354 ((Component) target).setVisible (true);
360 * Returns a string representation of this layout manager.
362 * @return A string representation of this object.
364 public String toString ()
366 return getClass ().getName () + "[hgap=" + hgap + ",vgap=" + vgap + "]";
370 * This implements first(), last(), next(), and previous().
372 * @param parent The parent container
373 * @param what The type of goto: FIRST, LAST, NEXT or PREV
375 * @throws IllegalArgumentException if parent has not this
376 * CardLayout set as its layout.
378 private void gotoComponent (Container parent, int what)
380 if (parent.getLayout() != this)
381 throw new IllegalArgumentException("parent's layout is not this CardLayout");
383 synchronized (parent.getTreeLock ())
385 int num = parent.ncomponents;
386 // This is more efficient than calling getComponents().
387 Component[] comps = parent.component;
391 comps[0].setVisible(true);
399 else if (what == LAST)
402 for (int i = 0; i < num; ++i)
404 if (comps[i].isVisible ())
408 // Do nothing if we're already looking at the right
412 else if (what == PREV)
418 else if (what == NEXT)
424 comps[i].setVisible (false);
430 comps[i].setVisible(true);
434 if (choice >= 0 && choice < num)
435 comps[choice].setVisible (true);
439 // Compute the size according to WHAT.
440 private Dimension getSize (Container parent, int what)
442 synchronized (parent.getTreeLock ())
444 int w = 0, h = 0, num = parent.ncomponents;
445 Component[] comps = parent.component;
447 for (int i = 0; i < num; ++i)
452 d = comps[i].getMinimumSize ();
453 else if (what == MAX)
454 d = comps[i].getMaximumSize ();
456 d = comps[i].getPreferredSize ();
458 w = Math.max (d.width, w);
459 h = Math.max (d.height, h);
462 Insets i = parent.getInsets ();
463 w += 2 * hgap + i.right + i.left;
464 h += 2 * vgap + i.bottom + i.top;
468 w = Integer.MAX_VALUE;
470 h = Integer.MAX_VALUE;
472 return new Dimension (w, h);
477 * @serial Horizontal gap value.
482 * @serial Vertical gap value.
487 * @serial Table of named components.
489 private Hashtable tab;
491 // These constants are used by the private gotoComponent method.
492 private static final int FIRST = 0;
493 private static final int LAST = 1;
494 private static final int NEXT = 2;
495 private static final int PREV = 3;
497 // These constants are used by the private getSize method.
498 private static final int MIN = 0;
499 private static final int MAX = 1;
500 private static final int PREF = 2;