• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hazendaz / displaytag / 1753

12 Feb 2026 03:17AM UTC coverage: 77.321% (-0.01%) from 77.334%
1753

push

github

web-flow
Merge pull request #1102 from hazendaz/renovate/javax-support-logback-monorepo

Update dependency ch.qos.logback:logback-classic to v1.5.29 (javax-support)

1438 of 2003 branches covered (71.79%)

Branch coverage included in aggregate %.

4034 of 5074 relevant lines covered (79.5%)

0.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

66.67
/displaytag/src/main/java/org/displaytag/render/ItextTableWriter.java
1
/*
2
 * SPDX-License-Identifier: MIT
3
 * See LICENSE file for details.
4
 *
5
 * Copyright 2002-2026 Fabrizio Giustina, the Displaytag team
6
 */
7
package org.displaytag.render;
8

9
import com.itextpdf.text.BadElementException;
10
import com.itextpdf.text.BaseColor;
11
import com.itextpdf.text.Chunk;
12
import com.itextpdf.text.Document;
13
import com.itextpdf.text.DocumentException;
14
import com.itextpdf.text.Element;
15
import com.itextpdf.text.Font;
16
import com.itextpdf.text.FontFactory;
17
import com.itextpdf.text.Paragraph;
18
import com.itextpdf.text.Phrase;
19
import com.itextpdf.text.pdf.PdfPCell;
20
import com.itextpdf.text.pdf.PdfPTable;
21

22
import java.util.Iterator;
23

24
import org.apache.commons.lang3.StringUtils;
25
import org.displaytag.decorator.TableDecorator;
26
import org.displaytag.exception.DecoratorException;
27
import org.displaytag.exception.ObjectLookupException;
28
import org.displaytag.model.Column;
29
import org.displaytag.model.HeaderCell;
30
import org.displaytag.model.TableModel;
31

32
/**
33
 * A table writer that formats table as and writes it to an iText document.
34
 *
35
 * @see org.displaytag.render.TableWriterTemplate
36
 */
