PageRenderTime 147ms CodeModel.GetById 109ms app.highlight 33ms RepoModel.GetById 1ms app.codeStats 0ms

/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
  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}