001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-present, by David Gilbert and Contributors.
006 *
007 * Project Info:  http://www.jfree.org/jfreechart/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 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 
025 * Other names may be trademarks of their respective owners.]
026 *
027 */
028
029package org.jfree.chart.ui;
030
031import java.awt.Component;
032import java.awt.Container;
033import java.awt.Dimension;
034import java.awt.Insets;
035import java.awt.LayoutManager;
036import java.io.Serializable;
037
038/**
039 * Specialised layout manager for a grid of components.
040 */
041public class LCBLayout implements LayoutManager, Serializable {
042
043    /** For serialization. */
044    private static final long serialVersionUID = -2531780832406163833L;
045    
046    /** A constant for the number of columns in the layout. */
047    private static final int COLUMNS = 3;
048
049    /** Tracks the column widths. */
050    private int[] colWidth;
051
052    /** Tracks the row heights. */
053    private int[] rowHeight;
054
055    /** The gap between each label and component. */
056    private int labelGap;
057
058    /** The gap between each component and button. */
059    private int buttonGap;
060
061    /** The gap between rows. */
062    private int vGap;
063
064    /**
065     * Creates a new LCBLayout with the specified maximum number of rows.
066     *
067     * @param maxrows  the maximum number of rows.
068     */
069    public LCBLayout(int maxrows) {
070        this.labelGap = 10;
071        this.buttonGap = 6;
072        this.vGap = 2;
073        this.colWidth = new int[COLUMNS];
074        this.rowHeight = new int[maxrows];
075    }
076
077    /**
078     * Returns the preferred size using this layout manager.
079     *
080     * @param parent  the parent.
081     *
082     * @return the preferred size using this layout manager.
083    */
084    @Override
085    public Dimension preferredLayoutSize(Container parent) {
086
087        synchronized (parent.getTreeLock()) {
088            Insets insets = parent.getInsets();
089            int ncomponents = parent.getComponentCount();
090            int nrows = ncomponents / COLUMNS;
091            for (int c = 0; c < COLUMNS; c++) {
092                for (int r = 0; r < nrows; r++) {
093                    Component component = parent.getComponent(r * COLUMNS + c);
094                    Dimension d = component.getPreferredSize();
095                    if (this.colWidth[c] < d.width) {
096                        this.colWidth[c] = d.width;
097                    }
098                    if (this.rowHeight[r] < d.height) {
099                        this.rowHeight[r] = d.height;
100                    }
101                }
102            }
103            int totalHeight = this.vGap * (nrows - 1);
104            for (int r = 0; r < nrows; r++) {
105                totalHeight = totalHeight + this.rowHeight[r];
106            }
107            int totalWidth = this.colWidth[0] + this.labelGap 
108                + this.colWidth[1] + this.buttonGap + this.colWidth[2];
109            return new Dimension(
110                insets.left + insets.right + totalWidth + this.labelGap 
111                    + this.buttonGap,
112                insets.top + insets.bottom + totalHeight + this.vGap
113            );
114        }
115
116    }
117
118    /**
119     * Returns the minimum size using this layout manager.
120     *
121     * @param parent  the parent.
122     *
123     * @return the minimum size using this layout manager.
124     */
125    @Override
126    public Dimension minimumLayoutSize(Container parent) {
127
128        synchronized (parent.getTreeLock()) {
129            Insets insets = parent.getInsets();
130            int ncomponents = parent.getComponentCount();
131            int nrows = ncomponents / COLUMNS;
132            for (int c = 0; c < COLUMNS; c++) {
133                for (int r = 0; r < nrows; r++) {
134                    Component component = parent.getComponent(r * COLUMNS + c);
135                    Dimension d = component.getMinimumSize();
136                    if (this.colWidth[c] < d.width) {
137                        this.colWidth[c] = d.width;
138                    }
139                    if (this.rowHeight[r] < d.height) {
140                        this.rowHeight[r] = d.height;
141                    }
142                }
143            }
144            int totalHeight = this.vGap * (nrows - 1);
145            for (int r = 0; r < nrows; r++) {
146                totalHeight = totalHeight + this.rowHeight[r];
147            }
148            int totalWidth = this.colWidth[0] + this.labelGap 
149                + this.colWidth[1] + this.buttonGap + this.colWidth[2];
150            return new Dimension(
151                insets.left + insets.right + totalWidth + this.labelGap 
152                + this.buttonGap,
153                insets.top + insets.bottom + totalHeight + this.vGap
154            );
155        }
156
157    }
158
159    /**
160     * Lays out the components.
161     *
162     * @param parent  the parent.
163     */
164    @Override
165    public void layoutContainer(Container parent) {
166
167        synchronized (parent.getTreeLock()) {
168            Insets insets = parent.getInsets();
169            int ncomponents = parent.getComponentCount();
170            int nrows = ncomponents / COLUMNS;
171            for (int c = 0; c < COLUMNS; c++) {
172                for (int r = 0; r < nrows; r++) {
173                    Component component = parent.getComponent(r * COLUMNS + c);
174                    Dimension d = component.getPreferredSize();
175                    if (this.colWidth[c] < d.width) {
176                        this.colWidth[c] = d.width;
177                    }
178                    if (this.rowHeight[r] < d.height) {
179                        this.rowHeight[r] = d.height;
180                    }
181                }
182            }
183            int totalHeight = this.vGap * (nrows - 1);
184            for (int r = 0; r < nrows; r++) {
185                totalHeight = totalHeight + this.rowHeight[r];
186            }
187            int totalWidth = this.colWidth[0] + this.colWidth[1] 
188                                                    + this.colWidth[2];
189
190            // adjust the width of the second column to use up all of parent
191            int available = parent.getWidth() - insets.left 
192                - insets.right - this.labelGap - this.buttonGap;
193            this.colWidth[1] = this.colWidth[1] + (available - totalWidth);
194
195            // *** DO THE LAYOUT ***
196            int x = insets.left;
197            for (int c = 0; c < COLUMNS; c++) {
198                int y = insets.top;
199                for (int r = 0; r < nrows; r++) {
200                    int i = r * COLUMNS + c;
201                    if (i < ncomponents) {
202                        Component component = parent.getComponent(i);
203                        Dimension d = component.getPreferredSize();
204                        int h = d.height;
205                        int adjust = (this.rowHeight[r] - h) / 2;
206                        parent.getComponent(i).setBounds(x, y + adjust, 
207                                this.colWidth[c], h);
208                    }
209                    y = y + this.rowHeight[r] + this.vGap;
210                }
211                x = x + this.colWidth[c];
212                if (c == 0) {
213                    x = x + this.labelGap;
214                }
215                if (c == 1) {
216                    x = x + this.buttonGap;
217                }
218            }
219
220        }
221
222    }
223
224    /**
225     * Not used.
226     *
227     * @param comp  the component.
228     */
229    public void addLayoutComponent(Component comp) {
230        // not used
231    }
232
233    /**
234     * Not used.
235     *
236     * @param comp  the component.
237     */
238    @Override
239    public void removeLayoutComponent(Component comp) {
240        // not used
241    }
242
243    /**
244     * Not used.
245     *
246     * @param name  the component name.
247     * @param comp  the component.
248     */
249    @Override
250    public void addLayoutComponent(String name, Component comp) {
251        // not used
252    }
253
254    /**
255     * Not used.
256     *
257     * @param name  the component name.
258     * @param comp  the component.
259     */
260    public void removeLayoutComponent(String name, Component comp) {
261        // not used
262    }
263
264}