package org.displaytag.render; import org.displaytag.model.*; import org.displaytag.exception.ObjectLookupException; import org.displaytag.exception.DecoratorException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.util.*; /** * This class just keeps a running grouped total. It does not output anything; it is the responsibility of the exporter * or of the decorator to actually output the results. * @author rapruitt * Date: May 21, 2010 * Time: 9:17:43 PM */ public class TableTotaler { protected Log logger = LogFactory.getLog(this.getClass()); public static final TableTotaler NULL = new TableTotaler(); protected Map<Integer,Integer> firstRowForEachGroup = new HashMap<Integer,Integer>(); protected int howManyGroups = 0; protected Integer currentRowNumber = 0; protected TableModel tableModel; List<Integer> openedColumns = new ArrayList<Integer>(); // in excel, i need to know which ones are currently open; in xml, just what has just opened TreeMap<Integer,String> groupingValuesByColumn = new TreeMap<Integer,String>(); // in excel, i need to know which ones are currently open; in xml, just what has just opened List<Integer> closedColumns = new ArrayList<Integer>(); /** * Magic constant to indicate that we want the whole list, not just a subgroup. */ public static final Integer WHOLE_TABLE = 0; public void init(TableModel model) { this.tableModel = model; firstRowForEachGroup = new HashMap<Integer,Integer>(); for (HeaderCell c : model.getHeaderCellList()) { if (c.getGroup() > 0) { firstRowForEachGroup.put(c.getGroup(), 0); howManyGroups++; } } } public void initRow(int currentViewIndex, int currentListIndex) { openedColumns.clear(); closedColumns.clear(); currentRowNumber = currentListIndex; } /** * * @param groupNumber * @return */ public int asColumn(int groupNumber) { return groupNumber; } public int asGroup(int columnNumber) { return columnNumber; } public void startGroup(String groupingValue, int groupNumber) { openedColumns.add(asColumn(groupNumber)); groupingValuesByColumn.put(asColumn(groupNumber), groupingValue); firstRowForEachGroup.put(groupNumber, currentRowNumber); } public List<Integer> getOpenedColumns() { return new ArrayList<Integer>(openedColumns); } public List<Integer> getClosedColumns() { return closedColumns; } public void stopGroup(String value, int groupNumber) { closedColumns.add(asColumn(groupNumber)); } /** * Override locally to perform your own math. * @param column * @param total * @param value * @return */ public Object add(Column column, Object total, Object value) { if (value == null) { return total; } else if (value instanceof Number) { Number oldTotal = (double) 0; if (total != null) { oldTotal = (Number) total; } return oldTotal.doubleValue() + ((Number) value).doubleValue(); } else { throw new UnsupportedOperationException("Cannot add a value of " + value + " in column " + column.getHeaderCell().getTitle()); } } /** * Override locally to format it yourself. * @param cell the current cell * @param total the current value * @return */ public String formatTotal(HeaderCell cell, Object total) { if (total == null) { total = ""; } return total instanceof String ? (String) total : total.toString(); } protected Object getTotalForList(List<Row> window, int columnNumber) { Object total = null; for (Row row : window) { ColumnIterator columnIterator = row.getColumnIterator(tableModel.getHeaderCellList()); while (columnIterator.hasNext()) { Column column = columnIterator.nextColumn(); if (column.getHeaderCell().getColumnNumber() == columnNumber) { Object value = null; try { value = column.getValue(false); } catch (ObjectLookupException e) { logger.error(e); } catch (DecoratorException e) { logger.error(e); } if (value != null && !"".equals(value)) { total = add(column, total, value); } } } } return total; } public Object getTotalForColumn(int columnNumber, int groupNumber) { List<Row> fullList = tableModel.getRowListFull(); Integer startRow = this.firstRowForEachGroup.get(groupNumber); Integer stopRow = currentRowNumber + 1; if (groupNumber == WHOLE_TABLE) { // asking for a total for the entire table startRow = 0; } List<Row> window = fullList.subList(startRow, stopRow); return getTotalForList(window, columnNumber); } public String getGroupingValue(Integer columnNumber) { return groupingValuesByColumn.get(columnNumber); } public void reset() { this.closedColumns.clear(); this.openedColumns.clear(); this.groupingValuesByColumn.clear(); this.currentRowNumber = 0; this.howManyGroups = 0; this.firstRowForEachGroup.clear(); } }