📄 beantablemodel.java
字号:
package com.ibm.j2x.swing.table;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.swing.table.AbstractTableModel;
import org.apache.commons.collections.BeanMap;
import org.apache.commons.collections.map.LinkedMap;
import com.ibm.j2x.util.collection.ObservableCollection;
import com.ibm.j2x.event.CollectionEvent;
import com.ibm.j2x.event.CollectionListener;
import com.ibm.j2x.util.ClassUtilities;
/**
* The BeanTableModel acts as the generic table model for all tables
* in the TMF design. Using the assumption that 99% of all tables are a list
* of JavaBeans, the BeanTableModel utilizes introspection on these beans through
* use of the Apache Jakarta Commons BeanMap to eliminate much of the code needed
* in a classical Table Model.
* <p>Introspection can be used to get and set the value, and can be used to get the
* class of the column.
* <p>The crucial information that's missing from the BeanTableModel that is needed
* to make the table work properly is both the column name and the field in the JavaBean
* that the introspection will use to display. As an example of the field in a JavaBean,
* a Bean with <code>getName()</code> and <code>setName()</code> functions would have a
* field name of <code>name</code>. This column-field relationship is
* treated as a key-value pairing. Since the order is important, a traditional Map
* cannot be used, and instead a Apache Jakarta Commons LinkedMap is used, which preserves
* the order of the columns. With the information from the LinkedMap, the BeanMap
* can return the correct field from the Bean.
* <p>The noticable time that the BeanTableModel needs to be subclassed is when the table
* needs to be editable. The BeanTableModel should be subclasses with only the
* <code>isCellEditable()</code> function needing to be overridden.
*
* @author MAbernethy
*/
public class BeanTableModel extends AbstractTableModel implements CollectionListener
{
/** the list of BeanMaps */
protected List mapValues = new ArrayList();
/** the column information in key-value form */
protected LinkedMap columnInfo = new LinkedMap();
/**
* Creates a BeanTableModel with no column information.
*/
public BeanTableModel()
{
this(new ArrayList());
}
/**
* Creates a BeanTableModel with no column information and the specified
* data.
* @param values the data
*/
public BeanTableModel(Collection values)
{
this(values, new LinkedMap());
}
/**
* Creates a BeanTableModel with the specified data and column information.
* @param values the data
* @param columnInfo the column information
*/
public BeanTableModel(Collection values, LinkedMap columnInfo)
{
initializeValues(values);
if (values instanceof ObservableCollection)
((ObservableCollection)values).addCollectionListener(this);
this.columnInfo = columnInfo;
}
/**
* Initializes the values of the data. During the initialization process,
* the BeanTableModel converts the data to a List, and then one by one, adds
* the contents of the list to a BeanMap which gets added to the list of BeanMaps.
* @param values the data
*/
protected void initializeValues(Collection values)
{
List listValues = new ArrayList(values);
mapValues.clear();
for (Iterator i=listValues.iterator(); i.hasNext();)
{
mapValues.add(new BeanMap(i.next()));
}
}
/**
* Adds a column to the table.
* @param columnName the column name
* @param columnField the column field
*/
public void addColumn(Object columnName, Object columnField)
{
columnInfo.put(columnName, columnField);
super.fireTableStructureChanged();
}
/**
* Sets the values in the table model. This calls the protected
* <code>initializeValues()</code> function, and also checks to see
* if the data is an implementor of ObservableCollection, and if it is,
* registers this class as a listener for CollectionEvents.
* @param values the data
*/
public void setValues(Collection values)
{
initializeValues(values);
if (values instanceof ObservableCollection)
((ObservableCollection)values).addCollectionListener(this);
super.fireTableDataChanged();
}
/**
* Sets the column information. The LinkedMap should be a key-value pairing of
* column name - column field in the order that the columns should be displayed.
* @param columnInfo
*/
public void setColumnInfo(LinkedMap columnInfo)
{
this.columnInfo = columnInfo;
super.fireTableStructureChanged();
}
/**
* Gets the row count.
* @return the number of rows of data
*/
public int getRowCount()
{
return mapValues.size();
}
/**
* Gets the column count.
* @return the number of columns in the columninfo
*/
public int getColumnCount()
{
return columnInfo.size();
}
/**
* Gets the column name. It uses the column number to find the key-value pairing
* from the LinkedMap and returns the key, which is the column name.
* @param col the column number
* @return the column name
*/
public String getColumnName(int col)
{
return columnInfo.get(col).toString();
}
/**
* Gets the column class. The column class is found by retrieving the value
* from the BeanMap that should be returned and then getting the class from this value.
* Since the BeanMap automatically autoboxes the primitives (i.e. it converts int to
* Integer to store in the map, and then back to an int when retrieved), and this function
* may only return Objects, it converts primitives back to their corresponding
* Object types.
* @param col the column number
* @return the Class of the column (used for table rendering)
*/
public Class getColumnClass(int col)
{
BeanMap map = (BeanMap)mapValues.get(0);
Class c = map.getType(columnInfo.getValue(col).toString());
if (c == null)
return Object.class;
else if (c.isPrimitive())
return ClassUtilities.convertPrimitiveToObject(c);
else
return c;
}
/**
* Returns whether this cell is editable. Always returns false.
* @param row the row number
* @param col the column number
* @return whether the cell is editable
*/
public boolean isCellEditable(int row, int col)
{
return false;
}
/**
* Gets the value at the specified cell. This returns the value by
* first getting the correct BeanMap from the list of BeanMaps using the
* row number. It then references the column information stored
* in the LinkedMap for the correct field, and uses this field to retrieve
* the value from the BeanMap.
* @param row the row number
* @param col the column number
* @return the value in the cell
*/
public Object getValueAt(int row, int col)
{
BeanMap map = (BeanMap)mapValues.get(row);
return map.get(columnInfo.getValue(col));
}
/**
* Sets the value at the specified cell. This sets the value by
* first getting the correct BeanMap from the list of BeanMaps using the
* row number. It then references the column information stored in the
* LinkedMap for the correct field, and uses this field to retrieve the value
* from the BeanMap.
* @param value the new cell value
* @param row the row number
* @param col the column number
*/
public void setValueAt(Object value, int row, int col)
{
BeanMap map = (BeanMap)mapValues.get(row);
map.put(columnInfo.getValue(col), value);
super.fireTableRowsUpdated(row, row);
}
/**
* Handles all changes to the data that occur and automatically
* updates the table.
* @param e the CollectionEvent
*/
public void collectionChanged(CollectionEvent e)
{
initializeValues((Collection)e.getSource());
super.fireTableDataChanged();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -