Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

Container.cs 31KB

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