FRWriter.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. using System;
  2. using System.IO;
  3. using System.Collections;
  4. using System.Drawing;
  5. using System.ComponentModel;
  6. using System.Reflection;
  7. using System.Collections.Generic;
  8. using System.Text;
  9. using System.Globalization;
  10. namespace FastReport.Utils
  11. {
  12. /// <summary>
  13. /// Specifies the target for the serialize operation.
  14. /// </summary>
  15. public enum SerializeTo
  16. {
  17. /// <summary>
  18. /// Serialize to the report file.
  19. /// </summary>
  20. Report,
  21. /// <summary>
  22. /// Serialize to the preview pages.
  23. /// </summary>
  24. Preview,
  25. /// <summary>
  26. /// Serialize to the source pages of a preview.
  27. /// </summary>
  28. SourcePages,
  29. /// <summary>
  30. /// Serialize to the designer's clipboard.
  31. /// </summary>
  32. Clipboard,
  33. /// <summary>
  34. /// Serialize to the designer's undo/redo buffer.
  35. /// </summary>
  36. Undo
  37. }
  38. internal class DiffEventArgs
  39. {
  40. private object obj;
  41. private object diffObject;
  42. public object Object
  43. {
  44. get { return obj; }
  45. set { obj = value; }
  46. }
  47. public object DiffObject
  48. {
  49. get { return diffObject; }
  50. set { diffObject = value; }
  51. }
  52. }
  53. internal delegate void DiffEventHandler(object sender, DiffEventArgs e);
  54. /// <summary>
  55. /// The writer used to serialize object's properties to a report file.
  56. /// </summary>
  57. public class FRWriter : IDisposable
  58. {
  59. #region Fields
  60. private XmlDocument doc;
  61. private XmlItem root;
  62. private XmlItem curItem;
  63. private XmlItem curRoot;
  64. //private StringBuilder FText;
  65. private object diffObject;
  66. private bool saveChildren;
  67. private bool writeHeader;
  68. private BlobStore blobStore;
  69. private SerializeTo serializeTo;
  70. private Hashtable diffObjects;
  71. #endregion
  72. #region Properties
  73. internal event DiffEventHandler GetDiff;
  74. internal BlobStore BlobStore
  75. {
  76. get { return blobStore; }
  77. set { blobStore = value; }
  78. }
  79. /// <summary>
  80. /// Gets or sets current xml item name.
  81. /// </summary>
  82. public string ItemName
  83. {
  84. get { return curItem.Name; }
  85. set { curItem.Name = value; }
  86. }
  87. /// <summary>
  88. /// Gets or sets target of serialization.
  89. /// </summary>
  90. public SerializeTo SerializeTo
  91. {
  92. get { return serializeTo; }
  93. set { serializeTo = value; }
  94. }
  95. /// <summary>
  96. /// Gets the ethalon object to compare with.
  97. /// </summary>
  98. public object DiffObject
  99. {
  100. get { return diffObject; }
  101. }
  102. /// <summary>
  103. /// Gets or sets a value that determines whether is necessary to serialize child objects.
  104. /// </summary>
  105. public bool SaveChildren
  106. {
  107. get { return saveChildren; }
  108. set { saveChildren = value; }
  109. }
  110. /// <summary>
  111. /// Gets or sets a value that determines whether is necessary to add xml header.
  112. /// </summary>
  113. public bool WriteHeader
  114. {
  115. get { return writeHeader; }
  116. set { writeHeader = value; }
  117. }
  118. #endregion
  119. #region Private Methods
  120. private string PropName(string name)
  121. {
  122. return serializeTo == SerializeTo.Preview ? ShortProperties.GetShortName(name) : name;
  123. }
  124. #endregion
  125. #region Public Methods
  126. /// <summary>
  127. /// Serializes the specified object.
  128. /// </summary>
  129. /// <param name="obj">The object to serialize.</param>
  130. /// <remarks>
  131. /// The object must implement the <see cref="IFRSerializable"/> interface. This method
  132. /// invokes the <b>Serialize</b> method of the object.
  133. /// </remarks>
  134. /// <example>This example demonstrates the use of writer.
  135. /// <code>
  136. /// public void Serialize(FRWriter writer)
  137. /// {
  138. /// // get the etalon object. It will be used to write changed properties only.
  139. /// Base c = writer.DiffObject as Base;
  140. ///
  141. /// // write the type name
  142. /// writer.ItemName = ClassName;
  143. ///
  144. /// // write properties
  145. /// if (Name != "")
  146. /// writer.WriteStr("Name", Name);
  147. /// if (Restrictions != c.Restrictions)
  148. /// writer.WriteValue("Restrictions", Restrictions);
  149. ///
  150. /// // write child objects if allowed
  151. /// if (writer.SaveChildren)
  152. /// {
  153. /// foreach (Base child in ChildObjects)
  154. /// {
  155. /// writer.Write(child);
  156. /// }
  157. /// }
  158. /// }
  159. /// </code>
  160. /// </example>
  161. public void Write(IFRSerializable obj)
  162. {
  163. Write(obj, null);
  164. }
  165. /// <summary>
  166. /// Serializes the object using specified etalon.
  167. /// </summary>
  168. /// <param name="obj">The object to serialize.</param>
  169. /// <param name="diff">The etalon object.</param>
  170. public void Write(IFRSerializable obj, object diff)
  171. {
  172. if (obj == null)
  173. return;
  174. XmlItem saveCurItem = curItem;
  175. XmlItem saveCurRoot = curRoot;
  176. //StringBuilder saveText = FText;
  177. object saveDiffObject = diffObject;
  178. try
  179. {
  180. //FText = new StringBuilder();
  181. curItem = curItem == null ? root : curItem.Add();
  182. curRoot = curItem;
  183. diffObject = diff;
  184. if (obj is Base && SerializeTo == SerializeTo.Preview)
  185. {
  186. diffObject = (obj as Base).OriginalComponent;
  187. curItem.Name = diffObject != null ? (obj as Base).Alias : (obj as Base).ClassName;
  188. }
  189. if (GetDiff != null)
  190. {
  191. DiffEventArgs e = new DiffEventArgs();
  192. e.Object = obj;
  193. GetDiff(this, e);
  194. diffObject = e.DiffObject;
  195. }
  196. if (diffObject == null)
  197. {
  198. try
  199. {
  200. Type objType = obj.GetType();
  201. if (!diffObjects.Contains(objType))
  202. diffObjects[objType] = Activator.CreateInstance(objType);
  203. diffObject = diffObjects[objType];
  204. }
  205. catch
  206. {
  207. }
  208. }
  209. obj.Serialize(this);
  210. }
  211. finally
  212. {
  213. //if (FText.Length > 0)
  214. // FText.Remove(FText.Length - 1, 1);
  215. //FCurRoot.Text = FText.ToString();
  216. //FText = saveText;
  217. curItem = saveCurItem;
  218. curRoot = saveCurRoot;
  219. diffObject = saveDiffObject;
  220. }
  221. }
  222. /// <summary>
  223. /// Writes a string property.
  224. /// </summary>
  225. /// <param name="name">Property name.</param>
  226. /// <param name="value">Property value.</param>
  227. public void WriteStr(string name, string value)
  228. {
  229. curRoot.SetProp(PropName(name), value);
  230. //FText.Append(PropName(name));
  231. //FText.Append("=\"");
  232. //FText.Append(Converter.ToXml(value));
  233. //FText.Append("\" ");
  234. }
  235. /// <summary>
  236. /// Writes a boolean property.
  237. /// </summary>
  238. /// <param name="name">Property name.</param>
  239. /// <param name="value">Property value.</param>
  240. public void WriteBool(string name, bool value)
  241. {
  242. curRoot.SetProp(PropName(name), value ? "true" : "false");
  243. // FText.Append(PropName(name));
  244. //FText.Append("=\"");
  245. //FText.Append(value ? "true" : "false");
  246. //FText.Append("\" ");
  247. }
  248. /// <summary>
  249. /// Writes an integer property.
  250. /// </summary>
  251. /// <param name="name">Property name.</param>
  252. /// <param name="value">Property value.</param>
  253. public void WriteInt(string name, int value)
  254. {
  255. curRoot.SetProp(PropName(name), value.ToString());
  256. //FText.Append(PropName(name));
  257. //FText.Append("=\"");
  258. //FText.Append(value.ToString());
  259. //FText.Append("\" ");
  260. }
  261. /// <summary>
  262. /// Writes a float property.
  263. /// </summary>
  264. /// <param name="name">Property name.</param>
  265. /// <param name="value">Property value.</param>
  266. public void WriteFloat(string name, float value)
  267. {
  268. curRoot.SetProp(PropName(name), value.ToString(CultureInfo.InvariantCulture.NumberFormat));
  269. //FText.Append(PropName(name));
  270. //FText.Append("=\"");
  271. //FText.Append(value.ToString(CultureInfo.InvariantCulture.NumberFormat));
  272. //FText.Append("\" ");
  273. }
  274. /// <summary>
  275. /// Writes a double property.
  276. /// </summary>
  277. /// <param name="name">Property name.</param>
  278. /// <param name="value">Property value.</param>
  279. public void WriteDouble(string name, double value)
  280. {
  281. curRoot.SetProp(PropName(name), value.ToString(CultureInfo.InvariantCulture.NumberFormat));
  282. //FText.Append(PropName(name));
  283. //FText.Append("=\"");
  284. //FText.Append(value.ToString(CultureInfo.InvariantCulture.NumberFormat));
  285. //FText.Append("\" ");
  286. }
  287. /// <summary>
  288. /// Writes an enumeration property.
  289. /// </summary>
  290. /// <param name="name">Property name.</param>
  291. /// <param name="value">Property value.</param>
  292. public void WriteValue(string name, object value)
  293. {
  294. curRoot.SetProp(PropName(name), value != null ? Converter.ToString(value) : "null");
  295. //FText.Append(PropName(name));
  296. //FText.Append("=\"");
  297. //FText.Append(value != null ? Converter.ToXml(value) : "null");
  298. //FText.Append("\" ");
  299. }
  300. /// <summary>
  301. /// Writes an object reference property.
  302. /// </summary>
  303. /// <param name="name">Property name.</param>
  304. /// <param name="value">Property value.</param>
  305. public void WriteRef(string name, Base value)
  306. {
  307. curRoot.SetProp(PropName(name), value != null ? value.Name : "null");
  308. //FText.Append(PropName(name));
  309. //FText.Append("=\"");
  310. //FText.Append(value != null ? value.Name : "null");
  311. //FText.Append("\" ");
  312. }
  313. /// <summary>
  314. /// Writes a standalone property value.
  315. /// </summary>
  316. /// <param name="name">Name of property.</param>
  317. /// <param name="value">Property value.</param>
  318. /// <remarks>
  319. /// This method produces the following output:
  320. /// &lt;PropertyName&gt;PropertyValue&lt;/PropertyName&gt;
  321. /// </remarks>
  322. public void WritePropertyValue(string name, string value)
  323. {
  324. XmlItem item = curItem.Add();
  325. item.Name = name;
  326. item.Value = value;
  327. }
  328. /// <summary>
  329. /// Determines if two objects are equal.
  330. /// </summary>
  331. /// <param name="obj1">The first object.</param>
  332. /// <param name="obj2">The second object.</param>
  333. /// <returns><b>true</b> if objects will be serialized to the same value.</returns>
  334. public bool AreEqual(object obj1, object obj2)
  335. {
  336. if (obj1 == obj2)
  337. return true;
  338. if (obj1 == null || obj2 == null)
  339. return false;
  340. string s1 = Converter.ToString(obj1);
  341. string s2 = Converter.ToString(obj2);
  342. return s1 == s2;
  343. }
  344. /// <summary>
  345. /// Disposes the writer.
  346. /// </summary>
  347. public void Dispose()
  348. {
  349. doc.Dispose();
  350. foreach (object obj in diffObjects.Values)
  351. {
  352. if (obj is IDisposable)
  353. (obj as IDisposable).Dispose();
  354. }
  355. }
  356. /// <summary>
  357. /// Saves the writer output to a stream.
  358. /// </summary>
  359. /// <param name="stream">Stream to save to.</param>
  360. public void Save(Stream stream)
  361. {
  362. doc.AutoIndent = serializeTo == SerializeTo.Report;
  363. doc.WriteHeader = WriteHeader;
  364. doc.Save(stream);
  365. }
  366. #endregion
  367. /// <summary>
  368. /// Initializes a new instance of the <b>FRWriter</b> class with default settings.
  369. /// </summary>
  370. public FRWriter()
  371. {
  372. doc = new XmlDocument();
  373. root = doc.Root;
  374. //FText = new StringBuilder();
  375. saveChildren = true;
  376. writeHeader = true;
  377. diffObjects = new Hashtable();
  378. }
  379. /// <summary>
  380. /// Initializes a new instance of the <b>FRWriter</b> class with specified xml item that will
  381. /// receive writer's output.
  382. /// </summary>
  383. /// <param name="root">The xml item that will receive writer's output.</param>
  384. public FRWriter(XmlItem root) : this()
  385. {
  386. this.root = root;
  387. }
  388. }
  389. }