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>
AMixedRowTableModel
for which the groups contain a header row followed by one or more detail rows. Multiple detail types are supported. ADetailAdapter
is used to determine a detail's type and to access the detail beans within a group. A set ofColumnAdapter
s must be provided for the header and for each detail type. The headerColumnAdapter
s operate on the group bean and the detailColumnAdapter
s 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. SeeHashList
for further details.This class implements
BeanTableModel
for 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 protected
HeaderDetailTableModel(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 void
addBean(int index, T bean)
Insert a group in the table at the specified group index.void
fireTableRowsDeleted(int firstRow, int lastRow)
Overridden to update group row offsets.void
fireTableRowsInserted(int firstRow, int lastRow)
Overridden to update group row offsets.T
getBean(int index)
Get the group bean at the specified index.T
getBeanAtRow(int rowIndex)
Get the group at the specified row.int
getBeanCount()
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)
int
getColumnCount()
ColumnAdapter<T,?>
getColumnIdentifier(int columnIndex)
ColumnAdapter<?,?>
getColumnIdentifier(int typeIndex, int columnIndex)
int
getColumnIndex(ColumnAdapter<T,?> identifier)
Get the column index for a headerColumnAdapter
.java.lang.String
getColumnName(int columnIndex)
java.lang.String
getColumnName(int typeIndex, int columnIndex)
java.awt.Cursor
getCursor(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)
int
getDetailColumnIndex(int subRowType, ColumnAdapter<?,?> adapter)
Get the column index for a detailColumnAdapter
.protected java.lang.Object
getDetailValueAt(java.lang.Object detail, int typeIndex, int columnIndex)
Get the detail value for the specified detail type and column.int
getGroupNumber(int rowIndex)
protected int
getInsertionIndex(T bean)
Get the index at which a bean should be inserted.int
getLeadRowForGroup(int beanIndex)
int
getRowCount()
int
getRowCount(int beanIndex)
int
getRowTypeCount()
int
getRowTypeIndex(int rowIndex)
int
getSubRowIndex(int rowIndex)
java.lang.Object
getValue(T bean, int columnIndex)
Get a column cell value for a bean.java.lang.Object
getValueAt(int rowIndex, int columnIndex)
void
handleClick(java.awt.event.MouseEvent event, javax.swing.JTable table, int rowIndex, int columnIndex)
Handle a mouse click on a cell.int
indexOf(java.util.function.Predicate<T> condition)
int
indexOf(T bean)
Get thd index of a group in the list of groups.boolean
isCellEditable(int rowIndex, int columnIndex)
Delegates to the header/detail column adapters.boolean
isSubRow(int rowIndex)
void
removeAll(java.util.List<T> rowBeans)
Clear the table data.void
removeBean(T bean)
Remove a group from the table.int
rowIndexOf(T bean)
Get the row index of the header of a group.void
setBean(int index, T bean)
Replace a group in the table.void
setBeans(java.util.Collection<T> beans)
Replace the list of groups.protected void
setCellValue(java.lang.Object value, int rowIndex, int columnIndex)
Set a value on a header or detail.protected void
setColumnAdapters(java.util.List<? extends ColumnAdapter<T,?>> columnAdapters)
Set the headerColumnAdapter
s.protected void
setDetailColumnAdapters(java.util.List<? extends java.util.List<? extends ColumnAdapter<?,?>>> detailColumnAdapters)
Set the detailColumnAdapter
s.void
updateBeans(java.util.Collection<T> beans, java.util.function.BiPredicate<T,T> isEqual)
Update existing rows and add missing rows to the table model.protected void
updateRowOffsets(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. TheColumnAdapter
s must be set to complete construction. Mostly intended to allowColumnAdapter
s to be defined as non-static inner classes of the model.- Parameters:
detailAdapter
- theDetailAdapter
for accessing detail rowsidFunction
- theFunction
for 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
- theDetailAdapter
for accessing detail rowsidFunction
- theFunction
for supplying the ID of a group.columnAdapters
- theColumnAdapter
s for the group header rowdetailColumnAdapters
- theColumnAdapter
s 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 headerColumnAdapter
s. Must be called beforesetDetailColumnAdapters(List)
.
-
setDetailColumnAdapters
protected void setDetailColumnAdapters(java.util.List<? extends java.util.List<? extends ColumnAdapter<?,?>>> detailColumnAdapters)
Set the detailColumnAdapter
s. The list must contain a list ofColumnAdapter
s 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:
getRowTypeCount
in interfaceMixedRowTableModel
- Returns:
- thw number of row types defined by this model.
-
getColumnCount
public int getColumnCount()
- Specified by:
getColumnCount
in interfacejavax.swing.table.TableModel
-
getColumnIdentifier
public ColumnAdapter<T,?> getColumnIdentifier(int columnIndex)
- Specified by:
getColumnIdentifier
in 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:
getBeanCount
in 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:
setBeans
in 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:BeanTableModel
Update existing rows and add missing rows to the table model.- Specified by:
updateBeans
in 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:
getBean
in 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:
fireTableRowsInserted
in classjavax.swing.table.AbstractTableModel
-
fireTableRowsDeleted
public void fireTableRowsDeleted(int firstRow, int lastRow)
Overridden to update group row offsets.- Overrides:
fireTableRowsDeleted
in 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:
getRowCount
in 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:
getLeadRowForGroup
in interfaceMixedRowTableModel
- Parameters:
beanIndex
- the index of the group.- Returns:
- the index of the first row of the group.
-
getRowCount
public int getRowCount()
- Specified by:
getRowCount
in interfacejavax.swing.table.TableModel
-
getCellClass
public java.lang.Class<?> getCellClass(int rowIndex, int columnIndex)
- Specified by:
getCellClass
in interfaceMixedRowTableModel
- Parameters:
rowIndex
- the index of the row.columnIndex
- the index of the column.- Returns:
- the
Class
of the cell value.
-
getColumnClass
public java.lang.Class<?> getColumnClass(int columnIndex)
- Specified by:
getColumnClass
in interfacejavax.swing.table.TableModel
- Overrides:
getColumnClass
in classjavax.swing.table.AbstractTableModel
-
getColumnClass
public java.lang.Class<?> getColumnClass(int typeIndex, int columnIndex)
- Specified by:
getColumnClass
in interfaceMixedRowTableModel
- Parameters:
typeIndex
- the row type index.columnIndex
- the column index.- Returns:
- the
Class
of the column value.
-
getColumnName
public java.lang.String getColumnName(int columnIndex)
- Specified by:
getColumnName
in interfacejavax.swing.table.TableModel
- Overrides:
getColumnName
in classjavax.swing.table.AbstractTableModel
-
getColumnName
public java.lang.String getColumnName(int typeIndex, int columnIndex)
- Specified by:
getColumnName
in 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:
getColumnIdentifier
in interfaceMixedRowTableModel
- Parameters:
typeIndex
- the row type index.columnIndex
- the column index.- Returns:
- the
TableColumn
identifier 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:
getGroupNumber
in 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:
getSubRowIndex
in 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:
getRowTypeIndex
in 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:
getValueAt
in 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:BeanTableModel
Get a column cell value for a bean.- Specified by:
getValue
in interfaceBeanTableModel<T>
-
isCellEditable
public boolean isCellEditable(int rowIndex, int columnIndex)
Delegates to the header/detail column adapters.- Specified by:
isCellEditable
in interfacejavax.swing.table.TableModel
- Overrides:
isCellEditable
in 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:BeanTableModel
Get the mouse cursor to display for a cell.- Specified by:
getCursor
in 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
null
to 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:BeanTableModel
Handle a mouse click on a cell.- Specified by:
handleClick
in 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
-
-