/Source/OxyPlot.Xps/Reporting/FlowDocumentReportWriter.cs

http://oxyplot.codeplex.com · C# · 432 lines · 207 code · 37 blank · 188 comment · 11 complexity · accb1bf105118dfeafbbdb52e674b45e MD5 · raw file

  1. // --------------------------------------------------------------------------------------------------------------------
  2. // <copyright file="FlowDocumentReportWriter.cs" company="OxyPlot">
  3. // The MIT License (MIT)
  4. //
  5. // Copyright (c) 2012 Oystein Bjorke
  6. //
  7. // Permission is hereby granted, free of charge, to any person obtaining a
  8. // copy of this software and associated documentation files (the
  9. // "Software"), to deal in the Software without restriction, including
  10. // without limitation the rights to use, copy, modify, merge, publish,
  11. // distribute, sublicense, and/or sell copies of the Software, and to
  12. // permit persons to whom the Software is furnished to do so, subject to
  13. // the following conditions:
  14. //
  15. // The above copyright notice and this permission notice shall be included
  16. // in all copies or substantial portions of the Software.
  17. //
  18. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  19. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  21. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  22. // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  23. // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  24. // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25. // </copyright>
  26. // <summary>
  27. // XPS report writer using MigraDoc.
  28. // </summary>
  29. // --------------------------------------------------------------------------------------------------------------------
  30. namespace OxyPlot.Xps
  31. {
  32. using System;
  33. using System.IO;
  34. using System.IO.Packaging;
  35. using System.Printing;
  36. using System.Windows;
  37. using System.Windows.Controls;
  38. using System.Windows.Controls.Primitives;
  39. using System.Windows.Documents;
  40. using System.Windows.Markup;
  41. using System.Windows.Media;
  42. using System.Windows.Media.Imaging;
  43. using System.Windows.Xps;
  44. using System.Windows.Xps.Packaging;
  45. using OxyPlot.Reporting;
  46. using Figure = System.Windows.Documents.Figure;
  47. using Image = OxyPlot.Reporting.Image;
  48. using Paragraph = OxyPlot.Reporting.Paragraph;
  49. using Table = OxyPlot.Reporting.Table;
  50. using TableCell = OxyPlot.Reporting.TableCell;
  51. using TableRow = System.Windows.Documents.TableRow;
  52. /// <summary>
  53. /// XPS report writer using MigraDoc.
  54. /// </summary>
  55. public class FlowDocumentReportWriter : IDisposable, IReportWriter
  56. {
  57. /// <summary>
  58. /// The doc.
  59. /// </summary>
  60. private readonly FlowDocument doc;
  61. /// <summary>
  62. /// The disposed flag.
  63. /// </summary>
  64. private bool disposed;
  65. /// <summary>
  66. /// Initializes a new instance of the <see cref="FlowDocumentReportWriter"/> class.
  67. /// </summary>
  68. public FlowDocumentReportWriter()
  69. {
  70. this.doc = new FlowDocument();
  71. }
  72. /// <summary>
  73. /// Gets FlowDocument.
  74. /// </summary>
  75. public FlowDocument FlowDocument
  76. {
  77. get
  78. {
  79. return this.doc;
  80. }
  81. }
  82. /// <summary>
  83. /// Gets or sets Style.
  84. /// </summary>
  85. public ReportStyle Style { get; set; }
  86. /// <summary>
  87. /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
  88. /// </summary>
  89. public void Dispose()
  90. {
  91. this.Dispose(true);
  92. GC.SuppressFinalize(this);
  93. }
  94. /// <summary>
  95. /// The print.
  96. /// </summary>
  97. public void Print()
  98. {
  99. PrintDocumentImageableArea area = null;
  100. XpsDocumentWriter xpsdw = PrintQueue.CreateXpsDocumentWriter(ref area);
  101. if (xpsdw != null)
  102. {
  103. xpsdw.Write(this.CreateFixedDocument(new Size(area.ExtentWidth, area.ExtentHeight)));
  104. }
  105. }
  106. /// <summary>
  107. /// Saves the document.
  108. /// </summary>
  109. /// <param name="filename">The filename.</param>
  110. /// <param name="width">The width.</param>
  111. /// <param name="height">The height.</param>
  112. public virtual void Save(string filename, double width = 816, double height = 1056)
  113. {
  114. using (var package = Package.Open(filename, FileMode.Create, FileAccess.ReadWrite))
  115. {
  116. using (var xpsdoc = new XpsDocument(package))
  117. {
  118. XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(xpsdoc);
  119. writer.Write(this.CreateFixedDocument(new Size(width, height)));
  120. }
  121. }
  122. }
  123. /// <summary>
  124. /// The write drawing.
  125. /// </summary>
  126. /// <param name="d">
  127. /// The d.
  128. /// </param>
  129. public void WriteDrawing(DrawingFigure d)
  130. {
  131. }
  132. /// <summary>
  133. /// The write equation.
  134. /// </summary>
  135. /// <param name="equation">
  136. /// The equation.
  137. /// </param>
  138. public void WriteEquation(Equation equation)
  139. {
  140. }
  141. /// <summary>
  142. /// The write header.
  143. /// </summary>
  144. /// <param name="h">
  145. /// The h.
  146. /// </param>
  147. public void WriteHeader(Header h)
  148. {
  149. var run = new Run { Text = h.Text };
  150. SetStyle(run, this.Style.HeaderStyles[h.Level - 1]);
  151. var p = new System.Windows.Documents.Paragraph(run);
  152. this.doc.Blocks.Add(p);
  153. }
  154. /// <summary>
  155. /// The write image.
  156. /// </summary>
  157. /// <param name="i">
  158. /// The i.
  159. /// </param>
  160. public void WriteImage(Image i)
  161. {
  162. // var figure = new Figure();
  163. var img = new System.Windows.Controls.Image();
  164. var bi = new BitmapImage();
  165. bi.BeginInit();
  166. bi.UriSource = new Uri(Path.GetFullPath(i.Source), UriKind.Absolute);
  167. bi.EndInit();
  168. img.Source = bi;
  169. var c = new BlockUIContainer(img) { Child = img };
  170. this.doc.Blocks.Add(c);
  171. }
  172. /// <summary>
  173. /// The write paragraph.
  174. /// </summary>
  175. /// <param name="pa">
  176. /// The pa.
  177. /// </param>
  178. public void WriteParagraph(Paragraph pa)
  179. {
  180. this.doc.Blocks.Add(this.CreateParagraph(pa.Text, this.Style.BodyTextStyle));
  181. }
  182. /// <summary>
  183. /// The write plot.
  184. /// </summary>
  185. /// <param name="plot">
  186. /// The plot.
  187. /// </param>
  188. public void WritePlot(PlotFigure plot)
  189. {
  190. }
  191. /// <summary>
  192. /// The write report.
  193. /// </summary>
  194. /// <param name="report">
  195. /// The report.
  196. /// </param>
  197. /// <param name="reportStyle">
  198. /// The style.
  199. /// </param>
  200. public void WriteReport(Report report, ReportStyle reportStyle)
  201. {
  202. this.Style = reportStyle;
  203. report.Write(this);
  204. }
  205. /// <summary>
  206. /// The write table.
  207. /// </summary>
  208. /// <param name="t">
  209. /// The t.
  210. /// </param>
  211. public void WriteTable(Table t)
  212. {
  213. var p = new System.Windows.Documents.Paragraph();
  214. var figure = new Figure();
  215. var table = new System.Windows.Documents.Table();
  216. // if (t.HasHeader())
  217. // {
  218. // var trg1 = new TableRowGroup();
  219. // SetStyle(trg1, Style.TableHeaderStyle);
  220. // var r = new TableRow();
  221. // foreach (var c in columns)
  222. // {
  223. // var cell = new TableCell();
  224. // var run = new Run() { Text = c.Header };
  225. // cell.Blocks.Add(new System.Windows.Documents.Paragraph(run));
  226. // r.Cells.Add(cell);
  227. // }
  228. // trg1.Rows.Add(r);
  229. // table.RowGroups.Add(trg1);
  230. // }
  231. var trg2 = new TableRowGroup();
  232. // SetStyle(trg2, Style.TableTextStyle);
  233. foreach (var row in t.Rows)
  234. {
  235. var r = new TableRow();
  236. if (row.IsHeader)
  237. {
  238. SetStyle(r, row.IsHeader ? this.Style.TableHeaderStyle : this.Style.TableTextStyle);
  239. }
  240. for (int j = 0; j < t.Columns.Count; j++)
  241. {
  242. TableCell c = row.Cells[j];
  243. var cell = new System.Windows.Documents.TableCell();
  244. var run = new Run { Text = c.Content };
  245. cell.Blocks.Add(new System.Windows.Documents.Paragraph(run));
  246. r.Cells.Add(cell);
  247. }
  248. trg2.Rows.Add(r);
  249. }
  250. table.RowGroups.Add(trg2);
  251. figure.Blocks.Add(this.CreateParagraph(t.Caption, this.Style.FigureTextStyle));
  252. figure.Blocks.Add(table);
  253. p.Inlines.Add(figure);
  254. this.doc.Blocks.Add(p);
  255. }
  256. /// <summary>
  257. /// The set style.
  258. /// </summary>
  259. /// <param name="run">
  260. /// The run.
  261. /// </param>
  262. /// <param name="s">
  263. /// The s.
  264. /// </param>
  265. private static void SetStyle(TextElement run, ParagraphStyle s)
  266. {
  267. run.FontFamily = new FontFamily(s.FontFamily);
  268. run.FontSize = s.FontSize;
  269. run.FontWeight = s.Bold ? FontWeights.Bold : FontWeights.Normal;
  270. FontStyle fontStyle = FontStyles.Normal;
  271. if (s.Italic)
  272. {
  273. fontStyle = FontStyles.Italic;
  274. }
  275. run.FontStyle = fontStyle;
  276. }
  277. /// <summary>
  278. /// The add page body.
  279. /// </summary>
  280. /// <param name="sourceFlowDocPaginator">
  281. /// The source flow doc paginator.
  282. /// </param>
  283. /// <param name="pageNo">
  284. /// The page no.
  285. /// </param>
  286. /// <param name="pageCanvas">
  287. /// The page canvas.
  288. /// </param>
  289. /// <param name="margins">
  290. /// The margins.
  291. /// </param>
  292. private void AddPageBody(
  293. DocumentPaginator sourceFlowDocPaginator, int pageNo, Canvas pageCanvas, Thickness margins)
  294. {
  295. using (var dpv = new DocumentPageView())
  296. {
  297. dpv.DocumentPaginator = sourceFlowDocPaginator;
  298. dpv.PageNumber = pageNo;
  299. Canvas.SetTop(dpv, margins.Top);
  300. Canvas.SetLeft(dpv, margins.Left);
  301. pageCanvas.Children.Add(dpv);
  302. }
  303. }
  304. /// <summary>
  305. /// The add page to document.
  306. /// </summary>
  307. /// <param name="fixedDocument">
  308. /// The fixed document.
  309. /// </param>
  310. /// <param name="pageCanvas">
  311. /// The page canvas.
  312. /// </param>
  313. /// <param name="pageSize">
  314. /// The page size.
  315. /// </param>
  316. private void AddPageToDocument(FixedDocument fixedDocument, Canvas pageCanvas, Size pageSize)
  317. {
  318. var fp = new FixedPage { Width = pageSize.Width, Height = pageSize.Height };
  319. fp.Children.Add(pageCanvas);
  320. var pc = new PageContent();
  321. ((IAddChild)pc).AddChild(fp);
  322. fixedDocument.Pages.Add(pc);
  323. }
  324. /// <summary>
  325. /// Builds the fixed document.
  326. /// </summary>
  327. /// <param name="sourceFlowDocPaginator">The source flow doc paginator.</param>
  328. /// <param name="size">The size.</param>
  329. /// <param name="margins">The margins.</param>
  330. /// <returns>The document.</returns>
  331. private FixedDocument BuildFixedDocument(DocumentPaginator sourceFlowDocPaginator, Size size, Thickness margins)
  332. {
  333. var fixedDocument = new FixedDocument();
  334. for (int pageNo = 0; pageNo < sourceFlowDocPaginator.PageCount; pageNo++)
  335. {
  336. var pageCanvas = new Canvas { Margin = margins };
  337. this.AddPageBody(sourceFlowDocPaginator, pageNo, pageCanvas, margins);
  338. this.AddPageToDocument(fixedDocument, pageCanvas, size);
  339. }
  340. return fixedDocument;
  341. }
  342. /// <summary>
  343. /// Creates the fixed document.
  344. /// </summary>
  345. /// <param name="size">The size.</param>
  346. /// <returns>The document.</returns>
  347. private FixedDocument CreateFixedDocument(Size size)
  348. {
  349. IDocumentPaginatorSource dps = this.doc;
  350. DocumentPaginator sourceFlowDocPaginator = dps.DocumentPaginator;
  351. sourceFlowDocPaginator.PageSize = new Size(
  352. size.Width - this.Style.Margins.Left - this.Style.Margins.Right,
  353. size.Height - this.Style.Margins.Top - this.Style.Margins.Bottom);
  354. if (!sourceFlowDocPaginator.IsPageCountValid)
  355. {
  356. sourceFlowDocPaginator.ComputePageCount();
  357. }
  358. var margins = new Thickness(
  359. this.Style.Margins.Left, this.Style.Margins.Top, this.Style.Margins.Width, this.Style.Margins.Height);
  360. return this.BuildFixedDocument(sourceFlowDocPaginator, size, margins);
  361. }
  362. /// <summary>
  363. /// Creates a paragraph.
  364. /// </summary>
  365. /// <param name="text">The text.</param>
  366. /// <param name="style">The style.</param>
  367. /// <returns>A paragraph.</returns>
  368. private System.Windows.Documents.Paragraph CreateParagraph(string text, ParagraphStyle style)
  369. {
  370. var run = new Run { Text = text };
  371. if (style != null)
  372. {
  373. SetStyle(run, style);
  374. }
  375. return new System.Windows.Documents.Paragraph(run);
  376. }
  377. /// <summary>
  378. /// Releases unmanaged and - optionally - managed resources
  379. /// </summary>
  380. /// <param name="disposing">
  381. /// <c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.
  382. /// </param>
  383. private void Dispose(bool disposing)
  384. {
  385. if (!this.disposed)
  386. {
  387. if (disposing)
  388. {
  389. // nothing...
  390. }
  391. }
  392. this.disposed = true;
  393. }
  394. }
  395. }