PageRenderTime 142ms CodeModel.GetById 103ms app.highlight 32ms RepoModel.GetById 1ms app.codeStats 1ms

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/jedit/print/BufferPrintable.java

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