OSDN Git Service

adf2ebf65f63d758fd7d90a978b73cd4c75bdbaf
[pf3gnuchains/gcc-fork.git] / libjava / classpath / java / awt / BorderLayout.java
1 /* BorderLayout.java -- A layout manager class
2    Copyright (C) 1999, 2002, 2005  Free Software Foundation, Inc.
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 /**
42   * This class implements a layout manager that positions components
43   * in certain sectors of the parent container.
44   *
45   * @author Aaron M. Renn (arenn@urbanophile.com)
46   * @author Rolf W. Rasmussen  (rolfwr@ii.uib.no)
47   */
48 public class BorderLayout implements LayoutManager2, java.io.Serializable
49 {
50
51   /**
52    * Constant indicating the top of the container
53    */
54   public static final String NORTH = "North";
55
56   /**
57    * Constant indicating the bottom of the container
58    */
59   public static final String SOUTH = "South";
60
61   /**
62    * Constant indicating the right side of the container
63    */
64   public static final String EAST = "East";
65
66   /**
67    * Constant indicating the left side of the container
68    */
69   public static final String WEST = "West";
70
71   /**
72    * Constant indicating the center of the container
73    */
74   public static final String CENTER = "Center";
75
76
77   /**
78    * The constant indicating the position before the first line of the
79    * layout.  The exact position depends on the writing system: For a
80    * top-to-bottom orientation, it is the same as {@link #NORTH}, for
81    * a bottom-to-top orientation, it is the same as {@link #SOUTH}.
82    *
83    * <p>This constant is an older name for {@link #PAGE_START} which
84    * has exactly the same value.
85    *
86    * @since 1.2
87    */
88   public static final String BEFORE_FIRST_LINE = "First";
89
90   /**
91    * The constant indicating the position after the last line of the
92    * layout.  The exact position depends on the writing system: For a
93    * top-to-bottom orientation, it is the same as {@link #SOUTH}, for
94    * a bottom-to-top orientation, it is the same as {@link #NORTH}.
95    *
96    * <p>This constant is an older name for {@link #PAGE_END} which
97    * has exactly the same value.
98    *
99    * @since 1.2
100    */
101   public static final String AFTER_LAST_LINE = "Last";
102
103   /**
104    * The constant indicating the position before the first item of the
105    * layout.  The exact position depends on the writing system: For a
106    * left-to-right orientation, it is the same as {@link #WEST}, for
107    * a right-to-left orientation, it is the same as {@link #EAST}.
108    *
109    * <p>This constant is an older name for {@link #LINE_START} which
110    * has exactly the same value.
111    *
112    * @since 1.2
113    */
114   public static final String BEFORE_LINE_BEGINS = "Before";
115
116   /**
117    * The constant indicating the position after the last item of the
118    * layout.  The exact position depends on the writing system: For a
119    * left-to-right orientation, it is the same as {@link #EAST}, for
120    * a right-to-left orientation, it is the same as {@link #WEST}.
121    *
122    * <p>This constant is an older name for {@link #LINE_END} which
123    * has exactly the same value.
124    *
125    * @since 1.2
126    */
127   public static final String AFTER_LINE_ENDS = "After";
128
129   /**
130    * The constant indicating the position before the first line of the
131    * layout.  The exact position depends on the writing system: For a
132    * top-to-bottom orientation, it is the same as {@link #NORTH}, for
133    * a bottom-to-top orientation, it is the same as {@link #SOUTH}.
134    *
135    * @since 1.4
136    */
137   public static final String PAGE_START = BEFORE_FIRST_LINE;
138
139   /**
140    * The constant indicating the position after the last line of the
141    * layout.  The exact position depends on the writing system: For a
142    * top-to-bottom orientation, it is the same as {@link #SOUTH}, for
143    * a bottom-to-top orientation, it is the same as {@link #NORTH}.
144    *
145    * @since 1.4
146    */
147   public static final String PAGE_END = AFTER_LAST_LINE;
148
149   /**
150    * The constant indicating the position before the first item of the
151    * layout.  The exact position depends on the writing system: For a
152    * left-to-right orientation, it is the same as {@link #WEST}, for
153    * a right-to-left orientation, it is the same as {@link #EAST}.
154    *
155    * @since 1.4
156    */
157   public static final String LINE_START = BEFORE_LINE_BEGINS;
158
159   /**
160    * The constant indicating the position after the last item of the
161    * layout.  The exact position depends on the writing system: For a
162    * left-to-right orientation, it is the same as {@link #EAST}, for
163    * a right-to-left orientation, it is the same as {@link #WEST}.
164    *
165    * @since 1.4
166    */
167   public static final String LINE_END = AFTER_LINE_ENDS;
168
169
170   /**
171    * Serialization constant.
172    */
173   private static final long serialVersionUID = -8658291919501921765L;
174
175
176   /**
177    * @serial
178    */
179   private Component north;
180
181   /**
182    * @serial
183    */
184   private Component south;
185
186   /**
187    * @serial
188    */
189   private Component east;
190
191   /**
192    * @serial
193    */
194   private Component west;
195
196   /**
197    * @serial
198   */
199   private Component center;
200
201   /**
202    * @serial
203    */
204   private Component firstLine;
205
206   /**
207    * @serial
208    */
209   private Component lastLine;
210
211   /**
212    * @serial
213    */
214   private Component firstItem;
215
216   /**
217    * @serial
218    */
219   private Component lastItem;
220
221   /**
222    * @serial The horizontal gap between components
223    */
224   private int hgap;
225
226   /**
227    * @serial The vertical gap between components
228    */
229   private int vgap;
230
231
232   /**
233    * Initializes a new instance of <code>BorderLayout</code> with no
234    * horiztonal or vertical gaps between components.
235    */
236   public BorderLayout()
237   {
238     this(0,0);
239   }
240
241   /**
242    * Initializes a new instance of <code>BorderLayout</code> with the
243    * specified horiztonal and vertical gaps between components.
244    *
245    * @param hgap The horizontal gap between components.
246    * @param vgap The vertical gap between components.
247    */
248   public BorderLayout(int hgap, int vgap)
249   {
250     this.hgap = hgap;
251     this.vgap = vgap;
252   }
253
254   /**
255    * Returns the horitzontal gap value.
256    *
257    * @return The horitzontal gap value.
258    */
259   public int getHgap()
260   {
261     return(hgap);
262   }
263
264   /**
265    * Sets the horizontal gap to the specified value.
266    *
267    * @param hgap The new horizontal gap.
268    */
269   public void setHgap(int hgap)
270   {
271     this.hgap = hgap;
272   }
273
274   /**
275    * Returns the vertical gap value.
276    *
277    * @return The vertical gap value.
278    */
279   public int getVgap()
280   {
281     return(vgap);
282   }
283
284   /**
285    * Sets the vertical gap to the specified value.
286    *
287    * @param vgap The new vertical gap value.
288    */
289   public void setVgap(int vgap)
290   {
291     this.vgap = vgap;
292   }
293
294   /**
295    * Adds a component to the layout in the specified constraint position, 
296    * which must be one of the string constants defined in this class.
297    *
298    * @param component The component to add.
299    * @param constraints The constraint string.
300    *
301    * @exception IllegalArgumentException If the constraint object is not
302    * a string, or is not one of the specified constants in this class.
303    */
304   public void addLayoutComponent(Component component, Object constraints)
305   {
306     if (constraints != null && ! (constraints instanceof String))
307       throw new IllegalArgumentException("Constraint must be a string");
308
309     addLayoutComponent((String) constraints, component);
310   }
311
312   /**
313    * Adds a component to the layout in the specified constraint position, 
314    * which must be one of the string constants defined in this class.
315    *
316    * @param constraints The constraint string.
317    * @param component The component to add.
318    *
319    * @exception IllegalArgumentException If the constraint object is not
320    *            one of the specified constants in this class.
321    *
322    * @deprecated This method is deprecated in favor of
323    *             <code>addLayoutComponent(Component, Object)</code>.
324    */
325   public void addLayoutComponent(String constraints, Component component)
326   {
327     String str = constraints;
328
329     if (str == null || str.equals(CENTER))
330       center = component;
331     else if (str.equals(NORTH))
332       north = component;
333     else if (str.equals(SOUTH))
334       south = component;
335     else if (str.equals(EAST))
336       east = component;
337     else if (str.equals(WEST))
338       west = component;
339     else if (str.equals(BEFORE_FIRST_LINE))
340       firstLine = component;
341     else if (str.equals(AFTER_LAST_LINE))
342       lastLine = component;
343     else if (str.equals(BEFORE_LINE_BEGINS))
344       firstItem = component;
345     else if (str.equals(AFTER_LINE_ENDS))
346       lastItem = component;
347     else
348       throw new IllegalArgumentException("Constraint value not valid: " + str);
349   }
350
351   /**
352    * Removes the specified component from the layout.
353    *
354    * @param component The component to remove from the layout.
355    */
356   public void removeLayoutComponent(Component component)
357   {
358     if (north == component)
359       north = null;
360     if (south == component)
361       south = null;
362     if (east == component)
363       east = null;
364     if (west == component)
365       west = null;
366     if (center == component)
367       center = null;
368     if (firstItem == component)
369       firstItem = null;
370     if (lastItem == component)
371       lastItem = null;
372     if (firstLine == component)
373       firstLine = null;
374     if (lastLine == component)
375       lastLine = null;
376   }
377
378   /**
379    * Returns the minimum size of the specified container using this layout.
380    *
381    * @param target The container to calculate the minimum size for.
382    *
383    * @return The minimum size of the container
384    */
385   public Dimension minimumLayoutSize(Container target)
386   {
387     return calcSize(target, MIN);
388   }
389
390   /**
391    * Returns the preferred size of the specified container using this layout.
392    *
393    * @param target The container to calculate the preferred size for.
394    *
395    * @return The preferred size of the container
396    */
397   public Dimension preferredLayoutSize(Container target)
398   {
399     return calcSize(target, PREF);
400   }
401
402   /**
403    * Returns the maximum size of the specified container using this layout.
404    *
405    * @param target The container to calculate the maximum size for.
406    *
407    * @return The maximum size of the container
408    */
409   public Dimension maximumLayoutSize(Container target)
410   {
411     return calcSize(target, MAX);
412   }
413
414   /**
415    * Returns the X axis alignment, which is a <code>float</code> indicating
416    * where along the X axis this container wishs to position its layout.
417    * 0 indicates align to the left, 1 indicates align to the right, and 0.5
418    * indicates align to the center.
419    *
420    * @param parent The parent container.
421    *
422    * @return The X alignment value.
423    */
424   public float getLayoutAlignmentX(Container parent)
425   {
426     return(parent.getAlignmentX());
427   }
428
429   /**
430    * Returns the Y axis alignment, which is a <code>float</code> indicating
431    * where along the Y axis this container wishs to position its layout.
432    * 0 indicates align to the top, 1 indicates align to the bottom, and 0.5
433    * indicates align to the center.
434    *
435    * @param parent The parent container.
436    *
437    * @return The Y alignment value.
438    */
439   public float getLayoutAlignmentY(Container parent)
440   {
441     return(parent.getAlignmentY());
442   }
443
444   /**
445    * Instructs this object to discard any layout information it might
446    * have cached.
447    *
448    * @param parent The parent container.
449    */
450   public void invalidateLayout(Container parent)
451   {
452     // FIXME: Implement this properly!
453   }
454
455   /**
456    * Lays out the specified container according to the constraints
457    * in this object.
458    *
459    * @param target The container to lay out.
460    */
461   public void layoutContainer(Container target)
462   {
463     synchronized (target.getTreeLock ())
464       {
465         Insets i = target.getInsets();
466
467         ComponentOrientation orient = target.getComponentOrientation ();
468         boolean left_to_right = orient.isLeftToRight ();
469
470         Component my_north = north;
471         Component my_east = east;
472         Component my_south = south;
473         Component my_west = west;
474
475         // Note that we currently don't handle vertical layouts.  Neither
476         // does JDK 1.3.
477         if (firstLine != null)
478           my_north = firstLine;
479         if (lastLine != null)
480           my_south = lastLine;
481         if (firstItem != null)
482           {
483             if (left_to_right)
484               my_west = firstItem;
485             else
486               my_east = firstItem;
487           }
488         if (lastItem != null)
489           {
490             if (left_to_right)
491               my_east = lastItem;
492             else
493               my_west = lastItem;
494           }
495
496         Dimension c = calcCompSize(center, PREF);
497         Dimension n = calcCompSize(my_north, PREF);
498         Dimension s = calcCompSize(my_south, PREF);
499         Dimension e = calcCompSize(my_east, PREF);
500         Dimension w = calcCompSize(my_west, PREF);
501         int targetWidth = target.getWidth();
502         int targetHeight = target.getHeight();
503
504         /*
505         <-> hgap     <-> hgap
506         +----------------------------+          }
507         |t                           |          } i.top
508         |  +----------------------+  |  --- y1  }
509         |  |n                     |  |
510         |  +----------------------+  |          } vgap
511         |  +---+ +----------+ +---+  |  --- y2  }        }
512         |  |w  | |c         | |e  |  |                   } hh
513         |  +---+ +----------+ +---+  |          } vgap   }
514         |  +----------------------+  |  --- y3  }
515         |  |s                     |  |
516         |  +----------------------+  |          }
517         |                            |          } i.bottom
518         +----------------------------+          }
519         |x1   |x2          |x3
520         <---------------------->
521         <-->         ww           <-->
522         i.left                    i.right
523         */
524
525         int x1 = i.left;
526         int x2 = x1 + w.width + (w.width == 0 ? 0 : hgap);
527         int x3;
528         if (targetWidth <= i.right + e.width)
529           x3 = x2 + w.width + (w.width == 0 ? 0 : hgap);
530         else
531           x3 = targetWidth - i.right - e.width;
532         int ww = targetWidth - i.right - i.left;
533
534         int y1 = i.top;
535         int y2 = y1 + n.height + (n.height == 0 ? 0 : vgap);
536         int midh = Math.max(e.height, Math.max(w.height, c.height));
537         int y3;
538         if (targetHeight <= i.bottom + s.height)
539           y3 = y2 + midh + vgap;
540         else
541           y3 = targetHeight - i.bottom - s.height;
542         int hh = y3-y2-(s.height == 0 ? 0 : vgap);
543
544         setBounds(center, x2, y2, x3-x2-(w.width == 0 ? 0 : hgap), hh);
545         setBounds(my_north, x1, y1, ww, n.height);
546         setBounds(my_south, x1, y3, ww, s.height);
547         setBounds(my_west, x1, y2, w.width, hh);
548         setBounds(my_east, x3, y2, e.width, hh);
549       }
550   }
551
552   /**
553    * Returns a string representation of this layout manager.
554    *
555    * @return A string representation of this object.
556    */
557   public String toString()
558   {
559     return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + "]";
560   }
561
562   /**
563    * FIXME: Document me!
564    */
565   private void setBounds(Component comp, int x, int y, int w, int h)
566   {
567     if (comp == null)
568       return;
569     comp.setBounds(x, y, w, h);
570   }
571
572   // FIXME: Maybe move to top of file.
573   // Some constants for use with calcSize().
574   private static final int MIN = 0;
575   private static final int MAX = 1;
576   private static final int PREF = 2;
577
578   private Dimension calcCompSize(Component comp, int what)
579   {
580     if (comp == null || !comp.isVisible())
581       return new Dimension(0, 0);
582     if (what == MIN)
583       return comp.getMinimumSize();
584     else if (what == MAX)
585       return comp.getMaximumSize();
586     return comp.getPreferredSize();
587   }
588
589   /**
590    * This is a helper function used to compute the various sizes for
591    * this layout.
592    */
593   private Dimension calcSize(Container target, int what)
594   {
595     synchronized (target.getTreeLock ())
596       {
597         Insets ins = target.getInsets();
598
599         ComponentOrientation orient = target.getComponentOrientation ();
600         boolean left_to_right = orient.isLeftToRight ();
601
602         Component my_north = north;
603         Component my_east = east;
604         Component my_south = south;
605         Component my_west = west;
606
607         // Note that we currently don't handle vertical layouts.  Neither
608         // does JDK 1.3.
609         if (firstLine != null)
610           my_north = firstLine;
611         if (lastLine != null)
612           my_south = lastLine;
613         if (firstItem != null)
614           {
615             if (left_to_right)
616               my_west = firstItem;
617             else
618               my_east = firstItem;
619           }
620         if (lastItem != null)
621           {
622             if (left_to_right)
623               my_east = lastItem;
624             else
625               my_west = lastItem;
626           }
627
628         Dimension ndim = calcCompSize(my_north, what);
629         Dimension sdim = calcCompSize(my_south, what);
630         Dimension edim = calcCompSize(my_east, what);
631         Dimension wdim = calcCompSize(my_west, what);
632         Dimension cdim = calcCompSize(center, what);
633
634         int width = edim.width + cdim.width + wdim.width + (hgap * 2);
635         // Check for overflow.
636         if (width < edim.width || width < cdim.width || width < cdim.width)
637           width = Integer.MAX_VALUE;
638
639         if (ndim.width > width)
640           width = ndim.width;
641         if (sdim.width > width)
642           width = sdim.width;
643
644         width += (ins.left + ins.right);
645
646         int height = edim.height;
647         if (cdim.height > height)
648           height = cdim.height;
649         if (wdim.height > height)
650           height = wdim.height;
651
652         int addedHeight = height + (ndim.height + sdim.height + (vgap * 2)
653                                     + ins.top + ins.bottom);
654         // Check for overflow.
655         if (addedHeight < height)
656           height = Integer.MAX_VALUE;
657         else
658           height = addedHeight;
659
660         return(new Dimension(width, height));
661       }
662   }
663 }