/* * Copyright 2008-2011 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jdal.swing.form; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.List; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JTextField; import javax.swing.border.Border; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.MessageSource; /** * A FormBuilder that create form using BoxLayouts * Add components using a implicit cursor. * * @author Jose Luis Martin - (jlm@joseluismartin.info) */ public class SimpleBoxFormBuilder { public static final int SIZE_UNDEFINED = Short.MAX_VALUE; private static final Log log = LogFactory.getLog(SimpleBoxFormBuilder.class); private Box container = Box.createHorizontalBox(); private List<Box> columns = new ArrayList<Box>(); private List<Integer> columnsWidth = new ArrayList<Integer>(); private List<Integer> rowsHeight = new ArrayList<Integer>(); private int index = 0; private int rows = 0; private int rowHeight = 25; private int defaultRowHeight = 25; private int defaultSpace = 5; private int charWidth = 6; private boolean debug = false; private boolean fixedHeight = false; private MessageSource messageSource; private FormFocusTransversalPolicy focusTransversal = new FormFocusTransversalPolicy(); private Border border = null; /** * Default Ctor */ public SimpleBoxFormBuilder() { this(calculateDefaultHeight(), null); } public SimpleBoxFormBuilder(Border border) { this(calculateDefaultHeight(), border); } public SimpleBoxFormBuilder(int defaultRowHeight) { this(defaultRowHeight, null); } public SimpleBoxFormBuilder(int defaultRowHeight, Border border) { this.defaultRowHeight = defaultRowHeight; this.border = border; } /** * Add a component to Form at position pointer by cursor, * Increments cursor by one. * @param c Component to add */ public void add(Component c) { if (debug) { if (c instanceof JComponent) ((JComponent) c).setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY)); } addBox(c); if (rowHeight < Short.MAX_VALUE) { Dimension d = c.getPreferredSize(); d.height = rowHeight; c.setPreferredSize(d); c.setMinimumSize(d); if (!c.isMaximumSizeSet() || c.getMaximumSize().getHeight() > rowHeight) { c.setMaximumSize(new Dimension(Short.MAX_VALUE, rowHeight)); } } } public void add(Component c, int maxWidth) { add(c); setMaxWidth(maxWidth); } public void addBox(Component c) { if (rows == 0 && rowsHeight.isEmpty()) { log.warn("You must call row() before adding components. I will add a row with default height for you"); row(); } Box column = getColumn(); if (rows > 1) column.add(Box.createVerticalStrut(defaultSpace)); column.add(c); // don't add Labels to focus transversal if (!(c instanceof JLabel)) { focusTransversal.add(c); } else { // null or empty labels don't size well if (StringUtils.isEmpty(((JLabel) c).getText())) ((JLabel) c).setText(" "); } index++; } /** * Gets current column pointed to cursor, create one if none. * @return a new or existent column Box. */ private Box getColumn() { Box column = null; if (index < columns.size()) { column = (Box) columns.get(index); } else { if (!columns.isEmpty()) container.add(Box.createHorizontalStrut(defaultSpace)); column = Box.createVerticalBox(); columns.add(column); container.add(column); columnsWidth.add(0); if (debug) { column.setBorder(BorderFactory.createLineBorder(Color.RED)); } } return column; } /** * Add a component with label, increments cursor by two. * @param name label string * @param c component. */ public void add(String name, Component c) { JLabel label = new JLabel(name); add(label); Rectangle2D rec = label.getFontMetrics(label.getFont()).getStringBounds(name, container.getGraphics()); setMaxWidth(rec.getBounds().width + 10); add(c); } /** * @param i */ public void setMaxWidth(int i) { if (i > columnsWidth.get(index - 1)) { columnsWidth.set(index - 1, i); } } public void row() { row(defaultRowHeight); } /** * Move cursor to next row. */ public void row(int rowHeight) { index = 0; rows++; rowsHeight.add(rowHeight); this.rowHeight = rowHeight; } /** * Builds the panel form. * @return the form component */ public JComponent getForm() { // set sizes; int columnHeight= 0; for (int h : rowsHeight) columnHeight += h; // add space into components (fillers) columnHeight += (rows -1) * defaultSpace; for (int i = 0; i < columns.size(); i++) { Box box = columns.get(i); int maxWidth = columnsWidth.get(i) == 0 ? Short.MAX_VALUE : columnsWidth.get(i); box.setMaximumSize(new Dimension(maxWidth, columnHeight)); if (maxWidth < Short.MAX_VALUE && columnHeight < Short.MAX_VALUE) { box.setMinimumSize(new Dimension(maxWidth, columnHeight)); box.setPreferredSize(new Dimension(maxWidth, columnHeight)); } } container.setFocusTraversalPolicy(focusTransversal); container.setFocusTraversalPolicyProvider(true); container.setSize(Short.MAX_VALUE, columnHeight); if (isFixedHeight()) { Dimension maxSize = new Dimension(Short.MAX_VALUE, columnHeight); if (container.isMaximumSizeSet()) { maxSize = container.getMaximumSize(); maxSize.height = columnHeight; } container.setMaximumSize(maxSize); } if (isDebug()) container.setBorder(BorderFactory.createLineBorder(Color.BLUE)); if (border != null) container.setBorder(border); return container; } /** * Reset the form builder to reuse for creating a new panel */ public void reset() { columns = new ArrayList<Box>(); columnsWidth = new ArrayList<Integer>(); rowsHeight = new ArrayList<Integer>(); container = Box.createHorizontalBox(); index = 0; rows = 0; focusTransversal = new FormFocusTransversalPolicy(); } public void next() { getColumn(); index++; } // Getters & Setters public int getHeight() { return rowHeight; } public void setHeight(int height) { this.rowHeight = height; if (rowsHeight.size() > 0 && rows > 0) { rowsHeight.remove(rows -1); rowsHeight.add(height); } } public boolean isDebug() { return debug; } public void setDebug(boolean debug) { this.debug = debug; } public MessageSource getMessageSource() { return messageSource; } public void setMessageSource(MessageSource messageSource) { this.messageSource = messageSource; } /** * @return the fixedHeight */ public boolean isFixedHeight() { return fixedHeight; } /** * @param fixedHeight the fixedHeight to set */ public void setFixedHeight(boolean fixedHeight) { this.fixedHeight = fixedHeight; } /** * @return the defaultRowHeight */ public int getDefaultRowHeight() { return defaultRowHeight; } /** * @param defaultRowHeight the defaultRowHeight to set */ public void setDefaultRowHeight(int defaultRowHeight) { this.defaultRowHeight = defaultRowHeight; } /** * @return the border */ public Border getBorder() { return border; } /** * @param border the border to set */ public void setBorder(Border border) { this.border = border; } /** * @return the defaultSpace */ public int getDefaultSpace() { return defaultSpace; } /** * @param defaultSpace the defaultSpace to set */ public void setDefaultSpace(int defaultSpace) { this.defaultSpace = defaultSpace; } /** * @return the charWidth */ public int getCharWidth() { return charWidth; } /** * @param charWidth the charWidth to set */ public void setCharWidth(int charWidth) { this.charWidth = charWidth; } /** * @return */ private static int calculateDefaultHeight() { Dimension d = new JTextField().getPreferredSize(); return d != null ? d.height : 25; } }