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
043package org.jfree.layout;
044
045import java.awt.Component;
046import java.awt.Container;
047import java.awt.Dimension;
048import java.awt.Insets;
049import java.awt.LayoutManager;
050import java.io.Serializable;
051
052/**
053 * Specialised layout manager for a grid of components.
054 *
055 * @author David Gilbert
056 */
057public 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}