package org.freehep.swing.print.table; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.font.FontRenderContext; import java.awt.geom.Line2D; import java.awt.geom.Rectangle2D.Float; import java.awt.print.PageFormat; import java.awt.print.Pageable; import java.awt.print.Printable; import javax.swing.table.TableModel; /** Utility for printing tables. */ public class TablePrinter implements Pageable, Printable { private Font cellFont; private Font headerFont; private FontRenderContext lastFontRenderContext; private PageFormat pf; private PrintableTableModel model; private float[] widths; private float headerHeight; private float rowHeight; private int nPages = UNKNOWN_NUMBER_OF_PAGES; private int rowsPerPage; /** Create a TablePrinter from a PrintableTableModel * @param model The table model to print * @param pf The page format to use for printing * @param headerFont The font to be used for the table header * @param cellFont The font to be used for the cells in the body of the table. * @param frc The font render context for the printing device */ public TablePrinter(PrintableTableModel model, PageFormat pf, Font headerFont, Font cellFont, FontRenderContext frc) { this.pf = pf; this.model = model; this.headerFont = headerFont; this.cellFont = cellFont; calculateTableSize(pf, frc); } /** Create a TablePrinter from a TableModel * @param model The table model to print * @param title The title to use for the print job * @param pf The page format to use for printing * @param headerFont The font to be used for the table header * @param cellFont The font to be used for the cells in the body of the table. * @param frc The font render context for the printing device */ public TablePrinter(TableModel model, String title, PageFormat pf, Font headerFont, Font cellFont, FontRenderContext frc) { this(new PrintModelAdapter(model, title),pf,headerFont,cellFont,frc); } public int getNumberOfPages() { return nPages; } public PageFormat getPageFormat(int p1) { return pf; } public Printable getPrintable(int p1) { return this; } public int print(Graphics g, PageFormat pf, int page) { Graphics2D g2 = (Graphics2D) g; FontRenderContext frc = g2.getFontRenderContext(); if (!frc.equals(lastFontRenderContext)) { calculateTableSize(pf, frc); } if (page >= nPages) { return NO_SUCH_PAGE; } g2.setColor(Color.black); g2.setStroke(new BasicStroke(0)); float xx = (float) pf.getImageableX(); float yy = (float) pf.getImageableY(); float totalWidth = 4; for (int i = 0; i < widths.length; i++) { if (widths[i] > 0) { totalWidth += (widths[i] + 3); } } float y = 4 + xx; float x = 4 + yy; Float rect = new Float(); for (int c = 0; c < model.numberOfColumns(); c++) { if (widths[c] == 0) { continue; } rect.setRect(x, y, widths[c], headerHeight); CellPrinter cp = model.getHeaderPrinter(c); cp.setFont(headerFont); cp.setValue(model.headerForColumn(c)); cp.print(g, rect); x += (widths[c] + 3); } y += (headerHeight + 1); Line2D line = new java.awt.geom.Line2D.Float(); for (int r = page * rowsPerPage; r < ((page + 1) * rowsPerPage); r++) { if (r >= model.numberOfRows()) { break; } x = 4 + xx; for (int c = 0; c < model.numberOfColumns(); c++) { if (widths[c] == 0) { continue; } rect.setRect(x, y, widths[c], rowHeight); CellPrinter cp = model.getCellPrinter(c); cp.setFont(cellFont); cp.setValue(model.valueAt(r, c)); cp.print(g, rect); x += (widths[c] + 3); } line.setLine(xx, y - 1, xx + totalWidth, y - 1); g2.draw(line); y += (rowHeight + 1); } x = xx + 2; for (int c = 0; c < (model.numberOfColumns() - 1); c++) { if (widths[c] == 0) { continue; } x += (widths[c] + 3); line.setLine(x, yy + 1, x, y); g2.draw(line); } g2.setStroke(new BasicStroke(2)); rect.setRect(xx + 1, yy + 2, totalWidth, y - yy); g2.draw(rect); String footer = "Page " + (page + 1) + " of " + nPages; // +" header="+headerFont+" cell="+cellFont; g2.drawString(footer, xx, (yy + (float) pf.getImageableHeight()) - g.getFontMetrics().getDescent()); return PAGE_EXISTS; } private void calculateTableSize(PageFormat pf, FontRenderContext frc) { lastFontRenderContext = frc; double height = pf.getImageableHeight(); widths = new float[model.numberOfColumns()]; headerHeight = 0; rowHeight = 0; for (int c = 0; c < model.numberOfColumns(); c++) { if (model.hideColumn(c)) { continue; } CellPrinter hp = model.getHeaderPrinter(c); hp.setFont(headerFont); hp.setValue(model.headerForColumn(c)); widths[c] = hp.getWidth(frc); float h = hp.getHeight(frc); if (h > headerHeight) { headerHeight = h; } CellPrinter cp = model.getCellPrinter(c); cp.setFont(cellFont); for (int r = 0; r < model.numberOfRows(); r++) { cp.setValue(model.valueAt(r, c)); float w = cp.getWidth(frc); if (w > widths[c]) { widths[c] = w; } h = cp.getHeight(frc); if (h > rowHeight) { rowHeight = h; } } } int nRows = model.numberOfRows(); double effectiveHeight = height - headerHeight - 6 - rowHeight; // leave room for header rowsPerPage = (int) Math.floor(effectiveHeight / (rowHeight + 1)); nPages = 1 + ((nRows - 1) / rowsPerPage); } }