/jEdit/tags/jedit-4-5-pre1/org/gjt/sp/jedit/print/BufferPrintable.java
Java | 418 lines | 305 code | 58 blank | 55 comment | 35 complexity | 10be6cc991bafbf677b558f4c9609a12 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
1/*
2 * BufferPrintable.java - Printable implementation
3 * :tabSize=8:indentSize=8:noTabs=false:
4 * :folding=explicit:collapseFolds=1:
5 *
6 * Copyright (C) 2001, 2003 Slava Pestov
7 * Portions copyright (C) 2002 Thomas Dilts
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24package org.gjt.sp.jedit.print;
25
26//{{{ Imports
27import javax.swing.text.TabExpander;
28import javax.swing.SwingUtilities;
29import java.awt.font.*;
30import java.awt.geom.*;
31import java.awt.print.*;
32import java.awt.*;
33import java.lang.reflect.Method;
34import java.util.*;
35import java.util.List;
36
37import org.gjt.sp.jedit.syntax.*;
38import org.gjt.sp.jedit.*;
39import org.gjt.sp.util.*;
40//}}}
41
42/**
43 * @version $Id: BufferPrintable.java 18832 2010-10-23 09:54:46Z kpouer $
44 */
45class BufferPrintable implements Printable
46{
47 //{{{ BufferPrintable constructor
48 BufferPrintable(PrinterJob job, Object format,
49 View view, Buffer buffer, Font font, boolean header,
50 boolean footer, boolean lineNumbers, boolean color)
51 {
52 this.job = job;
53 this.format = format;
54 this.view = view;
55 this.buffer = buffer;
56 this.font = font;
57 this.header = header;
58 this.footer = footer;
59 this.lineNumbers = lineNumbers;
60
61 styles = org.gjt.sp.util.SyntaxUtilities.loadStyles(jEdit.getProperty("print.font"),
62 jEdit.getIntegerProperty("print.fontsize",10),color);
63 styles[Token.NULL] = new SyntaxStyle(textColor,null,font);
64
65 // Change any white text to black
66 for(int i = 0; i < styles.length; i++)
67 {
68 SyntaxStyle s = styles[i];
69 if(s.getForegroundColor().equals(Color.WHITE)
70 && s.getBackgroundColor() == null)
71 {
72 styles[i] = new SyntaxStyle(
73 Color.BLACK,
74 styles[i].getBackgroundColor(),
75 styles[i].getFont());
76 }
77 }
78
79 lineList = new ArrayList<Chunk>();
80
81 tokenHandler = new DisplayTokenHandler();
82 } //}}}
83
84 //{{{ print() method
85 public void print()
86 {
87 try
88 {
89 //buffer.readLock();
90
91 if(format == null)
92 job.print();
93 else
94 {
95 Method method = PrinterJob.class.getMethod(
96 "print",new Class[] { Class.forName(
97 "javax.print.attribute.PrintRequestAttributeSet") });
98 method.invoke(job,new Object[] { format });
99 }
100 }
101 catch(PrinterAbortException ae)
102 {
103 Log.log(Log.DEBUG,this,ae);
104 }
105 catch(Exception e)
106 {
107 Log.log(Log.ERROR,this,e);
108 final String[] args = { e.toString() };
109 SwingUtilities.invokeLater(new Runnable()
110 {
111 public void run()
112 {
113 GUIUtilities.error(view,"print-error",args);
114 }
115 });
116 }
117 finally
118 {
119 //buffer.readUnlock();
120 }
121 } //}}}
122
123 //{{{ print() method
124 public int print(Graphics _gfx, PageFormat pageFormat, int pageIndex)
125 throws PrinterException
126 {
127 // we keep the first non-null frc we get, since sometimes
128 // we get invalid ones on subsequent pages on Windows
129 if(frc == null)
130 {
131 frc = ((Graphics2D)_gfx).getFontRenderContext();
132 Log.log(Log.DEBUG,this,"Font render context is " + frc);
133 }
134
135 Log.log(Log.DEBUG,this,"Asked to print page " + pageIndex);
136 Log.log(Log.DEBUG,this,"Current page is " + currentPage);
137
138 if(pageIndex > currentPage)
139 {
140 for(int i = currentPage; i < pageIndex; i++)
141 {
142 Log.log(Log.DEBUG,this,"Current physical line is now " + currentPageStart);
143 currentPhysicalLine = currentPageStart;
144 printPage(_gfx,pageFormat,i,true);
145 }
146
147 currentPage = pageIndex - 1;
148 Log.log(Log.DEBUG,this,"Current page is now " + currentPage);
149 }
150
151 if(pageIndex == currentPage + 1)
152 {
153 if(end)
154 {
155 Log.log(Log.DEBUG,this,"The end");
156 return NO_SUCH_PAGE;
157 }
158
159 currentPageStart = currentPhysicalLine;
160 Log.log(Log.DEBUG,this,"#2 - Current physical line is now " + currentPageStart);
161 currentPage = pageIndex;
162 Log.log(Log.DEBUG,this,"#2 - Current page is now " + currentPage);
163 }
164 else if(pageIndex == currentPage)
165 {
166 currentPhysicalLine = currentPageStart;
167 Log.log(Log.DEBUG,this,"#3 - Current physical line is now " + currentPageStart);
168 }
169
170 printPage(_gfx,pageFormat,pageIndex,true);
171
172 return PAGE_EXISTS;
173 } //}}}
174
175 //{{{ Private members
176
177 //{{{ Static variables
178 private static Color headerColor = Color.lightGray;
179 private static Color headerTextColor = Color.black;
180 private static Color footerColor = Color.lightGray;
181 private static Color footerTextColor = Color.black;
182 private static Color lineNumberColor = Color.gray;
183 private static Color textColor = Color.black;
184 //}}}
185
186 //{{{ Instance variables
187 private PrinterJob job;
188 private Object format;
189
190 private View view;
191 private Buffer buffer;
192 private Font font;
193 private SyntaxStyle[] styles;
194 private boolean header;
195 private boolean footer;
196 private boolean lineNumbers;
197
198 private int currentPage;
199 private int currentPageStart;
200 private int currentPhysicalLine;
201 private boolean end;
202
203 private LineMetrics lm;
204 private final List<Chunk> lineList;
205
206 private FontRenderContext frc;
207
208 private DisplayTokenHandler tokenHandler;
209 //}}}
210
211 //{{{ printPage() method
212 private void printPage(Graphics _gfx, PageFormat pageFormat, int pageIndex,
213 boolean actuallyPaint)
214 {
215 Log.log(Log.DEBUG,this,"printPage(" + pageIndex + ',' + actuallyPaint + ')');
216 Graphics2D gfx = (Graphics2D)_gfx;
217 gfx.setFont(font);
218
219 double pageX = pageFormat.getImageableX();
220 double pageY = pageFormat.getImageableY();
221 double pageWidth = pageFormat.getImageableWidth();
222 double pageHeight = pageFormat.getImageableHeight();
223
224 Log.log(Log.DEBUG,this,"#1 - Page dimensions: " + pageWidth
225 + 'x' + pageHeight);
226
227 if(header)
228 {
229 double headerHeight = paintHeader(gfx,pageX,pageY,pageWidth,
230 actuallyPaint);
231 pageY += headerHeight;
232 pageHeight -= headerHeight;
233 }
234
235 if(footer)
236 {
237 double footerHeight = paintFooter(gfx,pageX,pageY,pageWidth,
238 pageHeight,pageIndex,actuallyPaint);
239 pageHeight -= footerHeight;
240 }
241
242 boolean glyphVector = jEdit.getBooleanProperty("print.glyphVector");
243 double lineNumberWidth;
244
245 //{{{ determine line number width
246 if(lineNumbers)
247 {
248 // the +1's ensure that 99 gets 3 digits, 103 gets 4 digits,
249 // and so on.
250 int lineNumberDigits = (int)Math.ceil(Math.log(buffer.getLineCount() + 1)
251 / Math.log(10)) + 1;
252
253 // now that we know how many chars there are, get the width.
254 char[] chars = new char[lineNumberDigits];
255 for(int i = 0; i < chars.length; i++)
256 chars[i] = ' ';
257 lineNumberWidth = font.getStringBounds(chars,
258 0,lineNumberDigits,frc).getWidth();
259 }
260 else
261 lineNumberWidth = 0.0;
262 //}}}
263
264 Log.log(Log.DEBUG,this,"#2 - Page dimensions: "
265 + (pageWidth - lineNumberWidth)
266 + 'x' + pageHeight);
267
268 //{{{ calculate tab size
269 int tabSize = jEdit.getIntegerProperty("print.tabSize",8);
270 char[] chars = new char[tabSize];
271 for(int i = 0; i < chars.length; i++)
272 chars[i] = ' ';
273 double tabWidth = font.getStringBounds(chars,
274 0,tabSize,frc).getWidth();
275 PrintTabExpander e = new PrintTabExpander(tabWidth);
276 //}}}
277
278 lm = font.getLineMetrics("gGyYX",frc);
279 Log.log(Log.DEBUG,this,"Line height is " + lm.getHeight());
280
281 double y = 0.0;
282print_loop: for(;;)
283 {
284 if(currentPhysicalLine == buffer.getLineCount())
285 {
286 Log.log(Log.DEBUG,this,"Finished buffer");
287 end = true;
288 break print_loop;
289 }
290 if (!jEdit.getBooleanProperty("print.folds",true) &&
291 !view.getTextArea().getDisplayManager().isLineVisible(currentPhysicalLine))
292 {
293
294 Log.log(Log.DEBUG,this,"Skipping invisible line");
295 currentPhysicalLine++;
296 continue;
297 }
298
299 lineList.clear();
300
301 tokenHandler.init(styles,frc,e,lineList,
302 (float)(pageWidth - lineNumberWidth), -1);
303
304 buffer.markTokens(currentPhysicalLine,tokenHandler);
305 if(lineList.isEmpty())
306 lineList.add(null);
307
308 if(y + (lm.getHeight() * lineList.size()) >= pageHeight)
309 {
310 Log.log(Log.DEBUG,this,"Finished page before line " + currentPhysicalLine);
311 break print_loop;
312 }
313
314 if(lineNumbers && actuallyPaint)
315 {
316 gfx.setFont(font);
317 gfx.setColor(lineNumberColor);
318 gfx.drawString(String.valueOf(currentPhysicalLine + 1),
319 (float)pageX,(float)(pageY + y + lm.getHeight()));
320 }
321
322 for(int i = 0; i < lineList.size(); i++)
323 {
324 y += lm.getHeight();
325 Chunk chunks = lineList.get(i);
326 if(chunks != null && actuallyPaint)
327 {
328 FontMetrics metrics = gfx.getFontMetrics();
329 Chunk.paintChunkBackgrounds(chunks,gfx,
330 (float)(pageX + lineNumberWidth),
331 (float)(pageY + y), metrics.getHeight());
332 Chunk.paintChunkList(chunks,gfx,
333 (float)(pageX + lineNumberWidth),
334 (float)(pageY + y),glyphVector);
335 }
336 }
337
338 currentPhysicalLine++;
339 }
340 } //}}}
341
342 //{{{ paintHeader() method
343 private double paintHeader(Graphics2D gfx, double pageX, double pageY,
344 double pageWidth, boolean actuallyPaint)
345 {
346 String headerText = jEdit.getProperty("print.headerText",
347 new String[] { buffer.getName() });
348 FontRenderContext frc = gfx.getFontRenderContext();
349 lm = font.getLineMetrics(headerText,frc);
350
351 Rectangle2D bounds = font.getStringBounds(headerText,frc);
352 Rectangle2D headerBounds = new Rectangle2D.Double(
353 pageX,pageY,pageWidth,bounds.getHeight());
354
355 if(actuallyPaint)
356 {
357 gfx.setColor(headerColor);
358 gfx.fill(headerBounds);
359 gfx.setColor(headerTextColor);
360 gfx.drawString(headerText,
361 (float)(pageX + (pageWidth - bounds.getWidth()) / 2),
362 (float)(pageY + lm.getAscent()));
363 }
364
365 return headerBounds.getHeight();
366 }
367 //}}}
368
369 //{{{ paintFooter() method
370 private double paintFooter(Graphics2D gfx, double pageX, double pageY,
371 double pageWidth, double pageHeight, int pageIndex,
372 boolean actuallyPaint)
373 {
374 String footerText = jEdit.getProperty("print.footerText",
375 new Object[] { new Date(), Integer.valueOf(pageIndex + 1)});
376 FontRenderContext frc = gfx.getFontRenderContext();
377 lm = font.getLineMetrics(footerText,frc);
378
379 Rectangle2D bounds = font.getStringBounds(footerText,frc);
380 Rectangle2D footerBounds = new Rectangle2D.Double(
381 pageX,pageY + pageHeight - bounds.getHeight(),
382 pageWidth,bounds.getHeight());
383
384 if(actuallyPaint)
385 {
386 gfx.setColor(footerColor);
387 gfx.fill(footerBounds);
388 gfx.setColor(footerTextColor);
389 gfx.drawString(footerText,
390 (float)(pageX + (pageWidth - bounds.getWidth()) / 2),
391 (float)(pageY + pageHeight - bounds.getHeight()
392 + lm.getAscent()));
393 }
394
395 return footerBounds.getHeight();
396 } //}}}
397
398 //}}}
399
400 //{{{ PrintTabExpander class
401 static class PrintTabExpander implements TabExpander
402 {
403 private double tabWidth;
404
405 //{{{ PrintTabExpander constructor
406 PrintTabExpander(double tabWidth)
407 {
408 this.tabWidth = tabWidth;
409 } //}}}
410
411 //{{{ nextTabStop() method
412 public float nextTabStop(float x, int tabOffset)
413 {
414 int ntabs = (int)((x + 1) / tabWidth);
415 return (float)((ntabs + 1) * tabWidth);
416 } //}}}
417 } //}}}
418}