PageRenderTime 53ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

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