package com.jbidwatcher.ui; /* * Copyright (c) 2000-2007, CyberFOX Software, Inc. All Rights Reserved. * * Developed by mrs (Morgan Schweers) */ import com.jbidwatcher.util.config.JConfig; import javax.swing.*; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import java.awt.*; import java.awt.print.PageFormat; import java.awt.print.Printable; import java.awt.print.PrinterJob; public class JPrintable implements Printable, Runnable { JTable tableView; protected int m_maxNumPage = 1; private static Thread m_thr = null; public JPrintable(JTable _myTable) { tableView = _myTable; } public void doPrint() { //SwingUtilities.invokeLater(this); m_thr = new Thread(this, "Printing"); m_thr.start(); } public void run() { myPrint(); } public void myPrint() { PrinterJob pj = PrinterJob.getPrinterJob(); PageFormat pf = pj.defaultPage(); pf.setOrientation(PageFormat.LANDSCAPE); pj.setPrintable(this, pf); if (!pj.printDialog()) return; try { pj.print(); } catch (Exception pe) { JConfig.log().handleException("Failed to print: " + pe, pe); } } /** * @brief Print out the associated table, using the graphics of the header and the text or icons in the body, * specifically NOT drawing the rest of the table using the JTable.paint() function. * * @param graphics - The graphics 'object' for the print code to draw to. * @param pageFormat - The format of the page to be printed. * @param pageIndex - The page number we're printing. * @return NO_SUCH_PAGE if the page number is beyond the max number of pages of data we have, * PAGE_EXISTS if we have such a page and it was successfully filled out. */ public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) { if (pageIndex >= m_maxNumPage) return NO_SUCH_PAGE; Graphics2D g2 = (Graphics2D) graphics; g2.translate((int) pageFormat.getImageableX(), (int) pageFormat.getImageableY()); int fontHeight = g2.getFontMetrics().getHeight(); int fontDescent = g2.getFontMetrics().getDescent(); double pageHeight = pageFormat.getImageableHeight() - fontHeight; double pageWidth = pageFormat.getImageableWidth(); double tableWidth = (double) tableView.getColumnModel().getTotalColumnWidth(); double scale = 1; if (tableWidth >= pageWidth) { scale = pageWidth / tableWidth; } g2.setFont(tableView.getFont()); g2.setColor(Color.black); g2.drawString("Page: " + (pageIndex + 1), (int) pageWidth / 2 - 35, (int) (pageHeight + fontHeight - fontDescent));//bottom center TableColumnModel colModel = tableView.getColumnModel(); int nColumns = colModel.getColumnCount(); int[] x = new int[nColumns]; x[0] = 0; g2.scale(scale, scale); prepColumnWidths(nColumns, colModel, x); // Use the same font as the existing table. g2.setFont(tableView.getFont()); FontMetrics fm = g2.getFontMetrics(); int h = fm.getHeight(); double headerHeightOnPage = tableView.getTableHeader().getHeight() * scale; double tableWidthOnPage = tableWidth * scale; double oneRowHeight = (tableView.getRowHeight() + tableView.getRowMargin()) * scale; int numRowsOnAPage = (int) ((pageHeight - headerHeightOnPage) / oneRowHeight); // Start one font-line down from the drawn headers. Use getMaxAscent as it's tighter // than getHeight() which includes the descent (the font part under the baseline), and // it manages to avoid characters jutting up into the header, by using the max ascent. // Add the leading amount onto that, to make the space between lines look like the normal // inter-line spacing, and it's all good. int y = (int)headerHeightOnPage+fm.getMaxAscent() + fm.getLeading(); m_maxNumPage = (int) Math.ceil(((double) tableView.getRowCount()) / numRowsOnAPage); // Theoretically unnecessary, as it gets checked at the top, but a good idea anyway, // in case the answer is '0', and this is page 1? if (pageIndex >= m_maxNumPage) { return NO_SUCH_PAGE; } int iniRow = pageIndex * numRowsOnAPage; int endRow = Math.min(tableView.getRowCount(), iniRow + numRowsOnAPage); StringBuffer sbuf = new StringBuffer(); Rectangle r = new Rectangle(0, 0, 0, 0); for (int nRow = iniRow; nRow < endRow; nRow++) { for (int nCol = 0; nCol < nColumns; nCol++) { //int col = tableView.getColumnModel().getColumn(nCol).getModelIndex(); Object obj = tableView.getValueAt(nRow, nCol); int width = tableView.getColumnModel().getColumn(nCol).getWidth(); // The two things we support rendering are objects which can // be turned to text via toString() and Icons. Extend this to // extend the renderable components. if(obj instanceof Icon) { Icon drawme = (Icon)obj; int trueX = x[nCol] + ((width / 2) - (drawme.getIconWidth()/2)); g2.setClip(trueX, y, drawme.getIconWidth(), drawme.getIconHeight()); drawme.paintIcon(tableView, g2, trueX, y); } else { sbuf.setLength(0); if(obj != null) { sbuf.append(obj.toString()); } r.setBounds(x[nCol], y, width, h); g2.setClip(r); g2.drawString(sbuf.toString(), x[nCol], y+fm.getMaxAscent()); } } y += h; } g2.scale(1 / scale, 1 / scale); g2.setClip(0, 0, (int) Math.ceil(tableWidthOnPage), (int) Math.ceil(headerHeightOnPage)); g2.scale(scale, scale); tableView.getTableHeader().paint(g2);//paint header at top System.gc(); return PAGE_EXISTS; } private static void prepColumnWidths(int nColumns, TableColumnModel colModel, int[] x) { // Generate table widths and start-X locations. for (int nCol = 0; nCol < nColumns; nCol++) { TableColumn tk = colModel.getColumn(nCol); int width = tk.getWidth(); if (nCol + 1 < nColumns) x[nCol + 1] = x[nCol] + width; } } }