001    /* ========================================================================
002     * JCommon : a free general purpose class library for the Java(tm) platform
003     * ========================================================================
004     *
005     * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
006     * 
007     * Project Info:  http://www.jfree.org/jcommon/index.html
008     *
009     * This library is free software; you can redistribute it and/or modify it 
010     * under the terms of the GNU Lesser General Public License as published by 
011     * the Free Software Foundation; either version 2.1 of the License, or 
012     * (at your option) any later version.
013     *
014     * This library is distributed in the hope that it will be useful, but 
015     * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
016     * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
017     * License for more details.
018     *
019     * You should have received a copy of the GNU Lesser General Public
020     * License along with this library; if not, write to the Free Software
021     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
022     * USA.  
023     *
024     * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
025     * in the United States and other countries.]
026     * 
027     * --------------
028     * LCBLayout.java
029     * --------------
030     * (C) Copyright 2000-2005, by Object Refinery Limited.
031     *
032     * Original Author:  David Gilbert (for Object Refinery Limited);
033     * Contributor(s):   -;
034     *
035     * $Id: LCBLayout.java,v 1.5 2005/11/16 15:58:40 taqua Exp $
036     *
037     * Changes (from 26-Oct-2001)
038     * --------------------------
039     * 26-Oct-2001 : Changed package to com.jrefinery.layout.* (DG);
040     * 10-Oct-2002 : Fixed errors reported by Checkstyle (DG);
041     */
042    
043    package org.jfree.layout;
044    
045    import java.awt.Component;
046    import java.awt.Container;
047    import java.awt.Dimension;
048    import java.awt.Insets;
049    import java.awt.LayoutManager;
050    import java.io.Serializable;
051    
052    /**
053     * Specialised layout manager for a grid of components.
054     *
055     * @author David Gilbert
056     */
057    public class LCBLayout implements LayoutManager, Serializable {
058    
059        /** For serialization. */
060        private static final long serialVersionUID = -2531780832406163833L;
061        
062        /** A constant for the number of columns in the layout. */
063        private static final int COLUMNS = 3;
064    
065        /** Tracks the column widths. */
066        private int[] colWidth;
067    
068        /** Tracks the row heights. */
069        private int[] rowHeight;
070    
071        /** The gap between each label and component. */
072        private int labelGap;
073    
074        /** The gap between each component and button. */
075        private int buttonGap;
076    
077        /** The gap between rows. */
078        private int vGap;
079    
080        /**
081         * Creates a new LCBLayout with the specified maximum number of rows.
082         *
083         * @param maxrows  the maximum number of rows.
084         */
085        public LCBLayout(final int maxrows) {
086            this.labelGap = 10;
087            this.buttonGap = 6;
088            this.vGap = 2;
089            this.colWidth = new int[COLUMNS];
090            this.rowHeight = new int[maxrows];
091        }
092    
093        /**
094         * Returns the preferred size using this layout manager.
095         *
096         * @param parent  the parent.
097         *
098         * @return the preferred size using this layout manager.
099        */
100        public Dimension preferredLayoutSize(final Container parent) {
101    
102            synchronized (parent.getTreeLock()) {
103                final Insets insets = parent.getInsets();
104                final int ncomponents = parent.getComponentCount();
105                final int nrows = ncomponents / COLUMNS;
106                for (int c = 0; c < COLUMNS; c++) {
107                    for (int r = 0; r < nrows; r++) {
108                        final Component component 
109                            = parent.getComponent(r * COLUMNS + c);
110                        final Dimension d = component.getPreferredSize();
111                        if (this.colWidth[c] < d.width) {
112                            this.colWidth[c] = d.width;
113                        }
114                        if (this.rowHeight[r] < d.height) {
115                            this.rowHeight[r] = d.height;
116                        }
117                    }
118                }
119                int totalHeight = this.vGap * (nrows - 1);
120                for (int r = 0; r < nrows; r++) {
121                    totalHeight = totalHeight + this.rowHeight[r];
122                }
123                final int totalWidth = this.colWidth[0] + this.labelGap 
124                    + this.colWidth[1] + this.buttonGap + this.colWidth[2];
125                return new Dimension(
126                    insets.left + insets.right + totalWidth + this.labelGap 
127                        + this.buttonGap,
128                    insets.top + insets.bottom + totalHeight + this.vGap
129                );
130            }
131    
132        }
133    
134        /**
135         * Returns the minimum size using this layout manager.
136         *
137         * @param parent  the parent.
138         *
139         * @return the minimum size using this layout manager.
140         */
141        public Dimension minimumLayoutSize(final Container parent) {
142    
143            synchronized (parent.getTreeLock()) {
144                final Insets insets = parent.getInsets();
145                final int ncomponents = parent.getComponentCount();
146                final int nrows = ncomponents / COLUMNS;
147                for (int c = 0; c < COLUMNS; c++) {
148                    for (int r = 0; r < nrows; r++) {
149                        final Component component 
150                            = parent.getComponent(r * COLUMNS + c);
151                        final Dimension d = component.getMinimumSize();
152                        if (this.colWidth[c] < d.width) {
153                            this.colWidth[c] = d.width;
154                        }
155                        if (this.rowHeight[r] < d.height) {
156                            this.rowHeight[r] = d.height;
157                        }
158                    }
159                }
160                int totalHeight = this.vGap * (nrows - 1);
161                for (int r = 0; r < nrows; r++) {
162                    totalHeight = totalHeight + this.rowHeight[r];
163                }
164                final int totalWidth = this.colWidth[0] + this.labelGap 
165                    + this.colWidth[1] + this.buttonGap + this.colWidth[2];
166                return new Dimension(
167                    insets.left + insets.right + totalWidth + this.labelGap 
168                    + this.buttonGap,
169                    insets.top + insets.bottom + totalHeight + this.vGap
170                );
171            }
172    
173        }
174    
175        /**
176         * Lays out the components.
177         *
178         * @param parent  the parent.
179         */
180        public void layoutContainer(final Container parent) {
181    
182            synchronized (parent.getTreeLock()) {
183                final Insets insets = parent.getInsets();
184                final int ncomponents = parent.getComponentCount();
185                final int nrows = ncomponents / COLUMNS;
186                for (int c = 0; c < COLUMNS; c++) {
187                    for (int r = 0; r < nrows; r++) {
188                        final Component component 
189                            = parent.getComponent(r * COLUMNS + c);
190                        final Dimension d = component.getPreferredSize();
191                        if (this.colWidth[c] < d.width) {
192                            this.colWidth[c] = d.width;
193                        }
194                        if (this.rowHeight[r] < d.height) {
195                            this.rowHeight[r] = d.height;
196                        }
197                    }
198                }
199                int totalHeight = this.vGap * (nrows - 1);
200                for (int r = 0; r < nrows; r++) {
201                    totalHeight = totalHeight + this.rowHeight[r];
202                }
203                final int totalWidth = this.colWidth[0] + this.colWidth[1] 
204                                                        + this.colWidth[2];
205    
206                // adjust the width of the second column to use up all of parent
207                final int available = parent.getWidth() - insets.left 
208                    - insets.right - this.labelGap - this.buttonGap;
209                this.colWidth[1] = this.colWidth[1] + (available - totalWidth);
210    
211                // *** DO THE LAYOUT ***
212                int x = insets.left;
213                for (int c = 0; c < COLUMNS; c++) {
214                    int y = insets.top;
215                    for (int r = 0; r < nrows; r++) {
216                        final int i = r * COLUMNS + c;
217                        if (i < ncomponents) {
218                            final Component component = parent.getComponent(i);
219                            final Dimension d = component.getPreferredSize();
220                            final int h = d.height;
221                            final int adjust = (this.rowHeight[r] - h) / 2;
222                            parent.getComponent(i).setBounds(x, y + adjust, 
223                                    this.colWidth[c], h);
224                        }
225                        y = y + this.rowHeight[r] + this.vGap;
226                    }
227                    x = x + this.colWidth[c];
228                    if (c == 0) {
229                        x = x + this.labelGap;
230                    }
231                    if (c == 1) {
232                        x = x + this.buttonGap;
233                    }
234                }
235    
236            }
237    
238        }
239    
240        /**
241         * Not used.
242         *
243         * @param comp  the component.
244         */
245        public void addLayoutComponent(final Component comp) {
246            // not used
247        }
248    
249        /**
250         * Not used.
251         *
252         * @param comp  the component.
253         */
254        public void removeLayoutComponent(final Component comp) {
255            // not used
256        }
257    
258        /**
259         * Not used.
260         *
261         * @param name  the component name.
262         * @param comp  the component.
263         */
264        public void addLayoutComponent(final String name, final Component comp) {
265            // not used
266        }
267    
268        /**
269         * Not used.
270         *
271         * @param name  the component name.
272         * @param comp  the component.
273         */
274        public void removeLayoutComponent(final String name, final Component comp) {
275            // not used
276        }
277    
278    }