/* * Copyright 2004-2007 IDCA. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the * following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and * the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are those of the authors and * should not be interpreted as representing official policies, either expressed or implied, of IDCA. */ package com.idcanet.vasc.impl.swing; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Font; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.FileOutputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.Spring; import javax.swing.SpringLayout; import javax.swing.UIManager; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.JTableHeader; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import com.idcanet.fff.SwingImageHelper; import com.idcanet.vasc.core.VascDataExporter; import com.idcanet.vasc.core.VascEventListener; import com.idcanet.vasc.core.VascTable; import com.idcanet.vasc.core.VascUserOption; import com.idcanet.vasc.core.VascViewRenderer; import com.idcanet.vasc.core.actions.GlobalVascAction; import com.idcanet.vasc.core.actions.RowVascAction; import com.idcanet.vasc.core.column.VascTableColumn; import com.idcanet.vasc.core.ui.VascColorChooser; import com.idcanet.vasc.core.ui.VascColumnValueModelListener; import com.idcanet.vasc.core.ui.VascDate; import com.idcanet.vasc.core.ui.VascList; import com.idcanet.vasc.core.ui.VascTextField; import com.idcanet.vasc.core.ui.VascToggle; import com.idcanet.vasc.core.ui.VascUIComponent; import com.idcanet.vasc.core.ui.VascValueModel; import com.idcanet.vasc.impl.swing.ui.SwingColorChooser; import com.idcanet.vasc.impl.swing.ui.SwingDate; import com.idcanet.vasc.impl.swing.ui.SwingList; import com.idcanet.vasc.impl.swing.ui.SwingTextField; import com.idcanet.vasc.impl.swing.ui.SwingToggle; /** * * @author Willem Cazander * @version 1.0 Mar 21, 2007 */ public class SwingVascViewRenderer implements VascViewRenderer { private Logger logger = null; private JComponent parent = null; private VascTable table = null; public SwingVascViewRenderer(JComponent parent) { logger = Logger.getLogger(SwingVascViewRenderer.class.getName()); this.parent=parent; } public void initTable(VascTable table) throws Exception { if (table.getVascViewRenderer()==null) { table.setVascViewRenderer(this); } else { if (table.getVascViewRenderer()!=this) { throw new IllegalArgumentException("VascTable has already a differtent VascViewRenderer attected"); } } table.getVascTableController().finalizeVascColumns(table); table.getVascTableController().finalizeVascTable(table); table.getVascTableController().refreshData(table); table.putUIComponent(VascTextField.class, SwingTextField.class); table.putUIComponent(VascList.class, SwingList.class); table.putUIComponent(VascToggle.class, SwingToggle.class); table.putUIComponent(VascDate.class, SwingDate.class); table.putUIComponent(VascColorChooser.class, SwingColorChooser.class); this.table=table; } public ImageIcon getImageIcon(String imageResource) { /// TODO hack beter String key = table.getVascTextValue().getTextValue(imageResource); //logger.fine("KEY======================="+key); if (key.indexOf("META-INF")>0 | key.indexOf("resource")>0) { return SwingImageHelper.getImageIcon(key); } else { return null; } } /** * @see com.idcanet.vasc.core.VascViewRenderer#renderEdit(com.idcanet.vasc.core.VascTable, java.lang.Object) */ public void renderEdit(Object rowBean) throws Exception { logger.fine("Rending Edit View"); rowBean = table.getVascTableController().initEditObject(table, rowBean); String beanValue = rowBean.toString(); if (table.getUIIdentifierVascTableColomn()!=null) { Object vv = table.getUIIdentifierVascTableColomn().getVascColumnValue().getValue(table.getUIIdentifierVascTableColomn(), rowBean); if (vv==null) { beanValue=""; } else { beanValue=""+vv; } if (beanValue.length()>30) { beanValue=beanValue.substring(0, 30); } } SwingEditDialog dialog = new SwingEditDialog(parent,table,rowBean,table.getVascTextValue().getTextValue("vasc.dialog.edit.title"),table.getVascTextValue().getTextValue("vasc.dialog.edit.message",beanValue)); Object result = dialog.openDialog(); logger.finest("OPEN closed : "+result); if(result==null) { return; } table.getVascTableController().mergeObject(table, result); } public void renderDelete(Object rowBean) throws Exception { String beanValue = rowBean.toString(); if (table.getUIIdentifierVascTableColomn()!=null) { beanValue = ""+table.getUIIdentifierVascTableColomn().getVascColumnValue().getValue(table.getUIIdentifierVascTableColomn(), rowBean); if (beanValue.length()>30) { beanValue=beanValue.substring(0, 30); } } int response = JOptionPane.showOptionDialog( parent // Center in window. , table.getVascTextValue().getTextValue("vasc.dialog.delete.message",beanValue) // Message , table.getVascTextValue().getTextValue("vasc.dialog.delete.title") // Title in titlebar , JOptionPane.YES_NO_OPTION // Option type , JOptionPane.PLAIN_MESSAGE // messageType , null // Icon (none) , null // Button text as above. , null // Default button's label ); if (response==JOptionPane.YES_OPTION) { table.getVascDataSource().delete(rowBean); table.getTableData().remove(rowBean); table.setSelectedObject(null); table.getVascTableController().fireVascEvent(VascEventListener.VascEventType.DATA_UPDATE, rowBean); } } class SwingEditDialog extends JDialog { private static final long serialVersionUID = 10L; private String headerText = null; private Object result = null; private Object bean = null; public SwingEditDialog(JComponent parent,VascTable table,Object bean,String title,String headerText) throws Exception { super(); this.headerText = headerText; this.bean = bean; setTitle(table.getVascTextValue().getTextValue(title)); setModal(true); JPanel pane = new JPanel(); pane.setLayout(new BorderLayout()); JPanel header = new JPanel(); createHeader(header); pane.add(header,BorderLayout.NORTH); JPanel body = new JPanel(); createBody(body); pane.add(body,BorderLayout.CENTER); JPanel footer = new JPanel(); createFooter(footer); pane.add(footer,BorderLayout.SOUTH); add(pane); setDefaultCloseOperation(DISPOSE_ON_CLOSE); //Ensure the text field always gets the first focus. //addComponentListener(new ComponentAdapter() { // public void componentShown(ComponentEvent ce) { // textField.requestFocusInWindow(); // } /// }); pack(); setLocationRelativeTo(parent); } public Object openDialog() { setVisible(true); return result; } public void createHeader(JPanel header) { JLabel l = new JLabel(); l.setText(table.getVascTextValue().getTextValue(headerText)); l.setFont(new Font(null,Font.BOLD, 14)); //l.setToolTipText(table.getVascTextValue().getTextValue(headerText)); header.add(l); } public void createBody(JPanel body) throws Exception { body.setLayout(new SpringLayout()); int column = 0; for(VascTableColumn c:table.getTableColumns()) { table.getVascTableController().initEditObjectColumn(c, bean); if (c.isEditDisplay()==false) { continue; } column++; JLabel l = new JLabel(); l.setHorizontalAlignment(JLabel.TRAILING); l.setText(table.getVascTextValue().getTextValue(c.getName())); if(c.getToolTip()!=null) { l.setToolTipText(table.getVascTextValue().getTextValue(c.getToolTip())); } body.add(l); if (c.isEditReadonly()==true) { JLabel valueLabel = new JLabel(); valueLabel.setText(""+c.getVascColumnValue().getValue(c, bean)); c.setColumnEditor(valueLabel); body.add(valueLabel); continue; } if(c.getVascUIComponent()==null) { JLabel valueLabel = new JLabel(); valueLabel.setText(""+c.getVascColumnValue().getValue(c, bean)); c.setColumnEditor(valueLabel); body.add(valueLabel); } else { VascUIComponent comp = c.getVascUIComponent(); VascValueModel model = new VascValueModel(table); model.setValue(c.getVascColumnValue().getValue(c, bean)); model.addListener(new VascColumnValueModelListener(c,bean)); comp.createComponent(table, model, body); c.setColumnEditor(comp); } } //JComponent, rows, cols, initX, initY ,xPad, yPad SpringUtilities.makeCompactGrid(body, column,2, 6,6, 6,6); } public void createFooter(JPanel footer) { JButton saveButton = new JButton(); saveButton.setIcon(getImageIcon("vasc.dialog.save.image")); saveButton.setText(table.getVascTextValue().getTextValue("vasc.dialog.save.name")); saveButton.setToolTipText(table.getVascTextValue().getTextValue("vasc.dialog.save.tooltip")); saveButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { if(table.getVascTableController().setUIComponentsBeanErrors(table, bean)) { return; } result = bean; setVisible(false); } }); footer.add(saveButton); JButton cancelButton = new JButton(); cancelButton.setIcon(getImageIcon("vasc.dialog.cancel.image")); cancelButton.setText(table.getVascTextValue().getTextValue("vasc.dialog.cancel.name")); cancelButton.setToolTipText(table.getVascTextValue().getTextValue("vasc.dialog.cancel.tooltip")); cancelButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { result = null; setVisible(false); } }); footer.add(cancelButton); } } /** * @see com.idcanet.vasc.core.VascViewRenderer#renderExport(com.idcanet.vasc.core.VascTable, com.idcanet.vasc.core.VascDataExporter) */ public void renderExport(VascDataExporter exporter) throws Exception { String fileName = null; JFileChooser c = new JFileChooser(); // Demonstrate "Save" dialog: int rVal = c.showSaveDialog(null); if (rVal == JFileChooser.APPROVE_OPTION) { fileName = c.getSelectedFile().getAbsolutePath(); // filename.setText(c.getSelectedFile().getName()); //dir.setText(c.getCurrentDirectory().toString()); } if (rVal == JFileChooser.CANCEL_OPTION) { return; } logger.fine("FileName: "+fileName); if (fileName == null) { return; } OutputStream out = new FileOutputStream(fileName); try { exporter.doExport(out, table); } catch (Exception e) { table.getVascTableController().handleException(e, table); } finally { if (out!=null) { out.close(); } } } /** * @see com.idcanet.vasc.core.VascViewRenderer#renderView(com.idcanet.vasc.core.VascTable) */ public void renderView() throws Exception { JPanel topPanel = new JPanel(); topPanel.setLayout(new BorderLayout()); //topPanel.setBackground(Color.PINK); JPanel n = new JPanel(); topPanel.add(n,BorderLayout.NORTH); renderHeader(n); JPanel c = new JPanel(); c.setLayout(new BorderLayout()); topPanel.add(c,BorderLayout.CENTER); renderBody(c); JPanel f = new JPanel(); //f.setBackground(Color.BLUE); topPanel.add(f,BorderLayout.SOUTH); renderFooter(f); //parent.setBackground(Color.CYAN); parent.setLayout(new BorderLayout()); parent.add(topPanel); } private void renderHeader(JComponent parent2) { JPanel header = new JPanel(); header.setLayout(new BorderLayout()); header.setBackground(Color.WHITE); header.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); if(table.getHeaderImage()!=null) { JLabel l = new JLabel(); // TODO: hack images working l.setIcon(new ImageIcon(Toolkit.getDefaultToolkit().createImage(getClass().getResource(table.getHeaderImage())).getScaledInstance(32, 32, Image.SCALE_SMOOTH))); if (table.getHeaderToolTip()!=null) { l.setToolTipText(table.getVascTextValue().getTextValue(table.getHeaderToolTip())); } header.add(l,BorderLayout.WEST); } if(table.getHeaderName()!=null) { JLabel l = new JLabel(table.getVascTextValue().getTextValue(table.getHeaderName())); l.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); l.setFont(new Font(null,Font.BOLD, 18)); if (table.getHeaderToolTip()!=null) { l.setToolTipText(table.getVascTextValue().getTextValue(table.getHeaderToolTip())); } header.add(l,BorderLayout.CENTER); } JPanel top = new JPanel(); //top.setBackground(Color.BLUE); for (GlobalVascAction action:table.getGlobalActions()) { JButton but = new JButton(); but.setText(table.getVascTextValue().getTextValue(action.getName())); but.setToolTipText(table.getVascTextValue().getTextValue(action.getToolTip())); but.addActionListener(new GlobalActionListener(action)); but.setIcon(getImageIcon(action.getImage())); top.add(but); } // create options JPanel optionPanel = new JPanel(); //top.setBackground(Color.GREEN); for(VascUserOption option:table.getUserOptions()) { option.createUserOptionRenderer(table); } //top.add(header,BorderLayout.NORTH); parent2.setLayout(new BorderLayout()); parent2.add(header,BorderLayout.NORTH); parent2.add(optionPanel,BorderLayout.CENTER); parent2.add(top,BorderLayout.EAST); } private void renderBody(JComponent parent2) { VascColumnModel model = new VascColumnModel(); table.getVascTableController().addEventListener(model); JTable jTable = new JTable(); //TODO: remove this extra model for sorting, AND fixup a real sorting stuff TableSorter tableSorter = new TableSorter(); // this regs the listeners for the sorting tableSorter.setTableHeader(jTable.getTableHeader()); tableSorter.setTableModel(model); jTable.setModel(tableSorter); jTable.getTableHeader().setReorderingAllowed(false); // remove auto columns :( int cols = jTable.getColumnModel().getColumnCount(); for (int i=0;i<cols;i++) { TableColumn c = jTable.getColumnModel().getColumn(0); // idd, just remove index 0 every time jTable.removeColumn(c); } jTable.revalidate(); TableCellRenderer renderer = new JComponentTableCellRenderer(); int counter=0; for(VascTableColumn c:table.getTableColumns()) { if (c.isListDisplay()==false) { continue; } TableColumn t = new TableColumn(); t.setPreferredWidth(c.getWidth()); t.setHeaderValue(c); t.setHeaderRenderer(renderer); t.setModelIndex(counter); jTable.addColumn(t); counter++; } jTable.getSelectionModel().addListSelectionListener(new TableSectionListener(jTable,tableSorter)); jTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); jTable.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { if (e.getClickCount() == 2) { Object o = table.getSelectedObject(); if (o==null) { return; } try { // TODO: fix this table.getVascViewRenderer().renderEdit(o); } catch (Exception ee) { table.getVascTableController().handleException(ee, table); } } } }); JScrollPane scrollPane = new JScrollPane(jTable); parent2.add(scrollPane); } class TableSectionListener implements ListSelectionListener { JTable jTable; TableSorter tableSorter; TableSectionListener(JTable table,TableSorter tableSorter) { this.jTable = table; this.tableSorter=tableSorter; } public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting()) { return; } int rowIndex = jTable.getSelectedRow(); if (rowIndex!=-1) { // temp; gets index by sorter rowIndex = tableSorter.modelIndex(rowIndex); Object data = table.getTableData().get(rowIndex); table.setSelectedObject(data); } else { table.setSelectedObject(null); } } } class JComponentTableCellRenderer extends DefaultTableCellRenderer { private static final long serialVersionUID = 10L; public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,boolean hasFocus, int row, int column) { VascTableColumn c = (VascTableColumn)value; setText(c.getVascTable().getVascTextValue().getTextValue(c.getName())); setToolTipText(c.getVascTable().getVascTextValue().getTextValue(c.getToolTip())); if(c.getImage()!=null) { setIcon(getImageIcon(c.getImage())); } else { setIcon(null); } if (table != null) { JTableHeader header = table.getTableHeader(); if (header != null) { setForeground(header.getForeground()); setBackground(header.getBackground()); setFont(header.getFont()); } } setBorder(UIManager.getBorder("TableHeader.cellBorder")); return this; } } private void renderFooter(JComponent parent2) { logger.finest("Creating footer"); JPanel panel = new JPanel(); for(RowVascAction action:table.getRowActions()) { JButton but = new JButton(); but.setText(table.getVascTextValue().getTextValue(action.getName())); but.setToolTipText(table.getVascTextValue().getTextValue(action.getToolTip())); but.setIcon(getImageIcon(action.getImage())); but.addActionListener(new RowActionListener(action)); panel.add(but); } parent2.setLayout(new BorderLayout()); parent2.add(panel,BorderLayout.WEST); } class RowActionListener implements ActionListener { private RowVascAction action = null; public RowActionListener(RowVascAction action) { this.action=action; } public void actionPerformed(ActionEvent event) { logger.fine("Row Action"); try { action.doRowAction(table, table.getSelectedObject()); } catch (Exception e) { table.getVascTableController().handleException(e, table); } } } class GlobalActionListener implements ActionListener { private GlobalVascAction action = null; public GlobalActionListener(GlobalVascAction action) { this.action=action; } public void actionPerformed(ActionEvent event) { logger.fine("Global Action"); try { action.doGlobalAction(table); } catch (Exception e) { table.getVascTableController().handleException(e, table); } } } class VascColumnModel extends AbstractTableModel implements VascEventListener { private static final long serialVersionUID = 10L; public void vascEvent(VascEventType e,Object o) { if (e==VascEventType.DATA_UPDATE) { fireTableDataChanged(); } } /** * @see javax.swing.table.TableModel#getColumnCount() */ public int getColumnCount() { int result = 0; for(VascTableColumn c:table.getTableColumns()) { if (c.isListDisplay()==false) { continue; } result++; } return result; } /** * @see javax.swing.table.TableModel#getRowCount() */ public int getRowCount() { if (table.getTableData()==null) { return 0; } return table.getTableData().size(); } /** * @see javax.swing.table.TableModel#getValueAt(int, int) */ public Object getValueAt(int rowIndex, int columnIndex) { Object bean = table.getTableData().get(rowIndex); logger.finer("Rending column; "+columnIndex+" bean: "+bean); // TODO: this is slowing.... List<VascTableColumn> list = new ArrayList<VascTableColumn>(); for(VascTableColumn c:table.getTableColumns()) { if (c.isListDisplay()==false) { continue; } list.add(c); } VascTableColumn vtc = list.get(columnIndex); try { if (vtc.getVascColumnRenderer()!=null) { return vtc.getVascColumnRenderer().rendererColumn(vtc,bean); } else { return ""+vtc.getVascColumnValue().getValue(vtc,bean); } } catch (Exception e) { return "Error"; } } } } /** * A 1.4 file that provides utility methods for creating form- or grid-style * layouts with SpringLayout. These utilities are used by several programs, such * as SpringBox and SpringCompactGrid. */ class SpringUtilities { /** * Aligns the first <code>rows</code>*<code>cols</code> components of * <code>parent</code> in a grid. Each component is as big as the maximum * preferred width and height of the components. The parent is made just big * enough to fit them all. * * @param rows * number of rows * @param cols * number of columns * @param initialX * x location to start the grid at * @param initialY * y location to start the grid at * @param xPad * x padding between cells * @param yPad * y padding between cells */ public static void makeGrid(Container parent, int rows, int cols, int initialX, int initialY, int xPad, int yPad) { SpringLayout layout; try { layout = (SpringLayout) parent.getLayout(); } catch (ClassCastException exc) { System.err .println("The first argument to makeGrid must use SpringLayout."); return; } Spring xPadSpring = Spring.constant(xPad); Spring yPadSpring = Spring.constant(yPad); Spring initialXSpring = Spring.constant(initialX); Spring initialYSpring = Spring.constant(initialY); int max = rows * cols; //Calculate Springs that are the max of the width/height so that all //cells have the same size. Spring maxWidthSpring = layout.getConstraints(parent.getComponent(0)) .getWidth(); Spring maxHeightSpring = layout.getConstraints(parent.getComponent(0)) .getWidth(); for (int i = 1; i < max; i++) { SpringLayout.Constraints cons = layout.getConstraints(parent .getComponent(i)); maxWidthSpring = Spring.max(maxWidthSpring, cons.getWidth()); maxHeightSpring = Spring.max(maxHeightSpring, cons.getHeight()); } //Apply the new width/height Spring. This forces all the //components to have the same size. for (int i = 0; i < max; i++) { SpringLayout.Constraints cons = layout.getConstraints(parent .getComponent(i)); cons.setWidth(maxWidthSpring); cons.setHeight(maxHeightSpring); } //Then adjust the x/y constraints of all the cells so that they //are aligned in a grid. SpringLayout.Constraints lastCons = null; SpringLayout.Constraints lastRowCons = null; for (int i = 0; i < max; i++) { SpringLayout.Constraints cons = layout.getConstraints(parent .getComponent(i)); if (i % cols == 0) { //start of new row lastRowCons = lastCons; cons.setX(initialXSpring); } else { //x position depends on previous component cons.setX(Spring.sum(lastCons.getConstraint(SpringLayout.EAST), xPadSpring)); } if (i / cols == 0) { //first row cons.setY(initialYSpring); } else { //y position depends on previous row cons.setY(Spring.sum(lastRowCons .getConstraint(SpringLayout.SOUTH), yPadSpring)); } lastCons = cons; } //Set the parent's size. SpringLayout.Constraints pCons = layout.getConstraints(parent); pCons.setConstraint(SpringLayout.SOUTH, Spring.sum(Spring .constant(yPad), lastCons.getConstraint(SpringLayout.SOUTH))); pCons.setConstraint(SpringLayout.EAST, Spring.sum( Spring.constant(xPad), lastCons .getConstraint(SpringLayout.EAST))); } /* Used by makeCompactGrid. */ private static SpringLayout.Constraints getConstraintsForCell(int row, int col, Container parent, int cols) { SpringLayout layout = (SpringLayout) parent.getLayout(); Component c = parent.getComponent(row * cols + col); return layout.getConstraints(c); } /** * Aligns the first <code>rows</code>*<code>cols</code> components of * <code>parent</code> in a grid. Each component in a column is as wide as * the maximum preferred width of the components in that column; height is * similarly determined for each row. The parent is made just big enough to * fit them all. * * @param rows * number of rows * @param cols * number of columns * @param initialX * x location to start the grid at * @param initialY * y location to start the grid at * @param xPad * x padding between cells * @param yPad * y padding between cells */ public static void makeCompactGrid(Container parent, int rows, int cols, int initialX, int initialY, int xPad, int yPad) { SpringLayout layout; try { layout = (SpringLayout) parent.getLayout(); } catch (ClassCastException exc) { System.err .println("The first argument to makeCompactGrid must use SpringLayout."); return; } //Align all cells in each column and make them the same width. Spring x = Spring.constant(initialX); for (int c = 0; c < cols; c++) { Spring width = Spring.constant(0); for (int r = 0; r < rows; r++) { width = Spring.max(width, getConstraintsForCell(r, c, parent, cols).getWidth()); } for (int r = 0; r < rows; r++) { SpringLayout.Constraints constraints = getConstraintsForCell(r, c, parent, cols); constraints.setX(x); constraints.setWidth(width); } x = Spring.sum(x, Spring.sum(width, Spring.constant(xPad))); } //Align all cells in each row and make them the same height. Spring y = Spring.constant(initialY); for (int r = 0; r < rows; r++) { Spring height = Spring.constant(0); for (int c = 0; c < cols; c++) { height = Spring.max(height, getConstraintsForCell(r, c, parent, cols).getHeight()); } for (int c = 0; c < cols; c++) { SpringLayout.Constraints constraints = getConstraintsForCell(r, c, parent, cols); constraints.setY(y); constraints.setHeight(height); } y = Spring.sum(y, Spring.sum(height, Spring.constant(yPad))); } //Set the parent's size. SpringLayout.Constraints pCons = layout.getConstraints(parent); pCons.setConstraint(SpringLayout.SOUTH, y); pCons.setConstraint(SpringLayout.EAST, x); } }