/* * 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.frontends.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.VascEntry; import com.idcanet.vasc.core.VascEntryField; import com.idcanet.vasc.core.VascFrontend; import com.idcanet.vasc.core.actions.GlobalVascAction; import com.idcanet.vasc.core.actions.RowVascAction; import com.idcanet.vasc.core.entry.VascEntryExporter; import com.idcanet.vasc.core.entry.VascEntryEventListener.VascEventType; import com.idcanet.vasc.core.ui.VascColumnValueModelListener; import com.idcanet.vasc.core.ui.VascList; import com.idcanet.vasc.core.ui.VascUIComponent; import com.idcanet.vasc.core.ui.VascValueModel; /** * * @author Willem Cazander * @version 1.0 Mar 21, 2007 */ public class SwingVascFrontend implements VascFrontend { private String name = null; private Logger logger = null; private JComponent parent = null; private VascEntry entry = null; public SwingVascFrontend(JComponent parent) { logger = Logger.getLogger(SwingVascFrontend.class.getName()); this.parent=parent; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void initEntry(VascEntry entry) throws Exception { if (entry.getVascFrontendData().getVascFrontend()==null) { entry.getVascFrontendData().setVascFrontend(this); } else { if (entry.getVascFrontendData().getVascFrontend()!=this) { throw new IllegalArgumentException("VascEntry has already a differtent VascViewRenderer attected"); } } entry.getVascFrontendData().getVascFrontendHelper().refreshData(entry); /* entry.putUIComponent(VascTextField.class, SwingTextField.class); entry.putUIComponent(VascList.class, SwingList.class); entry.putUIComponent(VascToggle.class, SwingToggle.class); entry.putUIComponent(VascDate.class, SwingDate.class); entry.putUIComponent(VascColorChooser.class, SwingColorChooser.class); */ this.entry=entry; } public ImageIcon getImageIcon(String imageResource) { /// TODO hack beter String key = entry.getVascFrontendData().getVascEntryResourceResolver().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.VascEntry, java.lang.Object) */ public void renderEdit(Object rowBean) throws Exception { logger.fine("Rending Edit View"); rowBean = entry.getVascFrontendData().getVascFrontendHelper().initEditObject(entry, rowBean); String beanValue = rowBean.toString(); if (entry.getDisplayNameFieldId()!=null) { VascEntryField v = entry.getVascEntryFieldById(entry.getDisplayNameFieldId()); Object vv = v.getVascEntryFieldValue().getValue(v, rowBean); if (vv==null) { beanValue=""; } else { beanValue=""+vv; } if (beanValue.length()>30) { beanValue=beanValue.substring(0, 30); } } SwingEditDialog dialog = new SwingEditDialog(parent,entry,rowBean,entry.getVascFrontendData().getVascEntryResourceResolver().getTextValue("vasc.dialog.edit.title"),entry.getVascFrontendData().getVascEntryResourceResolver().getTextValue("vasc.dialog.edit.message",beanValue)); Object result = dialog.openDialog(); logger.finest("OPEN closed : "+result); if(result==null) { return; } entry.getVascFrontendData().getVascFrontendHelper().mergeObject(entry, result); } public void renderDelete(Object rowBean) throws Exception { String beanValue = rowBean.toString(); if (entry.getDisplayNameFieldId()!=null) { VascEntryField v = entry.getVascEntryFieldById(entry.getDisplayNameFieldId()); beanValue = ""+v.getVascEntryFieldValue().getValue(v, rowBean); if (beanValue.length()>30) { beanValue=beanValue.substring(0, 30); } } int response = JOptionPane.showOptionDialog( parent // Center in window. , entry.getVascFrontendData().getVascEntryResourceResolver().getTextValue("vasc.dialog.delete.message",beanValue) // Message , entry.getVascFrontendData().getVascEntryResourceResolver().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) { entry.getVascFrontendData().getVascBackend().delete(rowBean); entry.getVascFrontendData().getEntryDataList().remove(rowBean); entry.getVascFrontendData().setEntryDataObject(null); //entry.getVascFrontendController().getVascFrontendHelper().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,VascEntry entry,Object bean,String title,String headerText) throws Exception { super(); this.headerText = headerText; this.bean = bean; setTitle(entry.getVascFrontendData().getVascEntryResourceResolver().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(entry.getVascFrontendData().getVascEntryResourceResolver().getTextValue(headerText)); l.setFont(new Font(null,Font.BOLD, 14)); //l.setToolTipText(entry.getVascTextValue().getTextValue(headerText)); header.add(l); } public void createBody(JPanel body) throws Exception { body.setLayout(new SpringLayout()); int column = 0; for(VascEntryField c:entry.getVascEntryFields()) { entry.getVascFrontendData().getVascFrontendHelper().initEditObjectColumn(c, bean); if (c.isEdit()==false) { continue; } column++; JLabel l = new JLabel(); l.setHorizontalAlignment(JLabel.TRAILING); l.setText(entry.getVascFrontendData().getVascEntryResourceResolver().getTextValue(c.getName())); if(c.getDescription()!=null) { l.setToolTipText(entry.getVascFrontendData().getVascEntryResourceResolver().getTextValue(c.getDescription())); } body.add(l); if (c.isEditReadOnly()==true) { JLabel valueLabel = new JLabel(); valueLabel.setText(""+c.getVascEntryFieldValue().getValue(c, bean)); //c.setColumnEditor(valueLabel); body.add(valueLabel); continue; } if(c.getVascEntryFieldType().getVascUIComponent()==null) { JLabel valueLabel = new JLabel(); valueLabel.setText(""+c.getVascEntryFieldValue().getValue(c, bean)); //c.setColumnEditor(valueLabel); body.add(valueLabel); } else { VascUIComponent comp = c.getVascEntryFieldType().getVascUIComponent(); VascValueModel model = new VascValueModel(entry); model.setValue(c.getVascEntryFieldValue().getValue(c, bean)); model.addListener(new VascColumnValueModelListener(c,bean)); comp.createComponent(entry, 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(entry.getVascFrontendData().getVascEntryResourceResolver().getTextValue("vasc.dialog.save.name")); saveButton.setToolTipText(entry.getVascFrontendData().getVascEntryResourceResolver().getTextValue("vasc.dialog.save.tooltip")); saveButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { if(entry.getVascFrontendData().getVascFrontendHelper().setUIComponentsBeanErrors(entry, bean)) { return; } result = bean; setVisible(false); } }); footer.add(saveButton); JButton cancelButton = new JButton(); cancelButton.setIcon(getImageIcon("vasc.dialog.cancel.image")); cancelButton.setText(entry.getVascFrontendData().getVascEntryResourceResolver().getTextValue("vasc.dialog.cancel.name")); cancelButton.setToolTipText(entry.getVascFrontendData().getVascEntryResourceResolver().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.VascEntry, com.idcanet.vasc.core.VascDataExporter) */ public void renderExport(VascEntryExporter 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, entry); } catch (Exception e) { entry.getVascFrontendData().getVascFrontendHelper().handleException(e, entry); } finally { if (out!=null) { out.close(); } } } /** * @see com.idcanet.vasc.core.VascViewRenderer#renderView(com.idcanet.vasc.core.VascEntry) */ 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(entry.getHeaderImage()!=null) { JLabel l = new JLabel(); // TODO: hack images working l.setIcon(new ImageIcon(Toolkit.getDefaultToolkit().createImage(getClass().getResource(entry.getHeaderImage())).getScaledInstance(32, 32, Image.SCALE_SMOOTH))); if (entry.getHeaderDescription()!=null) { l.setToolTipText(entry.getVascFrontendData().getVascEntryResourceResolver().getTextValue(entry.getHeaderDescription())); } header.add(l,BorderLayout.WEST); } if(entry.getHeaderName()!=null) { JLabel l = new JLabel(entry.getVascFrontendData().getVascEntryResourceResolver().getTextValue(entry.getHeaderName())); l.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); l.setFont(new Font(null,Font.BOLD, 18)); if (entry.getHeaderDescription()!=null) { l.setToolTipText(entry.getVascFrontendData().getVascEntryResourceResolver().getTextValue(entry.getHeaderDescription())); } header.add(l,BorderLayout.CENTER); } JPanel top = new JPanel(); //top.setBackground(Color.BLUE); for (GlobalVascAction action:entry.getGlobalActions()) { JButton but = new JButton(); but.setText(entry.getVascFrontendData().getVascEntryResourceResolver().getTextValue(action.getName())); but.setToolTipText(entry.getVascFrontendData().getVascEntryResourceResolver().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:entry.getUserOptions()) { // option.createUserOptionRenderer(entry); //} //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(); //TODO: entry.getVascEntryController().addEventListener(model); JTable table = 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(table.getTableHeader()); tableSorter.setTableModel(model); table.setModel(tableSorter); table.getTableHeader().setReorderingAllowed(false); // remove auto columns :( int cols = table.getColumnModel().getColumnCount(); for (int i=0;i<cols;i++) { TableColumn c = table.getColumnModel().getColumn(0); // idd, just remove index 0 every time table.removeColumn(c); } table.revalidate(); TableCellRenderer renderer = new JComponententryCellRenderer(); int counter=0; for(VascEntryField c:entry.getVascEntryFields()) { if (c.isList()==false) { continue; } TableColumn t = new TableColumn(); if (c.getSizeList()!=null) { t.setPreferredWidth(c.getSizeList()); } else { t.setPreferredWidth(200); } t.setHeaderValue(c); t.setHeaderRenderer(renderer); t.setModelIndex(counter); table.addColumn(t); counter++; } table.getSelectionModel().addListSelectionListener(new entrySectionListener(table,tableSorter)); table.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); table.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { if (e.getClickCount() == 2) { Object o = entry.getVascFrontendData().getEntryDataObject(); if (o==null) { return; } try { // TODO: fix this entry.getVascFrontendData().getVascFrontend().renderEdit(o); } catch (Exception ee) { entry.getVascFrontendData().getVascFrontendHelper().handleException(ee, entry); } } } }); JScrollPane scrollPane = new JScrollPane(table); parent2.add(scrollPane); } class entrySectionListener implements ListSelectionListener { JTable table; TableSorter tableSorter; entrySectionListener(JTable table,TableSorter tableSorter) { this.table = table; this.tableSorter=tableSorter; } public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting()) { return; } int rowIndex = table.getSelectedRow(); if (rowIndex!=-1) { // temp; gets index by sorter rowIndex = tableSorter.modelIndex(rowIndex); Object data = entry.getVascFrontendData().getEntryDataList().get(rowIndex); entry.getVascFrontendData().setEntryDataObject(data); } else { entry.getVascFrontendData().setEntryDataObject(null); } } } class JComponententryCellRenderer extends DefaultTableCellRenderer { private static final long serialVersionUID = 10L; public Component getentryCellRendererComponent(JTable table, Object value, boolean isSelected,boolean hasFocus, int row, int column) { VascEntryField c = (VascEntryField)value; setText(c.getVascEntry().getVascFrontendData().getVascEntryResourceResolver().getTextValue(c.getName())); setToolTipText(c.getVascEntry().getVascFrontendData().getVascEntryResourceResolver().getTextValue(c.getDescription())); if(c.getImage()!=null) { setIcon(getImageIcon(c.getImage())); } else { setIcon(null); } if (entry != null) { JTableHeader header = table.getTableHeader(); if (header != null) { setForeground(header.getForeground()); setBackground(header.getBackground()); setFont(header.getFont()); } } setBorder(UIManager.getBorder("entryHeader.cellBorder")); return this; } } private void renderFooter(JComponent parent2) { logger.finest("Creating footer"); JPanel panel = new JPanel(); for(RowVascAction action:entry.getRowActions()) { JButton but = new JButton(); but.setText(entry.getVascFrontendData().getVascEntryResourceResolver().getTextValue(action.getName())); but.setToolTipText(entry.getVascFrontendData().getVascEntryResourceResolver().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(entry, entry.getVascFrontendData().getEntryDataObject()); } catch (Exception e) { entry.getVascFrontendData().getVascFrontendHelper().handleException(e, entry); } } } 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(entry); } catch (Exception e) { entry.getVascFrontendData().getVascFrontendHelper().handleException(e, entry); } } } 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.entry.entryModel#getColumnCount() */ public int getColumnCount() { int result = 0; for(VascEntryField c:entry.getVascEntryFields()) { if (c.isList()==false) { continue; } result++; } return result; } /** * @see javax.swing.entry.entryModel#getRowCount() */ public int getRowCount() { if (entry.getVascFrontendData().getEntryDataList()==null) { return 0; } return entry.getVascFrontendData().getEntryDataList().size(); } /** * @see javax.swing.entry.entryModel#getValueAt(int, int) */ public Object getValueAt(int rowIndex, int columnIndex) { Object bean = entry.getVascFrontendData().getEntryDataList().get(rowIndex); logger.finer("Rending column; "+columnIndex+" bean: "+bean); // TODO: this is slowing.... List<VascEntryField> list = new ArrayList<VascEntryField>(); for(VascEntryField c:entry.getVascEntryFields()) { if (c.isList()==false) { continue; } list.add(c); } VascEntryField vtc = list.get(columnIndex); try { //if (vtc.getVascColumnRenderer()!=null) { // return vtc.getVascColumnRenderer().rendererColumn(vtc,bean); //} else { return ""+vtc.getVascEntryFieldValue().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); } }