001 package net.sf.jolene.dom; 002 003 import net.sf.jolene.constants.StyleClasses; 004 import net.sf.jolene.constants.Tags; 005 import org.apache.commons.beanutils.PropertyUtils; 006 import org.apache.log4j.LogManager; 007 import org.apache.log4j.Logger; 008 009 import java.util.ArrayList; 010 import java.util.Iterator; 011 import java.util.List; 012 013 /** 014 * A renderable data bound grid object. A grid is detected by the parser by having a table using an ID tag 015 * that starts with 'grid'. The grid object can be accessed in the document just like any other object. 016 * See the bind method to see how to 'datalink' the grid to a list of data objects. 017 * 018 * @author Dan Howard 019 * @since Aug 1, 2005 5:54:59 PM 020 */ 021 public final class Grid extends HTMLElement { 022 023 private static final Logger log = LogManager.getLogger(Grid.class); 024 025 /** 026 * List of row objects created when a document is read. 027 */ 028 List<GridRow> rows; 029 030 /** 031 * Default constructor. 032 */ 033 public Grid() { 034 tag = Tags.table; 035 rows = new ArrayList<GridRow>(0); 036 } 037 038 /** 039 * Binds the grid object to the specified data. 040 * 041 * @param header List of GridColumn objects defining the column information for the grid. 042 * @param fields List of fields (property names) which are accessed via PropertyUtils to set the values for each cell. 043 * @param data List of data objects used to retrieve the values. 044 * @throws GridBindException if PropertyUtils fails. 045 */ 046 public void bind(List<GridColumn> header, List<String> fields, List data) throws GridBindException { 047 rows = new ArrayList<GridRow>(data.size()); 048 049 if (header.size() > 0) { 050 Iterator<GridColumn> it = header.iterator(); 051 rows.add(new GridRow()); 052 rows.get(0).setHeader(true); 053 while (it.hasNext()) { 054 rows.get(0).cells.add(new GridCell(it.next())); 055 } 056 } 057 058 if (data == null || data.size() == 0) { 059 return; 060 } 061 062 int rowPosition = 1; 063 Iterator it = data.iterator(); 064 065 while (it.hasNext()) { 066 Object row; 067 row = it.next(); 068 rows.add(new GridRow()); 069 070 Iterator<String> fit = fields.iterator(); 071 072 int colPosition = 0; 073 while (fit.hasNext()) { 074 String fieldName = fit.next(); 075 076 // Here we get the associated grid column header since it might 077 // have width and align properties defined which need be set on 078 // each cell. 079 GridColumn col = header.get(colPosition); 080 GridCell cell; 081 cell = new GridCell(col); 082 if (col.getCellObject() != null) { 083 cell.setCellObject(col.getCellObject().clone()); 084 085 int n1; 086 String cellName = cell.getCellObject().getName(); 087 n1 = cellName.indexOf("${"); 088 if (n1 > -1) { 089 // Means the user has a indexed property needs to be in a format propertyName(${indexerFieldName}) 090 // parse out the field name. 091 int n2 = cellName.indexOf("}"); 092 String propertyName = cellName.substring(n1 + 2, n2).trim(); 093 094 try { 095 cellName = cellName.substring(0, n1) + PropertyUtils.getProperty(row, propertyName) + cellName.substring(n2 + 1); 096 } catch (Exception e) { 097 throw new GridBindException(e); 098 } 099 cell.getCellObject().setName(cellName); 100 } 101 } 102 103 log.debug(fieldName + " " + row.getClass().getName()); 104 try { 105 cell.setValue("" + PropertyUtils.getProperty(row, fieldName)); 106 } catch (Exception e) { 107 throw new GridBindException(e); 108 } 109 rows.get(rowPosition).cells.add(cell); 110 111 if (rowPosition % 2 == 0) { 112 rows.get(rowPosition).setAttribute("class", StyleClasses.EvenRow.toString()); 113 } else { 114 rows.get(rowPosition).setAttribute("class", StyleClasses.OddRow.toString()); 115 } 116 colPosition++; 117 } 118 rowPosition++; 119 } 120 } 121 122 123 /** 124 * Returns a clone of the grid object. 125 * 126 * @return Grid object. 127 */ 128 @Override 129 public Grid clone() { 130 Grid grid = (Grid) super.clone(); 131 132 for (int j = 0; j < rows.size(); j++) { 133 GridRow r = rows(j).clone(); 134 for (int i = 0; i < rows(j).cells.size(); i++) { 135 r.cells.add(rows(j).cells(i).clone()); 136 } 137 grid.rows.add(r); 138 } 139 return grid; 140 } 141 142 /** 143 * Renders the grid. 144 * 145 * @return Grid as html string. 146 */ 147 @Override 148 public String toString() { 149 150 if (swapWith != null) { 151 return swapWith.toString(); 152 } 153 154 setAttribute("class", StyleClasses.Grid.toString()); 155 156 StringBuilder sb = new StringBuilder(super.toString()); 157 String lf = System.getProperty("line.separator"); 158 159 sb.append(lf); 160 161 Iterator it = rows.iterator(); 162 while (it.hasNext()) { 163 sb.append(it.next().toString()).append(lf); 164 } 165 sb.append("</").append(tag).append(">").append(lf); 166 return sb.toString(); 167 } 168 169 /** 170 * @param row row index to return. 171 * @return specified GridRow. 172 */ 173 GridRow rows(int row) { 174 return rows.get(row); 175 } 176 }