View Javadoc

1   /*
2    *  File: JaretTablePrinter.java 
3    *  Copyright (c) 2004-2007  Peter Kliem (Peter.Kliem@jaret.de)
4    *  A commercial license is available, see http://www.jaret.de.
5    *
6    * All rights reserved. This program and the accompanying materials
7    * are made available under the terms of the Common Public License v1.0
8    * which accompanies this distribution, and is available at
9    * http://www.eclipse.org/legal/cpl-v10.html
10   */
11  package de.jaret.util.ui.table;
12  
13  import org.eclipse.swt.SWT;
14  import org.eclipse.swt.graphics.Font;
15  import org.eclipse.swt.graphics.FontData;
16  import org.eclipse.swt.graphics.GC;
17  import org.eclipse.swt.graphics.Point;
18  import org.eclipse.swt.graphics.Rectangle;
19  import org.eclipse.swt.printing.Printer;
20  
21  import de.jaret.util.ui.table.model.IColumn;
22  import de.jaret.util.ui.table.model.IRow;
23  import de.jaret.util.ui.table.print.JaretTablePrintConfiguration;
24  import de.jaret.util.ui.table.renderer.ICellRenderer;
25  import de.jaret.util.ui.table.renderer.ICellStyle;
26  import de.jaret.util.ui.table.renderer.ITableHeaderRenderer;
27  
28  /***
29   * <p>
30   * Print utility for the jaret table. The table printer depends on implemented print functionality in the configured
31   * renderers. It "connects" directly to the jaret table thus no headless printing is possible.
32   * </p>
33   * <p>
34   * The Table printer should be disposed after using!
35   * </p>
36   * TODO this is a first hack.
37   * 
38   * @author Peter Kliem
39   * @version $Id: JaretTablePrinter.java 179 2007-01-07 17:37:50Z olk $
40   */
41  public class JaretTablePrinter {
42      /*** borders in cm. */
43      protected double _borderTop = 1;
44  
45      protected double _borderBottom = 1;
46  
47      protected double _borderLeft = 1;
48  
49      protected double _borderRight = 1;
50  
51      protected Rectangle _printingRect;
52  
53      protected Printer _printer;
54  
55      protected double _scaleX;
56  
57      protected double _scaleY;
58  
59      protected ITableHeaderRenderer _headerRenderer;
60  
61      protected JaretTable _table;
62  
63      protected int _pageHeight;
64  
65      protected int _pageWidth;
66  
67      protected int _footerHeight;
68  
69      protected double _scale = 1.0;
70  
71      public JaretTablePrinter(Printer printer, JaretTable table) {
72          _table = table;
73          setPrinter(printer);
74      }
75  
76      public void setPrinter(Printer printer) {
77          if (_printer != null) {
78              _printer.dispose();
79          }
80          _printer = printer;
81          if (printer != null) {
82              Point dpi = _printer.getDPI();
83              _scaleX = (double) dpi.x / 96.0;
84              _scaleY = (double) dpi.y / 96.0;
85          }
86  
87      }
88  
89      public int scaleX(int in) {
90          return (int) Math.round(_scaleX * (double) in * _scale);
91      }
92  
93      public double getScaleX() {
94          return _scaleX;
95      }
96  
97      public int scaleY(int in) {
98          return (int) Math.round(_scaleY * (double) in * _scale);
99      }
100 
101     public Printer getPrinter() {
102         return _printer;
103     }
104 
105     protected int pixelForCmX(double cm) {
106         Point dpi = _printer.getDPI();
107         double inch = cm / 2.54;
108         return (int) (dpi.x * inch);
109     }
110 
111     protected int pixelForCmY(double cm) {
112         Point dpi = _printer.getDPI();
113         double inch = cm / 2.54;
114         return (int) (dpi.y * inch);
115     }
116 
117     /***
118      * Calculate the number of pages generated when printing.
119      * 
120      * @param configuration
121      * @return
122      */
123     public Point calculatePageCount(JaretTablePrintConfiguration configuration) {
124         _scale = configuration.getScale();
125         _pageHeight = _printer.getClientArea().height - pixelForCmY(_borderTop + _borderBottom);
126         _pageWidth = _printer.getClientArea().width - pixelForCmX(_borderLeft + _borderRight);
127 
128         int tHeight;
129         if (configuration.getRowLimit() == -1) {
130             tHeight = _table.getTotalHeight();
131         } else {
132             tHeight = _table.getTotalHeight(configuration.getRowLimit());
133         }
134         int tWidth;
135         if (configuration.getColLimit() == -1) {
136             tWidth = _table.getTotalWidth();
137         } else {
138             tWidth = _table.getTotalWidth(configuration.getColLimit());
139         }
140 
141         int pagesx = (scaleX(tWidth) / _pageWidth) + 1;
142         int pagesy = (scaleY(tHeight) / (_pageHeight - _footerHeight)) + 1;
143 
144         int headerheight = _table.getDrawHeader() ? _table.getHeaderHeight() : 0;
145         headerheight = configuration.getRepeatHeader() ? headerheight + headerheight * (pagesy - 1) : headerheight;
146 
147         // corrected pagesy
148         pagesy = (scaleY(tHeight + headerheight) / (_pageHeight - _footerHeight)) + 1;
149 
150         return new Point(pagesx, pagesy);
151 
152     }
153 
154     public void print(JaretTablePrintConfiguration configuration) {
155         _printingRect = new Rectangle(pixelForCmX(_borderLeft), pixelForCmY(_borderTop), _pageWidth, _pageHeight);
156 
157         _headerRenderer = _table.getHeaderRenderer().getPrintRenderer(_printer);
158         Point pages = calculatePageCount(configuration);
159         int pagesx = pages.x;
160         int pagesy = pages.y;
161 
162         _printer.startJob(configuration.getName() != null ? configuration.getName() : "jarettable");
163 
164         GC gc = new GC(_printer);
165         Font oldfont = gc.getFont();
166         FontData fontdata = new FontData("Arial", (int) (8.0 * _scale), SWT.NULL);
167         Font printerFont = new Font(_printer, fontdata);
168         gc.setFont(printerFont);
169 
170         for (int px = 0; px < pagesx; px++) {
171             int startx = (int) ((px * _pageWidth) / (_scaleX * _scale));
172             IColumn column = _table.getColumnForAbsX(startx);
173             int offx = startx - _table.getAbsBeginXForColumn(column);
174             int beginColIdx = _table.getColIdxForAbsX(startx);
175             // System.out.println("PX "+px+" startx "+startx+" offx "+offx+" beginColIdx "+beginColIdx);
176             int rIdx = 0;
177             for (int py = 0; py < pagesy; py++) {
178                 int y = 0;
179                 String footerText = configuration.getFooterText() != null ? configuration.getFooterText() : "";
180                 footerText += "(" + (px + 1) + "/" + pagesx + "," + (py + 1) + "/" + pagesy + ")";
181                 _printer.startPage();
182 
183                 int starty = (int) (py * ((_pageHeight - _footerHeight - (configuration.getRepeatHeader() ? scaleY(_table
184                         .getHeaderHeight())
185                         : 0)) / (_scaleY * _scale)));
186                 rIdx = py == 0 ? 0 : rIdx;// _table.getRowIdxForAbsY(starty);
187                 Rectangle clipSave = gc.getClipping();
188 
189                 if (starty == 0 || configuration.getRepeatHeader()) {
190                     // draw header
191                     // draw headers table area
192                     int x = -offx;
193                     int cIdx = beginColIdx;
194                     while (scaleX(x) < _pageWidth && cIdx < _table.getColumnCount()
195                             && (configuration.getColLimit() == -1 || cIdx <= configuration.getColLimit())) {
196                         IColumn col = _table.getColumn(cIdx);
197                         int colwidth = _table.getTableViewState().getColumnWidth(col);
198                         int xx = x > 0 ? x : 0;
199                         int clipWidth = x > 0 ? colwidth : colwidth - offx;
200                         if (!_headerRenderer.disableClipping()) {
201                             gc.setClipping(scaleX(xx) + pixelForCmX(_borderLeft), pixelForCmY(_borderTop),
202                                     scaleX(clipWidth), scaleY(_table.getHeaderHeight()));
203                             gc.setClipping(gc.getClipping().intersection(_printingRect));
204                         }
205 
206                         drawHeader(gc, scaleX(x) + pixelForCmX(_borderLeft), scaleX(colwidth), col);
207 
208                         x += colwidth;
209                         cIdx++;
210                     }
211                     y += _table.getHeaderHeight();
212                     gc.setClipping(clipSave);
213                 }
214 
215                 // normal table area
216 
217                 gc.setClipping(_printingRect);
218 
219                 while (scaleY(y) < _pageHeight && rIdx < _table.getRowCount()
220                         && (configuration.getRowLimit() == -1 || rIdx <= configuration.getRowLimit())) {
221                     IRow row = _table.getRow(rIdx);
222                     int rHeight = _table.getTableViewState().getRowHeight(row);
223                     // do not draw a row that does not fit on th page
224                     if (scaleY(y) + scaleY(rHeight) > _pageHeight) {
225                         break;
226                     }
227                     int x = -offx;
228                     int cIdx = beginColIdx;
229                     while (scaleX(x) < _pageWidth && cIdx < _table.getColumnCount()
230                             && (configuration.getColLimit() == -1 || cIdx <= configuration.getColLimit())) {
231                         IColumn col = _table.getColumn(cIdx);
232                         int colwidth = _table.getTableViewState().getColumnWidth(col);
233                         Rectangle area = new Rectangle(scaleX(x) + pixelForCmX(_borderLeft), scaleY(y)
234                                 + pixelForCmY(_borderTop), scaleX(colwidth), scaleY(rHeight));
235                         drawCell(gc, area, row, col);
236                         x += colwidth;
237                         cIdx++;
238                     }
239                     y += rHeight;
240                     rIdx++;
241                 }
242 
243                 gc.setClipping(clipSave);
244                 drawFooter(gc, footerText);
245                 _printer.endPage();
246             }
247         }
248         _printer.endJob();
249         printerFont.dispose();
250         gc.setFont(oldfont);
251         gc.dispose();
252     }
253 
254     /***
255      * TODO creation and disposal of the cell renderers for printing is ... well should be changed!
256      * 
257      * @param gc
258      * @param area
259      * @param row
260      * @param col
261      */
262     private void drawCell(GC gc, Rectangle area, IRow row, IColumn col) {
263         ICellStyle bc = _table.getTableViewState().getCellStyle(row, col);
264         ICellRenderer cellRenderer = _table.getCellRenderer(row, col).createPrintRenderer(_printer);
265         if (cellRenderer != null) {
266             cellRenderer.draw(gc, _table, bc, area, row, col, false, false, true);
267         }
268         cellRenderer.dispose();
269     }
270 
271     private void drawFooter(GC gc, String footer) {
272         Point extent = gc.textExtent(footer);
273         int y = _printer.getClientArea().height - _footerHeight - pixelForCmY(_borderBottom);
274         // gc.drawLine(0,y,_pageWidth, y);
275         // gc.drawLine(0,y+extent.y,_pageWidth, y+extent.y);
276         gc.drawString(footer, pixelForCmX(_borderLeft), y);
277 
278     }
279 
280     private void drawHeader(GC gc, int x, int colwidth, IColumn col) {
281         Rectangle area = new Rectangle(x, pixelForCmY(_borderTop), colwidth, scaleY(_table.getHeaderHeight()));
282         int sortingPos = _table.getTableViewState().getColumnSortingPosition(col);
283         boolean sortingDir = _table.getTableViewState().getColumnSortingDirection(col);
284         _headerRenderer.draw(gc, area, col, sortingPos, sortingDir, true);
285     }
286 
287     public void dispose() {
288         if (_headerRenderer != null) {
289             _headerRenderer.dispose();
290         }
291     }
292 }