// $HeadURL$
// $Id$
//
// Copyright © 2006, 2010, 2011, 2012 by the President and Fellows of Harvard College.
//
// Screensaver is an open-source project developed by the ICCB-L and NSRB labs
// at Harvard Medical School. This software is distributed under the terms of
// the GNU General Public License.
package edu.harvard.med.screensaver.ui.screenresults;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import edu.harvard.med.screensaver.model.screenresults.AnnotationType;
import edu.harvard.med.screensaver.model.screenresults.DataColumn;
import edu.harvard.med.screensaver.model.screenresults.MetaDataType;
import edu.harvard.med.screensaver.ui.arch.util.HtmlUtils;
import edu.harvard.med.screensaver.ui.arch.view.AbstractBackingBean;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.log4j.Logger;
/**
* Backing bean for a "meta data" table, which displays information for a set of
* data types (e.g. {@link DataColumn} or {@link AnnotationType}), one data
* type per column, one row per data type attribute.
*
* @motivation Encapsulate common functionality for ScreenResultViewer's Data
* Headers table and Annotation table.
* @author <a mailto="andrew_tolopko@hms.harvard.edu">Andrew Tolopko</a>
* @author <a mailto="john_sullivan@hms.harvard.edu">John Sullivan</a>
*/
public abstract class MetaDataTable<T extends MetaDataType> extends AbstractBackingBean
{
// static members
private static Logger log = Logger.getLogger(MetaDataTable.class);
private static final DataModel EMPTY_METADATA_MODEL = new ListDataModel(new ArrayList<MetaDataTableRow<?>>());
// instance data members
private List<T> _metaDataTypes = Collections.emptyList();
private DataModel _columnModel;
private DataModel _dataModel;
// abstract methods
abstract protected List<MetaDataTableRowDefinition<T>> getMetaDataTableRowDefinitions();
// public constructors and methods
/**
* Set the meta data types (table columns), along with an observer that will
* be notified when the set of selected (visible) data types changes. Must be
* called before other public methods are called.
*/
public void initialize(List<T> metaDataTypes)
{
reset();
_metaDataTypes = metaDataTypes;
}
public DataModel getDataModel()
{
lazyBuildDataModel();
if (_dataModel == null) {
return EMPTY_METADATA_MODEL;
}
return _dataModel;
}
public DataModel getColumnModel()
{
if (_columnModel == null) {
_columnModel = new ListDataModel(getMetaDataTypeNames());
}
return _columnModel;
}
/**
* @motivation for "Columns" JSF data table component
*/
@SuppressWarnings("unchecked")
public Object getCellValue()
{
DataModel dataModel = getDataModel();
DataModel columnModel = getColumnModel();
if (columnModel.isRowAvailable()) {
String columnName = (String) columnModel.getRowData(); // getRowData() is really getColumnData()
MetaDataTableRow<T> row = (MetaDataTableRow<T>) dataModel.getRowData();
return row.getSinglePropertyValues().get(columnName);
}
return null;
}
// private methods
private void reset()
{
_metaDataTypes = Collections.emptyList();
_columnModel = null;
_dataModel = null;
}
private List<T> getDataTypes()
{
if (_metaDataTypes == null) {
throw new IllegalStateException("not initialized (hint: call initialize() first)");
}
return _metaDataTypes;
}
private List<String> getMetaDataTypeNames()
{
List<String> names= new ArrayList<String>();
for (T metaDataType : _metaDataTypes) {
names.add(metaDataType.getName());
}
return names;
}
private void lazyBuildDataModel()
{
if (_dataModel == null) {
List<MetaDataTableRow<T>> tableData = new ArrayList<MetaDataTableRow<T>>();
for (MetaDataTableRowDefinition<T> rowDef : getMetaDataTableRowDefinitions()) {
try {
tableData.add(new MetaDataTableRow<T>(getDataTypes(), rowDef));
}
catch (Exception e) {
log.error("could not obtain value for property " + rowDef.getPropertyName());
}
}
_dataModel = new ListDataModel(tableData);
}
}
// inner classes
public static class MetaDataTableRowDefinition<T extends MetaDataType>
{
private String _propertyName;
private String _displayName;
private String _description;
public MetaDataTableRowDefinition(String propertyName,
String displayName,
String description)
{
_propertyName = propertyName;
_displayName = HtmlUtils.toNonBreakingSpaces(displayName);
_description = description;
}
public String getDisplayName()
{
return _displayName;
}
public String getPropertyName()
{
return _propertyName;
}
public String getDescription()
{
return _description;
}
/**
* Override to format value in a custom way.
*/
public String formatValue(T metaDataType)
{
try {
return BeanUtils.getProperty(metaDataType, _propertyName);
}
catch (Exception e) {
log.error("for metaDataType: " + metaDataType + ", of : " + metaDataType.getClass().getName() + ", " + e.getMessage());
return "<error>";
}
}
}
public static class MetaDataTableRow<T extends MetaDataType>
{
private MetaDataTableRowDefinition<T> _rowDefinition;
/**
* Array containing the value of the same property for each MetaDataType
*/
private Map<String,Object> _propertyValues;
public MetaDataTableRow(Collection<T> metaDataTypes,
MetaDataTableRowDefinition<T> rowDefinition)
{
_rowDefinition = rowDefinition;
_propertyValues = new HashMap<String,Object>();
for (T metaDataType : metaDataTypes) {
_propertyValues.put(metaDataType.getName(),
rowDefinition.formatValue(metaDataType));
}
}
public String getRowLabel()
{
return _rowDefinition.getDisplayName();
}
public String getRowDescription()
{
return _rowDefinition.getDescription();
}
public Map<String,Object> getSinglePropertyValues()
{
return _propertyValues;
}
}
}