PreparedPage.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. using FastReport.Engine;
  2. using FastReport.Utils;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.ComponentModel;
  6. using System.Drawing;
  7. using System.IO;
  8. using System.Windows.Forms;
  9. namespace FastReport.Preview
  10. {
  11. internal partial class PreparedPage : Component
  12. {
  13. #region Fields
  14. private XmlItem xmlItem;
  15. private PreparedPages preparedPages;
  16. private SizeF pageSize;
  17. private long tempFilePosition;
  18. private bool uploaded;
  19. private PreparedPagePostprocessor postprocessor;
  20. #endregion Fields
  21. #region Properties
  22. private Report Report
  23. {
  24. get { return preparedPages.Report; }
  25. }
  26. private bool UseFileCache
  27. {
  28. get { return Report.UseFileCache; }
  29. }
  30. public XmlItem Xml
  31. {
  32. get { return xmlItem; }
  33. set
  34. {
  35. xmlItem = value;
  36. value.Parent = null;
  37. }
  38. }
  39. public SizeF PageSize
  40. {
  41. get
  42. {
  43. if (pageSize.IsEmpty)
  44. {
  45. ReCalcSizes();
  46. }
  47. return pageSize;
  48. }
  49. set
  50. {
  51. pageSize = value;
  52. }
  53. }
  54. public int CurPosition
  55. {
  56. get { return xmlItem.Count; }
  57. }
  58. #endregion Properties
  59. #region Private Methods
  60. private bool DoAdd(Base c, XmlItem item)
  61. {
  62. if (c == null)
  63. return false;
  64. ReportEngine engine = Report.Engine;
  65. bool isRunning = Report.IsRunning && engine != null;
  66. if (c is ReportComponentBase)
  67. {
  68. if (isRunning && !engine.CanPrint(c as ReportComponentBase))
  69. return false;
  70. }
  71. item = item.Add();
  72. using (FRWriter writer = new FRWriter(item))
  73. {
  74. writer.SerializeTo = SerializeTo.Preview;
  75. writer.SaveChildren = false;
  76. writer.BlobStore = preparedPages.BlobStore;
  77. writer.Write(c);
  78. }
  79. if (isRunning)
  80. engine.AddObjectToProcess(c, item);
  81. if ((c.Flags & Flags.CanWriteChildren) == 0)
  82. {
  83. ObjectCollection childObjects = c.ChildObjects;
  84. foreach (Base obj in childObjects)
  85. {
  86. DoAdd(obj, item);
  87. }
  88. }
  89. return true;
  90. }
  91. private Base ReadObject(Base parent, XmlItem item, bool readChildren, FRReader reader)
  92. {
  93. string objName = item.Name;
  94. // try to find the object in the dictionary
  95. Base obj = preparedPages.Dictionary.GetObject(objName);
  96. // object not found, objName is type name
  97. if (obj == null)
  98. {
  99. Type type = RegisteredObjects.FindType(objName);
  100. if (type == null)
  101. return null;
  102. obj = Activator.CreateInstance(type) as Base;
  103. }
  104. obj.SetRunning(true);
  105. // read object's properties
  106. if (!item.IsNullOrEmptyProps())
  107. {
  108. // since the BlobStore is shared resource, lock it to avoid problems with multi-thread access.
  109. // this may happen in the html export that uses several threads to export one report.
  110. lock (reader.BlobStore)
  111. {
  112. reader.Read(obj, item);
  113. }
  114. if (obj is TextObject txt)
  115. ProcessText(txt);
  116. }
  117. if (readChildren)
  118. {
  119. for (int i = 0; i < item.Count; i++)
  120. {
  121. ReadObject(obj, item[i], true, reader);
  122. }
  123. }
  124. obj.Parent = parent;
  125. return obj;
  126. }
  127. private void UpdateUnlimitedPage(Base obj, XmlItem item)
  128. {
  129. item.Clear();
  130. using (FRWriter writer = new FRWriter(item))
  131. {
  132. writer.SerializeTo = SerializeTo.Preview;
  133. writer.SaveChildren = false;
  134. writer.BlobStore = preparedPages.BlobStore;
  135. writer.Write(obj);
  136. }
  137. foreach (Base child in obj.ChildObjects)
  138. {
  139. UpdateUnlimitedPage(child, item.Add());
  140. }
  141. }
  142. #endregion Private Methods
  143. #region Internal Methods
  144. internal ReportPage ReadPage(Base parent, XmlItem item, bool readchild, FRReader reader)
  145. {
  146. ReportPage page = ReadObject(parent, item, false, reader) as ReportPage;
  147. if (readchild)
  148. for (int i = 0; i < item.Count; i++)
  149. {
  150. ReadObject(page, item[i], true, reader);
  151. }
  152. return page;
  153. }
  154. internal ReportPage StartGetPage(int index)
  155. {
  156. Load();
  157. ReportPage page;
  158. using (FRReader reader = new FRReader(null))
  159. {
  160. reader.DeserializeFrom = SerializeTo.Preview;
  161. reader.ReadChildren = false;
  162. reader.BlobStore = preparedPages.BlobStore;
  163. page = ReadPage(null, xmlItem, false, reader);
  164. if (!(page.UnlimitedHeight || page.UnlimitedWidth))
  165. {
  166. page.Dispose();
  167. page = ReadPage(null, xmlItem, true, reader);
  168. page.SetReport(preparedPages.Report);
  169. postprocessor = new PreparedPagePostprocessor();
  170. postprocessor.Postprocess(page);
  171. postprocessor = null;
  172. }
  173. else
  174. {
  175. page.SetReport(preparedPages.Report);
  176. postprocessor = new PreparedPagePostprocessor();
  177. postprocessor.PostprocessUnlimited(this, page);
  178. }
  179. }
  180. if (page.MirrorMargins && (index + 1) % 2 == 0)
  181. {
  182. float f = page.LeftMargin;
  183. page.LeftMargin = page.RightMargin;
  184. page.RightMargin = f;
  185. }
  186. return page;
  187. }
  188. internal void EndGetPage(ReportPage page)
  189. {
  190. if (postprocessor != null) postprocessor = null;
  191. if (page != null)
  192. page.Dispose();
  193. ClearUploadedXml();
  194. }
  195. internal IEnumerable<Base> GetPageItems(ReportPage page, bool postprocess)
  196. {
  197. if (!(page.UnlimitedHeight || page.UnlimitedWidth))
  198. {
  199. foreach (Base child in page.ChildObjects)
  200. {
  201. if (postprocess) yield return child;
  202. else
  203. using (child)
  204. yield return child;
  205. }
  206. }
  207. else
  208. {
  209. if (Export.ExportBase.HAVE_TO_WORK_WITH_OVERLAY)
  210. #pragma warning disable CS0162 // Unreachable code detected
  211. foreach (Base child in page.ChildObjects)
  212. #pragma warning restore CS0162 // Unreachable code detected
  213. {
  214. if (child is OverlayBand)
  215. yield return child;
  216. }
  217. using (FRReader reader = new FRReader(null))
  218. {
  219. reader.DeserializeFrom = SerializeTo.Preview;
  220. reader.ReadChildren = false;
  221. reader.BlobStore = preparedPages.BlobStore;
  222. for (int i = 0; i < xmlItem.Count; i++)
  223. {
  224. if (postprocess) yield return ReadObject(page, xmlItem[i], true, reader);
  225. else
  226. using (Base obj = ReadObject(page, xmlItem[i], true, reader))
  227. {
  228. using (Base obj2 = postprocessor.PostProcessBandUnlimitedPage(obj))
  229. yield return obj2;
  230. }
  231. }
  232. }
  233. }
  234. }
  235. internal string GetName()
  236. {
  237. using (FRReader reader = new FRReader(null))
  238. {
  239. reader.DeserializeFrom = SerializeTo.Preview;
  240. reader.ReadChildren = false;
  241. reader.BlobStore = preparedPages.BlobStore;
  242. ReportPage page = ReadObject(null, xmlItem, false, reader) as ReportPage;
  243. return page.Name;
  244. }
  245. }
  246. internal void ReCalcSizes()
  247. {
  248. XmlItem item = xmlItem;
  249. using (FRReader reader = new FRReader(null, item))
  250. {
  251. reader.DeserializeFrom = SerializeTo.Preview;
  252. reader.BlobStore = preparedPages.BlobStore;
  253. reader.ReadChildren = false;
  254. using (ReportPage page = ReadPage(Report, item, false, reader))
  255. {
  256. if (page.UnlimitedHeight | page.UnlimitedWidth)
  257. {
  258. float maxWidth = 0.0f;
  259. float maxHeight = 0.0f;
  260. for (int i = 0; i < item.Count; i++)
  261. {
  262. using (Base obj = ReadObject(page, item[i], true, reader))
  263. {
  264. if (obj is BandBase)
  265. {
  266. BandBase band = obj as BandBase;
  267. float bandsHeight = band.Top + band.Height;
  268. if (maxHeight < bandsHeight)
  269. maxHeight = bandsHeight;
  270. float bandWidth = 0.0f;
  271. foreach (ComponentBase comp in band.Objects)
  272. {
  273. if ((comp.Anchor & AnchorStyles.Right) == 0 && comp.Dock == DockStyle.None)
  274. {
  275. bandWidth = Math.Max(bandWidth, comp.Left + comp.Width);
  276. }
  277. }
  278. if (maxWidth < bandWidth)
  279. maxWidth = bandWidth;
  280. }
  281. }
  282. }
  283. if (page.UnlimitedHeight)
  284. page.UnlimitedHeightValue = maxHeight + (page.TopMargin + page.BottomMargin) * Units.Millimeters;
  285. if (page.UnlimitedWidth)
  286. page.UnlimitedWidthValue = maxWidth + (page.LeftMargin + page.RightMargin) * Units.Millimeters;
  287. }
  288. pageSize = new SizeF(page.WidthInPixels, page.HeightInPixels);
  289. using (FRWriter writer = new FRWriter(item))
  290. {
  291. writer.SerializeTo = SerializeTo.Preview;
  292. writer.SaveChildren = false;
  293. writer.BlobStore = preparedPages.BlobStore;
  294. writer.Write(page);
  295. }
  296. }
  297. }
  298. }
  299. #endregion Internal Methods
  300. #region Public Methods
  301. public PreparedPage(ReportPage page, PreparedPages preparedPages)
  302. {
  303. this.preparedPages = preparedPages;
  304. xmlItem = new XmlItem();
  305. // page == null when we load prepared report from a file
  306. if (page != null)
  307. {
  308. using (FRWriter writer = new FRWriter(xmlItem))
  309. {
  310. writer.SerializeTo = SerializeTo.Preview;
  311. writer.SaveChildren = false;
  312. writer.Write(page);
  313. }
  314. pageSize = new SizeF(page.WidthInPixels, page.HeightInPixels);
  315. }
  316. }
  317. public bool AddBand(BandBase band)
  318. {
  319. return DoAdd(band, xmlItem);
  320. }
  321. public ReportPage GetPage()
  322. {
  323. Load();
  324. ReportPage page;
  325. using (FRReader reader = new FRReader(null))
  326. {
  327. reader.DeserializeFrom = SerializeTo.Preview;
  328. reader.ReadChildren = false;
  329. reader.BlobStore = preparedPages.BlobStore;
  330. page = ReadPage(null, xmlItem, true, reader);
  331. }
  332. page.SetReport(preparedPages.Report);
  333. new PreparedPagePostprocessor().Postprocess(page);
  334. ClearUploadedXml();
  335. return page;
  336. }
  337. public void Load()
  338. {
  339. if (UseFileCache && uploaded)
  340. {
  341. preparedPages.TempFile.Position = tempFilePosition;
  342. XmlReader reader = new XmlReader(preparedPages.TempFile);
  343. reader.Read(xmlItem);
  344. }
  345. }
  346. public void ClearUploadedXml()
  347. {
  348. if (UseFileCache && uploaded)
  349. xmlItem.Clear();
  350. }
  351. public void Upload()
  352. {
  353. if (UseFileCache && !uploaded)
  354. {
  355. preparedPages.TempFile.Seek(0, SeekOrigin.End);
  356. tempFilePosition = preparedPages.TempFile.Position;
  357. XmlWriter writer = new XmlWriter(preparedPages.TempFile);
  358. writer.Write(xmlItem);
  359. xmlItem.Clear();
  360. uploaded = true;
  361. }
  362. }
  363. public XmlItem CutObjects(int index)
  364. {
  365. XmlItem result = new XmlItem();
  366. while (xmlItem.Count > index)
  367. {
  368. result.AddItem(xmlItem[index]);
  369. }
  370. return result;
  371. }
  372. public void PasteObjects(XmlItem objects, float deltaX, float deltaY)
  373. {
  374. if (objects.Count > 0)
  375. {
  376. while (objects.Count > 0)
  377. {
  378. XmlItem obj = objects[0];
  379. // shift the object's location
  380. float objX = (obj.GetProp("l") != "") ?
  381. Converter.StringToFloat(obj.GetProp("l")) : 0;
  382. float objY = (obj.GetProp("t") != "") ?
  383. Converter.StringToFloat(obj.GetProp("t")) : 0;
  384. obj.SetProp("l", Converter.ToString(objX + deltaX));
  385. obj.SetProp("t", Converter.ToString(objY + deltaY));
  386. // add object to a page
  387. xmlItem.AddItem(obj);
  388. }
  389. }
  390. }
  391. public float GetLastY()
  392. {
  393. float result = 0;
  394. for (int i = 0; i < xmlItem.Count; i++)
  395. {
  396. XmlItem xi = xmlItem[i];
  397. BandBase obj = preparedPages.Dictionary.GetOriginalObject(xi.Name) as BandBase;
  398. if (obj != null && !(obj is PageFooterBand) && !(obj is OverlayBand))
  399. {
  400. string s = xi.GetProp("t");
  401. float top = (s != "") ? Converter.StringToFloat(s) : obj.Top;
  402. s = xi.GetProp("h");
  403. float height = (s != "") ? Converter.StringToFloat(s) : obj.Height;
  404. if (top + height > result)
  405. result = top + height;
  406. }
  407. }
  408. return result;
  409. }
  410. public bool ContainsBand(Type bandType)
  411. {
  412. for (int i = 0; i < xmlItem.Count; i++)
  413. {
  414. XmlItem xi = xmlItem[i];
  415. BandBase obj = preparedPages.Dictionary.GetOriginalObject(xi.Name) as BandBase;
  416. if (obj != null && obj.GetType() == bandType)
  417. return true;
  418. }
  419. return false;
  420. }
  421. public bool ContainsBand(string bandName)
  422. {
  423. for (int i = 0; i < xmlItem.Count; i++)
  424. {
  425. XmlItem xi = xmlItem[i];
  426. BandBase obj = preparedPages.Dictionary.GetOriginalObject(xi.Name) as BandBase;
  427. if (obj != null && obj.Name == bandName)
  428. return true;
  429. }
  430. return false;
  431. }
  432. protected override void Dispose(bool disposing)
  433. {
  434. if (disposing)
  435. xmlItem.Dispose();
  436. base.Dispose(disposing);
  437. }
  438. #endregion Public Methods
  439. }
  440. }