001/*
002 * IzPack - Copyright 2001-2005 Julien Ponge, All Rights Reserved.
003 * 
004 * http://www.izforge.com/izpack/
005 * http://developer.berlios.de/projects/izpack/
006 * 
007 * Copyright 2002 Elmar Grom
008 * 
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 *     http://www.apache.org/licenses/LICENSE-2.0
014 *     
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 */
021
022package com.izforge.izpack.gui;
023
024import java.awt.BasicStroke;
025import java.awt.Color;
026import java.awt.Component;
027import java.awt.Container;
028import java.awt.Dimension;
029import java.awt.Graphics2D;
030import java.awt.LayoutManager2;
031import java.awt.Stroke;
032import java.util.Vector;
033
034/**
035 * This class implements a layout manager that generally lays out components in two columns. <BR>
036 * <BR>
037 * The design goal for this layout manager was to lay out forms for data entry, where there are
038 * several rows of entry fields with associated labels. The goal was to have the beginning off all
039 * labels line up, as well as the left edge of all the data entry fields. This leads to a situation
040 * where all components are essentially laid out in two columns. The columns adjust to accommodate
041 * components of various sizes. This means that components that are added are laid out top to
042 * bottom, either in the left column, in the right column or straddling both columns. In addition to
043 * this general behavior, the following additional layout capabilities are supported:<br>
044 * <ul>
045 * <li>Resizable margins are provided on the left and right side.
046 * <li>A special region is provided at the top that is only affected by the side margins but not by
047 * any other layout behavior.
048 * <li>It is possible to specify the vertical positioning of the cluster of laid out components for
049 * the case that they do not occupy the entire available real estate.
050 * <li>Individual components can be indented.
051 * </ul>
052 * 
053 * <b>The Layout Behavior</b> <br>
054 * <br>
055 * The left and right margin are absolute. This means that they can not be penetrated by components.
056 * All layout happens between the limits established by these margins. The purpose of these margins
057 * is to ensure that components are not laid out all the way to the edge of their container, without
058 * the need to set matching borders for each component. <br>
059 * <br>
060 * The title margin at the top factors only into the layout behavior if there is a component set to
061 * be laid out in that region, otherwise it is ignored. <br>
062 * <br>
063 * The vertical space available to each row of components depends on the space requirements of the
064 * tallest component in that row. Both components are placed vertically centered in their row. <br>
065 * <br>
066 * All horizontal layout is based on the position of three vertical rules, the left rule, the right
067 * rule and the center rule. <br>
068 * <br>
069 * <img src="doc-files/TwoColumnLayout.gif"/> <br>
070 * <br>
071 * The actual position of each rule depends on the alignment strategy, margin settings and component
072 * sizes. Regardless of these factors, components placed in the left column are <i>always</i>
073 * positioned with their left edge aligned with the left rule. Components placed in the right column
074 * are <i>always</i> positioned with their left edge aligned with the center rule. If a component
075 * straddles both columns, it is <i>always</i> positioned with the left edge aligned with the left
076 * rule, but is allowed to extend all the way to the right rule. The only exception is a component
077 * that is specified with an indent. In this case the component is moved to the right of the
078 * respective rule by the indent amount. <br>
079 * <br>
080 * The location of the rules is determined based on the alignment strategy as follows:<br>
081 * <ul>
082 * <li>The right rule is always located at the edge of the right margin.
083 * <li><b>Left Alignment:</b> The left rule is located the edge of the left margin. The center
084 * rule is located far enough to the right to clear the widest component in the left column.
085 * <li><b>Center Alignment:</b> The center rule is located at the center of the panel. The left
086 * rule is located far enough to the left to make the widest component in the left column fit.
087 * <li><b>Right Alignment</b> The center rule is located far enough to the left of the right rule
088 * to make the widest component in the right column fit. The left rule is located far enough to the
089 * left to make the widest component in the left column fit.
090 * </ul>
091 * All components clump together vertically and are positioned right beneath the title margin. This
092 * is of course not a very appealing presentation. By setting how the remaining vertical space is
093 * distributed above and below the cluster of components the cluster can be positioned more
094 * favorably (see the shaded area in the illustration).
095 * 
096 * @see com.izforge.izpack.gui.TwoColumnConstraints
097 * 
098 * @version 0.0.1 / 11/14/02
099 * @author Elmar Grom
100 */
101public class TwoColumnLayout implements LayoutManager2
102{
103
104    public static final int LEFT = 0;
105
106    public static final int RIGHT = 1;
107
108    public static final int CENTER = 2;
109
110    /** holds all the components and layout constraints. */
111    private Vector[] components = { new Vector(), new Vector()};
112
113    /**
114     * holds the component to be placed in the title region, including layout constraints.
115     */
116    private TwoColumnConstraints title = null;
117
118    /** the margin setting in % of the container's width */
119    private int margin = 0;
120
121    /**
122     * the setting for the buffer area on top of hte comonent cluster in % of the left over height.
123     */
124    private int topBuffer = 0;
125
126    /** the indent setting in % of the conteiner's width */
127    private int indent = 0;
128
129    /** the gap between the two columns */
130    private int gap = 5;
131
132    private int alignment = LEFT;
133
134    private int leftRule;
135
136    private int rightRule;
137
138    private int centerRule;
139
140    private int titleHeight;
141
142    /**
143     * Constructs a <code>TwoColumnLayout</code> layout manager. To add components use the
144     * container's <code>add(comp, constraints)</code> method with a TwoColumnConstraints object.
145     * 
146     * @param margin the margin width to use on the left and right side in % of the total container
147     * width. Values less than 0% and greater than 50% are not accepted.
148     * @param gap the gap between the two columns.
149     * @param indent the indent to use for components that have that constraint set. This is a value
150     * in pixels.
151     * @param topBuffer the percentage of left over vertical space to place on top of the component
152     * cluster. Values between 0% and 100% are accepted.
153     * @param alignment how to align the overall layout. Legal values are LEFT, CENTER, RIGHT.
154     */
155    public TwoColumnLayout(int margin, int gap, int indent, int topBuffer, int alignment)
156    {
157        this.indent = indent;
158        this.gap = gap;
159
160        if ((margin >= 0) && (margin <= 50))
161        {
162            this.margin = margin;
163        }
164        if ((topBuffer >= 0) && (topBuffer <= 100))
165        {
166            this.topBuffer = topBuffer;
167        }
168        if ((alignment == LEFT) || (alignment == CENTER) || (alignment == RIGHT))
169        {
170            this.alignment = alignment;
171        }
172    }
173
174    /**
175     * Sets the constraints for the specified component in this layout. <code>null</code> is a
176     * legal value for a component, but not for a constraints object.
177     * 
178     * @param comp the component to be modified.
179     * @param constraints the constraints to be applied.
180     */
181    public void addLayoutComponent(Component comp, Object constraints)
182    {
183        if (constraints == null) { return; }
184
185        TwoColumnConstraints component = null;
186        try
187        {
188            component = (TwoColumnConstraints) constraints;
189            component = (TwoColumnConstraints) component.clone();
190        }
191        catch (Throwable exception)
192        {
193            return;
194        }
195
196        component.component = comp;
197
198        // ----------------------------------------------------
199        // the title component is recorded in a separate
200        // variable, displacing any component that might have
201        // been previously recorded for that location.
202        // ----------------------------------------------------
203        if (component.position == TwoColumnConstraints.NORTH)
204        {
205            title = component;
206            if (title.stretch)
207            {
208                title.align = LEFT;
209            }
210        }
211
212        // ----------------------------------------------------
213        // components that straddle both columns are a bit
214        // tricky because these components are recorded in the
215        // left column and the same row cannot contain a
216        // component in the right column.
217        //
218        // If there are fewer components in the left column
219        // than in the right one, a null is inserted at this
220        // place in the right column. This allows the component
221        // to use both columns. The component that previously
222        // occupied this position and any that were placed
223        // below will be pushed down by one row due to this
224        // action.
225        //
226        // If there are the same number of components in both
227        // columns or if there are fewer in the right column
228        // then the component is added to the left column and
229        // then the right column filled with null until both
230        // contain the same number of components. this means
231        // that any components that will now be placed in the
232        // right column are positioned beneath this component.
233        // Unoccupied spots higher in the right column become
234        // inaccessible.
235        // ----------------------------------------------------
236        else if (component.position == TwoColumnConstraints.BOTH)
237        {
238            // first make sure that both columns have the same number of entries
239            while (components[RIGHT].size() > components[LEFT].size())
240            {
241                components[LEFT].add(null);
242            }
243
244            while (components[LEFT].size() > components[RIGHT].size())
245            {
246                components[RIGHT].add(null);
247            }
248
249            components[LEFT].add(component);
250            components[RIGHT].add(null);
251        }
252
253        // ----------------------------------------------------
254        // WEST components are added to the left column
255        // ----------------------------------------------------
256        else if (component.position == TwoColumnConstraints.WEST)
257        {
258            components[LEFT].add(component);
259        }
260
261        // ----------------------------------------------------
262        // WESTONLY components are added to the left column
263        // the right column has to be kept free
264        // ----------------------------------------------------
265        else if (component.position == TwoColumnConstraints.WESTONLY)
266        {
267            components[LEFT].add(component);
268
269            // fill right column to make sure nothing is placed there
270            while (components[RIGHT].size() < components[LEFT].size())
271            {
272                components[RIGHT].add(null);
273            }
274
275        }
276
277        // ----------------------------------------------------
278        // EAST components are added to the right column
279        // ----------------------------------------------------
280        else if (component.position == TwoColumnConstraints.EAST)
281        {
282            components[RIGHT].add(component);
283        }
284
285        // ----------------------------------------------------
286        // EASTONLY components are added to the left column
287        // the right column has to be kept free
288        // ----------------------------------------------------
289        else if (component.position == TwoColumnConstraints.EASTONLY)
290        {
291            components[RIGHT].add(component);
292
293            // fill left column to make sure nothing is placed there
294            while (components[LEFT].size() < components[RIGHT].size())
295            {
296                components[LEFT].add(null);
297            }
298
299        }
300
301        // ----------------------------------------------------
302        // If the position did not match any of the above
303        // criteria then the component is not added and
304        // consequently will not be laid out.
305        // ----------------------------------------------------
306    }
307
308    /**
309     * Lays out the container in the specified panel.
310     * 
311     * @param parent the component which needs to be laid out.
312     */
313    public void layoutContainer(Container parent)
314    {
315        positionRules(parent);
316        positionTitle(parent);
317        positionComponents(parent);
318    }
319
320    /**
321     * Positions the three rules in preparation for layout. Sets the variables:<br>
322     * <ul>
323     * <li><code>leftRule</code>
324     * <li><code>rightRule</code>
325     * <li><code>centerRule</code>
326     * </ul>
327     * 
328     * @param parent the component which needs to be laid out.
329     */
330    private void positionRules(Container parent)
331    {
332        int margin = margin(parent);
333
334        if (alignment == LEFT)
335        {
336            leftRule = margin;
337            centerRule = leftRule + minimumColumnWidth(LEFT, parent) + gap;
338            rightRule = parent.getWidth() - margin;
339        }
340
341        else if (alignment == CENTER)
342        {
343            centerRule = (int) (parent.getMinimumSize().getWidth() / 2);
344            leftRule = centerRule - minimumColumnWidth(LEFT, parent) - gap;
345            rightRule = parent.getWidth() - margin;
346        }
347
348        else if (alignment == RIGHT)
349        {
350            rightRule = parent.getWidth() - margin;
351            centerRule = rightRule - minimumColumnWidth(RIGHT, parent);
352            leftRule = centerRule - minimumColumnWidth(LEFT, parent) - gap;
353        }
354    }
355
356    /**
357     * Positions the title component and sets the variable <code>titleHeight</code>. <b>Note:</b>
358     * this method depends on the fact that the rules are set to their correct layout position.
359     * 
360     * @param parent the component which needs to be laid out.
361     */
362    private void positionTitle(Container parent)
363    {
364        if (title != null)
365        {
366            Component component = title.component;
367            int width = (int) component.getMinimumSize().getWidth();
368            titleHeight = (int) component.getMinimumSize().getHeight();
369
370            if (component != null)
371            {
372                if (title.stretch)
373                {
374                    width = rightRule - leftRule;
375                    component.setBounds(leftRule, 0, width, titleHeight);
376                }
377
378                else if (title.align == TwoColumnConstraints.LEFT)
379                {
380                    component.setBounds(leftRule, 0, width, titleHeight);
381                }
382
383                else if (title.align == TwoColumnConstraints.CENTER)
384                {
385                    int left = centerRule - (width / 2);
386                    component.setBounds(left, 0, width, titleHeight);
387                }
388
389                else if (title.align == TwoColumnConstraints.RIGHT)
390                {
391                    int left = rightRule - width;
392                    component.setBounds(left, 0, width, titleHeight);
393                }
394            }
395        }
396    }
397
398    /**
399     * Positions all components in the container.
400     * 
401     * @param parent the component which needs to be laid out.
402     */
403    private void positionComponents(Container parent)
404    {
405        int usedHeight = titleHeight + minimumClusterHeight();
406        int topBuffer = topBuffer(usedHeight, parent);
407        int leftHeight = 0;
408        int rightHeight = 0;
409
410        if (topBuffer < 0)
411        {
412            topBuffer = 0;
413        }
414
415        int y = titleHeight + topBuffer;
416
417        for (int i = 0; i < rows(); i++)
418        {
419            leftHeight = height(i, LEFT);
420            rightHeight = height(i, RIGHT);
421
422            if (leftHeight > rightHeight)
423            {
424                int offset = (leftHeight - rightHeight) / 2;
425
426                positionComponent(y, i, LEFT, parent);
427                positionComponent((y + offset), i, RIGHT, parent);
428
429                y = y + leftHeight;
430            }
431            else if (leftHeight < rightHeight)
432            {
433                int offset = (rightHeight - leftHeight) / 2;
434
435                positionComponent((y + offset), i, LEFT, parent);
436                positionComponent(y, i, RIGHT, parent);
437
438                y = y + rightHeight;
439            }
440            else
441            {
442                positionComponent(y, i, LEFT, parent);
443                positionComponent(y, i, RIGHT, parent);
444
445                y = y + leftHeight;
446            }
447        }
448    }
449
450    /**
451     * Positiones one component as instructed. Constraints for each component, such as
452     * <code>stretch</code>, <code>BOTH</code> and <code>indent</code> are taken into
453     * account. In addition, empty comonents are handled properly.
454     * 
455     * @param y the y location within the continer, where the component should be positioned.
456     * @param row the row of the component
457     * @param column the column of the component
458     * @param parent the container which needs to be laid out.
459     */
460    private void positionComponent(int y, int row, int column, Container parent)
461    {
462        TwoColumnConstraints constraints = null;
463
464        try
465        {
466            constraints = (TwoColumnConstraints) (components[column].elementAt(row));
467        }
468        catch (Throwable exception)
469        {
470            return;
471        }
472
473        int x = 0;
474
475        if (constraints != null)
476        {
477            Component component = constraints.component;
478            int width = (int) component.getPreferredSize().getWidth();
479            int height = (int) component.getPreferredSize().getHeight();
480
481            // --------------------------------------------------
482            // set x to the appropriate rule. The only need to
483            // modify this is for indent
484            // --------------------------------------------------
485            if (column == LEFT)
486            {
487                x = leftRule;
488            }
489            else
490            {
491                x = centerRule;
492            }
493
494            if (component != null)
495            {
496                // --------------------------------------------------
497                // set the width for stretch based on BOTH, LEFT and
498                // RIGHT positionsing
499                // --------------------------------------------------
500                if ((constraints.stretch) && (constraints.position == TwoColumnConstraints.BOTH))
501                {
502                    width = rightRule - leftRule;
503                    x = leftRule;
504                }
505                else if ((constraints.stretch) && (column == LEFT))
506                {
507                    width = centerRule - leftRule;
508                }
509                else if ((constraints.stretch) && (column == RIGHT))
510                {
511                    width = rightRule - centerRule;
512                }
513
514                // --------------------------------------------------
515                // if we straddle both columns but are not stretching
516                // use the preferred width as long as it is less then
517                // the width of both columns combined. Also set the x
518                // position to left, just to be sure.
519                // --------------------------------------------------
520                else if (constraints.position == TwoColumnConstraints.BOTH)
521                {
522                    if (width > (rightRule - leftRule))
523                    {
524                        width = rightRule - leftRule;
525                    }
526                    x = leftRule;
527                }
528
529                // --------------------------------------------------
530                // correct for indent if this option is set
531                // --------------------------------------------------
532                if (constraints.indent)
533                {
534                    width = width - indent;
535                    x = x + indent;
536                }
537
538                component.setBounds(x, y, width, height);
539            }
540        }
541    }
542
543    /**
544     * Returns the minimum width of the column requested.
545     * 
546     * @param column the columns to measure (LEFT / RIGHT)
547     * @param parent the component which needs to be laid out.
548     * 
549     * @return the minimum width required to fis the components in this column
550     */
551    private int minimumColumnWidth(int column, Container parent)
552    {
553        Component component = null;
554        TwoColumnConstraints constraints = null;
555        int width = 0;
556        int temp = 0;
557
558        for (int i = 0; i < components[column].size(); i++)
559        {
560            constraints = (TwoColumnConstraints) components[column].elementAt(i);
561
562            if ((constraints != null) && (constraints.position != TwoColumnConstraints.BOTH))
563            {
564                component = constraints.component;
565                temp = (int) component.getMinimumSize().getWidth();
566
567                if (constraints.indent)
568                {
569                    temp = temp + indent;
570                }
571
572                if (temp > width)
573                {
574                    width = temp;
575                }
576            }
577        }
578
579        return (width);
580    }
581
582    /**
583     * Retrunds the minimum width both columns together should have based on the minimum widths of
584     * all the components that straddle both columns and the minimum width of the title component.
585     * 
586     * @param parent the component which needs to be laid out.
587     * 
588     * @return the minimum width required to fis the components in this column
589     */
590    private int minimumBothColumnsWidth(Container parent)
591    {
592        Component component = null;
593        TwoColumnConstraints constraints = null;
594        int width = 0;
595        int temp = 0;
596
597        if (title != null)
598        {
599            component = title.component;
600            width = (int) component.getMinimumSize().getWidth();
601        }
602
603        for (int i = 0; i < components[LEFT].size(); i++)
604        {
605            constraints = (TwoColumnConstraints) components[LEFT].elementAt(i);
606
607            if ((constraints != null) && (constraints.position == TwoColumnConstraints.BOTH))
608            {
609                component = constraints.component;
610                temp = (int) component.getMinimumSize().getWidth();
611
612                if (constraints.indent)
613                {
614                    temp = temp + indent;
615                }
616
617                if (temp > width)
618                {
619                    width = temp;
620                }
621            }
622        }
623
624        return (width);
625    }
626
627    private int minimumClusterHeight()
628    {
629        int height = 0;
630
631        for (int i = 0; i < rows(); i++)
632        {
633            height = height + rowHeight(i);
634        }
635
636        return (height);
637    }
638
639    /**
640     * Returns the number of rows that need to be laid out.
641     */
642    private int rows()
643    {
644        int rows = 0;
645        int leftRows = components[LEFT].size();
646        int rightRows = components[RIGHT].size();
647
648        if (leftRows > rightRows)
649        {
650            rows = leftRows;
651        }
652        else
653        {
654            rows = rightRows;
655        }
656
657        return (rows);
658    }
659
660    /**
661     * Measures and returns the minimum height required to render the components in the indicated
662     * row.
663     * 
664     * @param row the index of the row to measure
665     */
666    private int rowHeight(int row)
667    {
668        int height = 0;
669        int height1 = height(row, LEFT);
670        int height2 = height(row, RIGHT);
671
672        // ----------------------------------------------------
673        // take the higher one
674        // ----------------------------------------------------
675        if (height1 > height2)
676        {
677            height = height1;
678        }
679        else
680        {
681            height = height2;
682        }
683
684        return (height);
685    }
686
687    /**
688     * Measures and returns the minimum height required to render the component in the indicated row
689     * and column.
690     * 
691     * @param row the index of the row to measure
692     * @param column the column of the component to measure (<code>LEFT</code> or
693     * <code>RIGHT</code>)
694     */
695    private int height(int row, int column)
696    {
697        int height = 0;
698        int width = 0;
699        Component component;
700        TwoColumnConstraints constraints;
701
702        try
703        {
704            constraints = (TwoColumnConstraints) components[column].elementAt(row);
705            if (constraints != null)
706            {
707                component = constraints.component;
708                width = (int) component.getMinimumSize().getWidth();
709                height = (int) component.getMinimumSize().getHeight();
710
711                if (constraints.position == TwoColumnConstraints.WEST)
712                {
713                    if (width > (centerRule - leftRule))
714                    {
715                        component.setBounds(0, 0, (centerRule - leftRule), height);
716                    }
717                }
718                else if (constraints.position == TwoColumnConstraints.EAST)
719                {
720                    if (width > (rightRule - centerRule))
721                    {
722                        component.setBounds(0, 0, (rightRule - centerRule), height);
723                    }
724                }
725                else if (constraints.position == TwoColumnConstraints.BOTH)
726                {
727                    if (width > (rightRule - leftRule))
728                    {
729                        component.setBounds(0, 0, (rightRule - leftRule), height);
730                    }
731                }
732
733                height = (int) component.getMinimumSize().getHeight();
734            }
735        }
736        // ----------------------------------------------------
737        // we might get an exception if one of the vectors is
738        // shorter, because we index out of bounds. If there
739        // is nothing there then the height is 0, nothing
740        // further to worry about!
741        // ----------------------------------------------------
742        catch (Throwable exception)
743        {}
744
745        return (height);
746    }
747
748    /**
749     * Computes the margin value based on the container width and the margin setting.
750     * 
751     * @param parent the component which needs to be laid out.
752     */
753    private int margin(Container parent)
754    {
755        int amount = (int) (((parent.getSize().getWidth()) * margin) / 100);
756
757        return (amount);
758    }
759
760    /**
761     * Computes the top buffer value based on the container width and the setting for the top buffer
762     * 
763     * @param usedHeight the amount of the parent component's height that is already in use (height
764     * of the title and the combined height of all rows).
765     * @param parent the component which needs to be laid out.
766     */
767    private int topBuffer(int usedHeight, Container parent)
768    {
769        int amount = ((int) parent.getSize().getHeight()) - usedHeight;
770        amount = (int) (amount * topBuffer) / 100;
771
772        return (amount);
773    }
774
775    /*--------------------------------------------------------------------------*/
776    /**
777     * Computes the indent value based on the container width and the indent setting.
778     * 
779     * @param parent the component which needs to be laid out.
780     */
781    /*--------------------------------------------------------------------------*/
782    /*
783     * private int indent (Container parent) { int amount = (int)(((parent.getMinimumSize
784     * ().getWidth ()) * indent) / 100);
785     * 
786     * return (amount); }
787     */
788    /**
789     * Calculates the preferred size dimensions for the specified panel given the components in the
790     * specified parent container.
791     * 
792     * @param parent the component to be laid out
793     */
794    public Dimension preferredLayoutSize(Container parent)
795    {
796        return (minimumLayoutSize(parent));
797    }
798
799    /**
800     * Calculates the minimum size dimensions for the specified panel given the components in the
801     * specified parent container.
802     * 
803     * @param parent the component to be laid out
804     */
805    public Dimension minimumLayoutSize(Container parent)
806    {
807        positionTitle(parent);
808
809        int width = minimumBothColumnsWidth(parent);
810        int height = minimumClusterHeight() + titleHeight;
811
812        return (new Dimension(width, height));
813    }
814
815    /**
816     * Calculates the maximum size dimensions for the specified panel given the components in the
817     * specified parent container.
818     * 
819     * @param parent the component to be laid out
820     */
821    public Dimension maximumLayoutSize(Container parent)
822    {
823        return (minimumLayoutSize(parent));
824    }
825
826    /**
827     * Returns the alignment along the x axis. This specifies how the component would like to be
828     * aligned relative to other components. The value should be a number between 0 and 1 where 0
829     * represents alignment along the origin, 1 is aligned the furthest away from the origin, 0.5 is
830     * centered, etc.
831     * 
832     * @param parent the component to be laid out
833     */
834    public float getLayoutAlignmentX(Container parent)
835    {
836        return (0);
837    }
838
839    /**
840     * Returns the alignment along the y axis. This specifies how the component would like to be
841     * aligned relative to other components. The value should be a number between 0 and 1 where 0
842     * represents alignment along the origin, 1 is aligned the furthest away from the origin, 0.5 is
843     * centered, etc.
844     * 
845     * @param parent the component to be laid out
846     */
847    public float getLayoutAlignmentY(Container parent)
848    {
849        return (0);
850    }
851
852    /**
853     * Invalidates the layout, indicating that if the layout manager has cached information it
854     * should be discarded.
855     * 
856     * @param parent the component to be laid out
857     */
858    public void invalidateLayout(Container parent)
859    {
860        leftRule = 0;
861        rightRule = 0;
862        centerRule = 0;
863        titleHeight = 0;
864    }
865
866    /**
867     * Adds the specified component with the specified name to the layout. This version is not
868     * supported, use <code>addLayoutComponent</code> with layout contsraints.
869     * 
870     * @param name the component name
871     * @param comp the component to be added
872     */
873    public void addLayoutComponent(String name, Component comp)
874    {
875    }
876
877    /**
878     * This functionality is not supported
879     * 
880     * @param comp the component to be removed
881     */
882    public void removeLayoutComponent(Component comp)
883    {
884    }
885
886    /**
887     * This method is provided for conveninence of debugging layout problems. It renders the three
888     * rules and the limit of the title marign visible after these positions have been computed. In
889     * addition, the indent locations are shown as dashed lines. To use this functionality do the
890     * following:<br>
891     * <br>
892     * <ul>
893     * <li>in the container using this layout manager override the <code>paint()</code> method.
894     * <li>in that method, first call <code>super.paint()</code>
895     * <li>then call this method
896     * </ul>
897     * <br>
898     * <b>Note:</b> cast the graphics object received in the <code>paint()</code> method to
899     * <code>Graphics2D</code> when making the call.<br>
900     * <br>
901     * 
902     * @param graphics the graphics context used for drawing.
903     * @param color the color to use for rendering the layout grid
904     */
905    public void showRules(Graphics2D graphics, Color color)
906    {
907        int height = graphics.getClipBounds().height;
908
909        Stroke currentStroke = graphics.getStroke();
910        Color currentColor = graphics.getColor();
911
912        Stroke stroke = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 1.5f,
913                new float[] { 10, 5}, 5);
914        graphics.setColor(color);
915
916        graphics.drawLine(leftRule, 0, leftRule, height);
917        graphics.drawLine(centerRule, titleHeight, centerRule, height);
918        graphics.drawLine(rightRule, 0, rightRule, height);
919        graphics.drawLine(leftRule, titleHeight, rightRule, titleHeight);
920
921        graphics.setStroke(stroke);
922        graphics.drawLine((leftRule + indent), titleHeight, (leftRule + indent), height);
923        graphics.drawLine((centerRule + indent), titleHeight, (centerRule + indent), height);
924
925        graphics.setStroke(currentStroke);
926        graphics.setColor(currentColor);
927    }
928}
929/*---------------------------------------------------------------------------*/