1 /** 2 * Licensed under the Artistic License; you may not use this file 3 * except in compliance with the License. 4 * You may obtain a copy of the License at 5 * 6 * http://displaytag.sourceforge.net/license.html 7 * 8 * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR 9 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 10 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 11 */ 12 package org.displaytag.render; 13 14 import java.awt.Color; 15 import java.util.Iterator; 16 17 import org.apache.commons.lang.ObjectUtils; 18 import org.apache.commons.lang.StringUtils; 19 import org.displaytag.decorator.TableDecorator; 20 import org.displaytag.exception.DecoratorException; 21 import org.displaytag.exception.ObjectLookupException; 22 import org.displaytag.model.Column; 23 import org.displaytag.model.HeaderCell; 24 import org.displaytag.model.TableModel; 25 26 import com.lowagie.text.BadElementException; 27 import com.lowagie.text.Cell; 28 import com.lowagie.text.Chunk; 29 import com.lowagie.text.Document; 30 import com.lowagie.text.DocumentException; 31 import com.lowagie.text.Element; 32 import com.lowagie.text.Font; 33 import com.lowagie.text.FontFactory; 34 import com.lowagie.text.Paragraph; 35 import com.lowagie.text.Rectangle; 36 import com.lowagie.text.Table; 37 38 39 /** 40 * A table writer that formats table as and writes it to an iText document. 41 * @author Jorge L. Barroso 42 * @version $Id$ 43 * @see org.displaytag.render.TableWriterTemplate 44 */ 45 public class ItextTableWriter extends TableWriterAdapter 46 { 47 48 /** 49 * iText representation of the table. 50 */ 51 private Table table; 52 53 /** 54 * iText document to which the table is written. 55 */ 56 private Document document; 57 58 /** 59 * The default font used in the document. 60 */ 61 private Font defaultFont; 62 63 /** 64 * This table writer uses an iText table and document to do its work. 65 * @param table iText representation of the table. 66 * @param document iText document to which the table is written. 67 */ 68 public ItextTableWriter(Table table, Document document) 69 { 70 this.table = table; 71 this.document = document; 72 } 73 74 /** 75 * Initialize the main info holder table, like the appropriate number of columns. 76 * @param model The table being represented as iText. 77 * @see org.displaytag.render.TableWriterTemplate#writeTableOpener(org.displaytag.model.TableModel) 78 */ 79 protected void writeTableOpener(TableModel model) 80 { 81 this.table.setDefaultVerticalAlignment(Element.ALIGN_TOP); 82 this.table.setCellsFitPage(true); 83 this.table.setWidth(100); 84 this.table.setPadding(2); 85 this.table.setSpacing(0); 86 this.table.setBorder(Rectangle.NO_BORDER); 87 this.defaultFont = this.getTableFont(); 88 } 89 90 /** 91 * Obtain the font used to render text in the table; Meant to be overriden if a different font is desired. 92 * @return The font used to render text in the table. 93 */ 94 protected Font getTableFont() 95 { 96 return FontFactory.getFont(FontFactory.HELVETICA, 10, Font.NORMAL, new Color(0x00, 0x00, 0x00)); 97 } 98 99 /** 100 * Write the table's caption to a iText document. 101 * @see org.displaytag.render.TableWriterTemplate#writeCaption(org.displaytag.model.TableModel) 102 */ 103 protected void writeCaption(TableModel model) throws Exception 104 { 105 this.decorateCaption(model); 106 } 107 108 /** 109 * Writes the table caption according to a set style. 110 * @param model The table model containing the caption. 111 * @throws DocumentException If an error occurrs while decorating the caption. 112 */ 113 private void decorateCaption(TableModel model) throws DocumentException 114 { 115 Paragraph caption = new Paragraph(new Chunk(model.getCaption(), this.getCaptionFont())); 116 caption.setAlignment(this.getCaptionHorizontalAlignment()); 117 this.document.add(caption); 118 } 119 120 /** 121 * Obtain the caption font; Meant to be overriden if a different style is desired. 122 * @return The caption font. 123 */ 124 protected Font getCaptionFont() 125 { 126 return FontFactory.getFont(FontFactory.HELVETICA, 17, Font.BOLD, new Color(0x00, 0x00, 0x00)); 127 } 128 129 /** 130 * Obtain the caption horizontal alignment; Meant to be overriden if a different style is desired. 131 * @return The caption horizontal alignment. 132 */ 133 protected int getCaptionHorizontalAlignment() 134 { 135 return Element.ALIGN_CENTER; 136 } 137 138 /** 139 * Write the table's header columns to an iText document. 140 * @see org.displaytag.render.TableWriterTemplate#writeTableHeader(org.displaytag.model.TableModel) 141 * @throws BadElementException if an error occurs while writing header. 142 */ 143 protected void writeTableHeader(TableModel model) throws BadElementException 144 { 145 Iterator iterator = model.getHeaderCellList().iterator(); 146 147 float[] widths = new float[model.getNumberOfColumns()]; 148 for (int i = 0; iterator.hasNext(); i++) 149 { 150 HeaderCell headerCell = (HeaderCell) iterator.next(); 151 widths[i] = this.getCellWidth(headerCell); 152 153 String columnHeader = headerCell.getTitle(); 154 155 if (columnHeader == null) 156 { 157 columnHeader = StringUtils.capitalize(headerCell.getBeanPropertyName()); 158 } 159 160 Cell hdrCell = this.getHeaderCell(columnHeader); 161 this.table.addCell(hdrCell); 162 } 163 this.table.setWidths(widths); 164 this.table.endHeaders(); 165 } 166 167 /** 168 * Returns the maximum size of all values in this column. 169 * @param headerCell Header cell for this column. 170 * @return The maximum size of all values in this column. 171 */ 172 private float getCellWidth(HeaderCell headerCell) 173 { 174 int maxWidth = headerCell.getMaxLength(); 175 return (maxWidth > 0) ? maxWidth : headerCell.getTitle().length(); 176 } 177 178 /** 179 * @see org.displaytag.render.TableWriterTemplate#writePostBodyFooter(org.displaytag.model.TableModel) 180 * @throws DocumentException if an error occurs while writing post-body footer. 181 */ 182 protected void writePostBodyFooter(TableModel model) throws DocumentException 183 { 184 Chunk cellContent = new Chunk(model.getFooter(), this.getFooterFont()); 185 this.setFooterFontStyle(cellContent); 186 Cell cell = new Cell(cellContent); 187 cell.setLeading(8); 188 cell.setBackgroundColor(this.getFooterBackgroundColor()); 189 cell.setHorizontalAlignment(this.getFooterHorizontalAlignment()); 190 cell.setColspan(model.getNumberOfColumns()); 191 table.addCell(cell); 192 } 193 194 /** 195 * Obtain the footer background color; Meant to be overriden if a different style is desired. 196 * @return The footer background color. 197 */ 198 protected Color getFooterBackgroundColor() 199 { 200 return new Color(0xce, 0xcf, 0xce); 201 } 202 203 /** 204 * Obtain the footer horizontal alignment; Meant to be overriden if a different style is desired. 205 * @return The footer horizontal alignment. 206 */ 207 protected int getFooterHorizontalAlignment() 208 { 209 return Element.ALIGN_LEFT; 210 } 211 212 /** 213 * Set the font style used to render the header text; Meant to be overridden if a different header style is desired. 214 * @param cellContent The header content whose font will be modified. 215 */ 216 protected void setFooterFontStyle(Chunk cellContent) 217 { 218 this.setBoldStyle(cellContent, this.getFooterFontColor()); 219 } 220 221 /** 222 * Obtain the footer font color; Meant to be overriden if a different style is desired. 223 * @return The footer font color. 224 */ 225 protected Color getFooterFontColor() 226 { 227 return new Color(0x00, 0x00, 0x00); 228 } 229 230 /** 231 * Obtain the footer font; Meant to be overriden if a different style is desired. 232 * @return The footer font. 233 */ 234 protected Font getFooterFont() 235 { 236 return FontFactory.getFont(FontFactory.HELVETICA, 10); 237 } 238 239 /** 240 * Decorators that help render the table to an iText document must implement ItextDecorator. 241 * @see org.displaytag.render.TableWriterTemplate#writeDecoratedRowStart(org.displaytag.model.TableModel) 242 */ 243 protected void writeDecoratedRowStart(TableModel model) 244 { 245 TableDecorator decorator = model.getTableDecorator(); 246 if (decorator instanceof ItextDecorator) 247 { 248 ItextDecorator idecorator = (ItextDecorator) decorator; 249 idecorator.setTable(this.table); 250 idecorator.setFont(this.defaultFont); 251 } 252 decorator.startRow(); 253 } 254 255 /** 256 * @see org.displaytag.render.TableWriterTemplate#writeDecoratedRowFinish(org.displaytag.model.TableModel) 257 */ 258 protected void writeDecoratedRowFinish(TableModel model) throws Exception 259 { 260 model.getTableDecorator().finishRow(); 261 } 262 263 /** 264 * Write a column's opening structure to an iText document. 265 * @see org.displaytag.render.TableWriterTemplate#writeColumnOpener(org.displaytag.model.Column) 266 */ 267 protected void writeColumnOpener(Column column) throws ObjectLookupException, DecoratorException 268 { 269 column.initialize(); // has side effect, setting its stringValue, which affects grouping logic. 270 } 271 272 /** 273 * Write a column's value to a iText document. 274 * @see org.displaytag.render.TableWriterTemplate#writeColumnValue(Object,org.displaytag.model.Column) 275 */ 276 protected void writeColumnValue(Object value, Column column) throws BadElementException 277 { 278 this.table.addCell(getCell(value)); 279 } 280 281 /** 282 * @see org.displaytag.render.TableWriterTemplate#writeDecoratedTableFinish(org.displaytag.model.TableModel) 283 */ 284 protected void writeDecoratedTableFinish(TableModel model) 285 { 286 model.getTableDecorator().finish(); 287 } 288 289 /** 290 * Returns a formatted cell for the given value. 291 * @param value cell value 292 * @return Cell 293 * @throws BadElementException if errors occurs while generating content. 294 */ 295 private Cell getCell(Object value) throws BadElementException 296 { 297 Cell cell = new Cell(new Chunk(StringUtils.trimToEmpty(ObjectUtils.toString(value)), this.defaultFont)); 298 cell.setVerticalAlignment(Element.ALIGN_TOP); 299 cell.setLeading(8); 300 return cell; 301 } 302 303 /** 304 * Obtain a header cell. 305 * @param value Cell content. 306 * @return A header cell with the given content. 307 * @throws BadElementException if errors occurs while generating content. 308 */ 309 private Cell getHeaderCell(String value) throws BadElementException 310 { 311 Chunk cellContent = new Chunk(value, this.getHeaderFont()); 312 setHeaderFontStyle(cellContent); 313 Cell cell = new Cell(cellContent); 314 cell.setLeading(8); 315 cell.setHeader(true); 316 cell.setHorizontalAlignment(this.getHeaderHorizontalAlignment()); 317 cell.setBackgroundColor(this.getHeaderBackgroundColor()); 318 return cell; 319 } 320 321 /** 322 * Obtain the font used to render the header text; Meant to be overridden if a different header font is desired. 323 * @return The font used to render the header text. 324 */ 325 protected Font getHeaderFont() 326 { 327 return this.defaultFont; 328 } 329 330 /** 331 * Obtain the background color used to render the header; Meant to be overridden if a different header background 332 * color is desired. 333 * @return The backgrounc color used to render the header. 334 */ 335 protected Color getHeaderBackgroundColor() 336 { 337 return new Color(0xee, 0xee, 0xee); 338 } 339 340 /** 341 * Set the font style used to render the header text; Meant to be overridden if a different header style is desired. 342 * @param cellContent The header content whose font will be modified. 343 */ 344 protected void setHeaderFontStyle(Chunk cellContent) 345 { 346 setBoldStyle(cellContent, this.getHeaderFontColor()); 347 } 348 349 /** 350 * Set the font color used to render the header text; Meant to be overridden if a different header style is desired. 351 * @return The font color used to render the header text. 352 */ 353 protected Color getHeaderFontColor() 354 { 355 return new Color(0x00, 0x00, 0x00); 356 } 357 358 /** 359 * Obtain the horizontal alignment used to render header text; Meant to be overridden if a different alignment is 360 * desired. 361 * @return The horizontal alignment used to render header text; 362 */ 363 protected int getHeaderHorizontalAlignment() 364 { 365 return Element.ALIGN_CENTER; 366 } 367 368 /** 369 * Makes chunk content bold. 370 * @param chunk The chunk whose content is to be rendered bold. 371 * @param color The font color desired. 372 */ 373 private void setBoldStyle(Chunk chunk, Color color) 374 { 375 Font font = chunk.font(); 376 chunk.setFont(FontFactory.getFont(font.getFamilyname(), font.size(), Font.BOLD, color)); 377 } 378 379 /** 380 * An implementor of this interface decorates tables and columns appearing in iText documents. 381 * @author Jorge L. Barroso 382 * @version $Revision$ ($Author$) 383 */ 384 public interface ItextDecorator 385 { 386 387 /** 388 * Set the iText table used to render a table model. 389 * @param table The iText table used to render a table model. 390 */ 391 void setTable(Table table); 392 393 /** 394 * Set the font used to render a table's content. 395 * @param font The font used to render a table's content. 396 */ 397 void setFont(Font font); 398 } 399 400 }