PageRenderTime 102ms CodeModel.GetById 50ms app.highlight 47ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-3-pre5/org/gjt/sp/jedit/print/BufferPrintable.java

#
Java | 406 lines | 297 code | 57 blank | 52 comment | 35 complexity | bdf4fdc74e8c6c5521de4c263834f399 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.Segment;
 28import javax.swing.text.TabExpander;
 29import javax.swing.SwingUtilities;
 30import java.awt.font.*;
 31import java.awt.geom.*;
 32import java.awt.print.*;
 33import java.awt.*;
 34import java.lang.reflect.Method;
 35import java.util.*;
 36import org.gjt.sp.jedit.syntax.*;
 37import org.gjt.sp.jedit.*;
 38import org.gjt.sp.util.*;
 39//}}}
 40
 41class BufferPrintable implements Printable
 42{
 43	//{{{ BufferPrintable constructor
 44	BufferPrintable(PrinterJob job, Object format,
 45		View view, Buffer buffer, Font font, boolean header,
 46		boolean footer, boolean lineNumbers, boolean color)
 47	{
 48		this.job = job;
 49		this.format = format;
 50		this.view = view;
 51		this.buffer = buffer;
 52		this.font = font;
 53		this.header = header;
 54		this.footer = footer;
 55		this.lineNumbers = lineNumbers;
 56
 57		styles = GUIUtilities.loadStyles(jEdit.getProperty("print.font"),
 58			jEdit.getIntegerProperty("print.fontsize",10),color);
 59		styles[Token.NULL] = new SyntaxStyle(textColor,null,font);
 60
 61		// Change any white text to black
 62		for(int i = 0; i < styles.length; i++)
 63		{
 64			SyntaxStyle s = styles[i];
 65			if(s.getForegroundColor().equals(Color.WHITE)
 66				&& s.getBackgroundColor() == null)
 67			{
 68				styles[i] = new SyntaxStyle(
 69					Color.BLACK,
 70					styles[i].getBackgroundColor(),
 71					styles[i].getFont());
 72			}
 73		}
 74
 75		lineList = new ArrayList();
 76
 77		tokenHandler = new DisplayTokenHandler();
 78	} //}}}
 79
 80	//{{{ print() method
 81	public void print()
 82	{
 83		try
 84		{
 85			//buffer.readLock();
 86
 87			if(format == null)
 88				job.print();
 89			else
 90			{
 91				Method method = PrinterJob.class.getMethod(
 92					"print",new Class[] { Class.forName(
 93					"javax.print.attribute.PrintRequestAttributeSet") });
 94				method.invoke(job,new Object[] { format });
 95			}
 96		}
 97		catch(PrinterAbortException ae)
 98		{
 99			Log.log(Log.DEBUG,this,ae);
100		}
101		catch(Exception e)
102		{
103			Log.log(Log.ERROR,this,e);
104			final String[] args = { e.toString() };
105			SwingUtilities.invokeLater(new Runnable()
106			{
107				public void run()
108				{
109					GUIUtilities.error(view,"print-error",args);
110				}
111			});
112		}
113		finally
114		{
115			//buffer.readUnlock();
116		}
117	} //}}}
118
119	//{{{ print() method
120	public int print(Graphics _gfx, PageFormat pageFormat, int pageIndex)
121		throws PrinterException
122	{
123		// we keep the first non-null frc we get, since sometimes
124		// we get invalid ones on subsequent pages on Windows
125		if(frc == null)
126		{
127			frc = ((Graphics2D)_gfx).getFontRenderContext();
128			Log.log(Log.DEBUG,this,"Font render context is " + frc);
129		}
130
131		Log.log(Log.DEBUG,this,"Asked to print page " + pageIndex);
132		Log.log(Log.DEBUG,this,"Current page is " + currentPage);
133
134		if(pageIndex > currentPage)
135		{
136			for(int i = currentPage; i < pageIndex; i++)
137			{
138				Log.log(Log.DEBUG,this,"Current physical line is now " + currentPageStart);
139				currentPhysicalLine = currentPageStart;
140				printPage(_gfx,pageFormat,i,true);
141			}
142
143			currentPage = pageIndex - 1;
144			Log.log(Log.DEBUG,this,"Current page is now " + currentPage);
145		}
146
147		if(pageIndex == currentPage + 1)
148		{
149			if(end)
150			{
151				Log.log(Log.DEBUG,this,"The end");
152				return NO_SUCH_PAGE;
153			}
154
155			currentPageStart = currentPhysicalLine;
156			Log.log(Log.DEBUG,this,"#2 - Current physical line is now " + currentPageStart);
157			currentPage = pageIndex;
158			Log.log(Log.DEBUG,this,"#2 - Current page is now " + currentPage);
159		}
160		else if(pageIndex == currentPage)
161		{
162			currentPhysicalLine = currentPageStart;
163			Log.log(Log.DEBUG,this,"#3 - Current physical line is now " + currentPageStart);
164		}
165
166		printPage(_gfx,pageFormat,pageIndex,true);
167
168		return PAGE_EXISTS;
169	} //}}}
170
171	//{{{ Private members
172
173	//{{{ Static variables
174	private static Color headerColor = Color.lightGray;
175	private static Color headerTextColor = Color.black;
176	private static Color footerColor = Color.lightGray;
177	private static Color footerTextColor = Color.black;
178	private static Color lineNumberColor = Color.gray;
179	private static Color textColor = Color.black;
180	//}}}
181
182	//{{{ Instance variables
183	private PrinterJob job;
184	private Object format;
185
186	private View view;
187	private Buffer buffer;
188	private Font font;
189	private SyntaxStyle[] styles;
190	private boolean header;
191	private boolean footer;
192	private boolean lineNumbers;
193
194	private int currentPage;
195	private int currentPageStart;
196	private int currentPhysicalLine;
197	private boolean end;
198
199	private LineMetrics lm;
200	private ArrayList lineList;
201
202	private FontRenderContext frc;
203
204	private DisplayTokenHandler tokenHandler;
205	//}}}
206
207	//{{{ printPage() method
208	private void printPage(Graphics _gfx, PageFormat pageFormat, int pageIndex,
209		boolean actuallyPaint)
210	{
211		Log.log(Log.DEBUG,this,"printPage(" + pageIndex + "," + actuallyPaint + ")");
212		Graphics2D gfx = (Graphics2D)_gfx;
213		gfx.setFont(font);
214
215		double pageX = pageFormat.getImageableX();
216		double pageY = pageFormat.getImageableY();
217		double pageWidth = pageFormat.getImageableWidth();
218		double pageHeight = pageFormat.getImageableHeight();
219
220		Log.log(Log.DEBUG,this,"#1 - Page dimensions: " + pageWidth
221			+ "x" + pageHeight);
222
223		if(header)
224		{
225			double headerHeight = paintHeader(gfx,pageX,pageY,pageWidth,
226				actuallyPaint);
227			pageY += headerHeight;
228			pageHeight -= headerHeight;
229		}
230
231		if(footer)
232		{
233			double footerHeight = paintFooter(gfx,pageX,pageY,pageWidth,
234				pageHeight,pageIndex,actuallyPaint);
235			pageHeight -= footerHeight;
236		}
237
238		boolean glyphVector = jEdit.getBooleanProperty("print.glyphVector");
239		double lineNumberWidth;
240
241		//{{{ determine line number width
242		if(lineNumbers)
243		{
244			// the +1's ensure that 99 gets 3 digits, 103 gets 4 digits,
245			// and so on.
246			int lineNumberDigits = (int)Math.ceil(Math.log(buffer.getLineCount() + 1)
247				/ Math.log(10)) + 1;
248
249			// now that we know how many chars there are, get the width.
250			char[] chars = new char[lineNumberDigits];
251			for(int i = 0; i < chars.length; i++)
252				chars[i] = ' ';
253			lineNumberWidth = font.getStringBounds(chars,
254				0,lineNumberDigits,frc).getWidth();
255		}
256		else
257			lineNumberWidth = 0.0;
258		//}}}
259
260		Log.log(Log.DEBUG,this,"#2 - Page dimensions: "
261			+ (pageWidth - lineNumberWidth)
262			+ "x" + pageHeight);
263
264		//{{{ calculate tab size
265		int tabSize = jEdit.getIntegerProperty("print.tabSize",8);
266		char[] chars = new char[tabSize];
267		for(int i = 0; i < chars.length; i++)
268			chars[i] = ' ';
269		double tabWidth = font.getStringBounds(chars,
270			0,tabSize,frc).getWidth();
271		PrintTabExpander e = new PrintTabExpander(tabWidth);
272		//}}}
273
274		double y = 0.0;
275
276		lm = font.getLineMetrics("gGyYX",frc);
277		Log.log(Log.DEBUG,this,"Line height is " + lm.getHeight());
278
279print_loop:	for(;;)
280		{
281			if(currentPhysicalLine == buffer.getLineCount())
282			{
283				Log.log(Log.DEBUG,this,"Finished buffer");
284				end = true;
285				break print_loop;
286			}
287
288			lineList.clear();
289
290			tokenHandler.init(styles,frc,e,lineList,
291				(float)(pageWidth - lineNumberWidth));
292
293			buffer.markTokens(currentPhysicalLine,tokenHandler);
294			if(lineList.size() == 0)
295				lineList.add(null);
296
297			if(y + (lm.getHeight() * lineList.size()) >= pageHeight)
298			{
299				Log.log(Log.DEBUG,this,"Finished page before line " + currentPhysicalLine);
300				break print_loop;
301			}
302
303			if(lineNumbers && actuallyPaint)
304			{
305				gfx.setFont(font);
306				gfx.setColor(lineNumberColor);
307				gfx.drawString(String.valueOf(currentPhysicalLine + 1),
308					(float)pageX,(float)(pageY + y + lm.getHeight()));
309			}
310
311			for(int i = 0; i < lineList.size(); i++)
312			{
313				y += lm.getHeight();
314				Chunk chunks = (Chunk)lineList.get(i);
315				if(chunks != null && actuallyPaint)
316				{
317					Chunk.paintChunkBackgrounds(chunks,gfx,
318						(float)(pageX + lineNumberWidth),
319						(float)(pageY + y));
320					Chunk.paintChunkList(chunks,gfx,
321						(float)(pageX + lineNumberWidth),
322						(float)(pageY + y),glyphVector);
323				}
324			}
325
326			currentPhysicalLine++;
327		}
328	} //}}}
329
330	//{{{ paintHeader() method
331	private double paintHeader(Graphics2D gfx, double pageX, double pageY,
332		double pageWidth, boolean actuallyPaint)
333	{
334		String headerText = jEdit.getProperty("print.headerText",
335			new String[] { buffer.getName() });
336		FontRenderContext frc = gfx.getFontRenderContext();
337		lm = font.getLineMetrics(headerText,frc);
338
339		Rectangle2D bounds = font.getStringBounds(headerText,frc);
340		Rectangle2D headerBounds = new Rectangle2D.Double(
341			pageX,pageY,pageWidth,bounds.getHeight());
342
343		if(actuallyPaint)
344		{
345			gfx.setColor(headerColor);
346			gfx.fill(headerBounds);
347			gfx.setColor(headerTextColor);
348			gfx.drawString(headerText,
349				(float)(pageX + (pageWidth - bounds.getWidth()) / 2),
350				(float)(pageY + lm.getAscent()));
351		}
352
353		return headerBounds.getHeight();
354	}
355	//}}}
356
357	//{{{ paintFooter() method
358	private double paintFooter(Graphics2D gfx, double pageX, double pageY,
359		double pageWidth, double pageHeight, int pageIndex,
360		boolean actuallyPaint)
361	{
362		String footerText = jEdit.getProperty("print.footerText",
363			new Object[] { new Date(), new Integer(pageIndex + 1) });
364		FontRenderContext frc = gfx.getFontRenderContext();
365		lm = font.getLineMetrics(footerText,frc);
366
367		Rectangle2D bounds = font.getStringBounds(footerText,frc);
368		Rectangle2D footerBounds = new Rectangle2D.Double(
369			pageX,pageY + pageHeight - bounds.getHeight(),
370			pageWidth,bounds.getHeight());
371
372		if(actuallyPaint)
373		{
374			gfx.setColor(footerColor);
375			gfx.fill(footerBounds);
376			gfx.setColor(footerTextColor);
377			gfx.drawString(footerText,
378				(float)(pageX + (pageWidth - bounds.getWidth()) / 2),
379				(float)(pageY + pageHeight - bounds.getHeight()
380				+ lm.getAscent()));
381		}
382
383		return footerBounds.getHeight();
384	} //}}}
385
386	//}}}
387
388	//{{{ PrintTabExpander class
389	static class PrintTabExpander implements TabExpander
390	{
391		private double tabWidth;
392
393		//{{{ PrintTabExpander constructor
394		public PrintTabExpander(double tabWidth)
395		{
396			this.tabWidth = tabWidth;
397		} //}}}
398
399		//{{{ nextTabStop() method
400		public float nextTabStop(float x, int tabOffset)
401		{
402			int ntabs = (int)((x + 1) / tabWidth);
403			return (float)((ntabs + 1) * tabWidth);
404		} //}}}
405	} //}}}
406}