PageRenderTime 52ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/Main/Source/Core/Contents/TokenContent.cs

#
C# | 462 lines | 340 code | 86 blank | 36 comment | 67 complexity | 209af8eba3edebc9fcde0d4591b356e7 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. using System;
  2. using System.IO;
  3. using System.Xml;
  4. using System.Text;
  5. using System.Diagnostics;
  6. using System.Collections.Generic;
  7. namespace Sandcastle.Contents
  8. {
  9. [Serializable]
  10. public sealed class TokenContent : BuildContent<TokenItem, TokenContent>
  11. {
  12. #region Public Fields
  13. public const string TagName = "content";
  14. #endregion
  15. #region Private Fields
  16. private bool _isLoaded;
  17. private BuildFilePath _contentFile;
  18. [NonSerialized]
  19. private IDictionary<string, int> _dicItems;
  20. #endregion
  21. #region Constructors and Destructor
  22. public TokenContent()
  23. : base(new BuildKeyedList<TokenItem>())
  24. {
  25. BuildKeyedList<TokenItem> keyedList =
  26. this.List as BuildKeyedList<TokenItem>;
  27. if (keyedList != null)
  28. {
  29. _dicItems = keyedList.Dictionary;
  30. }
  31. }
  32. public TokenContent(string contentFile)
  33. : this()
  34. {
  35. BuildExceptions.PathMustExist(contentFile, "contentFile");
  36. _contentFile = new BuildFilePath(contentFile);
  37. }
  38. public TokenContent(TokenContent source)
  39. : base(source)
  40. {
  41. _isLoaded = source._isLoaded;
  42. _contentFile = source._contentFile;
  43. _dicItems = source._dicItems;
  44. }
  45. #endregion
  46. #region Public Properties
  47. public override bool IsEmpty
  48. {
  49. get
  50. {
  51. if (_contentFile != null && _contentFile.Exists)
  52. {
  53. return false;
  54. }
  55. return base.IsEmpty;
  56. }
  57. }
  58. public bool IsLoaded
  59. {
  60. get
  61. {
  62. return _isLoaded;
  63. }
  64. }
  65. public BuildFilePath ContentFile
  66. {
  67. get
  68. {
  69. return _contentFile;
  70. }
  71. set
  72. {
  73. if (value != null)
  74. {
  75. _contentFile = value;
  76. }
  77. }
  78. }
  79. public TokenItem this[string itemKey]
  80. {
  81. get
  82. {
  83. if (String.IsNullOrEmpty(itemKey))
  84. {
  85. return null;
  86. }
  87. int curIndex = -1;
  88. if (_dicItems != null &&
  89. _dicItems.TryGetValue(itemKey, out curIndex))
  90. {
  91. return this[curIndex];
  92. }
  93. return null;
  94. }
  95. }
  96. public override bool IsKeyed
  97. {
  98. get
  99. {
  100. return true;
  101. }
  102. }
  103. /// <summary>
  104. /// Gets the name of the <c>XML</c> tag name, under which this object is stored.
  105. /// </summary>
  106. /// <value>
  107. /// A string containing the <c>XML</c> tag name of this object.
  108. /// <para>
  109. /// For the <see cref="TokenContent"/> class instance, this property is
  110. /// <see cref="TokenContent.TagName"/>.
  111. /// </para>
  112. /// </value>
  113. public override string XmlTagName
  114. {
  115. get
  116. {
  117. return TagName;
  118. }
  119. }
  120. #endregion
  121. #region Public Method
  122. #region Load Method
  123. public void Load()
  124. {
  125. if (_isLoaded)
  126. {
  127. return;
  128. }
  129. if (_contentFile == null || !_contentFile.Exists)
  130. {
  131. return;
  132. }
  133. XmlReader reader = null;
  134. try
  135. {
  136. XmlReaderSettings settings = new XmlReaderSettings();
  137. settings.IgnoreComments = true;
  138. settings.IgnoreWhitespace = true;
  139. settings.IgnoreProcessingInstructions = true;
  140. reader = XmlReader.Create(_contentFile, settings);
  141. this.ReadXml(reader);
  142. _isLoaded = true;
  143. this.Modified = false;
  144. }
  145. finally
  146. {
  147. if (reader != null)
  148. {
  149. reader.Close();
  150. reader = null;
  151. }
  152. }
  153. }
  154. public void Reload()
  155. {
  156. _isLoaded = false;
  157. this.Load();
  158. }
  159. #endregion
  160. #region Save Method
  161. public void Save()
  162. {
  163. if (_contentFile == null)
  164. {
  165. return;
  166. }
  167. // If this is not yet located, and the contents is empty, we
  168. // will simply not continue from here...
  169. if (_contentFile != null && _contentFile.Exists)
  170. {
  171. if (!this._isLoaded && base.IsEmpty)
  172. {
  173. return;
  174. }
  175. // If loaded but not modified, there is no need to save it...
  176. if (this.IsLoaded && !this.Modified)
  177. {
  178. return;
  179. }
  180. }
  181. XmlWriterSettings settings = new XmlWriterSettings();
  182. settings.Indent = true;
  183. settings.Encoding = Encoding.UTF8;
  184. settings.IndentChars = new string(' ', 4);
  185. settings.OmitXmlDeclaration = false;
  186. XmlWriter writer = null;
  187. try
  188. {
  189. writer = XmlWriter.Create(_contentFile, settings);
  190. writer.WriteStartDocument();
  191. this.WriteXml(writer);
  192. writer.WriteEndDocument();
  193. // The file content is now same as the memory, so it can be
  194. // considered loaded...
  195. _isLoaded = true;
  196. this.Modified = false;
  197. }
  198. finally
  199. {
  200. if (writer != null)
  201. {
  202. writer.Close();
  203. writer = null;
  204. }
  205. }
  206. }
  207. #endregion
  208. #region Item Methods
  209. public override void Add(TokenItem item)
  210. {
  211. if (item != null && !String.IsNullOrEmpty(item.Key))
  212. {
  213. if (_dicItems.ContainsKey(item.Key))
  214. {
  215. this.Insert(_dicItems[item.Key], item);
  216. }
  217. else
  218. {
  219. base.Add(item);
  220. }
  221. }
  222. }
  223. public bool Contains(string itemKey)
  224. {
  225. if (String.IsNullOrEmpty(itemKey) ||
  226. _dicItems == null || _dicItems.Count == 0)
  227. {
  228. return false;
  229. }
  230. return _dicItems.ContainsKey(itemKey);
  231. }
  232. public int IndexOf(string itemKey)
  233. {
  234. if (String.IsNullOrEmpty(itemKey) ||
  235. _dicItems == null || _dicItems.Count == 0)
  236. {
  237. return -1;
  238. }
  239. if (_dicItems.ContainsKey(itemKey))
  240. {
  241. return _dicItems[itemKey];
  242. }
  243. return -1;
  244. }
  245. public bool Remove(string itemKey)
  246. {
  247. int itemIndex = this.IndexOf(itemKey);
  248. if (itemIndex < 0)
  249. {
  250. return false;
  251. }
  252. if (_dicItems.Remove(itemKey))
  253. {
  254. base.Remove(itemIndex);
  255. return true;
  256. }
  257. return false;
  258. }
  259. public override bool Remove(TokenItem item)
  260. {
  261. if (base.Remove(item))
  262. {
  263. if (_dicItems != null && _dicItems.Count != 0)
  264. {
  265. _dicItems.Remove(item.Key);
  266. }
  267. return true;
  268. }
  269. return false;
  270. }
  271. public override void Clear()
  272. {
  273. if (_dicItems != null && _dicItems.Count != 0)
  274. {
  275. _dicItems.Clear();
  276. }
  277. base.Clear();
  278. }
  279. #endregion
  280. #endregion
  281. #region IXmlSerializable Members
  282. /// <summary>
  283. /// This reads and sets its state or attributes stored in a <c>XML</c> format
  284. /// with the given reader.
  285. /// </summary>
  286. /// <param name="reader">
  287. /// The reader with which the <c>XML</c> attributes of this object are accessed.
  288. /// </param>
  289. /// <exception cref="ArgumentNullException">
  290. /// If the <paramref name="reader"/> is <see langword="null"/>.
  291. /// </exception>
  292. public override void ReadXml(XmlReader reader)
  293. {
  294. BuildExceptions.NotNull(reader, "reader");
  295. Debug.Assert(reader.NodeType == XmlNodeType.Element);
  296. if (reader.NodeType != XmlNodeType.Element)
  297. {
  298. return;
  299. }
  300. if (!String.Equals(reader.Name, TagName,
  301. StringComparison.OrdinalIgnoreCase))
  302. {
  303. Debug.Assert(false, String.Format(
  304. "The element name '{0}' does not match the expected '{1}'.",
  305. reader.Name, TagName));
  306. return;
  307. }
  308. if (reader.IsEmptyElement)
  309. {
  310. return;
  311. }
  312. this.Clear();
  313. while (reader.Read())
  314. {
  315. if (reader.NodeType == XmlNodeType.Element)
  316. {
  317. if (String.Equals(reader.Name, TokenItem.TagName,
  318. StringComparison.OrdinalIgnoreCase))
  319. {
  320. TokenItem item = new TokenItem();
  321. item.Content = this;
  322. item.ReadXml(reader);
  323. this.Add(item);
  324. }
  325. }
  326. else if (reader.NodeType == XmlNodeType.EndElement)
  327. {
  328. if (String.Equals(reader.Name, TagName,
  329. StringComparison.OrdinalIgnoreCase))
  330. {
  331. break;
  332. }
  333. }
  334. }
  335. }
  336. /// <summary>
  337. /// This writes the current state or attributes of this object,
  338. /// in the <c>XML</c> format, to the media or storage accessible by the given writer.
  339. /// </summary>
  340. /// <param name="writer">
  341. /// The <c>XML</c> writer with which the <c>XML</c> format of this object's state
  342. /// is written.
  343. /// </param>
  344. /// <exception cref="ArgumentNullException">
  345. /// If the <paramref name="reader"/> is <see langword="null"/>.
  346. /// </exception>
  347. public override void WriteXml(XmlWriter writer)
  348. {
  349. BuildExceptions.NotNull(writer, "writer");
  350. writer.WriteStartElement(TagName);
  351. writer.WriteAttributeString("xml", "space", String.Empty, "preserve");
  352. writer.WriteAttributeString("xmlns", "ddue", String.Empty,
  353. "http://ddue.schemas.microsoft.com/authoring/2003/5");
  354. writer.WriteAttributeString("xmlns", "xlink", String.Empty,
  355. "http://www.w3.org/1999/xlink");
  356. for (int i = 0; i < this.Count; i++)
  357. {
  358. this[i].WriteXml(writer);
  359. }
  360. writer.WriteEndElement();
  361. }
  362. #endregion
  363. #region ICloneable Members
  364. public override TokenContent Clone()
  365. {
  366. TokenContent content = new TokenContent(this);
  367. this.Clone(content, new BuildKeyedList<TokenItem>());
  368. if (_contentFile != null)
  369. {
  370. content._contentFile = _contentFile.Clone();
  371. }
  372. return content;
  373. }
  374. #endregion
  375. }
  376. }