37
public class ItextTableWriter extends TableWriterAdapter {
38

39
    /**
40
     * iText representation of the table.
41
     */
42
    private final PdfPTable table;
43

44
    /**
45
     * iText document to which the table is written.
46
     */
47
    private final Document document;
48

49
    /**
50
     * The default font used in the document.
51
     */
52
    private Font defaultFont;
53

54
    /**
55
     * This table writer uses an iText table and document to do its work.
56
     *
57
     * @param table
58
     *            iText representation of the table.
59
     * @param document
60
     *            iText document to which the table is written.
61
     */
62
    public ItextTableWriter(final PdfPTable table, final Document document) {
1✔
63
        this.table = table;
1✔
64
        this.document = document;
1✔
65
    }
1✔
66

67
    /**
68
     * Initialize the main info holder table, like the appropriate number of columns.
69
     *
70
     * @param model
71
     *            The table being represented as iText.
72
     *
73
     * @see org.displaytag.render.TableWriterTemplate#writeTableOpener(org.displaytag.model.TableModel)
74
     */
75
    @Override
76
    protected void writeTableOpener(final TableModel model) {
77
        this.table.getDefaultCell().setVerticalAlignment(Element.ALIGN_TOP);
1✔
78
        this.table.setWidthPercentage(100);
1✔
79
        this.defaultFont = this.getTableFont();
1✔
80
    }
1✔
81

82
    /**
83
     * Obtain the font used to render text in the table; Meant to be overriden if a different font is desired.
84
     *
85
     * @return The font used to render text in the table.
86
     */
87
    protected Font getTableFont() {
88
        return FontFactory.getFont(FontFactory.HELVETICA, 10, Font.NORMAL, new BaseColor(0x00, 0x00, 0x00));
1✔
89
    }
90

91
    /**
92
     * Write the table's caption to a iText document.
93
     *
94
     * @param model
95
     *            the model
96
     *
97
     * @throws Exception
98
     *             the exception
99
     *
100
     * @see org.displaytag.render.TableWriterTemplate#writeCaption(org.displaytag.model.TableModel)
101
     */
102
    @Override
103
    protected void writeCaption(final TableModel model) throws Exception {
104
        this.decorateCaption(model);
×
105
    }
×
106

107
    /**
108
     * Writes the table caption according to a set style.
109
     *
110
     * @param model
111
     *            The table model containing the caption.
112
     *
113
     * @throws DocumentException
114
     *             If an error occurrs while decorating the caption.
115
     */
116
    private void decorateCaption(final TableModel model) throws DocumentException {
117
        final Paragraph caption = new Paragraph(new Chunk(model.getCaption(), this.getCaptionFont()));
×
118
        caption.setAlignment(this.getCaptionHorizontalAlignment());
×
119
        this.document.add(caption);
×
120
    }
×
121

122
    /**
123
     * Obtain the caption font; Meant to be overriden if a different style is desired.
124
     *
125
     * @return The caption font.
126
     */
127
    protected Font getCaptionFont() {
128
        return FontFactory.getFont(FontFactory.HELVETICA, 17, Font.BOLD, new BaseColor(0x00, 0x00, 0x00));
×
129
    }
130

131
    /**
132
     * Obtain the caption horizontal alignment; Meant to be overriden if a different style is desired.
133
     *
134
     * @return The caption horizontal alignment.
135
     */
136
    protected int getCaptionHorizontalAlignment() {
137
        return Element.ALIGN_CENTER;
×
138
    }
139

140
    /**
141
     * Write the table's header columns to an iText document.
142
     *
143
     * @param model
144
     *            the model
145
     *
146
     * @throws DocumentException
147
     *             if an error occurs while writing header.
148
     *
149
     * @see org.displaytag.render.TableWriterTemplate#writeTableHeader(org.displaytag.model.TableModel)
150
     */
151
    @Override
152
    protected void writeTableHeader(final TableModel model) throws DocumentException {
153
        final Iterator<HeaderCell> iterator = model.getHeaderCellList().iterator();
1✔
154

155
        final float[] widths = new float[model.getNumberOfColumns()];
1✔
156
        for (int i = 0; iterator.hasNext(); i++) {
1✔
157
            final HeaderCell headerCell = iterator.next();
1✔
158
            widths[i] = this.getCellWidth(headerCell);
1✔
159

160
            String columnHeader = headerCell.getTitle();
1✔
161

162
            if (columnHeader == null) {
1!
163
                columnHeader = StringUtils.capitalize(headerCell.getBeanPropertyName());
×
164
            }
165

166
            final PdfPCell hdrCell = this.getHeaderCell(columnHeader);
1✔
167
            this.table.addCell(hdrCell);
1✔
168
        }
169
        this.table.setHeaderRows(1);
1✔
170
        this.table.setWidths(widths);
1✔
171
    }
1✔
172

173
    /**
174
     * Returns the maximum size of all values in this column.
175
     *
176
     * @param headerCell
177
     *            Header cell for this column.
178
     *
179
     * @return The maximum size of all values in this column.
180
     */
181
    private float getCellWidth(final HeaderCell headerCell) {
182
        final int maxWidth = headerCell.getMaxLength();
1✔
183
        return maxWidth > 0 ? maxWidth : headerCell.getTitle().length();
1!
184
    }
185

186
    /**
187
     * Write post body footer.
188
     *
189
     * @param model
190
     *            the model
191
     *
192
     * @throws DocumentException
193
     *             if an error occurs while writing post-body footer.
194
     *
195
     * @see org.displaytag.render.TableWriterTemplate#writePostBodyFooter(org.displaytag.model.TableModel)
196
     */
197
    @Override
198
    protected void writePostBodyFooter(final TableModel model) throws DocumentException {
199
        final Chunk cellContent = new Chunk(model.getFooter(), this.getFooterFont());
×
200
        this.setFooterFontStyle(cellContent);
×
201
        final PdfPCell cell = new PdfPCell(new Phrase(cellContent));
×
202
        cell.setLeading(8, 0);
×
203
        cell.setBackgroundColor(this.getFooterBackgroundColor());
×
204
        cell.setHorizontalAlignment(this.getFooterHorizontalAlignment());
×
205
        cell.setColspan(model.getNumberOfColumns());
×
206
        this.table.addCell(cell);
×
207
    }
×
208

209
    /**
210
     * Obtain the footer background color; Meant to be overriden if a different style is desired.
211
     *
212
     * @return The footer background color.
213
     */
214
    protected BaseColor getFooterBackgroundColor() {
215
        return new BaseColor(0xce, 0xcf, 0xce);
×
216
    }
217

218
    /**
219
     * Obtain the footer horizontal alignment; Meant to be overriden if a different style is desired.
220
     *
221
     * @return The footer horizontal alignment.
222
     */
223
    protected int getFooterHorizontalAlignment() {
224
        return Element.ALIGN_LEFT;
×
225
    }
226

227
    /**
228
     * Set the font style used to render the header text; Meant to be overridden if a different header style is desired.
229
     *
230
     * @param cellContent
231
     *            The header content whose font will be modified.
232
     */
233
    protected void setFooterFontStyle(final Chunk cellContent) {
234
        this.setBoldStyle(cellContent, this.getFooterFontColor());
×
235
    }
×
236

237
    /**
238
     * Obtain the footer font color; Meant to be overriden if a different style is desired.
239
     *
240
     * @return The footer font color.
241
     */
242
    protected BaseColor getFooterFontColor() {
243
        return new BaseColor(0x00, 0x00, 0x00);
×
244
    }
245

246
    /**
247
     * Obtain the footer font; Meant to be overriden if a different style is desired.
248
     *
249
     * @return The footer font.
250
     */
251
    protected Font getFooterFont() {
252
        return FontFactory.getFont(FontFactory.HELVETICA, 10);
×
253
    }
254

255
    /**
256
     * Decorators that help render the table to an iText document must implement ItextDecorator.
257
     *
258
     * @param model
259
     *            the model
260
     *
261
     * @see org.displaytag.render.TableWriterTemplate#writeDecoratedRowStart(org.displaytag.model.TableModel)
262
     */
263
    @Override
264
    protected void writeDecoratedRowStart(final TableModel model) {
265
        final TableDecorator decorator = model.getTableDecorator();
1✔
266
        if (decorator instanceof ItextDecorator) {
1!
267
            final ItextDecorator idecorator = (ItextDecorator) decorator;
×
268
            idecorator.setTable(this.table);
×
269
            idecorator.setFont(this.defaultFont);
×
270
        }
271
        decorator.startRow();
1✔
272
    }
1✔
273

274
    /**
275
     * Write decorated row finish.
276
     *
277
     * @param model
278
     *            the model
279
     *
280
     * @throws Exception
281
     *             the exception
282
     *
283
     * @see org.displaytag.render.TableWriterTemplate#writeDecoratedRowFinish(org.displaytag.model.TableModel)
284
     */
285
    @Override
286
    protected void writeDecoratedRowFinish(final TableModel model) throws Exception {
287
        model.getTableDecorator().finishRow();
1✔
288
    }
1✔
289

290
    /**
291
     * Write a column's opening structure to an iText document.
292
     *
293
     * @param column
294
     *            the column
295
     *
296
     * @throws ObjectLookupException
297
     *             the object lookup exception
298
     * @throws DecoratorException
299
     *             the decorator exception
300
     *
301
     * @see org.displaytag.render.TableWriterTemplate#writeColumnOpener(org.displaytag.model.Column)
302
     */
303
    @Override
304
    protected void writeColumnOpener(final Column column) throws ObjectLookupException, DecoratorException {
305
        column.initialize(); // has side effect, setting its stringValue, which affects grouping logic.
1✔
306
    }
1✔
307

308
    /**
309
     * Write a column's value to a iText document.
310
     *
311
     * @param value
312
     *            the value
313
     * @param column
314
     *            the column
315
     *
316
     * @throws BadElementException
317
     *             the bad element exception
318
     *
319
     * @see org.displaytag.render.TableWriterTemplate#writeColumnValue(Object,org.displaytag.model.Column)
320
     */
321
    @Override
322
    protected void writeColumnValue(final Object value, final Column column) throws BadElementException {
323
        this.table.addCell(this.getCell(value));
1✔
324
    }
1✔
325

326
    /**
327
     * Write decorated table finish.
328
     *
329
     * @param model
330
     *            the model
331
     *
332
     * @see org.displaytag.render.TableWriterTemplate#writeDecoratedTableFinish(org.displaytag.model.TableModel)
333
     */
334
    @Override
335
    protected void writeDecoratedTableFinish(final TableModel model) {
336
        model.getTableDecorator().finish();
1✔
337
    }
1✔
338

339
    /**
340
     * Returns a formatted cell for the given value.
341
     *
342
     * @param value
343
     *            cell value
344
     *
345
     * @return Cell
346
     */
347
    private PdfPCell getCell(final Object value) {
348
        final PdfPCell cell = new PdfPCell(new Phrase(new Chunk(
1✔
349
                StringUtils.trimToEmpty(value != null ? value.toString() : StringUtils.EMPTY), this.defaultFont)));
1!
350
        cell.setVerticalAlignment(Element.ALIGN_TOP);
1✔
351
        cell.setLeading(8, 0);
1✔
352
        return cell;
1✔
353
    }
354

355
    /**
356
     * Obtain a header cell.
357
     *
358
     * @param value
359
     *            Cell content.
360
     *
361
     * @return A header cell with the given content.
362
     */
363
    private PdfPCell getHeaderCell(final String value) {
364
        final Chunk cellContent = new Chunk(value, this.getHeaderFont());
1✔
365
        this.setHeaderFontStyle(cellContent);
1✔
366
        final PdfPCell cell = new PdfPCell(new Phrase(cellContent));
1✔
367
        cell.setLeading(8, 0);
1✔
368
        cell.setHorizontalAlignment(this.getHeaderHorizontalAlignment());
1✔
369
        cell.setBackgroundColor(this.getHeaderBackgroundColor());
1✔
370
        return cell;
1✔
371
    }
372

373
    /**
374
     * Obtain the font used to render the header text; Meant to be overridden if a different header font is desired.
375
     *
376
     * @return The font used to render the header text.
377
     */
378
    protected Font getHeaderFont() {
379
        return this.defaultFont;
1✔
380
    }
381

382
    /**
383
     * Obtain the background color used to render the header; Meant to be overridden if a different header background
384
     * color is desired.
385
     *
386
     * @return The backgrounc color used to render the header.
387
     */
388
    protected BaseColor getHeaderBackgroundColor() {
389
        return new BaseColor(0xee, 0xee, 0xee);
1✔
390
    }
391

392
    /**
393
     * Set the font style used to render the header text; Meant to be overridden if a different header style is desired.
394
     *
395
     * @param cellContent
396
     *            The header content whose font will be modified.
397
     */
398
    protected void setHeaderFontStyle(final Chunk cellContent) {
399
        this.setBoldStyle(cellContent, this.getHeaderFontColor());
1✔
400
    }
1✔
401

402
    /**
403
     * Set the font color used to render the header text; Meant to be overridden if a different header style is desired.
404
     *
405
     * @return The font color used to render the header text.
406
     */
407
    protected BaseColor getHeaderFontColor() {
408
        return new BaseColor(0x00, 0x00, 0x00);
1✔
409
    }
410

411
    /**
412
     * Obtain the horizontal alignment used to render header text; Meant to be overridden if a different alignment is
413
     * desired.
414
     *
415
     * @return The horizontal alignment used to render header text;
416
     */
417
    protected int getHeaderHorizontalAlignment() {
418
        return Element.ALIGN_CENTER;
1✔
419
    }
420

421
    /**
422
     * Makes chunk content bold.
423
     *
424
     * @param chunk
425
     *            The chunk whose content is to be rendered bold.
426
     * @param color
427
     *            The font color desired.
428
     */
429
    private void setBoldStyle(final Chunk chunk, final BaseColor color) {
430
        final Font font = chunk.getFont();
1✔
431
        chunk.setFont(FontFactory.getFont(font.getFamilyname(), font.getSize(), Font.BOLD, color));
1✔
432
    }
1✔
433

434
    /**
435
     * An implementor of this interface decorates tables and columns appearing in iText documents.
436
     */
437
    public interface ItextDecorator {
438

439
        /**
440
         * Set the iText table used to render a table model.
441
         *
442
         * @param table
443
         *            The iText table used to render a table model.
444
         */
445
        void setTable(PdfPTable table);
446

447
        /**
448
         * Set the font used to render a table's content.
449
         *
450
         * @param font
451
         *            The font used to render a table's content.
452
         */
453
        void setFont(Font font);
454
    }
455

456
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc