Class HeaderDetailTableModel<T>
- java.lang.Object
-
- javax.swing.table.AbstractTableModel
-
- io.github.jonestimd.swing.table.model.HeaderDetailTableModel<T>
-
- Type Parameters:
T- the type of the group bean (typically the header)
- All Implemented Interfaces:
BeanTableModel<T>,ColumnIdentifier,MixedRowTableModel,java.io.Serializable,javax.swing.table.TableModel
- Direct Known Subclasses:
BufferedHeaderDetailTableModel
public class HeaderDetailTableModel<T> extends javax.swing.table.AbstractTableModel implements MixedRowTableModel, BeanTableModel<T>
AMixedRowTableModelfor which the groups contain a header row followed by one or more detail rows. Multiple detail types are supported. ADetailAdapteris used to determine a detail's type and to access the detail beans within a group. A set ofColumnAdapters must be provided for the header and for each detail type. The headerColumnAdapters operate on the group bean and the detailColumnAdapters operate on the detail bean returned by theDetailAdapter.To improve performance, the row indices of the group beans are kept in a lookup table. The key for this lookup table is provided by a
Function.Function.identity()can be used for that purpose if all group instances are guaranteed to be unique (i.e. multiple instances of a group can't exist) or if the group class overridesObject.equals(Object)andObject.hashCode(). Important: The ID of a group must not be modified after the group is added to the model, and any fields used for that ID should not be editable in the UI. SeeHashListfor further details.This class implements
BeanTableModelfor compatibility withBeanModelRowSorter. The implementation of the interface allows sorting and filtering of the group beans in the view.- See Also:
- Serialized Form
-
-
Field Summary
Fields Modifier and Type Field Description protected DetailAdapter<T>detailAdapter
-
Constructor Summary
Constructors Modifier Constructor Description protectedHeaderDetailTableModel(DetailAdapter<T> detailAdapter, java.util.function.Function<? super T,?> idFunction)Partial constructor for sub-classes.HeaderDetailTableModel(DetailAdapter<T> detailAdapter, java.util.function.Function<? super T,?> idFunction, java.util.List<? extends ColumnAdapter<T,?>> columnAdapters, java.util.List<? extends java.util.List<? extends ColumnAdapter<?,?>>> detailColumnAdapters)
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description voidaddBean(int index, T bean)Insert a group in the table at the specified group index.voidfireTableRowsDeleted(int firstRow, int lastRow)Overridden to update group row offsets.voidfireTableRowsInserted(int firstRow, int lastRow)Overridden to update group row offsets.TgetBean(int index)Get the group bean at the specified index.TgetBeanAtRow(int rowIndex)Get the group at the specified row.intgetBeanCount()Get the number of groups.java.util.List<T>getBeans()Get the group beans.java.lang.Class<?>getCellClass(int rowIndex, int columnIndex)ColumnAdapter<T,?>getColumnAdapter(int index)Get a headerColumnAdapter.java.lang.Class<?>getColumnClass(int columnIndex)java.lang.Class<?>getColumnClass(int typeIndex, int columnIndex)intgetColumnCount()ColumnAdapter<T,?>getColumnIdentifier(int columnIndex)ColumnAdapter<?,?>getColumnIdentifier(int typeIndex, int columnIndex)intgetColumnIndex(ColumnAdapter<T,?> identifier)Get the column index for a headerColumnAdapter.java.lang.StringgetColumnName(int columnIndex)java.lang.StringgetColumnName(int typeIndex, int columnIndex)java.awt.CursorgetCursor(java.awt.event.MouseEvent event, javax.swing.JTable table, int rowIndex, int columnIndex)Get the mouse cursor to display for a cell.protected ColumnAdapter<java.lang.Object,java.lang.Object>getDetailColumnAdapter(int typeIndex, int columnIndex)intgetDetailColumnIndex(int subRowType, ColumnAdapter<?,?> adapter)Get the column index for a detailColumnAdapter.protected java.lang.ObjectgetDetailValueAt(java.lang.Object detail, int typeIndex, int columnIndex)Get the detail value for the specified detail type and column.intgetGroupNumber(int rowIndex)protected intgetInsertionIndex(T bean)Get the index at which a bean should be inserted.intgetLeadRowForGroup(int beanIndex)intgetRowCount()intgetRowCount(int beanIndex)intgetRowTypeCount()intgetRowTypeIndex(int rowIndex)intgetSubRowIndex(int rowIndex)java.lang.ObjectgetValue(T bean, int columnIndex)Get a column cell value for a bean.java.lang.ObjectgetValueAt(int rowIndex, int columnIndex)voidhandleClick(java.awt.event.MouseEvent event, javax.swing.JTable table, int rowIndex, int columnIndex)Handle a mouse click on a cell.intindexOf(java.util.function.Predicate<T> condition)intindexOf(T bean)Get thd index of a group in the list of groups.booleanisCellEditable(int rowIndex, int columnIndex)Delegates to the header/detail column adapters.booleanisSubRow(int rowIndex)voidremoveAll(java.util.List<T> rowBeans)Clear the table data.voidremoveBean(T bean)Remove a group from the table.introwIndexOf(T bean)Get the row index of the header of a group.voidsetBean(int index, T bean)Replace a group in the table.voidsetBeans(java.util.Collection<T> beans)Replace the list of groups.protected voidsetCellValue(java.lang.Object value, int rowIndex, int columnIndex)Set a value on a header or detail.protected voidsetColumnAdapters(java.util.List<? extends ColumnAdapter<T,?>> columnAdapters)Set the headerColumnAdapters.protected voidsetDetailColumnAdapters(java.util.List<? extends java.util.List<? extends ColumnAdapter<?,?>>> detailColumnAdapters)Set the detailColumnAdapters.voidupdateBeans(java.util.Collection<T> beans, java.util.function.BiPredicate<T,T> isEqual)Update existing rows and add missing rows to the table model.protected voidupdateRowOffsets(int beanIndex)Update the group row offsets starting with the specified group.-
Methods inherited from class javax.swing.table.AbstractTableModel
addTableModelListener, findColumn, fireTableCellUpdated, fireTableChanged, fireTableDataChanged, fireTableRowsUpdated, fireTableStructureChanged, getListeners, getTableModelListeners, removeTableModelListener, setValueAt
-
-
-
-
Field Detail
-
detailAdapter
protected final DetailAdapter<T> detailAdapter
-
-
Constructor Detail
-
HeaderDetailTableModel
protected HeaderDetailTableModel(DetailAdapter<T> detailAdapter, java.util.function.Function<? super T,?> idFunction)
Partial constructor for sub-classes. TheColumnAdapters must be set to complete construction. Mostly intended to allowColumnAdapters to be defined as non-static inner classes of the model.- Parameters:
detailAdapter- theDetailAdapterfor accessing detail rowsidFunction- theFunctionfor supplying the ID of a group.
-
HeaderDetailTableModel
public HeaderDetailTableModel(DetailAdapter<T> detailAdapter, java.util.function.Function<? super T,?> idFunction, java.util.List<? extends ColumnAdapter<T,?>> columnAdapters, java.util.List<? extends java.util.List<? extends ColumnAdapter<?,?>>> detailColumnAdapters)
- Parameters:
detailAdapter- theDetailAdapterfor accessing detail rowsidFunction- theFunctionfor supplying the ID of a group.columnAdapters- theColumnAdapters for the group header rowdetailColumnAdapters- theColumnAdapters for the group detail rows
-
-
Method Detail
-
getColumnAdapter
public ColumnAdapter<T,?> getColumnAdapter(int index)
Get a headerColumnAdapter.- Parameters:
index- the column index
-
setColumnAdapters
protected void setColumnAdapters(java.util.List<? extends ColumnAdapter<T,?>> columnAdapters)
Set the headerColumnAdapters. Must be called beforesetDetailColumnAdapters(List).
-
setDetailColumnAdapters
protected void setDetailColumnAdapters(java.util.List<? extends java.util.List<? extends ColumnAdapter<?,?>>> detailColumnAdapters)
Set the detailColumnAdapters. The list must contain a list ofColumnAdapters for each detail type. The list should be ordered to correspond withDetailAdapter.getDetailTypeIndex(Object, int).- Throws:
java.lang.NullPointerException- if called beforesetColumnAdapters(List)java.lang.IllegalArgumentException- if the number of adapters for any detail type doesn't match the number of header adapters
-
getRowTypeCount
public int getRowTypeCount()
- Specified by:
getRowTypeCountin interfaceMixedRowTableModel- Returns:
- thw number of row types defined by this model.
-
getColumnCount
public int getColumnCount()
- Specified by:
getColumnCountin interfacejavax.swing.table.TableModel
-
getColumnIdentifier
public ColumnAdapter<T,?> getColumnIdentifier(int columnIndex)
- Specified by:
getColumnIdentifierin interfaceColumnIdentifier
-
getColumnIndex
public int getColumnIndex(ColumnAdapter<T,?> identifier)
Get the column index for a headerColumnAdapter.- Parameters:
identifier- a headerColumnAdapter
-
getDetailColumnIndex
public int getDetailColumnIndex(int subRowType, ColumnAdapter<?,?> adapter)Get the column index for a detailColumnAdapter.- Parameters:
subRowType- the detail type indexadapter- the detailColumnAdapter
-
getBeans
public java.util.List<T> getBeans()
Get the group beans.
-
getBeanCount
public int getBeanCount()
Get the number of groups.- Specified by:
getBeanCountin interfaceBeanTableModel<T>
-
setBeans
public void setBeans(java.util.Collection<T> beans)
Replace the list of groups. The groups will be added in iteration order.- Specified by:
setBeansin interfaceBeanTableModel<T>- Parameters:
beans- the new rows
-
updateBeans
public void updateBeans(java.util.Collection<T> beans, java.util.function.BiPredicate<T,T> isEqual)
Description copied from interface:BeanTableModelUpdate existing rows and add missing rows to the table model.- Specified by:
updateBeansin interfaceBeanTableModel<T>- Parameters:
beans- beans to update/appendisEqual- used to determine if a row is already in the model
-
getInsertionIndex
protected int getInsertionIndex(T bean)
Get the index at which a bean should be inserted. Used byupdateBeans(Collection, BiPredicate).- Returns:
- this implementation returns
getBeanCount()
-
getBean
public T getBean(int index)
Get the group bean at the specified index.- Specified by:
getBeanin interfaceBeanTableModel<T>- Parameters:
index- the index of the group in the bean list
-
getBeanAtRow
public T getBeanAtRow(int rowIndex)
Get the group at the specified row.- Parameters:
rowIndex- the index of a row in the table
-
addBean
public void addBean(int index, T bean)Insert a group in the table at the specified group index.- Parameters:
index- the insertion point in the list of groupsbean- the group to add
-
fireTableRowsInserted
public void fireTableRowsInserted(int firstRow, int lastRow)Overridden to update group row offsets.- Overrides:
fireTableRowsInsertedin classjavax.swing.table.AbstractTableModel
-
fireTableRowsDeleted
public void fireTableRowsDeleted(int firstRow, int lastRow)Overridden to update group row offsets.- Overrides:
fireTableRowsDeletedin classjavax.swing.table.AbstractTableModel
-
setBean
public void setBean(int index, T bean)Replace a group in the table.- Parameters:
index- the index in the list of groups.bean- the replacement group
-
removeBean
public void removeBean(T bean)
Remove a group from the table.- Parameters:
bean- the group to remove
-
removeAll
public void removeAll(java.util.List<T> rowBeans)
Clear the table data.
-
updateRowOffsets
protected void updateRowOffsets(int beanIndex)
Update the group row offsets starting with the specified group.- Parameters:
beanIndex- the index of the first group to be updated
-
getRowCount
public int getRowCount(int beanIndex)
- Specified by:
getRowCountin interfaceMixedRowTableModel- Parameters:
beanIndex- the group index.- Returns:
- the number of rows in the group.
-
indexOf
public int indexOf(T bean)
Get thd index of a group in the list of groups.- Parameters:
bean- the group
-
indexOf
public int indexOf(java.util.function.Predicate<T> condition)
-
rowIndexOf
public int rowIndexOf(T bean)
Get the row index of the header of a group.- Parameters:
bean- the group
-
getLeadRowForGroup
public int getLeadRowForGroup(int beanIndex)
- Specified by:
getLeadRowForGroupin interfaceMixedRowTableModel- Parameters:
beanIndex- the index of the group.- Returns:
- the index of the first row of the group.
-
getRowCount
public int getRowCount()
- Specified by:
getRowCountin interfacejavax.swing.table.TableModel
-
getCellClass
public java.lang.Class<?> getCellClass(int rowIndex, int columnIndex)- Specified by:
getCellClassin interfaceMixedRowTableModel- Parameters:
rowIndex- the index of the row.columnIndex- the index of the column.- Returns:
- the
Classof the cell value.
-
getColumnClass
public java.lang.Class<?> getColumnClass(int columnIndex)
- Specified by:
getColumnClassin interfacejavax.swing.table.TableModel- Overrides:
getColumnClassin classjavax.swing.table.AbstractTableModel
-
getColumnClass
public java.lang.Class<?> getColumnClass(int typeIndex, int columnIndex)- Specified by:
getColumnClassin interfaceMixedRowTableModel- Parameters:
typeIndex- the row type index.columnIndex- the column index.- Returns:
- the
Classof the column value.
-
getColumnName
public java.lang.String getColumnName(int columnIndex)
- Specified by:
getColumnNamein interfacejavax.swing.table.TableModel- Overrides:
getColumnNamein classjavax.swing.table.AbstractTableModel
-
getColumnName
public java.lang.String getColumnName(int typeIndex, int columnIndex)- Specified by:
getColumnNamein interfaceMixedRowTableModel- Parameters:
typeIndex- the row type index.columnIndex- the column index.- Returns:
- the header text for the column.
-
getColumnIdentifier
public ColumnAdapter<?,?> getColumnIdentifier(int typeIndex, int columnIndex)
- Specified by:
getColumnIdentifierin interfaceMixedRowTableModel- Parameters:
typeIndex- the row type index.columnIndex- the column index.- Returns:
- the
TableColumnidentifier of the column.
-
isSubRow
public boolean isSubRow(int rowIndex)
- Returns:
- true if the row is a detail or false if it is a header
-
getGroupNumber
public int getGroupNumber(int rowIndex)
- Specified by:
getGroupNumberin interfaceMixedRowTableModel- Parameters:
rowIndex- the index of the row.- Returns:
- the index of the group containing the row.
-
getSubRowIndex
public int getSubRowIndex(int rowIndex)
- Specified by:
getSubRowIndexin interfaceMixedRowTableModel- Parameters:
rowIndex- the index of the row.- Returns:
- the index of the row within its group.
-
getRowTypeIndex
public int getRowTypeIndex(int rowIndex)
- Specified by:
getRowTypeIndexin interfaceMixedRowTableModel- Parameters:
rowIndex- index of the row.- Returns:
- the type index of the row.
-
getDetailColumnAdapter
protected ColumnAdapter<java.lang.Object,java.lang.Object> getDetailColumnAdapter(int typeIndex, int columnIndex)
-
getValueAt
public java.lang.Object getValueAt(int rowIndex, int columnIndex)- Specified by:
getValueAtin interfacejavax.swing.table.TableModel
-
getDetailValueAt
protected java.lang.Object getDetailValueAt(java.lang.Object detail, int typeIndex, int columnIndex)Get the detail value for the specified detail type and column.
-
getValue
public java.lang.Object getValue(T bean, int columnIndex)
Description copied from interface:BeanTableModelGet a column cell value for a bean.- Specified by:
getValuein interfaceBeanTableModel<T>
-
isCellEditable
public boolean isCellEditable(int rowIndex, int columnIndex)Delegates to the header/detail column adapters.- Specified by:
isCellEditablein interfacejavax.swing.table.TableModel- Overrides:
isCellEditablein classjavax.swing.table.AbstractTableModel- Returns:
- the result of
ColumnAdapter.isEditable(Object)
-
getCursor
public java.awt.Cursor getCursor(java.awt.event.MouseEvent event, javax.swing.JTable table, int rowIndex, int columnIndex)Description copied from interface:BeanTableModelGet the mouse cursor to display for a cell.- Specified by:
getCursorin interfaceBeanTableModel<T>rowIndex- the row index of the cellcolumnIndex- the column index of the cell- Returns:
- the mouse cursor to use for the cell or
nullto use the default cursor.
-
handleClick
public void handleClick(java.awt.event.MouseEvent event, javax.swing.JTable table, int rowIndex, int columnIndex)Description copied from interface:BeanTableModelHandle a mouse click on a cell.- Specified by:
handleClickin interfaceBeanTableModel<T>- Parameters:
event- the click eventrowIndex- the row containing the cellcolumnIndex- the column index of the cell
-
setCellValue
protected void setCellValue(java.lang.Object value, int rowIndex, int columnIndex)Set a value on a header or detail.- Parameters:
value- the cell valuerowIndex- the table row indexcolumnIndex- the table column index
-
-