Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

Container.cs 38KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044
  1. using System;
  2. using System.IO;
  3. using System.Linq;
  4. using System.Xml.Linq;
  5. using System.IO.Packaging;
  6. using System.Collections.Generic;
  7. using System.Text.RegularExpressions;
  8. using System.Collections.ObjectModel;
  9. namespace Novacode
  10. {
  11. public abstract class Container : DocXElement
  12. {
  13. public virtual ReadOnlyCollection<Content> Contents
  14. {
  15. get
  16. {
  17. List<Content> contents = GetContents();
  18. return contents.AsReadOnly();
  19. }
  20. }
  21. /// <summary>
  22. /// Returns a list of all Paragraphs inside this container.
  23. /// </summary>
  24. /// <example>
  25. /// <code>
  26. /// Load a document.
  27. /// using (DocX document = DocX.Load(@"Test.docx"))
  28. /// {
  29. /// // All Paragraphs in this document.
  30. /// <![CDATA[ List<Paragraph> ]]> documentParagraphs = document.Paragraphs;
  31. ///
  32. /// // Make sure this document contains at least one Table.
  33. /// if (document.Tables.Count() > 0)
  34. /// {
  35. /// // Get the first Table in this document.
  36. /// Table t = document.Tables[0];
  37. ///
  38. /// // All Paragraphs in this Table.
  39. /// <![CDATA[ List<Paragraph> ]]> tableParagraphs = t.Paragraphs;
  40. ///
  41. /// // Make sure this Table contains at least one Row.
  42. /// if (t.Rows.Count() > 0)
  43. /// {
  44. /// // Get the first Row in this document.
  45. /// Row r = t.Rows[0];
  46. ///
  47. /// // All Paragraphs in this Row.
  48. /// <![CDATA[ List<Paragraph> ]]> rowParagraphs = r.Paragraphs;
  49. ///
  50. /// // Make sure this Row contains at least one Cell.
  51. /// if (r.Cells.Count() > 0)
  52. /// {
  53. /// // Get the first Cell in this document.
  54. /// Cell c = r.Cells[0];
  55. ///
  56. /// // All Paragraphs in this Cell.
  57. /// <![CDATA[ List<Paragraph> ]]> cellParagraphs = c.Paragraphs;
  58. /// }
  59. /// }
  60. /// }
  61. ///
  62. /// // Save all changes to this document.
  63. /// document.Save();
  64. /// }// Release this document from memory.
  65. /// </code>
  66. /// </example>
  67. public virtual ReadOnlyCollection<Paragraph> Paragraphs
  68. {
  69. get
  70. {
  71. List<Paragraph> paragraphs = GetParagraphs();
  72. foreach (var p in paragraphs)
  73. {
  74. if ((p.Xml.ElementsAfterSelf().FirstOrDefault() != null) && (p.Xml.ElementsAfterSelf().First().Name.Equals(DocX.w + "tbl")))
  75. p.FollowingTable = new Table(this.Document, p.Xml.ElementsAfterSelf().First());
  76. p.ParentContainer = GetParentFromXmlName(p.Xml.Ancestors().First().Name.LocalName);
  77. if (p.IsListItem)
  78. {
  79. GetListItemType(p);
  80. }
  81. }
  82. return paragraphs.AsReadOnly();
  83. }
  84. }
  85. public virtual ReadOnlyCollection<Paragraph> ParagraphsDeepSearch
  86. {
  87. get
  88. {
  89. List<Paragraph> paragraphs = GetParagraphs(true);
  90. foreach (var p in paragraphs)
  91. {
  92. if ((p.Xml.ElementsAfterSelf().FirstOrDefault() != null) && (p.Xml.ElementsAfterSelf().First().Name.Equals(DocX.w + "tbl")))
  93. p.FollowingTable = new Table(this.Document, p.Xml.ElementsAfterSelf().First());
  94. p.ParentContainer = GetParentFromXmlName(p.Xml.Ancestors().First().Name.LocalName);
  95. if (p.IsListItem)
  96. {
  97. GetListItemType(p);
  98. }
  99. }
  100. return paragraphs.AsReadOnly();
  101. }
  102. }
  103. /// <summary>
  104. /// Removes paragraph at specified position
  105. /// </summary>
  106. /// <param name="index">Index of paragraph to remove</param>
  107. /// <returns>True if removed</returns>
  108. public bool RemoveParagraphAt(int index)
  109. {
  110. int i = 0;
  111. foreach (var paragraph in Xml.Descendants(DocX.w + "p"))
  112. {
  113. if (i == index)
  114. {
  115. paragraph.Remove();
  116. return true;
  117. }
  118. ++i;
  119. }
  120. return false;
  121. }
  122. /// <summary>
  123. /// Removes paragraph
  124. /// </summary>
  125. /// <param name="p">Paragraph to remove</param>
  126. /// <returns>True if removed</returns>
  127. public bool RemoveParagraph(Paragraph p)
  128. {
  129. foreach (var paragraph in Xml.Descendants(DocX.w + "p"))
  130. {
  131. if (paragraph.Equals(p.Xml))
  132. {
  133. paragraph.Remove();
  134. return true;
  135. }
  136. }
  137. return false;
  138. }
  139. public virtual List<Section> Sections
  140. {
  141. get
  142. {
  143. var allParas = Paragraphs;
  144. var parasInASection = new List<Paragraph>();
  145. var sections = new List<Section>();
  146. foreach (var para in allParas)
  147. {
  148. var sectionInPara = para.Xml.Descendants().FirstOrDefault(s => s.Name.LocalName == "sectPr");
  149. if (sectionInPara == null)
  150. {
  151. parasInASection.Add(para);
  152. }
  153. else
  154. {
  155. parasInASection.Add(para);
  156. var section = new Section(Document, sectionInPara) { SectionParagraphs = parasInASection };
  157. sections.Add(section);
  158. parasInASection = new List<Paragraph>();
  159. }
  160. }
  161. XElement body = Xml.Element(XName.Get("body", DocX.w.NamespaceName));
  162. XElement baseSectionXml = body.Element(XName.Get("sectPr", DocX.w.NamespaceName));
  163. var baseSection = new Section(Document, baseSectionXml) { SectionParagraphs = parasInASection };
  164. sections.Add(baseSection);
  165. return sections;
  166. }
  167. }
  168. private void GetListItemType(Paragraph p)
  169. {
  170. var ilvlNode = p.ParagraphNumberProperties.Descendants().FirstOrDefault(el => el.Name.LocalName == "ilvl");
  171. var ilvlValue = ilvlNode.Attribute(DocX.w + "val").Value;
  172. var numIdNode = p.ParagraphNumberProperties.Descendants().FirstOrDefault(el => el.Name.LocalName == "numId");
  173. var numIdValue = numIdNode.Attribute(DocX.w + "val").Value;
  174. //find num node in numbering
  175. var numNodes = Document.numbering.Descendants().Where(n => n.Name.LocalName == "num");
  176. XElement numNode = numNodes.FirstOrDefault(node => node.Attribute(DocX.w + "numId").Value.Equals(numIdValue));
  177. if (numNode != null)
  178. {
  179. //Get abstractNumId node and its value from numNode
  180. var abstractNumIdNode = numNode.Descendants().First(n => n.Name.LocalName == "abstractNumId");
  181. var abstractNumNodeValue = abstractNumIdNode.Attribute(DocX.w + "val").Value;
  182. var abstractNumNodes = Document.numbering.Descendants().Where(n => n.Name.LocalName == "abstractNum");
  183. XElement abstractNumNode =
  184. abstractNumNodes.FirstOrDefault(node => node.Attribute(DocX.w + "abstractNumId").Value.Equals(abstractNumNodeValue));
  185. //Find lvl node
  186. var lvlNodes = abstractNumNode.Descendants().Where(n => n.Name.LocalName == "lvl");
  187. XElement lvlNode = null;
  188. foreach (XElement node in lvlNodes)
  189. {
  190. if (node.Attribute(DocX.w + "ilvl").Value.Equals(ilvlValue))
  191. {
  192. lvlNode = node;
  193. break;
  194. }
  195. }
  196. var numFmtNode = lvlNode.Descendants().First(n => n.Name.LocalName == "numFmt");
  197. p.ListItemType = GetListItemType(numFmtNode.Attribute(DocX.w + "val").Value);
  198. }
  199. }
  200. public ContainerType ParentContainer;
  201. internal List<Content> GetContents(bool deepSearch = false)
  202. {
  203. // Need some memory that can be updated by the recursive search.
  204. //int index = 0;
  205. List<Content> contents = new List<Content>();
  206. foreach (XElement e in Xml.Descendants(XName.Get("sdt", DocX.w.NamespaceName)))
  207. {
  208. Content content = new Content(Document, e, 0);
  209. XElement el = e.Elements(XName.Get("sdtPr", DocX.w.NamespaceName)).First();
  210. content.Name = GetAttribute(el, "alias", "val");
  211. content.Tag = GetAttribute(el, "tag", "val");
  212. contents.Add(content);
  213. }
  214. return contents;
  215. }
  216. private string GetAttribute(XElement e, string localName, string attributeName)
  217. {
  218. string val = string.Empty;
  219. try
  220. {
  221. val = e.Elements(XName.Get(localName, DocX.w.NamespaceName)).Attributes(XName.Get(attributeName, DocX.w.NamespaceName)).FirstOrDefault().Value;
  222. }
  223. catch (Exception)
  224. {
  225. val = "Missing";
  226. }
  227. return val;
  228. }
  229. internal List<Paragraph> GetParagraphs(bool deepSearch=false)
  230. {
  231. // Need some memory that can be updated by the recursive search.
  232. int index = 0;
  233. List<Paragraph> paragraphs = new List<Paragraph>();
  234. foreach (XElement e in Xml.Descendants(XName.Get("p", DocX.w.NamespaceName)))
  235. {
  236. index += HelperFunctions.GetText(e).Length;
  237. Paragraph paragraph = new Paragraph(Document, e, index);
  238. paragraphs.Add(paragraph);
  239. }
  240. // GetParagraphsRecursive(Xml, ref index, ref paragraphs, deepSearch);
  241. return paragraphs;
  242. }
  243. internal void GetParagraphsRecursive(XElement Xml, ref int index, ref List<Paragraph> paragraphs, bool deepSearch=false)
  244. {
  245. // sdtContent are for PageNumbers inside Headers or Footers, don't go any deeper.
  246. //if (Xml.Name.LocalName == "sdtContent")
  247. // return;
  248. var keepSearching = true;
  249. if (Xml.Name.LocalName == "p")
  250. {
  251. paragraphs.Add(new Paragraph(Document, Xml, index));
  252. index += HelperFunctions.GetText(Xml).Length;
  253. if (!deepSearch)
  254. keepSearching = false;
  255. }
  256. if (keepSearching && Xml.HasElements)
  257. {
  258. foreach (XElement e in Xml.Elements())
  259. {
  260. GetParagraphsRecursive(e, ref index, ref paragraphs, deepSearch);
  261. }
  262. }
  263. }
  264. public virtual List<Table> Tables
  265. {
  266. get
  267. {
  268. List<Table> tables =
  269. (
  270. from t in Xml.Descendants(DocX.w + "tbl")
  271. select new Table(Document, t)
  272. ).ToList();
  273. return tables;
  274. }
  275. }
  276. public virtual List<List> Lists
  277. {
  278. get
  279. {
  280. var lists = new List<List>();
  281. var list = new List(Document, Xml);
  282. foreach (var paragraph in Paragraphs)
  283. {
  284. if (paragraph.IsListItem)
  285. {
  286. if (list.CanAddListItem(paragraph))
  287. {
  288. list.AddItem(paragraph);
  289. }
  290. else
  291. {
  292. lists.Add(list);
  293. list = new List(Document, Xml);
  294. list.AddItem(paragraph);
  295. }
  296. }
  297. }
  298. lists.Add(list);
  299. return lists;
  300. }
  301. }
  302. public virtual List<Hyperlink> Hyperlinks
  303. {
  304. get
  305. {
  306. List<Hyperlink> hyperlinks = new List<Hyperlink>();
  307. foreach (Paragraph p in Paragraphs)
  308. hyperlinks.AddRange(p.Hyperlinks);
  309. return hyperlinks;
  310. }
  311. }
  312. public virtual List<Picture> Pictures
  313. {
  314. get
  315. {
  316. List<Picture> pictures = new List<Picture>();
  317. foreach (Paragraph p in Paragraphs)
  318. pictures.AddRange(p.Pictures);
  319. return pictures;
  320. }
  321. }
  322. /// <summary>
  323. /// Sets the Direction of content.
  324. /// </summary>
  325. /// <param name="direction">Direction either LeftToRight or RightToLeft</param>
  326. /// <example>
  327. /// Set the Direction of content in a Paragraph to RightToLeft.
  328. /// <code>
  329. /// // Load a document.
  330. /// using (DocX document = DocX.Load(@"Test.docx"))
  331. /// {
  332. /// // Get the first Paragraph from this document.
  333. /// Paragraph p = document.InsertParagraph();
  334. ///
  335. /// // Set the Direction of this Paragraph.
  336. /// p.Direction = Direction.RightToLeft;
  337. ///
  338. /// // Make sure the document contains at lest one Table.
  339. /// if (document.Tables.Count() > 0)
  340. /// {
  341. /// // Get the first Table from this document.
  342. /// Table t = document.Tables[0];
  343. ///
  344. /// /*
  345. /// * Set the direction of the entire Table.
  346. /// * Note: The same function is available at the Row and Cell level.
  347. /// */
  348. /// t.SetDirection(Direction.RightToLeft);
  349. /// }
  350. ///
  351. /// // Save all changes to this document.
  352. /// document.Save();
  353. /// }// Release this document from memory.
  354. /// </code>
  355. /// </example>
  356. public virtual void SetDirection(Direction direction)
  357. {
  358. foreach (Paragraph p in Paragraphs)
  359. p.Direction = direction;
  360. }
  361. public virtual List<int> FindAll(string str)
  362. {
  363. return FindAll(str, RegexOptions.None);
  364. }
  365. public virtual List<int> FindAll(string str, RegexOptions options)
  366. {
  367. List<int> list = new List<int>();
  368. foreach (Paragraph p in Paragraphs)
  369. {
  370. List<int> indexes = p.FindAll(str, options);
  371. for (int i = 0; i < indexes.Count(); i++)
  372. indexes[0] += p.startIndex;
  373. list.AddRange(indexes);
  374. }
  375. return list;
  376. }
  377. /// <summary>
  378. /// Find all unique instances of the given Regex Pattern,
  379. /// returning the list of the unique strings found
  380. /// </summary>
  381. /// <param name="pattern"></param>
  382. /// <param name="options"></param>
  383. /// <returns></returns>
  384. public virtual List<string> FindUniqueByPattern(string pattern, RegexOptions options)
  385. {
  386. List<string> rawResults = new List<string>();
  387. foreach (Paragraph p in Paragraphs)
  388. { // accumulate the search results from all paragraphs
  389. List<string> partials = p.FindAllByPattern(pattern, options);
  390. rawResults.AddRange(partials);
  391. }
  392. // this dictionary is used to collect results and test for uniqueness
  393. Dictionary<string, int> uniqueResults = new Dictionary<string, int>();
  394. foreach (string currValue in rawResults)
  395. {
  396. if (!uniqueResults.ContainsKey(currValue))
  397. { // if the dictionary doesn't have it, add it
  398. uniqueResults.Add(currValue, 0);
  399. }
  400. }
  401. return uniqueResults.Keys.ToList(); // return the unique list of results
  402. }
  403. public virtual void ReplaceText(string searchValue, string newValue, bool trackChanges = false, RegexOptions options = RegexOptions.None, Formatting newFormatting = null, Formatting matchFormatting = null, MatchFormattingOptions formattingOptions = MatchFormattingOptions.SubsetMatch, bool escapeRegEx = true, bool useRegExSubstitutions = false)
  404. {
  405. if (string.IsNullOrEmpty(searchValue))
  406. throw new ArgumentException("oldValue cannot be null or empty", "searchValue");
  407. if (newValue == null)
  408. throw new ArgumentException("newValue cannot be null or empty", "newValue");
  409. // ReplaceText in Headers of the document.
  410. var headerList = new List<Header> { Document.Headers.first, Document.Headers.even, Document.Headers.odd };
  411. foreach (var header in headerList)
  412. if (header != null)
  413. foreach (var paragraph in header.Paragraphs)
  414. paragraph.ReplaceText(searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, formattingOptions, escapeRegEx, useRegExSubstitutions);
  415. // ReplaceText int main body of document.
  416. foreach (var paragraph in Paragraphs)
  417. paragraph.ReplaceText(searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, formattingOptions, escapeRegEx, useRegExSubstitutions);
  418. // ReplaceText in Footers of the document.
  419. var footerList = new List<Footer> { Document.Footers.first, Document.Footers.even, Document.Footers.odd };
  420. foreach (var footer in footerList)
  421. if (footer != null)
  422. foreach (var paragraph in footer.Paragraphs)
  423. paragraph.ReplaceText(searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, formattingOptions, escapeRegEx, useRegExSubstitutions);
  424. }
  425. /// <summary>
  426. ///
  427. /// </summary>
  428. /// <param name="searchValue">Value to find</param>
  429. /// <param name="regexMatchHandler">A Func that accepts the matching regex search group value and passes it to this to return the replacement string</param>
  430. /// <param name="trackChanges">Enable trackchanges</param>
  431. /// <param name="options">Regex options</param>
  432. /// <param name="newFormatting"></param>
  433. /// <param name="matchFormatting"></param>
  434. /// <param name="formattingOptions"></param>
  435. public virtual void ReplaceText(string searchValue, Func<string,string> regexMatchHandler, bool trackChanges = false, RegexOptions options = RegexOptions.None, Formatting newFormatting = null, Formatting matchFormatting = null, MatchFormattingOptions formattingOptions = MatchFormattingOptions.SubsetMatch)
  436. {
  437. if (string.IsNullOrEmpty(searchValue))
  438. throw new ArgumentException("oldValue cannot be null or empty", "searchValue");
  439. if (regexMatchHandler == null)
  440. throw new ArgumentException("regexMatchHandler cannot be null", "regexMatchHandler");
  441. // ReplaceText in Headers/Footers of the document.
  442. var containerList = new List<IParagraphContainer> {
  443. Document.Headers.first, Document.Headers.even, Document.Headers.odd,
  444. Document.Footers.first, Document.Footers.even, Document.Footers.odd };
  445. foreach (var container in containerList)
  446. if (container != null)
  447. foreach (var paragraph in container.Paragraphs)
  448. paragraph.ReplaceText(searchValue, regexMatchHandler, trackChanges, options, newFormatting, matchFormatting, formattingOptions);
  449. // ReplaceText int main body of document.
  450. foreach (var paragraph in Paragraphs)
  451. paragraph.ReplaceText(searchValue, regexMatchHandler, trackChanges, options, newFormatting, matchFormatting, formattingOptions);
  452. }
  453. /// <summary>
  454. /// Removes all items with required formatting
  455. /// </summary>
  456. /// <returns>Numer of texts removed</returns>
  457. public int RemoveTextInGivenFormat(Formatting matchFormatting, MatchFormattingOptions fo = MatchFormattingOptions.SubsetMatch)
  458. {
  459. var deletedCount = 0;
  460. foreach (var x in Xml.Elements())
  461. {
  462. deletedCount += RemoveTextWithFormatRecursive(x, matchFormatting, fo);
  463. }
  464. return deletedCount;
  465. }
  466. internal int RemoveTextWithFormatRecursive(XElement element, Formatting matchFormatting, MatchFormattingOptions fo)
  467. {
  468. var deletedCount = 0;
  469. foreach (var x in element.Elements())
  470. {
  471. if ("rPr".Equals(x.Name.LocalName))
  472. {
  473. if (HelperFunctions.ContainsEveryChildOf(matchFormatting.Xml, x, fo))
  474. {
  475. x.Parent.Remove();
  476. ++deletedCount;
  477. }
  478. }
  479. deletedCount += RemoveTextWithFormatRecursive(x, matchFormatting, fo);
  480. }
  481. return deletedCount;
  482. }
  483. public virtual void InsertAtBookmark(string toInsert, string bookmarkName)
  484. {
  485. if (bookmarkName.IsNullOrWhiteSpace())
  486. throw new ArgumentException("bookmark cannot be null or empty", "bookmarkName");
  487. var headerCollection = Document.Headers;
  488. var headers = new List<Header> { headerCollection.first, headerCollection.even, headerCollection.odd };
  489. foreach (var header in headers.Where(x => x != null))
  490. foreach (var paragraph in header.Paragraphs)
  491. paragraph.InsertAtBookmark(toInsert, bookmarkName);
  492. foreach (var paragraph in Paragraphs)
  493. paragraph.InsertAtBookmark(toInsert, bookmarkName);
  494. var footerCollection = Document.Footers;
  495. var footers = new List<Footer> { footerCollection.first, footerCollection.even, footerCollection.odd };
  496. foreach (var footer in footers.Where(x => x != null))
  497. foreach (var paragraph in footer.Paragraphs)
  498. paragraph.InsertAtBookmark(toInsert, bookmarkName);
  499. }
  500. public string[] ValidateBookmarks(params string[] bookmarkNames)
  501. {
  502. var headers = new[] {Document.Headers.first, Document.Headers.even, Document.Headers.odd}.Where(h => h != null).ToList();
  503. var footers = new[] {Document.Footers.first, Document.Footers.even, Document.Footers.odd}.Where(f => f != null).ToList();
  504. var nonMatching = new List<string>();
  505. foreach (var bookmarkName in bookmarkNames)
  506. {
  507. if (headers.SelectMany(h => h.Paragraphs).Any(p => p.ValidateBookmark(bookmarkName))) return new string[0];
  508. if (footers.SelectMany(h => h.Paragraphs).Any(p => p.ValidateBookmark(bookmarkName))) return new string[0];
  509. if (Paragraphs.Any(p => p.ValidateBookmark(bookmarkName))) return new string[0];
  510. nonMatching.Add(bookmarkName);
  511. }
  512. return nonMatching.ToArray();
  513. }
  514. public virtual Paragraph InsertParagraph(int index, string text, bool trackChanges)
  515. {
  516. return InsertParagraph(index, text, trackChanges, null);
  517. }
  518. public virtual Paragraph InsertParagraph()
  519. {
  520. return InsertParagraph(string.Empty, false);
  521. }
  522. public virtual Paragraph InsertParagraph(int index, Paragraph p)
  523. {
  524. XElement newXElement = new XElement(p.Xml);
  525. p.Xml = newXElement;
  526. Paragraph paragraph = HelperFunctions.GetFirstParagraphEffectedByInsert(Document, index);
  527. if (paragraph == null)
  528. Xml.Add(p.Xml);
  529. else
  530. {
  531. XElement[] split = HelperFunctions.SplitParagraph(paragraph, index - paragraph.startIndex);
  532. paragraph.Xml.ReplaceWith
  533. (
  534. split[0],
  535. newXElement,
  536. split[1]
  537. );
  538. }
  539. GetParent(p);
  540. return p;
  541. }
  542. public virtual Paragraph InsertParagraph(Paragraph p)
  543. {
  544. #region Styles
  545. XDocument style_document;
  546. if (p.styles.Count() > 0)
  547. {
  548. Uri style_package_uri = new Uri("/word/styles.xml", UriKind.Relative);
  549. if (!Document.package.PartExists(style_package_uri))
  550. {
  551. PackagePart style_package = Document.package.CreatePart(style_package_uri, "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml", CompressionOption.Maximum);
  552. using (TextWriter tw = new StreamWriter(new PackagePartStream(style_package.GetStream())))
  553. {
  554. style_document = new XDocument
  555. (
  556. new XDeclaration("1.0", "UTF-8", "yes"),
  557. new XElement(XName.Get("styles", DocX.w.NamespaceName))
  558. );
  559. style_document.Save(tw);
  560. }
  561. }
  562. PackagePart styles_document = Document.package.GetPart(style_package_uri);
  563. using (TextReader tr = new StreamReader(styles_document.GetStream()))
  564. {
  565. style_document = XDocument.Load(tr);
  566. XElement styles_element = style_document.Element(XName.Get("styles", DocX.w.NamespaceName));
  567. var ids = from d in styles_element.Descendants(XName.Get("style", DocX.w.NamespaceName))
  568. let a = d.Attribute(XName.Get("styleId", DocX.w.NamespaceName))
  569. where a != null
  570. select a.Value;
  571. foreach (XElement style in p.styles)
  572. {
  573. // If styles_element does not contain this element, then add it.
  574. if (!ids.Contains(style.Attribute(XName.Get("styleId", DocX.w.NamespaceName)).Value))
  575. styles_element.Add(style);
  576. }
  577. }
  578. using (TextWriter tw = new StreamWriter(new PackagePartStream(styles_document.GetStream())))
  579. style_document.Save(tw);
  580. }
  581. #endregion
  582. XElement newXElement = new XElement(p.Xml);
  583. Xml.Add(newXElement);
  584. int index = 0;
  585. if (Document.paragraphLookup.Keys.Count() > 0)
  586. {
  587. index = Document.paragraphLookup.Last().Key;
  588. if (Document.paragraphLookup.Last().Value.Text.Length == 0)
  589. index++;
  590. else
  591. index += Document.paragraphLookup.Last().Value.Text.Length;
  592. }
  593. Paragraph newParagraph = new Paragraph(Document, newXElement, index);
  594. Document.paragraphLookup.Add(index, newParagraph);
  595. GetParent(newParagraph);
  596. return newParagraph;
  597. }
  598. public virtual Paragraph InsertParagraph(int index, string text, bool trackChanges, Formatting formatting)
  599. {
  600. Paragraph newParagraph = new Paragraph(Document, new XElement(DocX.w + "p"), index);
  601. newParagraph.InsertText(0, text, trackChanges, formatting);
  602. Paragraph firstPar = HelperFunctions.GetFirstParagraphEffectedByInsert(Document, index);
  603. if (firstPar != null)
  604. {
  605. var splitindex = index - firstPar.startIndex;
  606. if (splitindex <= 0)
  607. {
  608. firstPar.Xml.ReplaceWith(newParagraph.Xml, firstPar.Xml);
  609. }
  610. else {
  611. XElement[] splitParagraph = HelperFunctions.SplitParagraph(firstPar, splitindex);
  612. firstPar.Xml.ReplaceWith
  613. (
  614. splitParagraph[0],
  615. newParagraph.Xml,
  616. splitParagraph[1]
  617. );
  618. }
  619. }
  620. else
  621. Xml.Add(newParagraph);
  622. GetParent(newParagraph);
  623. return newParagraph;
  624. }
  625. private ContainerType GetParentFromXmlName(string xmlName)
  626. {
  627. ContainerType parent;
  628. switch (xmlName)
  629. {
  630. case "body":
  631. parent = ContainerType.Body;
  632. break;
  633. case "p":
  634. parent = ContainerType.Paragraph;
  635. break;
  636. case "tbl":
  637. parent = ContainerType.Table;
  638. break;
  639. case "sectPr":
  640. parent = ContainerType.Section;
  641. break;
  642. case "tc":
  643. parent = ContainerType.Cell;
  644. break;
  645. default:
  646. parent = ContainerType.None;
  647. break;
  648. }
  649. return parent;
  650. }
  651. private void GetParent(Paragraph newParagraph)
  652. {
  653. var containerType = GetType();
  654. switch (containerType.Name)
  655. {
  656. case "Body":
  657. newParagraph.ParentContainer = ContainerType.Body;
  658. break;
  659. case "Table":
  660. newParagraph.ParentContainer = ContainerType.Table;
  661. break;
  662. case "TOC":
  663. newParagraph.ParentContainer = ContainerType.TOC;
  664. break;
  665. case "Section":
  666. newParagraph.ParentContainer = ContainerType.Section;
  667. break;
  668. case "Cell":
  669. newParagraph.ParentContainer = ContainerType.Cell;
  670. break;
  671. case "Header":
  672. newParagraph.ParentContainer = ContainerType.Header;
  673. break;
  674. case "Footer":
  675. newParagraph.ParentContainer = ContainerType.Footer;
  676. break;
  677. case "Paragraph":
  678. newParagraph.ParentContainer = ContainerType.Paragraph;
  679. break;
  680. }
  681. }
  682. private ListItemType GetListItemType(string styleName)
  683. {
  684. ListItemType listItemType;
  685. switch (styleName)
  686. {
  687. case "bullet":
  688. listItemType = ListItemType.Bulleted;
  689. break;
  690. default:
  691. listItemType = ListItemType.Numbered;
  692. break;
  693. }
  694. return listItemType;
  695. }
  696. public virtual void InsertSection()
  697. {
  698. InsertSection(false);
  699. }
  700. public virtual void InsertSection(bool trackChanges)
  701. {
  702. var newParagraphSection = new XElement
  703. (
  704. XName.Get("p", DocX.w.NamespaceName), new XElement(XName.Get("pPr", DocX.w.NamespaceName), new XElement(XName.Get("sectPr", DocX.w.NamespaceName), new XElement(XName.Get("type", DocX.w.NamespaceName), new XAttribute(DocX.w + "val", "continuous"))))
  705. );
  706. if (trackChanges)
  707. newParagraphSection = HelperFunctions.CreateEdit(EditType.ins, DateTime.Now, newParagraphSection);
  708. Xml.Add(newParagraphSection);
  709. }
  710. public virtual void InsertSectionPageBreak(bool trackChanges = false)
  711. {
  712. var newParagraphSection = new XElement
  713. (
  714. XName.Get("p", DocX.w.NamespaceName), new XElement(XName.Get("pPr", DocX.w.NamespaceName), new XElement(XName.Get("sectPr", DocX.w.NamespaceName)))
  715. );
  716. if (trackChanges)
  717. newParagraphSection = HelperFunctions.CreateEdit(EditType.ins, DateTime.Now, newParagraphSection);
  718. Xml.Add(newParagraphSection);
  719. }
  720. public virtual Paragraph InsertParagraph(string text)
  721. {
  722. return InsertParagraph(text, false, new Formatting());
  723. }
  724. public virtual Paragraph InsertParagraph(string text, bool trackChanges)
  725. {
  726. return InsertParagraph(text, trackChanges, new Formatting());
  727. }
  728. public virtual Paragraph InsertParagraph(string text, bool trackChanges, Formatting formatting)
  729. {
  730. XElement newParagraph = new XElement
  731. (
  732. XName.Get("p", DocX.w.NamespaceName), new XElement(XName.Get("pPr", DocX.w.NamespaceName)), HelperFunctions.FormatInput(text, formatting.Xml)
  733. );
  734. if (trackChanges)
  735. newParagraph = HelperFunctions.CreateEdit(EditType.ins, DateTime.Now, newParagraph);
  736. Xml.Add(newParagraph);
  737. var paragraphAdded = new Paragraph(Document, newParagraph, 0);
  738. if (this is Cell)
  739. {
  740. var cell = this as Cell;
  741. paragraphAdded.PackagePart = cell.mainPart;
  742. }
  743. else if (this is DocX)
  744. {
  745. paragraphAdded.PackagePart = Document.mainPart;
  746. }
  747. else if (this is Footer)
  748. {
  749. var f = this as Footer;
  750. paragraphAdded.mainPart = f.mainPart;
  751. }
  752. else if (this is Header)
  753. {
  754. var h = this as Header;
  755. paragraphAdded.mainPart = h.mainPart;
  756. }
  757. else
  758. {
  759. Console.WriteLine("No idea what we are {0}", this);
  760. paragraphAdded.PackagePart = Document.mainPart;
  761. }
  762. GetParent(paragraphAdded);
  763. return paragraphAdded;
  764. }
  765. public virtual Paragraph InsertEquation(string equation)
  766. {
  767. Paragraph p = InsertParagraph();
  768. p.AppendEquation(equation);
  769. return p;
  770. }
  771. public virtual Paragraph InsertBookmark(String bookmarkName)
  772. {
  773. var p = InsertParagraph();
  774. p.AppendBookmark(bookmarkName);
  775. return p;
  776. }
  777. public virtual Table InsertTable(int rowCount, int columnCount) //Dmitchern, changed to virtual, and overrided in Table.Cell
  778. {
  779. XElement newTable = HelperFunctions.CreateTable(rowCount, columnCount);
  780. Xml.Add(newTable);
  781. return new Table(Document, newTable) { mainPart = mainPart};
  782. }
  783. public Table InsertTable(int index, int rowCount, int columnCount)
  784. {
  785. XElement newTable = HelperFunctions.CreateTable(rowCount, columnCount);
  786. Paragraph p = HelperFunctions.GetFirstParagraphEffectedByInsert(Document, index);
  787. if (p == null)
  788. Xml.Elements().First().AddFirst(newTable);
  789. else
  790. {
  791. XElement[] split = HelperFunctions.SplitParagraph(p, index - p.startIndex);
  792. p.Xml.ReplaceWith
  793. (
  794. split[0],
  795. newTable,
  796. split[1]
  797. );
  798. }
  799. return new Table(Document, newTable) { mainPart = mainPart };
  800. }
  801. public Table InsertTable(Table t)
  802. {
  803. XElement newXElement = new XElement(t.Xml);
  804. Xml.Add(newXElement);
  805. Table newTable = new Table(Document, newXElement)
  806. {
  807. mainPart = mainPart,
  808. Design = t.Design
  809. };
  810. return newTable;
  811. }
  812. public Table InsertTable(int index, Table t)
  813. {
  814. Paragraph p = HelperFunctions.GetFirstParagraphEffectedByInsert(Document, index);
  815. XElement[] split = HelperFunctions.SplitParagraph(p, index - p.startIndex);
  816. XElement newXElement = new XElement(t.Xml);
  817. p.Xml.ReplaceWith
  818. (
  819. split[0],
  820. newXElement,
  821. split[1]
  822. );
  823. Table newTable = new Table(Document, newXElement)
  824. {
  825. mainPart = mainPart,
  826. Design = t.Design
  827. };
  828. return newTable;
  829. }
  830. internal Container(DocX document, XElement xml)
  831. : base(document, xml)
  832. {
  833. }
  834. public List InsertList(List list)
  835. {
  836. foreach (var item in list.Items)
  837. {
  838. Xml.Add(item.Xml);
  839. }
  840. return list;
  841. }
  842. public List InsertList(List list, double fontSize)
  843. {
  844. foreach (var item in list.Items)
  845. {
  846. item.FontSize(fontSize);
  847. Xml.Add(item.Xml);
  848. }
  849. return list;
  850. }
  851. public List InsertList(List list, System.Drawing.FontFamily fontFamily, double fontSize)
  852. {
  853. foreach (var item in list.Items)
  854. {
  855. item.Font(fontFamily);
  856. item.FontSize(fontSize);
  857. Xml.Add(item.Xml);
  858. }
  859. return list;
  860. }
  861. public List InsertList(int index, List list)
  862. {
  863. Paragraph p = HelperFunctions.GetFirstParagraphEffectedByInsert(Document, index);
  864. XElement[] split = HelperFunctions.SplitParagraph(p, index - p.startIndex);
  865. var elements = new List<XElement> { split[0] };
  866. elements.AddRange(list.Items.Select(i => new XElement(i.Xml)));
  867. elements.Add(split[1]);
  868. p.Xml.ReplaceWith(elements.ToArray());
  869. return list;
  870. }
  871. }
  872. }