1 12 package org.displaytag.decorator; 13 14 import java.util.ArrayList ; 15 import java.util.HashMap ; 16 import java.util.Iterator ; 17 import java.util.List ; 18 import java.util.Map ; 19 20 import javax.servlet.jsp.PageContext ; 21 22 import org.apache.commons.lang.ObjectUtils; 23 import org.apache.commons.lang.StringUtils; 24 import org.apache.commons.logging.Log; 25 import org.apache.commons.logging.LogFactory; 26 import org.displaytag.exception.DecoratorException; 27 import org.displaytag.exception.ObjectLookupException; 28 import org.displaytag.model.Column; 29 import org.displaytag.model.ColumnIterator; 30 import org.displaytag.model.HeaderCell; 31 import org.displaytag.model.Row; 32 import org.displaytag.model.TableModel; 33 import org.displaytag.util.TagConstants; 34 35 36 42 public class MultilevelTotalTableDecorator extends TableDecorator 43 { 44 45 48 private static final int NO_RESET_GROUP = 4200; 49 50 53 protected int innermostGroup; 54 55 58 private Log logger = LogFactory.getLog(MultilevelTotalTableDecorator.class); 59 60 63 private String grandTotalLabel = "grandtotal-sum"; 64 65 68 private String subtotalHeaderClass = "subtotal-header"; 69 70 73 private String subtotalLabelClass = "subtotal-label"; 74 75 78 private String subtotalValueClass = "subtotal-sum"; 79 80 83 private Map groupNumberToGroupTotal = new HashMap (); 84 85 88 private int deepestResetGroup = NO_RESET_GROUP; 89 90 93 private List headerRows = new ArrayList (5); 94 95 public void init(PageContext context, Object decorated, TableModel model) 96 { 97 super.init(context, decorated, model); 98 List headerCells = model.getHeaderCellList(); 99 for (Iterator iterator = headerCells.iterator(); iterator.hasNext();) 101 { 102 HeaderCell headerCell = (HeaderCell) iterator.next(); 103 if (headerCell.getGroup() > 0) 104 { 105 groupNumberToGroupTotal.put(new Integer (headerCell.getGroup()), new GroupTotals(headerCell 106 .getColumnNumber())); 107 if (headerCell.getGroup() > innermostGroup) 108 { 109 innermostGroup = headerCell.getGroup(); 110 } 111 } 112 } 113 } 114 115 public String getGrandTotalLabel() 116 { 117 return grandTotalLabel; 118 } 119 120 public void setGrandTotalLabel(String grandTotalLabel) 121 { 122 this.grandTotalLabel = grandTotalLabel; 123 } 124 125 public String getSubtotalValueClass() 126 { 127 return subtotalValueClass; 128 } 129 130 public void setSubtotalValueClass(String subtotalValueClass) 131 { 132 this.subtotalValueClass = subtotalValueClass; 133 } 134 135 public String getSubtotalLabelClass() 136 { 137 return subtotalLabelClass; 138 } 139 140 public void setSubtotalLabelClass(String subtotalLabelClass) 141 { 142 this.subtotalLabelClass = subtotalLabelClass; 143 } 144 145 public String getSubtotalHeaderClass() 146 { 147 return subtotalHeaderClass; 148 } 149 150 public void setSubtotalHeaderClass(String subtotalHeaderClass) 151 { 152 this.subtotalHeaderClass = subtotalHeaderClass; 153 } 154 155 public void startOfGroup(String value, int group) 156 { 157 StringBuffer tr = new StringBuffer (); 158 tr.append("<tr>"); 159 for (int i = 1; i < group; i++) 160 { 161 tr.append("<td></td>\n"); 162 } 163 tr.append("<td class=\"").append(getSubtotalHeaderClass()).append(" group-").append(group).append("\">"); 164 tr.append(value).append("</td>\n"); 165 tr.append("</tr>"); 166 headerRows.add(tr); 167 } 168 169 public String displayGroupedValue(String value, short groupingStatus) 170 { 171 return ""; 172 } 173 174 public String startRow() 175 { 176 StringBuffer sb = new StringBuffer (); 177 for (Iterator iterator = headerRows.iterator(); iterator.hasNext();) 178 { 179 StringBuffer stringBuffer = (StringBuffer ) iterator.next(); 180 sb.append(stringBuffer); 181 } 182 return sb.toString(); 183 } 184 185 public void endOfGroup(String value, int groupNumber) 186 { 187 if (deepestResetGroup > groupNumber) 188 { 189 deepestResetGroup = groupNumber; 190 } 191 } 192 193 public String finishRow() 194 { 195 String returnValue; 196 if (innermostGroup > 0 && deepestResetGroup != NO_RESET_GROUP) 197 { 198 StringBuffer out = new StringBuffer (); 199 for (int i = innermostGroup; i >= deepestResetGroup; i--) 201 { 202 Integer groupNumber = new Integer (i); 203 204 GroupTotals totals = (GroupTotals) groupNumberToGroupTotal.get(groupNumber); 205 if (totals == null) 206 { 207 logger.warn("There is a gap in the defined groups - no group defined for " + groupNumber); 208 continue; 209 } 210 totals.printTotals(getListIndex(), out); 211 totals.setStartRow(getListIndex() + 1); 212 } 213 returnValue = out.toString(); 214 } 215 else 216 { 217 returnValue = null; 218 } 219 deepestResetGroup = NO_RESET_GROUP; 220 headerRows.clear(); 221 if (isLastRow()) 222 { 223 returnValue = StringUtils.defaultString(returnValue); 224 returnValue += totalAllRows(); 225 } 226 return returnValue; 227 } 228 229 233 protected String totalAllRows() 234 { 235 GroupTotals grandTotal = new GroupTotals(-1); 236 StringBuffer out = new StringBuffer (); 237 grandTotal.setStartRow(0); 238 grandTotal.setTotalValueClass(getGrandTotalLabel()); 239 grandTotal.printTotals(getListIndex(), out); 240 return out.toString(); 241 } 242 243 protected String getCellValue(int columnNumber, int rowNumber) 244 { 245 List fullList = tableModel.getRowListFull(); 246 Row row = (Row) fullList.get(rowNumber); 247 ColumnIterator columnIterator = row.getColumnIterator(tableModel.getHeaderCellList()); 248 while (columnIterator.hasNext()) 249 { 250 Column column = columnIterator.nextColumn(); 251 if (column.getHeaderCell().getColumnNumber() == columnNumber) 252 { 253 try 254 { 255 column.initialize(); 256 return column.getChoppedAndLinkedValue(); 257 } 258 catch (ObjectLookupException e) 259 { 260 logger.error("Error: " + e.getMessage(), e); 261 throw new RuntimeException ("Error: " + e.getMessage(), e); 262 } 263 catch (DecoratorException e) 264 { 265 logger.error("Error: " + e.getMessage(), e); 266 throw new RuntimeException ("Error: " + e.getMessage(), e); 267 } 268 } 269 } 270 throw new RuntimeException ("Unable to find column " + columnNumber + " in the list of columns"); 271 } 272 273 protected double getTotalForColumn(int columnNumber, int startRow, int stopRow) 274 { 275 List fullList = tableModel.getRowListFull(); 276 List window = fullList.subList(startRow, stopRow + 1); 277 double total = 0; 278 for (Iterator iterator = window.iterator(); iterator.hasNext();) 279 { 280 Row row = (Row) iterator.next(); 281 ColumnIterator columnIterator = row.getColumnIterator(tableModel.getHeaderCellList()); 282 while (columnIterator.hasNext()) 283 { 284 Column column = columnIterator.nextColumn(); 285 if (column.getHeaderCell().getColumnNumber() == columnNumber) 286 { 287 Number value = null; 288 try 289 { 290 value = (Number ) column.getValue(false); 291 } 292 catch (ObjectLookupException e) 293 { 294 logger.error(e); 295 } 296 catch (DecoratorException e) 297 { 298 logger.error(e); 299 } 300 if (value != null) 301 { 302 total += value.doubleValue(); 303 } 304 } 305 } 306 } 307 return total; 308 } 309 310 public String getTotalsTdOpen(HeaderCell header, String totalClass) 311 { 312 313 String cssClass = ObjectUtils.toString(header.getHtmlAttributes().get("class")); 314 315 StringBuffer buffer = new StringBuffer (); 316 buffer.append(TagConstants.TAG_OPEN); 317 buffer.append(TagConstants.TAGNAME_COLUMN); 318 if (cssClass != null || totalClass != null) 319 { 320 buffer.append(" class=\""); 321 322 if (cssClass != null) 323 { 324 buffer.append(cssClass); 325 if (totalClass != null) 326 { 327 buffer.append(" "); 328 } 329 } 330 if (totalClass != null) 331 { 332 buffer.append(totalClass); 333 } 334 buffer.append("\""); 335 } 336 buffer.append(TagConstants.TAG_CLOSE); 337 return buffer.toString(); 338 } 339 340 public String getTotalsRowOpen() 341 { 342 return TagConstants.TAG_OPEN + TagConstants.TAGNAME_ROW + " class=\"subtotal\"" + TagConstants.TAG_CLOSE; 343 } 344 345 public String getTotalRowLabel(String groupingValue) 346 { 347 return groupingValue + " Total"; 348 } 349 350 public String formatTotal(HeaderCell header, double total) 351 { 352 Object displayValue = new Double (total); 353 if (header.getColumnDecorators().length > 0) 354 { 355 for (int i = 0; i < header.getColumnDecorators().length; i++) 356 { 357 DisplaytagColumnDecorator decorator = header.getColumnDecorators()[i]; 358 try 359 { 360 displayValue = decorator.decorate(displayValue, this.getPageContext(), tableModel.getMedia()); 361 } 362 catch (DecoratorException e) 363 { 364 logger.warn(e.getMessage(), e); 365 } 367 } 368 } 369 return displayValue.toString(); 370 } 371 372 class GroupTotals 373 { 374 375 378 protected String totalLabelClass = getSubtotalLabelClass(); 379 380 383 protected String totalValueClass = getSubtotalValueClass(); 384 385 private int columnNumber; 386 387 private int firstRowOfCurrentSet; 388 389 public GroupTotals(int headerCellColumn) 390 { 391 this.columnNumber = headerCellColumn; 392 this.firstRowOfCurrentSet = 0; 393 } 394 395 public void printTotals(int currentRow, StringBuffer out) 396 { 397 398 List headerCells = tableModel.getHeaderCellList(); 400 if (firstRowOfCurrentSet < currentRow) { 402 out.append(getTotalsRowOpen()); 403 for (Iterator iterator = headerCells.iterator(); iterator.hasNext();) 404 { 405 HeaderCell headerCell = (HeaderCell) iterator.next(); 406 407 if (columnNumber == headerCell.getColumnNumber()) 408 { 409 String currentLabel = getCellValue(columnNumber, firstRowOfCurrentSet); 411 out.append(getTotalsTdOpen(headerCell, getTotalLabelClass() + " group-" + (columnNumber + 1))); 412 out.append(getTotalRowLabel(currentLabel)); 413 } 414 else if (headerCell.isTotaled()) 415 { 416 double total = getTotalForColumn(headerCell.getColumnNumber(), firstRowOfCurrentSet, currentRow); 418 out.append(getTotalsTdOpen(headerCell, getTotalValueClass() + " group-" + (columnNumber + 1))); 419 out.append(formatTotal(headerCell, total)); 420 } 421 else 422 { 423 String style = "group-" + (columnNumber + 1); 425 if (headerCell.getColumnNumber() < innermostGroup) 426 { 427 style += " " + getTotalLabelClass() + " "; 428 } 429 out.append(getTotalsTdOpen(headerCell, style)); 430 } 431 out.append(TagConstants.TAG_OPENCLOSING + TagConstants.TAGNAME_COLUMN + TagConstants.TAG_CLOSE); 432 } 433 out.append("</tr>\n"); 434 } 435 } 436 437 public void setStartRow(int i) 438 { 439 firstRowOfCurrentSet = i; 440 } 441 442 public String getTotalLabelClass() 443 { 444 return totalLabelClass; 445 } 446 447 public void setTotalLabelClass(String totalLabelClass) 448 { 449 this.totalLabelClass = totalLabelClass; 450 } 451 452 public String getTotalValueClass() 453 { 454 return totalValueClass; 455 } 456 457 public void setTotalValueClass(String totalValueClass) 458 { 459 this.totalValueClass = totalValueClass; 460 } 461 } 462 } 463 | Popular Tags |