package Klausurplan;
import java.awt.Component;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableColumn;
/** this is where the magic happens */
public class TableColumnSynchronizer
{
private JTable tbl;
private List<Integer> adjustColumns;
/** watch for changes in the table which require changes */
private TableModelListener dataWatcher = new TableModelListener()
{
public void tableChanged(TableModelEvent tme)
{
if (adjustColumns.contains(tme.getColumn()))
{
performAdjustment();
}
}
};
/**
* constructor for TableColumnSynchronizer
* @param tbl table you want to have synchronization of columns
* @param adjustColumns indices of columns to synchronize
* @throws IllegalArgumentException if table or the adjusted Columns is/are 'null'
*/
public TableColumnSynchronizer(final JTable tbl, final List<Integer> adjustColumns) throws IllegalArgumentException
{
if (tbl == null || adjustColumns == null)
{
throw new IllegalArgumentException("sry, but your table or your columns are null, cant work with that");
}
this.tbl = tbl;
this.adjustColumns = new ArrayList<Integer>(adjustColumns);
tbl.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
tbl.getModel().addTableModelListener(dataWatcher);
}
/**
* perform adjustments for the synchronized cells
* you can call this method by hand if you require it
* (e.g. initial adjust)
*/
public void performAdjustment()
{
List<Integer> requiredWidths = new ArrayList<Integer>();
// get the preferred with of each column to determine to highest
for (Integer colIdx : adjustColumns)
{
requiredWidths.add(getRequiredWidthOfColumn(colIdx));
}
// now determine which column is the "biggest"
int newTotalWidth = getHeighestNumber(requiredWidths);
// adjust all columns to have the determined width
for (Integer colIdx : adjustColumns)
{
tbl.getColumnModel().getColumn(colIdx).setPreferredWidth(newTotalWidth);
}
}
/**
* determine how much width the given column require to display it's content
* @param column index in the table
* @return
*/
private int getRequiredWidthOfColumn(int column)
{
int width = getHeaderWidth(column);
// to have initial value, get the width the header requires
if(tbl.getRowCount()>0)
{
// now get the required width of each row of this column
for(int row = 0; row< tbl.getRowCount(); row++)
{
width = Math.max(width, getCellWidth(row, column));
}
}
return width + tbl.getIntercellSpacing().width;
}
/**
* determine how much width the header given column require to display
* this ise used if no rows are available
* @param column
* @return
*/
private int getHeaderWidth(int column)
{
TableColumn tableColumn = tbl.getColumnModel().getColumn(column);
Component headerCell = tbl.getTableHeader().getDefaultRenderer().getTableCellRendererComponent
(
tbl,
tableColumn.getIdentifier(),
false,
false,
-1,
column);
return (int)headerCell.getPreferredSize().getWidth();
}
/**
* determine how much width the cell at the given row/col require to display
* @param row
* @param column
* @return
*/
private int getCellWidth(int row, int column)
{
Component cell = tbl.getCellRenderer(row, column).getTableCellRendererComponent(
tbl,
tbl.getValueAt(row, column),
false,
false,
row,
column);
return (int)cell.getPreferredSize().getWidth();
}
/** copy from my toolbox to determine highest (numeric) value of a list */
public int getHeighestNumber(List<Integer> items)
{
int highest = -1;
for (Integer value : items)
{
if (value > highest)
{
highest = value;
}
}
return highest;
}
}