OSDN Git Service

* javax/naming/CompoundName.java (CompoundName): Don't check for
[pf3gnuchains/gcc-fork.git] / libjava / javax / swing / SpringLayout.java
1 /* SpringLayout.java -- 
2    Copyright (C) 2004 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., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 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 javax.swing;
40
41 import java.awt.Component;
42 import java.awt.Container;
43 import java.awt.Dimension;
44 import java.awt.LayoutManager2;
45
46 import java.util.HashMap;
47 import java.util.Map;
48
49 import javax.swing.Spring;
50
51 /**
52  * A very flexible layout manager. Components are laid out by defining the
53  * relationships between them. The relationships are expressed as
54  * {@link Spring}s. You can attach a Spring for each edge of a component and
55  * link it to an edge of a different component. For example, you can say,
56  * the northern edge of component A should be attached to the southern edge
57  * of component B, and the space between them should be something between
58  * x and y pixels, and preferably z pixels.
59  * <p>While quite simple, this layout manager can be used to emulate most other
60  * layout managers, and can also be used to solve some layout problems, which
61  * would be hard to solve with other layout managers.</p>
62  *
63  * @author Roman Kennke (roman@ontographics.com)
64  */
65 public class SpringLayout implements LayoutManager2
66 {
67
68   /** The right edge of a component. */
69   public static final String EAST = "East";
70
71   /** The top edge of a component. */
72   public static final String NORTH = "North";
73
74   /** The bottom edge of a component. */
75   public static final String SOUTH = "South";
76
77   /** The left edge of a component. */
78   public static final String WEST = "West";
79
80   /** maps components to their constraints. */
81   private Map constraintsMap;
82
83   /**
84    * The constraints that define the relationships between components.
85    * Each Constraints object can hold 4 Springs: one for each edge of the
86    * component. Additionally it can hold Springs for the components width
87    * and the components height. Since the height and width constraints are
88    * dependend on the other constraints, a component can be over-constraint.
89    * In this case (like when all of NORTH, SOUTH and HEIGHT are constraint),
90    * the values are adjusted, so that the mathematics still hold true.
91    *
92    * @author Roman Kennke (roman@ontographics.com)
93    */
94   public final static class Constraints
95   {
96
97     // The constraints for each edge, and width and height.
98     /** The Spring for the left edge. */
99     private Spring x;
100
101     /** The Spring for the upper edge. */
102     private Spring y;
103
104     /** The Spring for the height. */
105     private Spring height;
106
107     /** The Spring for the width. */
108     private Spring width;
109
110     /** The Spring for the right edge. */
111     private Spring east;
112
113     /** The Spring for the bottom edge. */
114     private Spring south;
115
116     /**
117      * Creates a new Constraints object.
118      * There is no constraint set.
119      */
120     public Constraints()
121     {
122       x = y = height = width = east = south = null;
123     }
124
125     /**
126      * Creates a new Constraints object.
127      *
128      * @param x the constraint for the left edge of the component.
129      * @param y the constraint for the upper edge of the component.
130      */
131     public Constraints(Spring x, Spring y)
132     {
133       this.x = x;
134       this.y = y;
135       width = height = east = south = null;
136     }
137
138     /**
139      * Creates a new Constraints object.
140      *
141      * @param x the constraint for the left edge of the component.
142      * @param y the constraint for the upper edge of the component.
143      * @param width the constraint for the width of the component.
144      * @param height the constraint for the height of the component.
145      */
146     public Constraints(Spring x, Spring y, Spring width, Spring height)
147     {
148       this.x = x;
149       this.y = y;
150       this.width = width;
151       this.height = height;
152       east = south = null;
153     }
154
155     /**
156      * Returns the constraint for the edge with the <code>edgeName</code>.
157      * This is expected to be one of
158      * {@link #EAST}, {@link #WEST}, {@link NORTH} or {@link SOUTH}.
159      *
160      * @param edgeName the name of the edge.
161      * @return the constraint for the specified edge.
162      */
163     public Spring getConstraint(String edgeName)
164     {
165       Spring retVal = null;
166       if (edgeName.equals(SpringLayout.NORTH))
167         retVal = y;
168       else if (edgeName.equals(SpringLayout.WEST))
169         retVal = x;
170       else if (edgeName.equals(SpringLayout.SOUTH))
171         {
172           retVal = south;
173           if ((retVal == null) && (y != null) && (height != null))
174             retVal = Spring.sum(y, height);
175         }
176       else if (edgeName.equals(SpringLayout.EAST))
177         {
178           retVal = east;
179           if ((retVal == null) && (x != null) && (width != null))
180             retVal = Spring.sum(x, width);
181         }
182
183       return retVal;
184     }
185
186     /**
187      * Returns the constraint for the height of the component.
188      *
189      * @return the height constraint. 
190      */
191     public Spring getHeight()
192     {
193       Spring retVal = height;
194       if ((retVal == null) && (y != null) && (south != null))
195         {
196           retVal = Spring.sum(south, Spring.minus(y));
197         }
198       return retVal;
199     }
200
201     /**
202      * Returns the constraint for the width of the component.
203      *
204      * @return the width constraint.
205      */
206     public Spring getWidth()
207     {
208       Spring retVal = width;
209       if ((retVal == null) && (x != null) && (east != null))
210         {
211           retVal = Spring.sum(east, Spring.minus(x));
212         }
213       return retVal;
214     }
215
216     /**
217      * Returns the constraint for the left edge of the component.
218      *
219      * @return the left-edge constraint (== WEST).
220      */
221     public Spring getX()
222     {
223       Spring retVal = x;
224       if ((retVal == null) && (width != null) && (east != null))
225         {
226           retVal = Spring.sum(east, Spring.minus(width));
227         }
228       return retVal;
229     }
230
231     /**
232      * Returns the constraint for the upper edge of the component.
233      *
234      * @return the upper-edge constraint (== NORTH).
235      */
236     public Spring getY()
237     {
238       Spring retVal = y;
239       if ((retVal == null) && (height != null) && (south != null))
240         {
241           retVal = Spring.sum(south, Spring.minus(height));
242         }
243       return retVal;
244     }
245
246     /**
247      * Sets a constraint for the specified edge. If this leads to an
248      * over-constrained situation, the constraints get adjusted, so that
249      * the mathematics still hold true.
250      *
251      * @param edgeName the name of the edge, one of {@link #EAST},
252      *     {@link #WEST}, {@link NORTH} or {@link SOUTH}.
253      * @param s the constraint to be set.
254      */
255     public void setConstraint(String edgeName, Spring s)
256     {
257     
258       if (edgeName.equals(SpringLayout.WEST))
259         {
260           x = s;
261           if ((width != null) && (east != null))
262             width = Spring.sum(east, Spring.minus(x));
263         }
264       else if (edgeName.equals(SpringLayout.NORTH))
265         {
266           y = s;
267           if ((height != null) && (south != null))
268           height = Spring.sum(south, Spring.minus(y));
269         }
270       else if (edgeName.equals(SpringLayout.EAST))
271         {
272           east = s;
273           if ((x != null) && (width != null))
274             x = Spring.sum(east, Spring.minus(width));
275         }
276       else if (edgeName.equals(SpringLayout.SOUTH))
277         {
278           south = s;
279           if ((height != null) && (y != null))
280             y = Spring.sum(south, Spring.minus(height));
281         }
282
283     }
284
285     /**
286      * Sets the height-constraint.
287      *
288      * @param s the constraint to be set.
289      */
290     public void setHeight(Spring s)
291     {
292       height = s;
293       if ((south != null) && (y != null))
294         south = Spring.sum(y, height);
295
296     }
297
298     /**
299      * Sets the width-constraint.
300      *
301      * @param s the constraint to be set.
302      */
303     public void setWidth(Spring s)
304     {
305       width = s;
306       if ((east != null) && (x != null))
307         east = Spring.sum(x, width);
308
309     }
310
311     /**
312      * Sets the WEST-constraint.
313      *
314      * @param s the constraint to be set.
315      */
316     public void setX(Spring s)
317     {
318       x = s;
319       if ((width != null) && (east != null))
320         width = Spring.sum(east, Spring.minus(x));
321
322     }
323
324     /**
325      * Sets the NORTH-constraint.
326      *
327      * @param s the constraint to be set.
328      */
329     public void setY(Spring s)
330     {
331       y = s;
332       if ((height != null) && (south != null))
333         height = Spring.sum(south, Spring.minus(y));
334
335     }
336   }
337
338   /**
339    * Creates a new SpringLayout.
340    */
341   public SpringLayout()
342   {
343
344     constraintsMap = new HashMap();
345   }
346
347   /**
348    * Adds a layout component and a constraint object to this layout.
349    * This method is usually only called by a {@java.awt.Container}s add
350    * Method.
351    *
352    * @param component the component to be added.
353    * @param constraint the constraint to be set.
354    */
355   public void addLayoutComponent(Component component, Object constraint)
356   {
357     constraintsMap.put(component, constraint);
358   }
359
360
361   /**
362    * Adds a layout component and a constraint object to this layout.
363    * This method is usually only called by a {@java.awt.Container}s add
364    * Method. This method does nothing, since SpringLayout does not manage
365    * String-indexed components.
366    *
367    * @param component the component to be added.
368    * @param constraint the constraint to be set.
369    */
370   public void addLayoutComponent(String name, Component c)
371   {
372     // do nothing here.
373   }
374
375   /**
376    * Returns the constraint of the edge named by <code>edgeName</code>.
377    *
378    * @param c the component from which to get the constraint.
379    * @param edgeName the name of the edge, one of {@link #EAST},
380    *     {@link #WEST}, {@link NORTH} or {@link SOUTH}.
381    * @return the constraint of the edge <code>edgeName</code> of the
382    * component c.
383    */
384   public Spring getConstraint(String edgeName, Component c)
385   {
386     Constraints constraints = getConstraints(c);
387     return constraints.getConstraint(edgeName);
388   }
389
390   /**
391    * Returns the {@link Constraints} object associated with the specified
392    * component.
393    *
394    * @param c the component for which to determine the constraint.
395    * @return the {@link Constraints} object associated with the specified
396    *      component.
397    */
398   public SpringLayout.Constraints getConstraints(Component c)
399   {
400     Constraints constraints = (Constraints) constraintsMap.get(c);
401     if (constraints == null)
402       {
403         Container parent = c.getParent();
404         constraints = new Constraints();
405         if (parent != null)
406           {
407             constraints.setX
408               (Spring.constant(parent.getInsets().left));
409             constraints.setY
410               (Spring.constant(parent.getInsets().top));
411           }
412         else
413           {
414             constraints.setX
415               (Spring.constant(0));
416             constraints.setY
417               (Spring.constant(0));
418
419           }
420         constraints.setWidth
421           (Spring.constant(c.getMinimumSize().width,
422                            c.getPreferredSize().width,
423                            c.getMaximumSize().width));
424         constraints.setHeight
425           (Spring.constant(c.getMinimumSize().height,
426                            c.getPreferredSize().height,
427                            c.getMaximumSize().height));
428
429         constraintsMap.put(c, constraints);
430
431       }
432
433     return constraints;
434   }
435
436   /**
437    * Returns the X alignment of the Container <code>p</code>.
438    *
439    * @param p the {@link java.awt.Container} for which to determine the X
440    *     alignment.
441    * @return always 0.0
442    */
443   public float getLayoutAlignmentX(Container p)
444   {
445     return 0.0F;
446   }
447
448   /**
449    * Returns the Y alignment of the Container <code>p</code>.
450    *
451    * @param p the {@link java.awt.Container} for which to determine the Y
452    *     alignment.
453    * @return always 0.0
454    */
455   public float getLayoutAlignmentY(Container p)
456   {
457     return 0.0F;
458   }
459
460   /**
461    * Recalculate a possibly cached layout.
462    */
463   public void invalidateLayout(Container p)
464   {
465     // nothing to do here yet
466   }
467
468   /**
469    * Lays out the container <code>p</code>.
470    *
471    * @param p the container to be laid out.
472    */
473   public void layoutContainer(Container p)
474   {
475
476     addLayoutComponent(p, new Constraints(Spring.constant(0),
477                                           Spring.constant(0)));
478
479     int offsetX = p.getInsets().left;
480     int offsetY = p.getInsets().right;
481
482     Component[] components = p.getComponents();
483     for (int index = 0; index < components.length; index++)
484       {
485         Component c = components[index];
486         Constraints constraints = getConstraints(c);
487         int x = constraints.getX().getValue();
488         int y = constraints.getY().getValue();
489         int width = constraints.getWidth().getValue();
490         int height = constraints.getHeight().getValue();
491
492         c.setLocation(x + offsetX, y + offsetY);
493         c.setSize(width, height);
494       }
495
496   }
497
498   /**
499    * Calculates the maximum size of the layed out container. This
500    * respects the maximum sizes of all contained components.
501    *
502    * @param p the container to be laid out.
503    * @return the maximum size of the container.
504    */
505   public Dimension maximumLayoutSize(Container p)
506   {
507     int maxX = 0;
508     int maxY = 0;
509
510     int offsetX = p.getInsets().left;
511     int offsetY = p.getInsets().right;
512
513     Component[] components = p.getComponents();
514     for (int index = 0; index < components.length; index++)
515       {
516         Component c = components[index];
517         Constraints constraints = getConstraints(c);
518         int x = constraints.getX().getMaximumValue();
519         int y = constraints.getY().getMaximumValue();
520         int width = constraints.getWidth().getMaximumValue();
521         int height = constraints.getHeight().getMaximumValue();
522
523         int rightEdge = offsetX + x + width;
524         if (rightEdge > maxX)
525           maxX = rightEdge;
526         int bottomEdge = offsetY + y + height;
527         if (bottomEdge > maxY)
528           maxY = bottomEdge;
529       }
530
531     return new Dimension(maxX, maxY);
532   }
533
534
535   /**
536    * Calculates the minimum size of the layed out container. This
537    * respects the minimum sizes of all contained components.
538    *
539    * @param p the container to be laid out.
540    * @return the minimum size of the container.
541    */
542   public Dimension minimumLayoutSize(Container p)
543   {
544     int maxX = 0;
545     int maxY = 0;
546
547     int offsetX = p.getInsets().left;
548     int offsetY = p.getInsets().right;
549
550     Component[] components = p.getComponents();
551     for (int index = 0; index < components.length; index++)
552       {
553         Component c = components[index];
554         Constraints constraints = getConstraints(c);
555         int x = constraints.getX().getMinimumValue();
556         int y = constraints.getY().getMinimumValue();
557         int width = constraints.getWidth().getMinimumValue();
558         int height = constraints.getHeight().getMinimumValue();
559
560         int rightEdge = offsetX + x + width;
561         if (rightEdge > maxX)
562           maxX = rightEdge;
563         int bottomEdge = offsetY + y + height;
564         if (bottomEdge > maxY)
565           maxY = bottomEdge;
566       }
567
568     return new Dimension(maxX, maxY);
569   }
570
571   /**
572    * Calculates the preferred size of the layed out container. This
573    * respects the preferred sizes of all contained components.
574    *
575    * @param p the container to be laid out.
576    * @return the preferred size of the container.
577    */
578   public Dimension preferredLayoutSize(Container p)
579   {
580     int maxX = 0;
581     int maxY = 0;
582
583     int offsetX = p.getInsets().left;
584     int offsetY = p.getInsets().right;
585
586     Component[] components = p.getComponents();
587     for (int index = 0; index < components.length; index++)
588       {
589         Component c = components[index];
590         Constraints constraints = getConstraints(c);
591         int x = constraints.getX().getPreferredValue();
592         int y = constraints.getY().getPreferredValue();
593         int width = constraints.getWidth().getPreferredValue();
594         int height = constraints.getHeight().getPreferredValue();
595
596         int rightEdge = offsetX + x + width;
597         if (rightEdge > maxX)
598           maxX = rightEdge;
599         int bottomEdge = offsetY + y + height;
600         if (bottomEdge > maxY)
601           maxY = bottomEdge;
602       }
603
604     return new Dimension(maxX, maxY);
605   }
606
607   /**
608    * Attaches the edge <code>e1</code> of component <code>c1</code> to
609    * the edge <code>e2</code> of component <code>c2</code> width the
610    * fixed strut <code>pad</code>.
611    *
612    * @param e1 the edge of component 1.
613    * @param c1 the component 1.
614    * @param pad the space between the components in pixels.
615    * @param e2 the edge of component 2.
616    * @param c2 the component 2.
617    */
618   public void putConstraint(String e1, Component c1, int pad, String e2, 
619                             Component c2)
620   {
621     Constraints constraints1 = getConstraints(c1);
622     Constraints constraints2 = getConstraints(c2);
623
624     Spring strut = Spring.constant(pad);
625     Spring otherEdge = constraints2.getConstraint(e2);
626     constraints1.setConstraint(e1, Spring.sum(strut, otherEdge));
627
628   }
629
630   /**
631    * Attaches the edge <code>e1</code> of component <code>c1</code> to
632    * the edge <code>e2</code> of component <code>c2</code> width the
633    * {@link Spring} <code>s</code>.
634    *
635    * @param e1 the edge of component 1.
636    * @param c1 the component 1.
637    * @param s the space between the components as a {@link Spring} object.
638    * @param e2 the edge of component 2.
639    * @param c2 the component 2.
640    */
641   public void putConstraint(String e1, Component c1, Spring s, String e2, 
642                             Component c2)
643   {
644     Constraints constraints1 = getConstraints(c1);
645     Constraints constraints2 = getConstraints(c2);
646
647     Spring otherEdge = constraints2.getConstraint(e2);
648     constraints1.setConstraint(e1, Spring.sum(s, otherEdge));
649
650   }
651
652   /**
653    * Removes a layout component.
654    * @param c the layout component to remove.
655    */
656   public void removeLayoutComponent(Component c)
657   {
658     // do nothing here
659   }
660 }