OSDN Git Service

Merged gcj-eclipse branch to trunk.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / java / awt / CardLayout.java
1 /* CardLayout.java -- Card-based layout engine
2    Copyright (C) 1999, 2000, 2002, 2003, 2004  Free Software Foundation
3
4 This file is part of GNU Classpath.
5
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)
9 any later version.
10
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.
15
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
19 02110-1301 USA.
20
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
24 combination.
25
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. */
37
38
39 package java.awt;
40
41 import java.io.Serializable;
42 import java.util.Enumeration;
43 import java.util.Hashtable;
44
45 /**
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
49  * shown.
50  *
51  * @author Tom Tromey (tromey@redhat.com)
52  * @author Aaron M. Renn (arenn@urbanophile.com)
53  */
54 public class CardLayout implements LayoutManager2, Serializable
55 {
56   private static final long serialVersionUID = -4328196481005934313L;
57
58   /**
59    * Initializes a new instance of <code>CardLayout</code> with horizontal
60    * and vertical gaps of 0.
61    */
62   public CardLayout ()
63   {
64     this (0, 0);
65   }
66
67   /**
68    * Create a new <code>CardLayout</code> object with the specified
69    * horizontal and vertical gaps.
70    *
71    * @param hgap The horizontal gap
72    * @param vgap The vertical gap
73    */
74   public CardLayout (int hgap, int vgap)
75   {
76     this.hgap = hgap;
77     this.vgap = vgap;
78     this.tab = new Hashtable ();
79   }
80
81   /**
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.
85    *
86    * @param comp The component to add
87    * @param constraints The name by which the component can later be called
88    * 
89    * @exception IllegalArgumentException If `constraints' is not a
90    * <code>String</code>
91    */
92   public void addLayoutComponent (Component comp, Object constraints)
93   {
94     if (! (constraints instanceof String))
95       throw new IllegalArgumentException ("Object " + constraints
96                                           + " is not a string");
97     addLayoutComponent ((String) constraints, comp);
98   }
99
100   /**
101    * Add a new component to the layout.  The name can be used later
102    * to refer to the component.
103    * 
104    * @param name The name by which the component can later be called
105    * @param comp The component to add
106    * 
107    * @deprecated This method is deprecated in favor of
108    * <code>addLayoutComponent(Component, Object)</code>.
109    */
110   public void addLayoutComponent (String name, Component comp)
111   {
112     tab.put (name, comp);
113     // First component added is the default component.
114     comp.setVisible(tab.size() == 1);
115   }
116
117   /**
118    * Cause the first component in the container to be displayed.
119    *
120    * @param parent The parent container, not <code>null</code>.
121    */
122   public void first (Container parent)
123   {
124     gotoComponent (parent, FIRST);
125   }
126
127   /**
128    * Return this layout manager's horizontal gap.
129    *
130    * @return the horizontal gap
131    */
132   public int getHgap ()
133   {
134     return hgap;
135   }
136
137   /**
138    * Return this layout manager's x alignment.  This method always
139    * returns Component.CENTER_ALIGNMENT.
140    * 
141    * @param parent Container using this layout manager instance
142    *
143    * @return the x-axis alignment
144    */
145   public float getLayoutAlignmentX (Container parent)
146   {
147     return Component.CENTER_ALIGNMENT;
148   }
149
150   /**
151    * Returns this layout manager's y alignment.  This method always
152    * returns Component.CENTER_ALIGNMENT.
153    * 
154    * @param parent Container using this layout manager instance
155    *
156    * @return the y-axis alignment
157    */
158   public float getLayoutAlignmentY (Container parent)
159   {
160     return Component.CENTER_ALIGNMENT;
161   }
162
163   /**
164    * Return this layout manager's vertical gap.
165    *
166    * @return the vertical gap
167    */
168   public int getVgap ()
169   {
170     return vgap;
171   }
172
173   /**
174    * Invalidate this layout manager's state.
175    */
176   public void invalidateLayout (Container target)
177   {
178     // Do nothing.
179   }
180
181   /**
182    * Cause the last component in the container to be displayed.
183    * 
184    * @param parent The parent container, not <code>null</code>.
185    */
186   public void last (Container parent)
187   {
188     gotoComponent (parent, LAST);
189   }
190
191   /**
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.
194    *
195    * @param parent The parent container.
196    */ 
197   public void layoutContainer (Container parent)
198   {
199     synchronized (parent.getTreeLock ())
200       {
201         int width = parent.width;
202         int height = parent.height;
203
204         Insets ins = parent.getInsets ();
205
206         int num = parent.ncomponents;
207         Component[] comps = parent.component;
208
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;
213
214         for (int i = 0; i < num; ++i)
215           comps[i].setBounds (x, y, width, height);
216       }
217   }
218
219   /**
220    * Get the maximum layout size of the container.
221    * 
222    * @param target The parent container
223    *
224    * @return the maximum layout size
225    */
226   public Dimension maximumLayoutSize (Container target)
227   {
228     if (target == null)
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);
233   }
234
235   /**
236    * Get the minimum layout size of the container.
237    * 
238    * @param target The parent container
239    *
240    * @return the minimum layout size
241    */
242   public Dimension minimumLayoutSize (Container target)
243   {
244     return getSize (target, MIN);
245   }
246
247   /**
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.
251    * 
252    * @param parent The parent container, not <code>null</code>.
253    */
254   public void next (Container parent)
255   {
256     gotoComponent (parent, NEXT);
257   }
258
259   /**
260    * Get the preferred layout size of the container.
261    * 
262    * @param parent The parent container
263    *
264    * @return the preferred layout size
265    */
266   public Dimension preferredLayoutSize (Container parent)
267   {
268     return getSize (parent, PREF);
269   }
270
271   /**
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.
275    * 
276    * @param parent The parent container, not <code>null</code>.
277    */
278   public void previous (Container parent)
279   {
280     gotoComponent (parent, PREV);
281   }
282
283   /**
284    * Remove the indicated component from this layout manager.
285    * 
286    * @param comp The component to remove
287    */
288   public void removeLayoutComponent (Component comp)
289   {
290     Enumeration e = tab.keys ();
291     while (e.hasMoreElements ())
292       {
293         Object key = e.nextElement ();
294         if (tab.get (key) == comp)
295           {
296             tab.remove (key);
297             Container parent = comp.getParent();
298             next(parent);
299             break;
300           }
301       }
302   }
303
304   /**
305    * Set this layout manager's horizontal gap.
306    * 
307    * @param hgap The new gap
308    */
309   public void setHgap (int hgap)
310   {
311     this.hgap = hgap;
312   }
313
314   /**
315    * Set this layout manager's vertical gap.
316    * 
317    * @param vgap The new gap
318    */
319   public void setVgap (int vgap)
320   {
321     this.vgap = vgap;
322   }
323
324   /**
325    * Cause the named component to be shown.  If the component name is
326    * unknown or <code>null</code>, this method does nothing.
327    * 
328    * @param parent The parent container, not <code>null</code>.
329    * @param name The name of the component to show 
330    */
331   public void show (Container parent, String name)
332   {
333     if (name == null)
334       return;
335    
336     if (parent.getLayout() != this)
337       throw new IllegalArgumentException("parent's layout is not this CardLayout");
338     
339     Object target = tab.get (name);
340     if (target != null)
341       {
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)
346           {
347             if (comps[i].isVisible())
348               {
349                 if (target == comps[i])
350                   return;
351                 comps[i].setVisible (false);
352               }
353           }
354         ((Component) target).setVisible (true);
355         parent.validate();
356       }
357   }
358
359   /**
360    * Returns a string representation of this layout manager.
361    *
362    * @return A string representation of this object.
363    */
364   public String toString ()
365   {
366     return getClass ().getName () + "[hgap=" + hgap + ",vgap=" + vgap + "]";
367   }
368
369   /**
370    * This implements first(), last(), next(), and previous().
371    * 
372    * @param parent The parent container
373    * @param what The type of goto: FIRST, LAST, NEXT or PREV
374    * 
375    * @throws IllegalArgumentException if parent has not this 
376    * CardLayout set as its layout.
377    */
378   private void gotoComponent (Container parent, int what)
379   {
380     if (parent.getLayout() != this)
381       throw new IllegalArgumentException("parent's layout is not this CardLayout");
382     
383     synchronized (parent.getTreeLock ())
384       {
385         int num = parent.ncomponents;
386         // This is more efficient than calling getComponents().
387         Component[] comps = parent.component;
388
389         if (num == 1)
390           {
391             comps[0].setVisible(true);
392             return;
393           }
394
395         int choice = -1;
396
397         if (what == FIRST)
398           choice = 0;
399         else if (what == LAST)
400           choice = num - 1;
401
402         for (int i = 0; i < num; ++i)
403           {
404             if (comps[i].isVisible ())
405               {
406                 if (choice == i)
407                   {
408                     // Do nothing if we're already looking at the right
409                     // component.
410                     return;
411                   }
412                 else if (what == PREV)
413                   {
414                     choice = i - 1;
415                     if (choice < 0)
416                       choice = num - 1;
417                   }
418                 else if (what == NEXT)
419                   {
420                     choice = i + 1;
421                     if (choice == num)
422                       choice = 0;
423                   }
424                 comps[i].setVisible (false);
425  
426                 if (choice >= 0)
427                   break;
428               } else 
429                 {
430                   comps[i].setVisible(true);
431                 }
432           }
433
434         if (choice >= 0 && choice < num)
435           comps[choice].setVisible (true);
436       }
437   }
438
439   // Compute the size according to WHAT.
440   private Dimension getSize (Container parent, int what)
441   {
442     synchronized (parent.getTreeLock ())
443       {
444         int w = 0, h = 0, num = parent.ncomponents;
445         Component[] comps = parent.component;
446
447         for (int i = 0; i < num; ++i)
448           {
449             Dimension d;
450
451             if (what == MIN)
452               d = comps[i].getMinimumSize ();
453             else if (what == MAX)
454               d = comps[i].getMaximumSize ();
455             else
456               d = comps[i].getPreferredSize ();
457
458             w = Math.max (d.width, w);
459             h = Math.max (d.height, h);
460           }
461
462         Insets i = parent.getInsets ();
463         w += 2 * hgap + i.right + i.left;
464         h += 2 * vgap + i.bottom + i.top;
465
466         // Handle overflow.
467         if (w < 0)
468           w = Integer.MAX_VALUE;
469         if (h < 0)
470           h = Integer.MAX_VALUE;
471
472         return new Dimension (w, h);
473       }
474   }
475
476   /**
477    * @serial Horizontal gap value.
478    */
479   private int hgap;
480
481   /**
482    * @serial Vertical gap value.
483    */
484   private int vgap;
485
486   /**
487    * @serial Table of named components.
488    */
489   private Hashtable tab;
490
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;
496
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;
501 }