選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

Paragraph.cs 189KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696
  1. using System;
  2. using System.Linq;
  3. using System.Drawing;
  4. using System.Xml.Linq;
  5. using System.Collections;
  6. using System.IO.Packaging;
  7. using System.Globalization;
  8. using System.Security.Principal;
  9. using System.Collections.Generic;
  10. using System.IO;
  11. using System.Text.RegularExpressions;
  12. namespace Novacode
  13. {
  14. /// <summary>
  15. /// Represents a document paragraph.
  16. /// </summary>
  17. public class Paragraph : InsertBeforeOrAfter
  18. {
  19. // The Append family of functions use this List to apply style.
  20. internal List<XElement> runs;
  21. // This paragraphs text alignment
  22. private Alignment alignment;
  23. public ContainerType ParentContainer;
  24. private XElement ParagraphNumberPropertiesBacker { get; set; }
  25. /// <summary>
  26. /// Fetch the paragraph number properties for a list element.
  27. /// </summary>
  28. public XElement ParagraphNumberProperties
  29. {
  30. get
  31. {
  32. return ParagraphNumberPropertiesBacker ?? (ParagraphNumberPropertiesBacker = GetParagraphNumberProperties());
  33. }
  34. }
  35. private XElement GetParagraphNumberProperties()
  36. {
  37. var numPrNode = Xml.Descendants().FirstOrDefault(el => el.Name.LocalName == "numPr");
  38. if (numPrNode != null)
  39. {
  40. var numIdNode = numPrNode.Descendants().First(numId => numId.Name.LocalName == "numId");
  41. var numIdAttribute = numIdNode.Attribute(DocX.w + "val");
  42. if (numIdAttribute != null && numIdAttribute.Value.Equals("0"))
  43. {
  44. return null;
  45. }
  46. }
  47. return numPrNode;
  48. }
  49. private bool? IsListItemBacker { get; set; }
  50. /// <summary>
  51. /// Determine if this paragraph is a list element.
  52. /// </summary>
  53. public bool IsListItem
  54. {
  55. get
  56. {
  57. IsListItemBacker = IsListItemBacker ?? (ParagraphNumberProperties != null);
  58. return (bool)IsListItemBacker;
  59. }
  60. }
  61. private int? IndentLevelBacker { get; set; }
  62. /// <summary>
  63. /// If this element is a list item, get the indentation level of the list item.
  64. /// </summary>
  65. public int? IndentLevel
  66. {
  67. get
  68. {
  69. if (!IsListItem)
  70. {
  71. return null;
  72. }
  73. return IndentLevelBacker ?? (IndentLevelBacker = int.Parse(ParagraphNumberProperties.Descendants().First(el => el.Name.LocalName == "ilvl").GetAttribute(DocX.w + "val")));
  74. }
  75. }
  76. /// <summary>
  77. /// Determine if the list element is a numbered list of bulleted list element
  78. /// </summary>
  79. public ListItemType ListItemType;
  80. internal int startIndex, endIndex;
  81. /// <summary>
  82. /// Returns a list of all Pictures in a Paragraph.
  83. /// </summary>
  84. /// <example>
  85. /// Returns a list of all Pictures in a Paragraph.
  86. /// <code>
  87. /// <![CDATA[
  88. /// // Create a document.
  89. /// using (DocX document = DocX.Load(@"Test.docx"))
  90. /// {
  91. /// // Get the first Paragraph in a document.
  92. /// Paragraph p = document.Paragraphs[0];
  93. ///
  94. /// // Get all of the Pictures in this Paragraph.
  95. /// List<Picture> pictures = p.Pictures;
  96. ///
  97. /// // Save this document.
  98. /// document.Save();
  99. /// }
  100. /// ]]>
  101. /// </code>
  102. /// </example>
  103. public List<Picture> Pictures
  104. {
  105. get
  106. {
  107. List<Picture> pictures =
  108. (
  109. from p in Xml.Descendants()
  110. where (p.Name.LocalName == "drawing")
  111. let id =
  112. (
  113. from e in p.Descendants()
  114. where e.Name.LocalName.Equals("blip")
  115. select e.Attribute(XName.Get("embed", "http://schemas.openxmlformats.org/officeDocument/2006/relationships")).Value
  116. ).SingleOrDefault()
  117. where id != null
  118. let img = new Image(Document, mainPart.GetRelationship(id))
  119. select new Picture(Document, p, img)
  120. ).ToList();
  121. List<Picture> shapes =
  122. (
  123. from p in Xml.Descendants()
  124. where (p.Name.LocalName == "pict")
  125. let id =
  126. (
  127. from e in p.Descendants()
  128. where e.Name.LocalName.Equals("imagedata")
  129. select e.Attribute(XName.Get("id", "http://schemas.openxmlformats.org/officeDocument/2006/relationships")).Value
  130. ).SingleOrDefault()
  131. where id != null
  132. let img = new Image(Document, mainPart.GetRelationship(id))
  133. select new Picture(Document, p, img)
  134. ).ToList();
  135. foreach (Picture p in shapes)
  136. pictures.Add(p);
  137. return pictures;
  138. }
  139. }
  140. /// <summary>
  141. /// Returns a list of Hyperlinks in this Paragraph.
  142. /// </summary>
  143. /// <example>
  144. /// <code>
  145. /// // Create a document.
  146. /// using (DocX document = DocX.Load(@"Test.docx"))
  147. /// {
  148. /// // Get the first Paragraph in this document.
  149. /// Paragraph p = document.Paragraphs[0];
  150. ///
  151. /// // Get all of the hyperlinks in this Paragraph.
  152. /// <![CDATA[ List<Hyperlink> ]]> hyperlinks = paragraph.Hyperlinks;
  153. ///
  154. /// // Change the first hyperlinks text and Uri
  155. /// Hyperlink h0 = hyperlinks[0];
  156. /// h0.Text = "DocX";
  157. /// h0.Uri = new Uri("http://docx.codeplex.com");
  158. ///
  159. /// // Save this document.
  160. /// document.Save();
  161. /// }
  162. /// </code>
  163. /// </example>
  164. public List<Hyperlink> Hyperlinks
  165. {
  166. get
  167. {
  168. List<Hyperlink> hyperlinks = new List<Hyperlink>();
  169. List<XElement> hyperlink_elements =
  170. (
  171. from h in Xml.Descendants()
  172. where (h.Name.LocalName == "hyperlink" || h.Name.LocalName == "instrText")
  173. select h
  174. ).ToList();
  175. foreach (XElement he in hyperlink_elements)
  176. {
  177. if (he.Name.LocalName == "hyperlink")
  178. {
  179. try
  180. {
  181. Hyperlink h = new Hyperlink(Document, mainPart, he);
  182. h.mainPart = mainPart;
  183. hyperlinks.Add(h);
  184. }
  185. catch (Exception) { }
  186. }
  187. else
  188. {
  189. // Find the parent run, no matter how deeply nested we are.
  190. XElement e = he;
  191. while (e.Name.LocalName != "r")
  192. e = e.Parent;
  193. // Take every element until we reach w:fldCharType="end"
  194. List<XElement> hyperlink_runs = new List<XElement>();
  195. foreach (XElement r in e.ElementsAfterSelf(XName.Get("r", DocX.w.NamespaceName)))
  196. {
  197. // Add this run to the list.
  198. hyperlink_runs.Add(r);
  199. XElement fldChar = r.Descendants(XName.Get("fldChar", DocX.w.NamespaceName)).SingleOrDefault<XElement>();
  200. if (fldChar != null)
  201. {
  202. XAttribute fldCharType = fldChar.Attribute(XName.Get("fldCharType", DocX.w.NamespaceName));
  203. if (fldCharType != null && fldCharType.Value.Equals("end", StringComparison.CurrentCultureIgnoreCase))
  204. {
  205. try
  206. {
  207. Hyperlink h = new Hyperlink(Document, he, hyperlink_runs);
  208. h.mainPart = mainPart;
  209. hyperlinks.Add(h);
  210. }
  211. catch (Exception) { }
  212. break;
  213. }
  214. }
  215. }
  216. }
  217. }
  218. return hyperlinks;
  219. }
  220. }
  221. ///<summary>
  222. /// The style name of the paragraph.
  223. ///</summary>
  224. public string StyleName
  225. {
  226. get
  227. {
  228. var element = this.GetOrCreate_pPr();
  229. var styleElement = element.Element(XName.Get("pStyle", DocX.w.NamespaceName));
  230. var attr = styleElement?.Attribute(XName.Get("val", DocX.w.NamespaceName));
  231. if (!string.IsNullOrEmpty(attr?.Value))
  232. {
  233. return attr.Value;
  234. }
  235. return "Normal";
  236. }
  237. set
  238. {
  239. if (string.IsNullOrEmpty(value))
  240. {
  241. value = "Normal";
  242. }
  243. var element = this.GetOrCreate_pPr();
  244. var styleElement = element.Element(XName.Get("pStyle", DocX.w.NamespaceName));
  245. if (styleElement == null)
  246. {
  247. element.Add(new XElement(XName.Get("pStyle", DocX.w.NamespaceName)));
  248. styleElement = element.Element(XName.Get("pStyle", DocX.w.NamespaceName));
  249. }
  250. styleElement.SetAttributeValue(XName.Get("val", DocX.w.NamespaceName), value);
  251. }
  252. }
  253. // A collection of field type DocProperty.
  254. private List<DocProperty> docProperties;
  255. internal List<XElement> styles = new List<XElement>();
  256. /// <summary>
  257. /// Returns a list of field type DocProperty in this document.
  258. /// </summary>
  259. public List<DocProperty> DocumentProperties
  260. {
  261. get { return docProperties; }
  262. }
  263. internal Paragraph(DocX document, XElement xml, int startIndex, ContainerType parent = ContainerType.None)
  264. : base(document, xml)
  265. {
  266. ParentContainer = parent;
  267. this.startIndex = startIndex;
  268. this.endIndex = startIndex + GetElementTextLength(xml);
  269. RebuildDocProperties();
  270. // As per Unused code affecting performance (Wiki Link: [discussion:454191]) and coffeycathal suggestion no longer requeried
  271. //#region It's possible that a Paragraph may have pStyle references
  272. //// Check if this Paragraph references any pStyle elements.
  273. //var stylesElements = xml.Descendants(XName.Get("pStyle", DocX.w.NamespaceName));
  274. //// If one or more pStyles are referenced.
  275. //if (stylesElements.Count() > 0)
  276. //{
  277. // Uri style_package_uri = new Uri("/word/styles.xml", UriKind.Relative);
  278. // PackagePart styles_document = document.package.GetPart(style_package_uri);
  279. // using (TextReader tr = new StreamReader(styles_document.GetStream()))
  280. // {
  281. // XDocument style_document = XDocument.Load(tr);
  282. // XElement styles_element = style_document.Element(XName.Get("styles", DocX.w.NamespaceName));
  283. // var styles_element_ids = stylesElements.Select(e => e.Attribute(XName.Get("val", DocX.w.NamespaceName)).Value);
  284. // //foreach(string id in styles_element_ids)
  285. // //{
  286. // // var style =
  287. // // (
  288. // // from d in styles_element.Descendants()
  289. // // let styleId = d.Attribute(XName.Get("styleId", DocX.w.NamespaceName))
  290. // // let type = d.Attribute(XName.Get("type", DocX.w.NamespaceName))
  291. // // where type != null && type.Value == "paragraph" && styleId != null && styleId.Value == id
  292. // // select d
  293. // // ).First();
  294. // // styles.Add(style);
  295. // //}
  296. // }
  297. //}
  298. //#endregion
  299. this.runs = Xml.Elements(XName.Get("r", DocX.w.NamespaceName)).ToList();
  300. }
  301. /// <summary>
  302. /// Insert a new Table before this Paragraph, this Table can be from this document or another document.
  303. /// </summary>
  304. /// <param name="t">The Table t to be inserted.</param>
  305. /// <returns>A new Table inserted before this Paragraph.</returns>
  306. /// <example>
  307. /// Insert a new Table before this Paragraph.
  308. /// <code>
  309. /// // Place holder for a Table.
  310. /// Table t;
  311. ///
  312. /// // Load document a.
  313. /// using (DocX documentA = DocX.Load(@"a.docx"))
  314. /// {
  315. /// // Get the first Table from this document.
  316. /// t = documentA.Tables[0];
  317. /// }
  318. ///
  319. /// // Load document b.
  320. /// using (DocX documentB = DocX.Load(@"b.docx"))
  321. /// {
  322. /// // Get the first Paragraph in document b.
  323. /// Paragraph p2 = documentB.Paragraphs[0];
  324. ///
  325. /// // Insert the Table from document a before this Paragraph.
  326. /// Table newTable = p2.InsertTableBeforeSelf(t);
  327. ///
  328. /// // Save all changes made to document b.
  329. /// documentB.Save();
  330. /// }// Release this document from memory.
  331. /// </code>
  332. /// </example>
  333. public override Table InsertTableBeforeSelf(Table t)
  334. {
  335. t = base.InsertTableBeforeSelf(t);
  336. t.mainPart = mainPart;
  337. return t;
  338. }
  339. private Direction direction;
  340. /// <summary>
  341. /// Gets or Sets the Direction of content in this Paragraph.
  342. /// <example>
  343. /// Create a Paragraph with content that flows right to left. Default is left to right.
  344. /// <code>
  345. /// // Create a new document.
  346. /// using (DocX document = DocX.Create("Test.docx"))
  347. /// {
  348. /// // Create a new Paragraph with the text "Hello World".
  349. /// Paragraph p = document.InsertParagraph("Hello World.");
  350. ///
  351. /// // Make this Paragraph flow right to left. Default is left to right.
  352. /// p.Direction = Direction.RightToLeft;
  353. ///
  354. /// // Save all changes made to this document.
  355. /// document.Save();
  356. /// }
  357. /// </code>
  358. /// </example>
  359. /// </summary>
  360. public Direction Direction
  361. {
  362. get
  363. {
  364. XElement pPr = GetOrCreate_pPr();
  365. XElement bidi = pPr.Element(XName.Get("bidi", DocX.w.NamespaceName));
  366. return bidi == null ? Direction.LeftToRight : Direction.RightToLeft;
  367. }
  368. set
  369. {
  370. direction = value;
  371. XElement pPr = GetOrCreate_pPr();
  372. XElement bidi = pPr.Element(XName.Get("bidi", DocX.w.NamespaceName));
  373. if (direction == Direction.RightToLeft)
  374. {
  375. if (bidi == null)
  376. pPr.Add(new XElement(XName.Get("bidi", DocX.w.NamespaceName)));
  377. }
  378. else
  379. {
  380. bidi?.Remove();
  381. }
  382. }
  383. }
  384. public bool IsKeepWithNext
  385. {
  386. get
  387. {
  388. var pPr = GetOrCreate_pPr();
  389. var keepWithNextE = pPr.Element(XName.Get("keepNext", DocX.w.NamespaceName));
  390. if (keepWithNextE == null)
  391. {
  392. return false;
  393. }
  394. return true;
  395. }
  396. }
  397. /// <summary>
  398. /// This paragraph will be kept on the same page as the next paragraph
  399. /// </summary>
  400. /// <example>
  401. /// Create a Paragraph that will stay on the same page as the paragraph that comes next
  402. /// <code>
  403. /// // Create a new document.
  404. /// using (DocX document = DocX.Create("Test.docx"))
  405. ///
  406. /// {
  407. /// // Create a new Paragraph with the text "Hello World".
  408. /// Paragraph p = document.InsertParagraph("Hello World.");
  409. /// p.KeepWithNext();
  410. /// document.InsertParagraph("Previous paragraph will appear on the same page as this paragraph");
  411. /// // Save all changes made to this document.
  412. /// document.Save();
  413. /// }
  414. /// </code>
  415. /// </example>
  416. /// <param name="keepWithNext"></param>
  417. /// <returns></returns>
  418. public Paragraph KeepWithNext(bool keepWithNext = true)
  419. {
  420. var pPr = GetOrCreate_pPr();
  421. var keepWithNextE = pPr.Element(XName.Get("keepNext", DocX.w.NamespaceName));
  422. if (keepWithNextE == null && keepWithNext)
  423. {
  424. pPr.Add(new XElement(XName.Get("keepNext", DocX.w.NamespaceName)));
  425. }
  426. if (!keepWithNext && keepWithNextE != null)
  427. {
  428. keepWithNextE.Remove();
  429. }
  430. return this;
  431. }
  432. /// <summary>
  433. /// Keep all lines in this paragraph together on a page
  434. /// </summary>
  435. /// <example>
  436. /// Create a Paragraph whose lines will stay together on a single page
  437. /// <code>
  438. /// // Create a new document.
  439. /// using (DocX document = DocX.Create("Test.docx"))
  440. /// {
  441. /// // Create a new Paragraph with the text "Hello World".
  442. /// Paragraph p = document.InsertParagraph("All lines of this paragraph will appear on the same page...\nLine 2\nLine 3\nLine 4\nLine 5\nLine 6...");
  443. /// p.KeepLinesTogether();
  444. /// // Save all changes made to this document.
  445. /// document.Save();
  446. /// }
  447. /// </code>
  448. /// </example>
  449. /// <param name="keepTogether"></param>
  450. /// <returns></returns>
  451. public Paragraph KeepLinesTogether(bool keepTogether = true)
  452. {
  453. var pPr = GetOrCreate_pPr();
  454. var keepLinesE = pPr.Element(XName.Get("keepLines", DocX.w.NamespaceName));
  455. if (keepLinesE == null && keepTogether)
  456. {
  457. pPr.Add(new XElement(XName.Get("keepLines", DocX.w.NamespaceName)));
  458. }
  459. if (!keepTogether)
  460. {
  461. keepLinesE?.Remove();
  462. }
  463. return this;
  464. }
  465. /// <summary>
  466. /// If the pPr element doesent exist it is created, either way it is returned by this function.
  467. /// </summary>
  468. /// <returns>The pPr element for this Paragraph.</returns>
  469. internal XElement GetOrCreate_pPr()
  470. {
  471. // Get the element.
  472. XElement pPr = Xml.Element(XName.Get("pPr", DocX.w.NamespaceName));
  473. // If it dosen't exist, create it.
  474. if (pPr == null)
  475. {
  476. Xml.AddFirst(new XElement(XName.Get("pPr", DocX.w.NamespaceName)));
  477. pPr = Xml.Element(XName.Get("pPr", DocX.w.NamespaceName));
  478. }
  479. // Return the pPr element for this Paragraph.
  480. return pPr;
  481. }
  482. /// <summary>
  483. /// If the ind element doesent exist it is created, either way it is returned by this function.
  484. /// </summary>
  485. /// <returns>The ind element for this Paragraphs pPr.</returns>
  486. internal XElement GetOrCreate_pPr_ind()
  487. {
  488. // Get the element.
  489. XElement pPr = GetOrCreate_pPr();
  490. XElement ind = pPr.Element(XName.Get("ind", DocX.w.NamespaceName));
  491. // If it dosen't exist, create it.
  492. if (ind == null)
  493. {
  494. pPr.Add(new XElement(XName.Get("ind", DocX.w.NamespaceName)));
  495. ind = pPr.Element(XName.Get("ind", DocX.w.NamespaceName));
  496. }
  497. // Return the pPr element for this Paragraph.
  498. return ind;
  499. }
  500. private float indentationFirstLine;
  501. /// <summary>
  502. /// Get or set the indentation of the first line of this Paragraph.
  503. /// </summary>
  504. /// <example>
  505. /// Indent only the first line of a Paragraph.
  506. /// <code>
  507. /// // Create a new document.
  508. /// using (DocX document = DocX.Create("Test.docx"))
  509. /// {
  510. /// // Create a new Paragraph.
  511. /// Paragraph p = document.InsertParagraph("Line 1\nLine 2\nLine 3");
  512. ///
  513. /// // Indent only the first line of the Paragraph.
  514. /// p.IndentationFirstLine = 2.0f;
  515. ///
  516. /// // Save all changes made to this document.
  517. /// document.Save();
  518. /// }
  519. /// </code>
  520. /// </example>
  521. public float IndentationFirstLine
  522. {
  523. get
  524. {
  525. GetOrCreate_pPr();
  526. XElement ind = GetOrCreate_pPr_ind();
  527. XAttribute firstLine = ind.Attribute(XName.Get("firstLine", DocX.w.NamespaceName));
  528. if (firstLine != null)
  529. return float.Parse(firstLine.Value);
  530. return 0.0f;
  531. }
  532. set
  533. {
  534. if (IndentationFirstLine != value)
  535. {
  536. indentationFirstLine = value;
  537. XElement pPr = GetOrCreate_pPr();
  538. XElement ind = GetOrCreate_pPr_ind();
  539. // Paragraph can either be firstLine or hanging (Remove hanging).
  540. XAttribute hanging = ind.Attribute(XName.Get("hanging", DocX.w.NamespaceName));
  541. hanging?.Remove();
  542. string indentation = ((indentationFirstLine / 0.1) * 57).ToString();
  543. XAttribute firstLine = ind.Attribute(XName.Get("firstLine", DocX.w.NamespaceName));
  544. if (firstLine != null)
  545. firstLine.Value = indentation;
  546. else
  547. ind.Add(new XAttribute(XName.Get("firstLine", DocX.w.NamespaceName), indentation));
  548. }
  549. }
  550. }
  551. private float indentationHanging;
  552. /// <summary>
  553. /// Get or set the indentation of all but the first line of this Paragraph.
  554. /// </summary>
  555. /// <example>
  556. /// Indent all but the first line of a Paragraph.
  557. /// <code>
  558. /// // Create a new document.
  559. /// using (DocX document = DocX.Create("Test.docx"))
  560. /// {
  561. /// // Create a new Paragraph.
  562. /// Paragraph p = document.InsertParagraph("Line 1\nLine 2\nLine 3");
  563. ///
  564. /// // Indent all but the first line of the Paragraph.
  565. /// p.IndentationHanging = 1.0f;
  566. ///
  567. /// // Save all changes made to this document.
  568. /// document.Save();
  569. /// }
  570. /// </code>
  571. /// </example>
  572. public float IndentationHanging
  573. {
  574. get
  575. {
  576. GetOrCreate_pPr();
  577. XElement ind = GetOrCreate_pPr_ind();
  578. XAttribute hanging = ind.Attribute(XName.Get("hanging", DocX.w.NamespaceName));
  579. if (hanging != null)
  580. return float.Parse(hanging.Value) / (57 * 10);
  581. return 0.0f;
  582. }
  583. set
  584. {
  585. if (IndentationHanging != value)
  586. {
  587. indentationHanging = value;
  588. XElement pPr = GetOrCreate_pPr();
  589. XElement ind = GetOrCreate_pPr_ind();
  590. // Paragraph can either be firstLine or hanging (Remove firstLine).
  591. XAttribute firstLine = ind.Attribute(XName.Get("firstLine", DocX.w.NamespaceName));
  592. if (firstLine != null)
  593. firstLine.Remove();
  594. string indentation = ((indentationHanging / 0.1) * 57).ToString();
  595. XAttribute hanging = ind.Attribute(XName.Get("hanging", DocX.w.NamespaceName));
  596. if (hanging != null)
  597. hanging.Value = indentation;
  598. else
  599. ind.Add(new XAttribute(XName.Get("hanging", DocX.w.NamespaceName), indentation));
  600. }
  601. }
  602. }
  603. private float indentationBefore;
  604. /// <summary>
  605. /// Set the before indentation in cm for this Paragraph.
  606. /// </summary>
  607. /// <example>
  608. /// // Indent an entire Paragraph from the left.
  609. /// <code>
  610. /// // Create a new document.
  611. /// using (DocX document = DocX.Create("Test.docx"))
  612. /// {
  613. /// // Create a new Paragraph.
  614. /// Paragraph p = document.InsertParagraph("Line 1\nLine 2\nLine 3");
  615. ///
  616. /// // Indent this entire Paragraph from the left.
  617. /// p.IndentationBefore = 2.0f;
  618. ///
  619. /// // Save all changes made to this document.
  620. /// document.Save();
  621. ///}
  622. /// </code>
  623. /// </example>
  624. public float IndentationBefore
  625. {
  626. get
  627. {
  628. XElement pPr = GetOrCreate_pPr();
  629. XElement ind = GetOrCreate_pPr_ind();
  630. XAttribute left = ind.Attribute(XName.Get("left", DocX.w.NamespaceName));
  631. if (left != null)
  632. return float.Parse(left.Value) / (57 * 10);
  633. return 0.0f;
  634. }
  635. set
  636. {
  637. if (IndentationBefore != value)
  638. {
  639. indentationBefore = value;
  640. XElement pPr = GetOrCreate_pPr();
  641. XElement ind = GetOrCreate_pPr_ind();
  642. string indentation = ((indentationBefore / 0.1) * 57).ToString(CultureInfo.GetCultureInfo("en-GB"));
  643. XAttribute left = ind.Attribute(XName.Get("left", DocX.w.NamespaceName));
  644. if (left != null)
  645. left.Value = indentation;
  646. else
  647. ind.Add(new XAttribute(XName.Get("left", DocX.w.NamespaceName), indentation));
  648. }
  649. }
  650. }
  651. private float indentationAfter;
  652. /// <summary>
  653. /// Set the after indentation in cm for this Paragraph.
  654. /// </summary>
  655. /// <example>
  656. /// // Indent an entire Paragraph from the right.
  657. /// <code>
  658. /// // Create a new document.
  659. /// using (DocX document = DocX.Create("Test.docx"))
  660. /// {
  661. /// // Create a new Paragraph.
  662. /// Paragraph p = document.InsertParagraph("Line 1\nLine 2\nLine 3");
  663. ///
  664. /// // Make the content of this Paragraph flow right to left.
  665. /// p.Direction = Direction.RightToLeft;
  666. ///
  667. /// // Indent this entire Paragraph from the right.
  668. /// p.IndentationAfter = 2.0f;
  669. ///
  670. /// // Save all changes made to this document.
  671. /// document.Save();
  672. /// }
  673. /// </code>
  674. /// </example>
  675. public float IndentationAfter
  676. {
  677. get
  678. {
  679. GetOrCreate_pPr();
  680. XElement ind = GetOrCreate_pPr_ind();
  681. XAttribute right = ind.Attribute(XName.Get("right", DocX.w.NamespaceName));
  682. if (right != null)
  683. return float.Parse(right.Value);
  684. return 0.0f;
  685. }
  686. set
  687. {
  688. if (IndentationAfter != value)
  689. {
  690. indentationAfter = value;
  691. XElement pPr = GetOrCreate_pPr();
  692. XElement ind = GetOrCreate_pPr_ind();
  693. string indentation = ((indentationAfter / 0.1) * 57).ToString();
  694. XAttribute right = ind.Attribute(XName.Get("right", DocX.w.NamespaceName));
  695. if (right != null)
  696. right.Value = indentation;
  697. else
  698. ind.Add(new XAttribute(XName.Get("right", DocX.w.NamespaceName), indentation));
  699. }
  700. }
  701. }
  702. /// <summary>
  703. /// Insert a new Table into this document before this Paragraph.
  704. /// </summary>
  705. /// <param name="rowCount">The number of rows this Table should have.</param>
  706. /// <param name="columnCount">The number of columns this Table should have.</param>
  707. /// <returns>A new Table inserted before this Paragraph.</returns>
  708. /// <example>
  709. /// <code>
  710. /// // Create a new document.
  711. /// using (DocX document = DocX.Create(@"Test.docx"))
  712. /// {
  713. /// //Insert a Paragraph into this document.
  714. /// Paragraph p = document.InsertParagraph("Hello World", false);
  715. ///
  716. /// // Insert a new Table before this Paragraph.
  717. /// Table newTable = p.InsertTableBeforeSelf(2, 2);
  718. /// newTable.Design = TableDesign.LightShadingAccent2;
  719. /// newTable.Alignment = Alignment.center;
  720. ///
  721. /// // Save all changes made to this document.
  722. /// document.Save();
  723. /// }// Release this document from memory.
  724. /// </code>
  725. /// </example>
  726. public override Table InsertTableBeforeSelf(int rowCount, int columnCount)
  727. {
  728. return base.InsertTableBeforeSelf(rowCount, columnCount);
  729. }
  730. /// <summary>
  731. /// Insert a new Table after this Paragraph.
  732. /// </summary>
  733. /// <param name="t">The Table t to be inserted.</param>
  734. /// <returns>A new Table inserted after this Paragraph.</returns>
  735. /// <example>
  736. /// Insert a new Table after this Paragraph.
  737. /// <code>
  738. /// // Place holder for a Table.
  739. /// Table t;
  740. ///
  741. /// // Load document a.
  742. /// using (DocX documentA = DocX.Load(@"a.docx"))
  743. /// {
  744. /// // Get the first Table from this document.
  745. /// t = documentA.Tables[0];
  746. /// }
  747. ///
  748. /// // Load document b.
  749. /// using (DocX documentB = DocX.Load(@"b.docx"))
  750. /// {
  751. /// // Get the first Paragraph in document b.
  752. /// Paragraph p2 = documentB.Paragraphs[0];
  753. ///
  754. /// // Insert the Table from document a after this Paragraph.
  755. /// Table newTable = p2.InsertTableAfterSelf(t);
  756. ///
  757. /// // Save all changes made to document b.
  758. /// documentB.Save();
  759. /// }// Release this document from memory.
  760. /// </code>
  761. /// </example>
  762. public override Table InsertTableAfterSelf(Table t)
  763. {
  764. t = base.InsertTableAfterSelf(t);
  765. t.mainPart = mainPart;
  766. return t;
  767. }
  768. /// <summary>
  769. /// Insert a new Table into this document after this Paragraph.
  770. /// </summary>
  771. /// <param name="rowCount">The number of rows this Table should have.</param>
  772. /// <param name="columnCount">The number of columns this Table should have.</param>
  773. /// <returns>A new Table inserted after this Paragraph.</returns>
  774. /// <example>
  775. /// <code>
  776. /// // Create a new document.
  777. /// using (DocX document = DocX.Create(@"Test.docx"))
  778. /// {
  779. /// //Insert a Paragraph into this document.
  780. /// Paragraph p = document.InsertParagraph("Hello World", false);
  781. ///
  782. /// // Insert a new Table after this Paragraph.
  783. /// Table newTable = p.InsertTableAfterSelf(2, 2);
  784. /// newTable.Design = TableDesign.LightShadingAccent2;
  785. /// newTable.Alignment = Alignment.center;
  786. ///
  787. /// // Save all changes made to this document.
  788. /// document.Save();
  789. /// }// Release this document from memory.
  790. /// </code>
  791. /// </example>
  792. public override Table InsertTableAfterSelf(int rowCount, int columnCount)
  793. {
  794. return base.InsertTableAfterSelf(rowCount, columnCount);
  795. }
  796. /// <summary>
  797. /// Insert a Paragraph before this Paragraph, this Paragraph may have come from the same or another document.
  798. /// </summary>
  799. /// <param name="p">The Paragraph to insert.</param>
  800. /// <returns>The Paragraph now associated with this document.</returns>
  801. /// <example>
  802. /// Take a Paragraph from document a, and insert it into document b before this Paragraph.
  803. /// <code>
  804. /// // Place holder for a Paragraph.
  805. /// Paragraph p;
  806. ///
  807. /// // Load document a.
  808. /// using (DocX documentA = DocX.Load(@"a.docx"))
  809. /// {
  810. /// // Get the first paragraph from this document.
  811. /// p = documentA.Paragraphs[0];
  812. /// }
  813. ///
  814. /// // Load document b.
  815. /// using (DocX documentB = DocX.Load(@"b.docx"))
  816. /// {
  817. /// // Get the first Paragraph in document b.
  818. /// Paragraph p2 = documentB.Paragraphs[0];
  819. ///
  820. /// // Insert the Paragraph from document a before this Paragraph.
  821. /// Paragraph newParagraph = p2.InsertParagraphBeforeSelf(p);
  822. ///
  823. /// // Save all changes made to document b.
  824. /// documentB.Save();
  825. /// }// Release this document from memory.
  826. /// </code>
  827. /// </example>
  828. public override Paragraph InsertParagraphBeforeSelf(Paragraph p)
  829. {
  830. Paragraph p2 = base.InsertParagraphBeforeSelf(p);
  831. p2.PackagePart = mainPart;
  832. return p2;
  833. }
  834. /// <summary>
  835. /// Insert a new Paragraph before this Paragraph.
  836. /// </summary>
  837. /// <param name="text">The initial text for this new Paragraph.</param>
  838. /// <returns>A new Paragraph inserted before this Paragraph.</returns>
  839. /// <example>
  840. /// Insert a new paragraph before the first Paragraph in this document.
  841. /// <code>
  842. /// // Create a new document.
  843. /// using (DocX document = DocX.Create(@"Test.docx"))
  844. /// {
  845. /// // Insert a Paragraph into this document.
  846. /// Paragraph p = document.InsertParagraph("I am a Paragraph", false);
  847. ///
  848. /// p.InsertParagraphBeforeSelf("I was inserted before the next Paragraph.");
  849. ///
  850. /// // Save all changes made to this new document.
  851. /// document.Save();
  852. /// }// Release this new document form memory.
  853. /// </code>
  854. /// </example>
  855. public override Paragraph InsertParagraphBeforeSelf(string text)
  856. {
  857. Paragraph p = base.InsertParagraphBeforeSelf(text);
  858. p.PackagePart = mainPart;
  859. return p;
  860. }
  861. /// <summary>
  862. /// Insert a new Paragraph before this Paragraph.
  863. /// </summary>
  864. /// <param name="text">The initial text for this new Paragraph.</param>
  865. /// <param name="trackChanges">Should this insertion be tracked as a change?</param>
  866. /// <returns>A new Paragraph inserted before this Paragraph.</returns>
  867. /// <example>
  868. /// Insert a new paragraph before the first Paragraph in this document.
  869. /// <code>
  870. /// // Create a new document.
  871. /// using (DocX document = DocX.Create(@"Test.docx"))
  872. /// {
  873. /// // Insert a Paragraph into this document.
  874. /// Paragraph p = document.InsertParagraph("I am a Paragraph", false);
  875. ///
  876. /// p.InsertParagraphBeforeSelf("I was inserted before the next Paragraph.", false);
  877. ///
  878. /// // Save all changes made to this new document.
  879. /// document.Save();
  880. /// }// Release this new document form memory.
  881. /// </code>
  882. /// </example>
  883. public override Paragraph InsertParagraphBeforeSelf(string text, bool trackChanges)
  884. {
  885. Paragraph p = base.InsertParagraphBeforeSelf(text, trackChanges);
  886. p.PackagePart = mainPart;
  887. return p;
  888. }
  889. /// <summary>
  890. /// Insert a new Paragraph before this Paragraph.
  891. /// </summary>
  892. /// <param name="text">The initial text for this new Paragraph.</param>
  893. /// <param name="trackChanges">Should this insertion be tracked as a change?</param>
  894. /// <param name="formatting">The formatting to apply to this insertion.</param>
  895. /// <returns>A new Paragraph inserted before this Paragraph.</returns>
  896. /// <example>
  897. /// Insert a new paragraph before the first Paragraph in this document.
  898. /// <code>
  899. /// // Create a new document.
  900. /// using (DocX document = DocX.Create(@"Test.docx"))
  901. /// {
  902. /// // Insert a Paragraph into this document.
  903. /// Paragraph p = document.InsertParagraph("I am a Paragraph", false);
  904. ///
  905. /// Formatting boldFormatting = new Formatting();
  906. /// boldFormatting.Bold = true;
  907. ///
  908. /// p.InsertParagraphBeforeSelf("I was inserted before the next Paragraph.", false, boldFormatting);
  909. ///
  910. /// // Save all changes made to this new document.
  911. /// document.Save();
  912. /// }// Release this new document form memory.
  913. /// </code>
  914. /// </example>
  915. public override Paragraph InsertParagraphBeforeSelf(string text, bool trackChanges, Formatting formatting)
  916. {
  917. Paragraph p = base.InsertParagraphBeforeSelf(text, trackChanges, formatting);
  918. p.PackagePart = mainPart;
  919. return p;
  920. }
  921. /// <summary>
  922. /// Insert a page break before a Paragraph.
  923. /// </summary>
  924. /// <example>
  925. /// Insert 2 Paragraphs into a document with a page break between them.
  926. /// <code>
  927. /// using (DocX document = DocX.Create(@"Test.docx"))
  928. /// {
  929. /// // Insert a new Paragraph.
  930. /// Paragraph p1 = document.InsertParagraph("Paragraph 1", false);
  931. ///
  932. /// // Insert a new Paragraph.
  933. /// Paragraph p2 = document.InsertParagraph("Paragraph 2", false);
  934. ///
  935. /// // Insert a page break before Paragraph two.
  936. /// p2.InsertPageBreakBeforeSelf();
  937. ///
  938. /// // Save this document.
  939. /// document.Save();
  940. /// }// Release this document from memory.
  941. /// </code>
  942. /// </example>
  943. public override void InsertPageBreakBeforeSelf()
  944. {
  945. base.InsertPageBreakBeforeSelf();
  946. }
  947. /// <summary>
  948. /// Insert a page break after a Paragraph.
  949. /// </summary>
  950. /// <example>
  951. /// Insert 2 Paragraphs into a document with a page break between them.
  952. /// <code>
  953. /// using (DocX document = DocX.Create(@"Test.docx"))
  954. /// {
  955. /// // Insert a new Paragraph.
  956. /// Paragraph p1 = document.InsertParagraph("Paragraph 1", false);
  957. ///
  958. /// // Insert a page break after this Paragraph.
  959. /// p1.InsertPageBreakAfterSelf();
  960. ///
  961. /// // Insert a new Paragraph.
  962. /// Paragraph p2 = document.InsertParagraph("Paragraph 2", false);
  963. ///
  964. /// // Save this document.
  965. /// document.Save();
  966. /// }// Release this document from memory.
  967. /// </code>
  968. /// </example>
  969. public override void InsertPageBreakAfterSelf()
  970. {
  971. base.InsertPageBreakAfterSelf();
  972. }
  973. [Obsolete("Instead use: InsertHyperlink(Hyperlink h, int index)")]
  974. public Paragraph InsertHyperlink(int index, Hyperlink h) { return InsertHyperlink(h, index); }
  975. /// <summary>
  976. /// This function inserts a hyperlink into a Paragraph at a specified character index.
  977. /// </summary>
  978. /// <param name="index">The index to insert at.</param>
  979. /// <param name="h">The hyperlink to insert.</param>
  980. /// <returns>The Paragraph with the Hyperlink inserted at the specified index.</returns>
  981. /// <!--
  982. /// This function was added by Brian Campbell aka chickendelicious on Jun 16 2010
  983. /// Thank you Brian.
  984. /// -->
  985. public Paragraph InsertHyperlink(Hyperlink h, int index = 0)
  986. {
  987. // Convert the path of this mainPart to its equilivant rels file path.
  988. string path = mainPart.Uri.OriginalString.Replace("/word/", "");
  989. Uri rels_path = new Uri(String.Format("/word/_rels/{0}.rels", path), UriKind.Relative);
  990. // Check to see if the rels file exists and create it if not.
  991. if (!Document.package.PartExists(rels_path))
  992. HelperFunctions.CreateRelsPackagePart(Document, rels_path);
  993. // Check to see if a rel for this Picture exists, create it if not.
  994. var Id = GetOrGenerateRel(h);
  995. XElement h_xml;
  996. if (index == 0)
  997. {
  998. // Add this hyperlink as the first element.
  999. Xml.AddFirst(h.Xml);
  1000. // Extract the picture back out of the DOM.
  1001. h_xml = (XElement)Xml.FirstNode;
  1002. }
  1003. else
  1004. {
  1005. // Get the first run effected by this Insert
  1006. Run run = GetFirstRunEffectedByEdit(index);
  1007. if (run == null)
  1008. {
  1009. // Add this hyperlink as the last element.
  1010. Xml.Add(h.Xml);
  1011. // Extract the picture back out of the DOM.
  1012. h_xml = (XElement)Xml.LastNode;
  1013. }
  1014. else
  1015. {
  1016. // Split this run at the point you want to insert
  1017. XElement[] splitRun = Run.SplitRun(run, index);
  1018. // Replace the origional run.
  1019. run.Xml.ReplaceWith
  1020. (
  1021. splitRun[0],
  1022. h.Xml,
  1023. splitRun[1]
  1024. );
  1025. // Get the first run effected by this Insert
  1026. run = GetFirstRunEffectedByEdit(index);
  1027. // The picture has to be the next element, extract it back out of the DOM.
  1028. h_xml = (XElement)run.Xml.NextNode;
  1029. }
  1030. }
  1031. h_xml.SetAttributeValue( DocX.r + "id", Id );
  1032. this.runs = Xml.Elements().Last().Elements( XName.Get( "r", DocX.w.NamespaceName ) ).ToList();
  1033. return this;
  1034. }
  1035. /// <summary>
  1036. /// Remove the Hyperlink at the provided index. The first hyperlink is at index 0.
  1037. /// Using a negative index or an index greater than the index of the last hyperlink will cause an ArgumentOutOfRangeException() to be thrown.
  1038. /// </summary>
  1039. /// <param name="index">The index of the hyperlink to be removed.</param>
  1040. /// <example>
  1041. /// <code>
  1042. /// // Crete a new document.
  1043. /// using (DocX document = DocX.Create("Test.docx"))
  1044. /// {
  1045. /// // Add a Hyperlink into this document.
  1046. /// Hyperlink h = document.AddHyperlink("link", new Uri("http://www.google.com"));
  1047. ///
  1048. /// // Insert a new Paragraph into the document.
  1049. /// Paragraph p1 = document.InsertParagraph("AC");
  1050. ///
  1051. /// // Insert the hyperlink into this Paragraph.
  1052. /// p1.InsertHyperlink(1, h);
  1053. /// Assert.IsTrue(p1.Text == "AlinkC"); // Make sure the hyperlink was inserted correctly;
  1054. ///
  1055. /// // Remove the hyperlink
  1056. /// p1.RemoveHyperlink(0);
  1057. /// Assert.IsTrue(p1.Text == "AC"); // Make sure the hyperlink was removed correctly;
  1058. /// }
  1059. /// </code>
  1060. /// </example>
  1061. public void RemoveHyperlink(int index)
  1062. {
  1063. // Dosen't make sense to remove a Hyperlink at a negative index.
  1064. if (index < 0)
  1065. throw new ArgumentOutOfRangeException();
  1066. // Need somewhere to store the count.
  1067. int count = 0;
  1068. bool found = false;
  1069. RemoveHyperlinkRecursive(Xml, index, ref count, ref found);
  1070. // If !found then the user tried to remove a hyperlink at an index greater than the last.
  1071. if (!found)
  1072. throw new ArgumentOutOfRangeException();
  1073. }
  1074. internal void RemoveHyperlinkRecursive(XElement xml, int index, ref int count, ref bool found)
  1075. {
  1076. if (xml.Name.LocalName.Equals("hyperlink", StringComparison.CurrentCultureIgnoreCase))
  1077. {
  1078. // This is the hyperlink to be removed.
  1079. if (count == index)
  1080. {
  1081. found = true;
  1082. xml.Remove();
  1083. }
  1084. else
  1085. count++;
  1086. }
  1087. if (xml.HasElements)
  1088. foreach (XElement e in xml.Elements())
  1089. if (!found)
  1090. RemoveHyperlinkRecursive(e, index, ref count, ref found);
  1091. }
  1092. /// <summary>
  1093. /// Insert a Paragraph after this Paragraph, this Paragraph may have come from the same or another document.
  1094. /// </summary>
  1095. /// <param name="p">The Paragraph to insert.</param>
  1096. /// <returns>The Paragraph now associated with this document.</returns>
  1097. /// <example>
  1098. /// Take a Paragraph from document a, and insert it into document b after this Paragraph.
  1099. /// <code>
  1100. /// // Place holder for a Paragraph.
  1101. /// Paragraph p;
  1102. ///
  1103. /// // Load document a.
  1104. /// using (DocX documentA = DocX.Load(@"a.docx"))
  1105. /// {
  1106. /// // Get the first paragraph from this document.
  1107. /// p = documentA.Paragraphs[0];
  1108. /// }
  1109. ///
  1110. /// // Load document b.
  1111. /// using (DocX documentB = DocX.Load(@"b.docx"))
  1112. /// {
  1113. /// // Get the first Paragraph in document b.
  1114. /// Paragraph p2 = documentB.Paragraphs[0];
  1115. ///
  1116. /// // Insert the Paragraph from document a after this Paragraph.
  1117. /// Paragraph newParagraph = p2.InsertParagraphAfterSelf(p);
  1118. ///
  1119. /// // Save all changes made to document b.
  1120. /// documentB.Save();
  1121. /// }// Release this document from memory.
  1122. /// </code>
  1123. /// </example>
  1124. public override Paragraph InsertParagraphAfterSelf(Paragraph p)
  1125. {
  1126. Paragraph p2 = base.InsertParagraphAfterSelf(p);
  1127. p2.PackagePart = mainPart;
  1128. return p2;
  1129. }
  1130. /// <summary>
  1131. /// Insert a new Paragraph after this Paragraph.
  1132. /// </summary>
  1133. /// <param name="text">The initial text for this new Paragraph.</param>
  1134. /// <param name="trackChanges">Should this insertion be tracked as a change?</param>
  1135. /// <param name="formatting">The formatting to apply to this insertion.</param>
  1136. /// <returns>A new Paragraph inserted after this Paragraph.</returns>
  1137. /// <example>
  1138. /// Insert a new paragraph after the first Paragraph in this document.
  1139. /// <code>
  1140. /// // Create a new document.
  1141. /// using (DocX document = DocX.Create(@"Test.docx"))
  1142. /// {
  1143. /// // Insert a Paragraph into this document.
  1144. /// Paragraph p = document.InsertParagraph("I am a Paragraph", false);
  1145. ///
  1146. /// Formatting boldFormatting = new Formatting();
  1147. /// boldFormatting.Bold = true;
  1148. ///
  1149. /// p.InsertParagraphAfterSelf("I was inserted after the previous Paragraph.", false, boldFormatting);
  1150. ///
  1151. /// // Save all changes made to this new document.
  1152. /// document.Save();
  1153. /// }// Release this new document form memory.
  1154. /// </code>
  1155. /// </example>
  1156. public override Paragraph InsertParagraphAfterSelf(string text, bool trackChanges, Formatting formatting)
  1157. {
  1158. Paragraph p = base.InsertParagraphAfterSelf(text, trackChanges, formatting);
  1159. p.PackagePart = mainPart;
  1160. return p;
  1161. }
  1162. /// <summary>
  1163. /// Insert a new Paragraph after this Paragraph.
  1164. /// </summary>
  1165. /// <param name="text">The initial text for this new Paragraph.</param>
  1166. /// <param name="trackChanges">Should this insertion be tracked as a change?</param>
  1167. /// <returns>A new Paragraph inserted after this Paragraph.</returns>
  1168. /// <example>
  1169. /// Insert a new paragraph after the first Paragraph in this document.
  1170. /// <code>
  1171. /// // Create a new document.
  1172. /// using (DocX document = DocX.Create(@"Test.docx"))
  1173. /// {
  1174. /// // Insert a Paragraph into this document.
  1175. /// Paragraph p = document.InsertParagraph("I am a Paragraph", false);
  1176. ///
  1177. /// p.InsertParagraphAfterSelf("I was inserted after the previous Paragraph.", false);
  1178. ///
  1179. /// // Save all changes made to this new document.
  1180. /// document.Save();
  1181. /// }// Release this new document form memory.
  1182. /// </code>
  1183. /// </example>
  1184. public override Paragraph InsertParagraphAfterSelf(string text, bool trackChanges)
  1185. {
  1186. Paragraph p = base.InsertParagraphAfterSelf(text, trackChanges);
  1187. p.PackagePart = mainPart;
  1188. return p;
  1189. }
  1190. /// <summary>
  1191. /// Insert a new Paragraph after this Paragraph.
  1192. /// </summary>
  1193. /// <param name="text">The initial text for this new Paragraph.</param>
  1194. /// <returns>A new Paragraph inserted after this Paragraph.</returns>
  1195. /// <example>
  1196. /// Insert a new paragraph after the first Paragraph in this document.
  1197. /// <code>
  1198. /// // Create a new document.
  1199. /// using (DocX document = DocX.Create(@"Test.docx"))
  1200. /// {
  1201. /// // Insert a Paragraph into this document.
  1202. /// Paragraph p = document.InsertParagraph("I am a Paragraph", false);
  1203. ///
  1204. /// p.InsertParagraphAfterSelf("I was inserted after the previous Paragraph.");
  1205. ///
  1206. /// // Save all changes made to this new document.
  1207. /// document.Save();
  1208. /// }// Release this new document form memory.
  1209. /// </code>
  1210. /// </example>
  1211. public override Paragraph InsertParagraphAfterSelf(string text)
  1212. {
  1213. Paragraph p = base.InsertParagraphAfterSelf(text);
  1214. p.PackagePart = mainPart;
  1215. return p;
  1216. }
  1217. private void RebuildDocProperties()
  1218. {
  1219. docProperties =
  1220. (
  1221. from xml in Xml.Descendants(XName.Get("fldSimple", DocX.w.NamespaceName))
  1222. select new DocProperty(Document, xml)
  1223. ).ToList();
  1224. }
  1225. /// <summary>
  1226. /// Gets or set this Paragraphs text alignment.
  1227. /// </summary>
  1228. public Alignment Alignment
  1229. {
  1230. get
  1231. {
  1232. XElement pPr = GetOrCreate_pPr();
  1233. XElement jc = pPr.Element(XName.Get("jc", DocX.w.NamespaceName));
  1234. if (jc != null)
  1235. {
  1236. XAttribute a = jc.Attribute(XName.Get("val", DocX.w.NamespaceName));
  1237. switch (a.Value.ToLower())
  1238. {
  1239. case "left": return Novacode.Alignment.left;
  1240. case "right": return Novacode.Alignment.right;
  1241. case "center": return Novacode.Alignment.center;
  1242. case "both": return Novacode.Alignment.both;
  1243. }
  1244. }
  1245. return Novacode.Alignment.left;
  1246. }
  1247. set
  1248. {
  1249. alignment = value;
  1250. XElement pPr = GetOrCreate_pPr();
  1251. XElement jc = pPr.Element(XName.Get("jc", DocX.w.NamespaceName));
  1252. if (alignment != Novacode.Alignment.left)
  1253. {
  1254. if (jc == null)
  1255. pPr.Add(new XElement(XName.Get("jc", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), alignment.ToString())));
  1256. else
  1257. jc.Attribute(XName.Get("val", DocX.w.NamespaceName)).Value = alignment.ToString();
  1258. }
  1259. else
  1260. {
  1261. if (jc != null)
  1262. jc.Remove();
  1263. }
  1264. }
  1265. }
  1266. /// <summary>
  1267. /// Remove this Paragraph from the document.
  1268. /// </summary>
  1269. /// <param name="trackChanges">Should this remove be tracked as a change?</param>
  1270. /// <example>
  1271. /// Remove a Paragraph from a document and track it as a change.
  1272. /// <code>
  1273. /// // Create a document using a relative filename.
  1274. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  1275. /// {
  1276. /// // Create and Insert a new Paragraph into this document.
  1277. /// Paragraph p = document.InsertParagraph("Hello", false);
  1278. ///
  1279. /// // Remove the Paragraph and track this as a change.
  1280. /// p.Remove(true);
  1281. ///
  1282. /// // Save all changes made to this document.
  1283. /// document.Save();
  1284. /// }// Release this document from memory.
  1285. /// </code>
  1286. /// </example>
  1287. public void Remove(bool trackChanges)
  1288. {
  1289. if (trackChanges)
  1290. {
  1291. DateTime now = DateTime.Now.ToUniversalTime();
  1292. List<XElement> elements = Xml.Elements().ToList();
  1293. List<XElement> temp = new List<XElement>();
  1294. for (int i = 0; i < elements.Count(); i++)
  1295. {
  1296. XElement e = elements[i];
  1297. if (e.Name.LocalName != "del")
  1298. {
  1299. temp.Add(e);
  1300. e.Remove();
  1301. }
  1302. else
  1303. {
  1304. if (temp.Count() > 0)
  1305. {
  1306. e.AddBeforeSelf(CreateEdit(EditType.del, now, temp.Elements()));
  1307. temp.Clear();
  1308. }
  1309. }
  1310. }
  1311. if (temp.Count() > 0)
  1312. Xml.Add(CreateEdit(EditType.del, now, temp));
  1313. }
  1314. else
  1315. {
  1316. // If this is the only Paragraph in the Cell then we cannot remove it.
  1317. if (Xml.Parent.Name.LocalName == "tc" && Xml.Parent.Elements(XName.Get("p", DocX.w.NamespaceName)).Count() == 1)
  1318. Xml.Value = string.Empty;
  1319. else
  1320. {
  1321. // Remove this paragraph from the document
  1322. Xml.Remove();
  1323. Xml = null;
  1324. }
  1325. }
  1326. }
  1327. /// <summary>
  1328. /// Gets the text value of this Paragraph.
  1329. /// </summary>
  1330. public string Text
  1331. {
  1332. // Returns the underlying XElement's Value property.
  1333. get
  1334. {
  1335. return HelperFunctions.GetText(Xml);
  1336. }
  1337. }
  1338. /// <summary>
  1339. /// Gets the formatted text value of this Paragraph.
  1340. /// </summary>
  1341. public List<FormattedText> MagicText
  1342. {
  1343. // Returns the underlying XElement's Value property.
  1344. get
  1345. {
  1346. try
  1347. {
  1348. return HelperFunctions.GetFormattedText(Xml);
  1349. }
  1350. catch (Exception)
  1351. {
  1352. return null;
  1353. }
  1354. }
  1355. }
  1356. //public Picture InsertPicture(Picture picture)
  1357. //{
  1358. // Picture newPicture = picture;
  1359. // newPicture.i = new XElement(picture.i);
  1360. // xml.Add(newPicture.i);
  1361. // pictures.Add(newPicture);
  1362. // return newPicture;
  1363. //}
  1364. // <summary>
  1365. // Insert a Picture at the end of this paragraph.
  1366. // </summary>
  1367. // <param name="description">A string to describe this Picture.</param>
  1368. // <param name="imageID">The unique id that identifies the Image this Picture represents.</param>
  1369. // <param name="name">The name of this image.</param>
  1370. // <returns>A Picture.</returns>
  1371. // <example>
  1372. // <code>
  1373. // // Create a document using a relative filename.
  1374. // using (DocX document = DocX.Create(@"Test.docx"))
  1375. // {
  1376. // // Add a new Paragraph to this document.
  1377. // Paragraph p = document.InsertParagraph("Here is Picture 1", false);
  1378. //
  1379. // // Add an Image to this document.
  1380. // Novacode.Image img = document.AddImage(@"Image.jpg");
  1381. //
  1382. // // Insert pic at the end of Paragraph p.
  1383. // Picture pic = p.InsertPicture(img.Id, "Photo 31415", "A pie I baked.");
  1384. //
  1385. // // Rotate the Picture clockwise by 30 degrees.
  1386. // pic.Rotation = 30;
  1387. //
  1388. // // Resize the Picture.
  1389. // pic.Width = 400;
  1390. // pic.Height = 300;
  1391. //
  1392. // // Set the shape of this Picture to be a cube.
  1393. // pic.SetPictureShape(BasicShapes.cube);
  1394. //
  1395. // // Flip the Picture Horizontally.
  1396. // pic.FlipHorizontal = true;
  1397. //
  1398. // // Save all changes made to this document.
  1399. // document.Save();
  1400. // }// Release this document from memory.
  1401. // </code>
  1402. // </example>
  1403. // Removed to simplify the API.
  1404. //public Picture InsertPicture(string imageID, string name, string description)
  1405. //{
  1406. // Picture p = CreatePicture(Document, imageID, name, description);
  1407. // Xml.Add(p.Xml);
  1408. // return p;
  1409. //}
  1410. // Removed because it confusses the API.
  1411. //public Picture InsertPicture(string imageID)
  1412. //{
  1413. // return InsertPicture(imageID, string.Empty, string.Empty);
  1414. //}
  1415. //public Picture InsertPicture(int index, Picture picture)
  1416. //{
  1417. // Picture p = picture;
  1418. // p.i = new XElement(picture.i);
  1419. // Run run = GetFirstRunEffectedByEdit(index);
  1420. // if (run == null)
  1421. // xml.Add(p.i);
  1422. // else
  1423. // {
  1424. // // Split this run at the point you want to insert
  1425. // XElement[] splitRun = Run.SplitRun(run, index);
  1426. // // Replace the origional run
  1427. // run.Xml.ReplaceWith
  1428. // (
  1429. // splitRun[0],
  1430. // p.i,
  1431. // splitRun[1]
  1432. // );
  1433. // }
  1434. // // Rebuild the run lookup for this paragraph
  1435. // runLookup.Clear();
  1436. // BuildRunLookup(xml);
  1437. // DocX.RenumberIDs(document);
  1438. // return p;
  1439. //}
  1440. // <summary>
  1441. // Insert a Picture into this Paragraph at a specified index.
  1442. // </summary>
  1443. // <param name="description">A string to describe this Picture.</param>
  1444. // <param name="imageID">The unique id that identifies the Image this Picture represents.</param>
  1445. // <param name="name">The name of this image.</param>
  1446. // <param name="index">The index to insert this Picture at.</param>
  1447. // <returns>A Picture.</returns>
  1448. // <example>
  1449. // <code>
  1450. // // Create a document using a relative filename.
  1451. // using (DocX document = DocX.Create(@"Test.docx"))
  1452. // {
  1453. // // Add a new Paragraph to this document.
  1454. // Paragraph p = document.InsertParagraph("Here is Picture 1", false);
  1455. //
  1456. // // Add an Image to this document.
  1457. // Novacode.Image img = document.AddImage(@"Image.jpg");
  1458. //
  1459. // // Insert pic at the start of Paragraph p.
  1460. // Picture pic = p.InsertPicture(0, img.Id, "Photo 31415", "A pie I baked.");
  1461. //
  1462. // // Rotate the Picture clockwise by 30 degrees.
  1463. // pic.Rotation = 30;
  1464. //
  1465. // // Resize the Picture.
  1466. // pic.Width = 400;
  1467. // pic.Height = 300;
  1468. //
  1469. // // Set the shape of this Picture to be a cube.
  1470. // pic.SetPictureShape(BasicShapes.cube);
  1471. //
  1472. // // Flip the Picture Horizontally.
  1473. // pic.FlipHorizontal = true;
  1474. //
  1475. // // Save all changes made to this document.
  1476. // document.Save();
  1477. // }// Release this document from memory.
  1478. // </code>
  1479. // </example>
  1480. // Removed to simplify API.
  1481. //public Picture InsertPicture(int index, string imageID, string name, string description)
  1482. //{
  1483. // Picture picture = CreatePicture(Document, imageID, name, description);
  1484. // Run run = GetFirstRunEffectedByEdit(index);
  1485. // if (run == null)
  1486. // Xml.Add(picture.Xml);
  1487. // else
  1488. // {
  1489. // // Split this run at the point you want to insert
  1490. // XElement[] splitRun = Run.SplitRun(run, index);
  1491. // // Replace the origional run
  1492. // run.Xml.ReplaceWith
  1493. // (
  1494. // splitRun[0],
  1495. // picture.Xml,
  1496. // splitRun[1]
  1497. // );
  1498. // }
  1499. // HelperFunctions.RenumberIDs(Document);
  1500. // return picture;
  1501. //}
  1502. /// <summary>
  1503. /// Create a new Picture.
  1504. /// </summary>
  1505. /// <param name="document"></param>
  1506. /// <param name="id">A unique id that identifies an Image embedded in this document.</param>
  1507. /// <param name="name">The name of this Picture.</param>
  1508. /// <param name="descr">The description of this Picture.</param>
  1509. static internal Picture CreatePicture(DocX document, string id, string name, string descr)
  1510. {
  1511. PackagePart part = document.package.GetPart(document.mainPart.GetRelationship(id).TargetUri);
  1512. long newDocPrId = document.GetNextFreeDocPrId();
  1513. int cx, cy;
  1514. using (PackagePartStream packagePartStream = new PackagePartStream(part.GetStream()))
  1515. {
  1516. using (System.Drawing.Image img = System.Drawing.Image.FromStream(packagePartStream, useEmbeddedColorManagement: false, validateImageData: false))
  1517. {
  1518. cx = img.Width*9526;
  1519. cy = img.Height*9526;
  1520. }
  1521. }
  1522. XElement xml = XElement.Parse
  1523. (string.Format(@"<w:r xmlns:w=""http://schemas.openxmlformats.org/wordprocessingml/2006/main"">
  1524. <w:drawing xmlns = ""http://schemas.openxmlformats.org/wordprocessingml/2006/main"">
  1525. <wp:inline distT=""0"" distB=""0"" distL=""0"" distR=""0"" xmlns:wp=""http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"">
  1526. <wp:extent cx=""{0}"" cy=""{1}"" />
  1527. <wp:effectExtent l=""0"" t=""0"" r=""0"" b=""0"" />
  1528. <wp:docPr id=""{5}"" name=""{3}"" descr=""{4}"" />
  1529. <wp:cNvGraphicFramePr>
  1530. <a:graphicFrameLocks xmlns:a=""http://schemas.openxmlformats.org/drawingml/2006/main"" noChangeAspect=""1"" />
  1531. </wp:cNvGraphicFramePr>
  1532. <a:graphic xmlns:a=""http://schemas.openxmlformats.org/drawingml/2006/main"">
  1533. <a:graphicData uri=""http://schemas.openxmlformats.org/drawingml/2006/picture"">
  1534. <pic:pic xmlns:pic=""http://schemas.openxmlformats.org/drawingml/2006/picture"">
  1535. <pic:nvPicPr>
  1536. <pic:cNvPr id=""0"" name=""{3}"" />
  1537. <pic:cNvPicPr />
  1538. </pic:nvPicPr>
  1539. <pic:blipFill>
  1540. <a:blip r:embed=""{2}"" xmlns:r=""http://schemas.openxmlformats.org/officeDocument/2006/relationships""/>
  1541. <a:stretch>
  1542. <a:fillRect />
  1543. </a:stretch>
  1544. </pic:blipFill>
  1545. <pic:spPr>
  1546. <a:xfrm>
  1547. <a:off x=""0"" y=""0"" />
  1548. <a:ext cx=""{0}"" cy=""{1}"" />
  1549. </a:xfrm>
  1550. <a:prstGeom prst=""rect"">
  1551. <a:avLst />
  1552. </a:prstGeom>
  1553. </pic:spPr>
  1554. </pic:pic>
  1555. </a:graphicData>
  1556. </a:graphic>
  1557. </wp:inline>
  1558. </w:drawing></w:r>
  1559. ", cx, cy, id, name, descr, newDocPrId.ToString()));
  1560. return new Picture(document, xml, new Image(document, document.mainPart.GetRelationship(id)));
  1561. }
  1562. // Removed because it confusses the API.
  1563. //public Picture InsertPicture(int index, string imageID)
  1564. //{
  1565. // return InsertPicture(index, imageID, string.Empty, string.Empty);
  1566. //}
  1567. /// <summary>
  1568. /// Creates an Edit either a ins or a del with the specified content and date
  1569. /// </summary>
  1570. /// <param name="t">The type of this edit (ins or del)</param>
  1571. /// <param name="edit_time">The time stamp to use for this edit</param>
  1572. /// <param name="content">The initial content of this edit</param>
  1573. /// <returns></returns>
  1574. internal static XElement CreateEdit(EditType t, DateTime edit_time, object content)
  1575. {
  1576. if (t == EditType.del)
  1577. {
  1578. foreach (object o in (IEnumerable<XElement>)content)
  1579. {
  1580. if (o is XElement)
  1581. {
  1582. XElement e = (o as XElement);
  1583. IEnumerable<XElement> ts = e.DescendantsAndSelf(XName.Get("t", DocX.w.NamespaceName));
  1584. for (int i = 0; i < ts.Count(); i++)
  1585. {
  1586. XElement text = ts.ElementAt(i);
  1587. text.ReplaceWith(new XElement(DocX.w + "delText", text.Attributes(), text.Value));
  1588. }
  1589. }
  1590. }
  1591. }
  1592. return
  1593. (
  1594. new XElement(DocX.w + t.ToString(),
  1595. new XAttribute(DocX.w + "id", 0),
  1596. new XAttribute(DocX.w + "author", WindowsIdentity.GetCurrent().Name),
  1597. new XAttribute(DocX.w + "date", edit_time),
  1598. content)
  1599. );
  1600. }
  1601. internal Run GetFirstRunEffectedByEdit(int index, EditType type = EditType.ins)
  1602. {
  1603. int len = HelperFunctions.GetText(Xml).Length;
  1604. // Make sure we are looking within an acceptable index range.
  1605. if (index < 0 || ((type == EditType.ins && index > len) || (type == EditType.del && index >= len)))
  1606. throw new ArgumentOutOfRangeException();
  1607. // Need some memory that can be updated by the recursive search for the XElement to Split.
  1608. int count = 0;
  1609. Run theOne = null;
  1610. GetFirstRunEffectedByEditRecursive(Xml, index, ref count, ref theOne, type);
  1611. return theOne;
  1612. }
  1613. internal void GetFirstRunEffectedByEditRecursive(XElement Xml, int index, ref int count, ref Run theOne, EditType type)
  1614. {
  1615. count += HelperFunctions.GetSize(Xml);
  1616. // If the EditType is deletion then we must return the next blah
  1617. if (count > 0 && ((type == EditType.del && count > index) || (type == EditType.ins && count >= index)))
  1618. {
  1619. // Correct the index
  1620. foreach (XElement e in Xml.ElementsBeforeSelf())
  1621. count -= HelperFunctions.GetSize(e);
  1622. count -= HelperFunctions.GetSize(Xml);
  1623. // We have found the element, now find the run it belongs to.
  1624. while ((Xml.Name.LocalName != "r") && (Xml.Name.LocalName != "pPr"))
  1625. Xml = Xml.Parent;
  1626. theOne = new Run(Document, Xml, count);
  1627. return;
  1628. }
  1629. if (Xml.HasElements)
  1630. foreach (XElement e in Xml.Elements())
  1631. if (theOne == null)
  1632. GetFirstRunEffectedByEditRecursive(e, index, ref count, ref theOne, type);
  1633. }
  1634. /// <!--
  1635. /// Bug found and fixed by krugs525 on August 12 2009.
  1636. /// Use TFS compare to see exact code change.
  1637. /// -->
  1638. static internal int GetElementTextLength(XElement run)
  1639. {
  1640. int count = 0;
  1641. if (run == null)
  1642. return count;
  1643. foreach (var d in run.Descendants())
  1644. {
  1645. switch (d.Name.LocalName)
  1646. {
  1647. case "tab":
  1648. if (d.Parent.Name.LocalName != "tabs")
  1649. goto case "br"; break;
  1650. case "br": count++; break;
  1651. case "t": goto case "delText";
  1652. case "delText": count += d.Value.Length; break;
  1653. default: break;
  1654. }
  1655. }
  1656. return count;
  1657. }
  1658. internal XElement[] SplitEdit(XElement edit, int index, EditType type)
  1659. {
  1660. Run run = GetFirstRunEffectedByEdit(index, type);
  1661. XElement[] splitRun = Run.SplitRun(run, index, type);
  1662. XElement splitLeft = new XElement(edit.Name, edit.Attributes(), run.Xml.ElementsBeforeSelf(), splitRun[0]);
  1663. if (GetElementTextLength(splitLeft) == 0)
  1664. splitLeft = null;
  1665. XElement splitRight = new XElement(edit.Name, edit.Attributes(), splitRun[1], run.Xml.ElementsAfterSelf());
  1666. if (GetElementTextLength(splitRight) == 0)
  1667. splitRight = null;
  1668. return
  1669. (
  1670. new XElement[]
  1671. {
  1672. splitLeft,
  1673. splitRight
  1674. }
  1675. );
  1676. }
  1677. /// <summary>
  1678. /// Inserts a specified instance of System.String into a Novacode.DocX.Paragraph at a specified index position.
  1679. /// </summary>
  1680. /// <example>
  1681. /// <code>
  1682. /// // Create a document using a relative filename.
  1683. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  1684. /// {
  1685. /// // Create a text formatting.
  1686. /// Formatting f = new Formatting();
  1687. /// f.FontColor = Color.Red;
  1688. /// f.Size = 30;
  1689. ///
  1690. /// // Iterate through the Paragraphs in this document.
  1691. /// foreach (Paragraph p in document.Paragraphs)
  1692. /// {
  1693. /// // Insert the string "Start: " at the begining of every Paragraph and flag it as a change.
  1694. /// p.InsertText("Start: ", true, f);
  1695. /// }
  1696. ///
  1697. /// // Save all changes made to this document.
  1698. /// document.Save();
  1699. /// }// Release this document from memory.
  1700. /// </code>
  1701. /// </example>
  1702. /// <example>
  1703. /// Inserting tabs using the \t switch.
  1704. /// <code>
  1705. /// // Create a document using a relative filename.
  1706. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  1707. /// {
  1708. /// // Create a text formatting.
  1709. /// Formatting f = new Formatting();
  1710. /// f.FontColor = Color.Red;
  1711. /// f.Size = 30;
  1712. ///
  1713. /// // Iterate through the paragraphs in this document.
  1714. /// foreach (Paragraph p in document.Paragraphs)
  1715. /// {
  1716. /// // Insert the string "\tEnd" at the end of every paragraph and flag it as a change.
  1717. /// p.InsertText("\tEnd", true, f);
  1718. /// }
  1719. ///
  1720. /// // Save all changes made to this document.
  1721. /// document.Save();
  1722. /// }// Release this document from memory.
  1723. /// </code>
  1724. /// </example>
  1725. /// <seealso cref="Paragraph.RemoveText(int, bool)"/>
  1726. /// <seealso cref="Paragraph.RemoveText(int, int, bool, bool)"/>
  1727. /// <param name="value">The System.String to insert.</param>
  1728. /// <param name="trackChanges">Flag this insert as a change.</param>
  1729. /// <param name="formatting">The text formatting.</param>
  1730. public void InsertText(string value, bool trackChanges = false, Formatting formatting = null)
  1731. {
  1732. // Default values for optional parameters must be compile time constants.
  1733. // Would have like to write 'public void InsertText(string value, bool trackChanges = false, Formatting formatting = new Formatting())
  1734. if (formatting == null) formatting = new Formatting();
  1735. List<XElement> newRuns = HelperFunctions.FormatInput(value, formatting.Xml);
  1736. Xml.Add(newRuns);
  1737. HelperFunctions.RenumberIDs(Document);
  1738. }
  1739. /// <summary>
  1740. /// Inserts a specified instance of System.String into a Novacode.DocX.Paragraph at a specified index position.
  1741. /// </summary>
  1742. /// <example>
  1743. /// <code>
  1744. /// // Create a document using a relative filename.
  1745. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  1746. /// {
  1747. /// // Create a text formatting.
  1748. /// Formatting f = new Formatting();
  1749. /// f.FontColor = Color.Red;
  1750. /// f.Size = 30;
  1751. ///
  1752. /// // Iterate through the Paragraphs in this document.
  1753. /// foreach (Paragraph p in document.Paragraphs)
  1754. /// {
  1755. /// // Insert the string "Start: " at the begining of every Paragraph and flag it as a change.
  1756. /// p.InsertText(0, "Start: ", true, f);
  1757. /// }
  1758. ///
  1759. /// // Save all changes made to this document.
  1760. /// document.Save();
  1761. /// }// Release this document from memory.
  1762. /// </code>
  1763. /// </example>
  1764. /// <example>
  1765. /// Inserting tabs using the \t switch.
  1766. /// <code>
  1767. /// // Create a document using a relative filename.
  1768. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  1769. /// {
  1770. /// // Create a text formatting.
  1771. /// Formatting f = new Formatting();
  1772. /// f.FontColor = Color.Red;
  1773. /// f.Size = 30;
  1774. ///
  1775. /// // Iterate through the paragraphs in this document.
  1776. /// foreach (Paragraph p in document.Paragraphs)
  1777. /// {
  1778. /// // Insert the string "\tStart:\t" at the begining of every paragraph and flag it as a change.
  1779. /// p.InsertText(0, "\tStart:\t", true, f);
  1780. /// }
  1781. ///
  1782. /// // Save all changes made to this document.
  1783. /// document.Save();
  1784. /// }// Release this document from memory.
  1785. /// </code>
  1786. /// </example>
  1787. /// <seealso cref="Paragraph.RemoveText(int, bool)"/>
  1788. /// <seealso cref="Paragraph.RemoveText(int, int, bool, bool)"/>
  1789. /// <param name="index">The index position of the insertion.</param>
  1790. /// <param name="value">The System.String to insert.</param>
  1791. /// <param name="trackChanges">Flag this insert as a change.</param>
  1792. /// <param name="formatting">The text formatting.</param>
  1793. public void InsertText(int index, string value, bool trackChanges = false, Formatting formatting = null)
  1794. {
  1795. // Timestamp to mark the start of insert
  1796. DateTime now = DateTime.Now;
  1797. DateTime insert_datetime = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0, DateTimeKind.Utc);
  1798. // Get the first run effected by this Insert
  1799. Run run = GetFirstRunEffectedByEdit(index);
  1800. if (run == null)
  1801. {
  1802. object insert;
  1803. if (formatting != null) //not sure how to get original formatting here when run == null
  1804. insert = HelperFunctions.FormatInput(value, formatting.Xml);
  1805. else
  1806. insert = HelperFunctions.FormatInput(value, null);
  1807. if (trackChanges)
  1808. insert = CreateEdit(EditType.ins, insert_datetime, insert);
  1809. Xml.Add(insert);
  1810. }
  1811. else
  1812. {
  1813. object newRuns;
  1814. var rprel = run.Xml.Element(XName.Get("rPr", DocX.w.NamespaceName));
  1815. if (formatting != null)
  1816. {
  1817. //merge 2 formattings properly
  1818. Formatting finfmt = null;
  1819. Formatting oldfmt = null;
  1820. if (rprel != null)
  1821. {
  1822. oldfmt = Formatting.Parse(rprel);
  1823. }
  1824. if (oldfmt != null)
  1825. {
  1826. finfmt = oldfmt.Clone();
  1827. if (formatting.Bold.HasValue) { finfmt.Bold = formatting.Bold; }
  1828. if (formatting.CapsStyle.HasValue) { finfmt.CapsStyle = formatting.CapsStyle; }
  1829. if (formatting.FontColor.HasValue) { finfmt.FontColor = formatting.FontColor; }
  1830. finfmt.FontFamily = formatting.FontFamily;
  1831. if (formatting.Hidden.HasValue) { finfmt.Hidden = formatting.Hidden; }
  1832. if (formatting.Highlight.HasValue) { finfmt.Highlight = formatting.Highlight; }
  1833. if (formatting.Italic.HasValue) { finfmt.Italic = formatting.Italic; }
  1834. if (formatting.Kerning.HasValue) { finfmt.Kerning = formatting.Kerning; }
  1835. finfmt.Language = formatting.Language;
  1836. if (formatting.Misc.HasValue) { finfmt.Misc = formatting.Misc; }
  1837. if (formatting.PercentageScale.HasValue) { finfmt.PercentageScale = formatting.PercentageScale; }
  1838. if (formatting.Position.HasValue) { finfmt.Position = formatting.Position; }
  1839. if (formatting.Script.HasValue) { finfmt.Script = formatting.Script; }
  1840. if (formatting.Size.HasValue) { finfmt.Size = formatting.Size; }
  1841. if (formatting.Spacing.HasValue) { finfmt.Spacing = formatting.Spacing; }
  1842. if (formatting.StrikeThrough.HasValue) { finfmt.StrikeThrough = formatting.StrikeThrough; }
  1843. if (formatting.UnderlineColor.HasValue) { finfmt.UnderlineColor = formatting.UnderlineColor; }
  1844. if (formatting.UnderlineStyle.HasValue) { finfmt.UnderlineStyle = formatting.UnderlineStyle; }
  1845. }
  1846. else
  1847. {
  1848. finfmt = formatting;
  1849. }
  1850. newRuns = HelperFunctions.FormatInput(value, finfmt.Xml);
  1851. }
  1852. else
  1853. {
  1854. newRuns = HelperFunctions.FormatInput(value, rprel);
  1855. }
  1856. // The parent of this Run
  1857. XElement parentElement = run.Xml.Parent;
  1858. switch (parentElement.Name.LocalName)
  1859. {
  1860. case "ins":
  1861. {
  1862. // The datetime that this ins was created
  1863. DateTime parent_ins_date = DateTime.Parse(parentElement.Attribute(XName.Get("date", DocX.w.NamespaceName)).Value);
  1864. /*
  1865. * Special case: You want to track changes,
  1866. * and the first Run effected by this insert
  1867. * has a datetime stamp equal to now.
  1868. */
  1869. if (trackChanges && parent_ins_date.CompareTo(insert_datetime) == 0)
  1870. {
  1871. /*
  1872. * Inserting into a non edit and this special case, is the same procedure.
  1873. */
  1874. goto default;
  1875. }
  1876. /*
  1877. * If not the special case above,
  1878. * then inserting into an ins or a del, is the same procedure.
  1879. */
  1880. goto case "del";
  1881. }
  1882. case "del":
  1883. {
  1884. object insert = newRuns;
  1885. if (trackChanges)
  1886. insert = CreateEdit(EditType.ins, insert_datetime, newRuns);
  1887. // Split this Edit at the point you want to insert
  1888. XElement[] splitEdit = SplitEdit(parentElement, index, EditType.ins);
  1889. // Replace the origional run
  1890. parentElement.ReplaceWith
  1891. (
  1892. splitEdit[0],
  1893. insert,
  1894. splitEdit[1]
  1895. );
  1896. break;
  1897. }
  1898. default:
  1899. {
  1900. object insert = newRuns;
  1901. if (trackChanges && !parentElement.Name.LocalName.Equals("ins"))
  1902. insert = CreateEdit(EditType.ins, insert_datetime, newRuns);
  1903. // Special case to deal with Page Number elements.
  1904. //if (parentElement.Name.LocalName.Equals("fldSimple"))
  1905. // parentElement.AddBeforeSelf(insert);
  1906. else
  1907. {
  1908. // Split this run at the point you want to insert
  1909. XElement[] splitRun = Run.SplitRun(run, index);
  1910. // Replace the origional run
  1911. run.Xml.ReplaceWith
  1912. (
  1913. splitRun[0],
  1914. insert,
  1915. splitRun[1]
  1916. );
  1917. }
  1918. break;
  1919. }
  1920. }
  1921. }
  1922. HelperFunctions.RenumberIDs(Document);
  1923. }
  1924. /// <summary>
  1925. /// For use with Append() and AppendLine()
  1926. /// </summary>
  1927. /// <returns>This Paragraph in curent culture</returns>
  1928. /// <example>
  1929. /// Add a new Paragraph with russian text to this document and then set language of text to local culture.
  1930. /// <code>
  1931. /// // Load a document.
  1932. /// using (DocX document = DocX.Create(@"Test.docx"))
  1933. /// {
  1934. /// // Insert a new Paragraph with russian text and set curent local culture to it.
  1935. /// Paragraph p = document.InsertParagraph("Привет мир!").CurentCulture();
  1936. ///
  1937. /// // Save this document.
  1938. /// document.Save();
  1939. /// }
  1940. /// </code>
  1941. /// </example>
  1942. public Paragraph CurentCulture()
  1943. {
  1944. ApplyTextFormattingProperty(XName.Get("lang", DocX.w.NamespaceName),
  1945. string.Empty,
  1946. new XAttribute(XName.Get("val", DocX.w.NamespaceName), CultureInfo.CurrentCulture.Name));
  1947. return this;
  1948. }
  1949. /// <summary>
  1950. /// For use with Append() and AppendLine()
  1951. /// </summary>
  1952. /// <param name="culture">The CultureInfo for text</param>
  1953. /// <returns>This Paragraph in curent culture</returns>
  1954. /// <example>
  1955. /// Add a new Paragraph with russian text to this document and then set language of text to local culture.
  1956. /// <code>
  1957. /// // Load a document.
  1958. /// using (DocX document = DocX.Create(@"Test.docx"))
  1959. /// {
  1960. /// // Insert a new Paragraph with russian text and set specific culture to it.
  1961. /// Paragraph p = document.InsertParagraph("Привет мир").Culture(CultureInfo.CreateSpecificCulture("ru-RU"));
  1962. ///
  1963. /// // Save this document.
  1964. /// document.Save();
  1965. /// }
  1966. /// </code>
  1967. /// </example>
  1968. public Paragraph Culture(CultureInfo culture)
  1969. {
  1970. ApplyTextFormattingProperty(XName.Get("lang", DocX.w.NamespaceName), string.Empty,
  1971. new XAttribute(XName.Get("val", DocX.w.NamespaceName), culture.Name));
  1972. return this;
  1973. }
  1974. /// <summary>
  1975. /// Append text to this Paragraph.
  1976. /// </summary>
  1977. /// <param name="text">The text to append.</param>
  1978. /// <returns>This Paragraph with the new text appened.</returns>
  1979. /// <example>
  1980. /// Add a new Paragraph to this document and then append some text to it.
  1981. /// <code>
  1982. /// // Load a document.
  1983. /// using (DocX document = DocX.Create(@"Test.docx"))
  1984. /// {
  1985. /// // Insert a new Paragraph and Append some text to it.
  1986. /// Paragraph p = document.InsertParagraph().Append("Hello World!!!");
  1987. ///
  1988. /// // Save this document.
  1989. /// document.Save();
  1990. /// }
  1991. /// </code>
  1992. /// </example>
  1993. public Paragraph Append(string text)
  1994. {
  1995. List<XElement> newRuns = HelperFunctions.FormatInput(text, null);
  1996. Xml.Add(newRuns);
  1997. this.runs = Xml.Elements(XName.Get("r", DocX.w.NamespaceName)).Reverse().Take(newRuns.Count()).ToList();
  1998. return this;
  1999. }
  2000. public void InsertHorizontalLine(string lineType = "single", int size = 6, int space = 1, string color = "auto")
  2001. {
  2002. var pPr = this.GetOrCreate_pPr();
  2003. var border = pPr.Element(XName.Get("pBdr", DocX.w.NamespaceName));
  2004. if (border == null)
  2005. {
  2006. pPr.Add(new XElement(XName.Get("pBdr", DocX.w.NamespaceName)));
  2007. border = pPr.Element(XName.Get("pBdr", DocX.w.NamespaceName));
  2008. border.Add(new XElement(XName.Get("bottom", DocX.w.NamespaceName)));
  2009. var bottom = border.Element(XName.Get("bottom", DocX.w.NamespaceName));
  2010. bottom.SetAttributeValue(XName.Get("val", DocX.w.NamespaceName), lineType);
  2011. bottom.SetAttributeValue(XName.Get("sz", DocX.w.NamespaceName), size.ToString());
  2012. bottom.SetAttributeValue(XName.Get("space", DocX.w.NamespaceName), space.ToString());
  2013. bottom.SetAttributeValue(XName.Get("color", DocX.w.NamespaceName), color);
  2014. }
  2015. }
  2016. /// <summary>
  2017. /// Append a hyperlink to a Paragraph.
  2018. /// </summary>
  2019. /// <param name="h">The hyperlink to append.</param>
  2020. /// <returns>The Paragraph with the hyperlink appended.</returns>
  2021. /// <example>
  2022. /// Creates a Paragraph with some text and a hyperlink.
  2023. /// <code>
  2024. /// // Create a document.
  2025. /// using (DocX document = DocX.Create(@"Test.docx"))
  2026. /// {
  2027. /// // Add a hyperlink to this document.
  2028. /// Hyperlink h = document.AddHyperlink("Google", new Uri("http://www.google.com"));
  2029. ///
  2030. /// // Add a new Paragraph to this document.
  2031. /// Paragraph p = document.InsertParagraph();
  2032. /// p.Append("My favourite search engine is ");
  2033. /// p.AppendHyperlink(h);
  2034. /// p.Append(", I think it's great.");
  2035. ///
  2036. /// // Save all changes made to this document.
  2037. /// document.Save();
  2038. /// }
  2039. /// </code>
  2040. /// </example>
  2041. public Paragraph AppendHyperlink(Hyperlink h)
  2042. {
  2043. // Convert the path of this mainPart to its equilivant rels file path.
  2044. string path = mainPart.Uri.OriginalString.Replace("/word/", "");
  2045. Uri rels_path = new Uri("/word/_rels/" + path + ".rels", UriKind.Relative);
  2046. // Check to see if the rels file exists and create it if not.
  2047. if (!Document.package.PartExists(rels_path))
  2048. HelperFunctions.CreateRelsPackagePart(Document, rels_path);
  2049. // Check to see if a rel for this Hyperlink exists, create it if not.
  2050. var Id = GetOrGenerateRel(h);
  2051. Xml.Add(h.Xml);
  2052. Xml.Elements().Last().SetAttributeValue(DocX.r + "id", Id);
  2053. this.runs = Xml.Elements().Last().Elements(XName.Get("r", DocX.w.NamespaceName)).ToList();
  2054. return this;
  2055. }
  2056. /// <summary>
  2057. /// Add an image to a document, create a custom view of that image (picture) and then insert it into a Paragraph using append.
  2058. /// </summary>
  2059. /// <param name="p">The Picture to append.</param>
  2060. /// <returns>The Paragraph with the Picture now appended.</returns>
  2061. /// <example>
  2062. /// Add an image to a document, create a custom view of that image (picture) and then insert it into a Paragraph using append.
  2063. /// <code>
  2064. /// using (DocX document = DocX.Create("Test.docx"))
  2065. /// {
  2066. /// // Add an image to the document.
  2067. /// Image i = document.AddImage(@"Image.jpg");
  2068. ///
  2069. /// // Create a picture i.e. (A custom view of an image)
  2070. /// Picture p = i.CreatePicture();
  2071. /// p.FlipHorizontal = true;
  2072. /// p.Rotation = 10;
  2073. ///
  2074. /// // Create a new Paragraph.
  2075. /// Paragraph par = document.InsertParagraph();
  2076. ///
  2077. /// // Append content to the Paragraph.
  2078. /// par.Append("Here is a cool picture")
  2079. /// .AppendPicture(p)
  2080. /// .Append(" don't you think so?");
  2081. ///
  2082. /// // Save all changes made to this document.
  2083. /// document.Save();
  2084. /// }
  2085. /// </code>
  2086. /// </example>
  2087. public Paragraph AppendPicture(Picture p)
  2088. {
  2089. // Convert the path of this mainPart to its equilivant rels file path.
  2090. string path = mainPart.Uri.OriginalString.Replace("/word/", "");
  2091. Uri rels_path = new Uri("/word/_rels/" + path + ".rels", UriKind.Relative);
  2092. // Check to see if the rels file exists and create it if not.
  2093. if (!Document.package.PartExists(rels_path))
  2094. HelperFunctions.CreateRelsPackagePart(Document, rels_path);
  2095. // Check to see if a rel for this Picture exists, create it if not.
  2096. var Id = GetOrGenerateRel(p);
  2097. // Add the Picture Xml to the end of the Paragragraph Xml.
  2098. Xml.Add(p.Xml);
  2099. // Extract the attribute id from the Pictures Xml.
  2100. XAttribute a_id =
  2101. (
  2102. from e in Xml.Elements().Last().Descendants()
  2103. where e.Name.LocalName.Equals("blip")
  2104. select e.Attribute(XName.Get("embed", "http://schemas.openxmlformats.org/officeDocument/2006/relationships"))
  2105. ).Single();
  2106. // Set its value to the Pictures relationships id.
  2107. a_id.SetValue(Id);
  2108. // For formatting such as .Bold()
  2109. this.runs = Xml.Elements(XName.Get("r", DocX.w.NamespaceName)).Reverse().Take(p.Xml.Elements(XName.Get("r", DocX.w.NamespaceName)).Count()).ToList();
  2110. return this;
  2111. }
  2112. /// <summary>
  2113. /// Add an equation to a document.
  2114. /// </summary>
  2115. /// <param name="equation">The Equation to append.</param>
  2116. /// <returns>The Paragraph with the Equation now appended.</returns>
  2117. /// <example>
  2118. /// Add an equation to a document.
  2119. /// <code>
  2120. /// using (DocX document = DocX.Create("Test.docx"))
  2121. /// {
  2122. /// // Add an equation to the document.
  2123. /// document.AddEquation("x=y+z");
  2124. ///
  2125. /// // Save all changes made to this document.
  2126. /// document.Save();
  2127. /// }
  2128. /// </code>
  2129. /// </example>
  2130. public Paragraph AppendEquation(String equation)
  2131. {
  2132. // Create equation element
  2133. XElement oMathPara =
  2134. new XElement
  2135. (
  2136. XName.Get("oMathPara", DocX.m.NamespaceName),
  2137. new XElement
  2138. (
  2139. XName.Get("oMath", DocX.m.NamespaceName),
  2140. new XElement
  2141. (
  2142. XName.Get("r", DocX.w.NamespaceName),
  2143. new Formatting() { FontFamily = new Font("Cambria Math") }.Xml, // create formatting
  2144. new XElement(XName.Get("t", DocX.m.NamespaceName), equation) // create equation string
  2145. )
  2146. )
  2147. );
  2148. // Add equation element into paragraph xml and update runs collection
  2149. Xml.Add(oMathPara);
  2150. runs = Xml.Elements(XName.Get("oMathPara", DocX.m.NamespaceName)).ToList();
  2151. // Return paragraph with equation
  2152. return this;
  2153. }
  2154. public bool ValidateBookmark(string bookmarkName)
  2155. {
  2156. return GetBookmarks().Any(b => b.Name.Equals(bookmarkName));
  2157. }
  2158. public Paragraph AppendBookmark(String bookmarkName)
  2159. {
  2160. XElement wBookmarkStart = new XElement(
  2161. XName.Get("bookmarkStart", DocX.w.NamespaceName),
  2162. new XAttribute(XName.Get("id", DocX.w.NamespaceName), 0),
  2163. new XAttribute(XName.Get("name", DocX.w.NamespaceName), bookmarkName));
  2164. Xml.Add(wBookmarkStart);
  2165. XElement wBookmarkEnd = new XElement(
  2166. XName.Get("bookmarkEnd", DocX.w.NamespaceName),
  2167. new XAttribute(XName.Get("id", DocX.w.NamespaceName), 0),
  2168. new XAttribute(XName.Get("name", DocX.w.NamespaceName), bookmarkName));
  2169. Xml.Add(wBookmarkEnd);
  2170. return this;
  2171. }
  2172. public IEnumerable<Bookmark> GetBookmarks()
  2173. {
  2174. return Xml.Descendants(XName.Get("bookmarkStart", DocX.w.NamespaceName))
  2175. .Select(x => x.Attribute(XName.Get("name", DocX.w.NamespaceName)))
  2176. .Select(x => new Bookmark
  2177. {
  2178. Name = x.Value,
  2179. Paragraph = this
  2180. });
  2181. }
  2182. public void InsertAtBookmark(string toInsert, string bookmarkName)
  2183. {
  2184. var bookmark = Xml.Descendants(XName.Get("bookmarkStart", DocX.w.NamespaceName))
  2185. .Where(x => x.Attribute(XName.Get("name", DocX.w.NamespaceName)).Value == bookmarkName).SingleOrDefault();
  2186. if (bookmark != null)
  2187. {
  2188. var run = HelperFunctions.FormatInput(toInsert, null);
  2189. bookmark.AddBeforeSelf(run);
  2190. runs = Xml.Elements(XName.Get("r", DocX.w.NamespaceName)).ToList();
  2191. HelperFunctions.RenumberIDs(Document);
  2192. }
  2193. }
  2194. public void ReplaceAtBookmark(string toInsert, string bookmarkName)
  2195. {
  2196. XElement bookmark = Xml.Descendants(XName.Get("bookmarkStart", DocX.w.NamespaceName))
  2197. .Where(x => x.Attribute(XName.Get("name", DocX.w.NamespaceName)).Value == bookmarkName)
  2198. .SingleOrDefault();
  2199. if (bookmark == null)
  2200. return;
  2201. XNode nextNode = bookmark.NextNode;
  2202. XElement nextElement = nextNode as XElement;
  2203. while (nextElement == null || nextElement.Name.NamespaceName != DocX.w.NamespaceName || (nextElement.Name.LocalName != "r" && nextElement.Name.LocalName != "bookmarkEnd"))
  2204. {
  2205. nextNode = nextNode.NextNode;
  2206. nextElement = nextNode as XElement;
  2207. }
  2208. // Check if next element is a bookmarkEnd
  2209. if (nextElement.Name.LocalName == "bookmarkEnd")
  2210. {
  2211. ReplaceAtBookmark_Add(toInsert, bookmark);
  2212. return;
  2213. }
  2214. XElement contentElement = nextElement.Elements(XName.Get("t", DocX.w.NamespaceName)).FirstOrDefault();
  2215. if (contentElement == null)
  2216. {
  2217. ReplaceAtBookmark_Add(toInsert, bookmark);
  2218. return;
  2219. }
  2220. contentElement.Value = toInsert;
  2221. }
  2222. private void ReplaceAtBookmark_Add(string toInsert, XElement bookmark)
  2223. {
  2224. var run = HelperFunctions.FormatInput(toInsert, null);
  2225. bookmark.AddAfterSelf(run);
  2226. runs = Xml.Elements(XName.Get("r", DocX.w.NamespaceName)).ToList();
  2227. HelperFunctions.RenumberIDs(Document);
  2228. }
  2229. internal string GetOrGenerateRel(Picture p)
  2230. {
  2231. string image_uri_string = p.img.pr.TargetUri.OriginalString;
  2232. // Search for a relationship with a TargetUri that points at this Image.
  2233. string id = null;
  2234. foreach (var r in mainPart.GetRelationshipsByType(DocX.relationshipImage))
  2235. {
  2236. if (string.Equals(r.TargetUri.OriginalString, image_uri_string, StringComparison.Ordinal))
  2237. {
  2238. id = r.Id;
  2239. break;
  2240. }
  2241. }
  2242. // If such a relation doesn't exist, create one.
  2243. if (id == null)
  2244. {
  2245. // Check to see if a relationship for this Picture exists and create it if not.
  2246. PackageRelationship pr = mainPart.CreateRelationship(p.img.pr.TargetUri, TargetMode.Internal, DocX.relationshipImage);
  2247. id = pr.Id;
  2248. }
  2249. return id;
  2250. }
  2251. internal string GetOrGenerateRel(Hyperlink h)
  2252. {
  2253. string image_uri_string = h.Uri.OriginalString;
  2254. // Search for a relationship with a TargetUri that points at this Image.
  2255. var Id =
  2256. (
  2257. from r in mainPart.GetRelationshipsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink")
  2258. where r.TargetUri.OriginalString == image_uri_string
  2259. select r.Id
  2260. ).SingleOrDefault();
  2261. // If such a relation dosen't exist, create one.
  2262. if (Id == null)
  2263. {
  2264. // Check to see if a relationship for this Picture exists and create it if not.
  2265. PackageRelationship pr = mainPart.CreateRelationship(h.Uri, TargetMode.External, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink");
  2266. Id = pr.Id;
  2267. }
  2268. return Id;
  2269. }
  2270. /// <summary>
  2271. /// Insert a Picture into a Paragraph at the given text index.
  2272. /// If not index is provided defaults to 0.
  2273. /// </summary>
  2274. /// <param name="p">The Picture to insert.</param>
  2275. /// <param name="index">The text index to insert at.</param>
  2276. /// <returns>The modified Paragraph.</returns>
  2277. /// <example>
  2278. /// <code>
  2279. ///Load test document.
  2280. ///using (DocX document = DocX.Create("Test.docx"))
  2281. ///{
  2282. /// // Add Headers and Footers into this document.
  2283. /// document.AddHeaders();
  2284. /// document.AddFooters();
  2285. /// document.DifferentFirstPage = true;
  2286. /// document.DifferentOddAndEvenPages = true;
  2287. ///
  2288. /// // Add an Image to this document.
  2289. /// Novacode.Image img = document.AddImage(directory_documents + "purple.png");
  2290. ///
  2291. /// // Create a Picture from this Image.
  2292. /// Picture pic = img.CreatePicture();
  2293. ///
  2294. /// // Main document.
  2295. /// Paragraph p0 = document.InsertParagraph("Hello");
  2296. /// p0.InsertPicture(pic, 3);
  2297. ///
  2298. /// // Header first.
  2299. /// Paragraph p1 = document.Headers.first.InsertParagraph("----");
  2300. /// p1.InsertPicture(pic, 2);
  2301. ///
  2302. /// // Header odd.
  2303. /// Paragraph p2 = document.Headers.odd.InsertParagraph("----");
  2304. /// p2.InsertPicture(pic, 2);
  2305. ///
  2306. /// // Header even.
  2307. /// Paragraph p3 = document.Headers.even.InsertParagraph("----");
  2308. /// p3.InsertPicture(pic, 2);
  2309. ///
  2310. /// // Footer first.
  2311. /// Paragraph p4 = document.Footers.first.InsertParagraph("----");
  2312. /// p4.InsertPicture(pic, 2);
  2313. ///
  2314. /// // Footer odd.
  2315. /// Paragraph p5 = document.Footers.odd.InsertParagraph("----");
  2316. /// p5.InsertPicture(pic, 2);
  2317. ///
  2318. /// // Footer even.
  2319. /// Paragraph p6 = document.Footers.even.InsertParagraph("----");
  2320. /// p6.InsertPicture(pic, 2);
  2321. ///
  2322. /// // Save this document.
  2323. /// document.Save();
  2324. ///}
  2325. /// </code>
  2326. /// </example>
  2327. public Paragraph InsertPicture(Picture p, int index = 0)
  2328. {
  2329. // Convert the path of this mainPart to its equilivant rels file path.
  2330. string path = mainPart.Uri.OriginalString.Replace("/word/", "");
  2331. Uri rels_path = new Uri("/word/_rels/" + path + ".rels", UriKind.Relative);
  2332. // Check to see if the rels file exists and create it if not.
  2333. if (!Document.package.PartExists(rels_path))
  2334. HelperFunctions.CreateRelsPackagePart(Document, rels_path);
  2335. // Check to see if a rel for this Picture exists, create it if not.
  2336. var Id = GetOrGenerateRel(p);
  2337. XElement p_xml;
  2338. if (index == 0)
  2339. {
  2340. // Add this hyperlink as the last element.
  2341. Xml.AddFirst(p.Xml);
  2342. // Extract the picture back out of the DOM.
  2343. p_xml = (XElement)Xml.FirstNode;
  2344. }
  2345. else
  2346. {
  2347. // Get the first run effected by this Insert
  2348. Run run = GetFirstRunEffectedByEdit(index);
  2349. if (run == null)
  2350. {
  2351. // Add this picture as the last element.
  2352. Xml.Add(p.Xml);
  2353. // Extract the picture back out of the DOM.
  2354. p_xml = (XElement)Xml.LastNode;
  2355. }
  2356. else
  2357. {
  2358. // Split this run at the point you want to insert
  2359. XElement[] splitRun = Run.SplitRun(run, index);
  2360. // Replace the origional run.
  2361. run.Xml.ReplaceWith
  2362. (
  2363. splitRun[0],
  2364. p.Xml,
  2365. splitRun[1]
  2366. );
  2367. // Get the first run effected by this Insert
  2368. run = GetFirstRunEffectedByEdit(index);
  2369. // The picture has to be the next element, extract it back out of the DOM.
  2370. p_xml = (XElement)run.Xml.NextNode;
  2371. }
  2372. }
  2373. // Extract the attribute id from the Pictures Xml.
  2374. XAttribute a_id =
  2375. (
  2376. from e in p_xml.Descendants()
  2377. where e.Name.LocalName.Equals("blip")
  2378. select e.Attribute(XName.Get("embed", "http://schemas.openxmlformats.org/officeDocument/2006/relationships"))
  2379. ).Single();
  2380. // Set its value to the Pictures relationships id.
  2381. a_id.SetValue(Id);
  2382. return this;
  2383. }
  2384. /// <summary>
  2385. /// Append text on a new line to this Paragraph.
  2386. /// </summary>
  2387. /// <param name="text">The text to append.</param>
  2388. /// <returns>This Paragraph with the new text appened.</returns>
  2389. /// <example>
  2390. /// Add a new Paragraph to this document and then append a new line with some text to it.
  2391. /// <code>
  2392. /// // Load a document.
  2393. /// using (DocX document = DocX.Create(@"Test.docx"))
  2394. /// {
  2395. /// // Insert a new Paragraph and Append a new line with some text to it.
  2396. /// Paragraph p = document.InsertParagraph().AppendLine("Hello World!!!");
  2397. ///
  2398. /// // Save this document.
  2399. /// document.Save();
  2400. /// }
  2401. /// </code>
  2402. /// </example>
  2403. public Paragraph AppendLine(string text)
  2404. {
  2405. return Append("\n" + text);
  2406. }
  2407. /// <summary>
  2408. /// Append a new line to this Paragraph.
  2409. /// </summary>
  2410. /// <returns>This Paragraph with a new line appeneded.</returns>
  2411. /// <example>
  2412. /// Add a new Paragraph to this document and then append a new line to it.
  2413. /// <code>
  2414. /// // Load a document.
  2415. /// using (DocX document = DocX.Create(@"Test.docx"))
  2416. /// {
  2417. /// // Insert a new Paragraph and Append a new line with some text to it.
  2418. /// Paragraph p = document.InsertParagraph().AppendLine();
  2419. ///
  2420. /// // Save this document.
  2421. /// document.Save();
  2422. /// }
  2423. /// </code>
  2424. /// </example>
  2425. public Paragraph AppendLine()
  2426. {
  2427. return Append("\n");
  2428. }
  2429. internal void ApplyTextFormattingProperty(XName textFormatPropName, string value, object content)
  2430. {
  2431. XElement rPr = null;
  2432. if (runs.Count == 0)
  2433. {
  2434. XElement pPr = Xml.Element(XName.Get("pPr", DocX.w.NamespaceName));
  2435. if (pPr == null)
  2436. {
  2437. Xml.AddFirst(new XElement(XName.Get("pPr", DocX.w.NamespaceName)));
  2438. pPr = Xml.Element(XName.Get("pPr", DocX.w.NamespaceName));
  2439. }
  2440. rPr = pPr.Element(XName.Get("rPr", DocX.w.NamespaceName));
  2441. if (rPr == null)
  2442. {
  2443. pPr.AddFirst(new XElement(XName.Get("rPr", DocX.w.NamespaceName)));
  2444. rPr = pPr.Element(XName.Get("rPr", DocX.w.NamespaceName));
  2445. }
  2446. rPr.SetElementValue(textFormatPropName, value);
  2447. var last = rPr.Elements(textFormatPropName).Last();
  2448. if (content as XAttribute != null)//If content is an attribute
  2449. {
  2450. if (last.Attribute(((XAttribute)(content)).Name) == null)
  2451. {
  2452. last.Add(content); //Add this attribute if element doesn't have it
  2453. }
  2454. else
  2455. {
  2456. last.Attribute(((XAttribute)(content)).Name).Value = ((XAttribute)(content)).Value; //Apply value only if element already has it
  2457. }
  2458. }
  2459. return;
  2460. }
  2461. var contentIsListOfFontProperties = false;
  2462. var fontProps = content as IEnumerable;
  2463. if (fontProps != null)
  2464. {
  2465. foreach (object property in fontProps)
  2466. {
  2467. contentIsListOfFontProperties = (property as XAttribute != null);
  2468. }
  2469. }
  2470. foreach (XElement run in runs)
  2471. {
  2472. rPr = run.Element(XName.Get("rPr", DocX.w.NamespaceName));
  2473. if (rPr == null)
  2474. {
  2475. run.AddFirst(new XElement(XName.Get("rPr", DocX.w.NamespaceName)));
  2476. rPr = run.Element(XName.Get("rPr", DocX.w.NamespaceName));
  2477. }
  2478. rPr.SetElementValue(textFormatPropName, value);
  2479. XElement last = rPr.Elements(textFormatPropName).Last();
  2480. if (contentIsListOfFontProperties) //if content is a list of attributes, as in the case when specifying a font family
  2481. {
  2482. foreach (object property in fontProps)
  2483. {
  2484. if (last.Attribute(((XAttribute)(property)).Name) == null)
  2485. {
  2486. last.Add(property); //Add this attribute if element doesn't have it
  2487. }
  2488. else
  2489. {
  2490. last.Attribute(((XAttribute)(property)).Name).Value =
  2491. ((XAttribute)(property)).Value; //Apply value only if element already has it
  2492. }
  2493. }
  2494. }
  2495. if (content as XAttribute != null)//If content is an attribute
  2496. {
  2497. if (last.Attribute(((XAttribute)(content)).Name) == null)
  2498. {
  2499. last.Add(content); //Add this attribute if element doesn't have it
  2500. }
  2501. else
  2502. {
  2503. last.Attribute(((XAttribute)(content)).Name).Value = ((XAttribute)(content)).Value; //Apply value only if element already has it
  2504. }
  2505. }
  2506. else
  2507. {
  2508. //IMPORTANT
  2509. //But what to do if it is not?
  2510. }
  2511. }
  2512. }
  2513. /// <summary>
  2514. /// For use with Append() and AppendLine()
  2515. /// </summary>
  2516. /// <returns>This Paragraph with the last appended text bold.</returns>
  2517. /// <example>
  2518. /// Append text to this Paragraph and then make it bold.
  2519. /// <code>
  2520. /// // Create a document.
  2521. /// using (DocX document = DocX.Create(@"Test.docx"))
  2522. /// {
  2523. /// // Insert a new Paragraph.
  2524. /// Paragraph p = document.InsertParagraph();
  2525. ///
  2526. /// p.Append("I am ")
  2527. /// .Append("Bold").Bold()
  2528. /// .Append(" I am not");
  2529. ///
  2530. /// // Save this document.
  2531. /// document.Save();
  2532. /// }// Release this document from memory.
  2533. /// </code>
  2534. /// </example>
  2535. public Paragraph Bold()
  2536. {
  2537. ApplyTextFormattingProperty(XName.Get("b", DocX.w.NamespaceName), string.Empty, null);
  2538. return this;
  2539. }
  2540. /// <summary>
  2541. /// For use with Append() and AppendLine()
  2542. /// </summary>
  2543. /// <returns>This Paragraph with the last appended text italic.</returns>
  2544. /// <example>
  2545. /// Append text to this Paragraph and then make it italic.
  2546. /// <code>
  2547. /// // Create a document.
  2548. /// using (DocX document = DocX.Create(@"Test.docx"))
  2549. /// {
  2550. /// // Insert a new Paragraph.
  2551. /// Paragraph p = document.InsertParagraph();
  2552. ///
  2553. /// p.Append("I am ")
  2554. /// .Append("Italic").Italic()
  2555. /// .Append(" I am not");
  2556. ///
  2557. /// // Save this document.
  2558. /// document.Save();
  2559. /// }// Release this document from memory.
  2560. /// </code>
  2561. /// </example>
  2562. public Paragraph Italic()
  2563. {
  2564. ApplyTextFormattingProperty(XName.Get("i", DocX.w.NamespaceName), string.Empty, null);
  2565. return this;
  2566. }
  2567. /// <summary>
  2568. /// For use with Append() and AppendLine()
  2569. /// </summary>
  2570. /// <param name="c">A color to use on the appended text.</param>
  2571. /// <returns>This Paragraph with the last appended text colored.</returns>
  2572. /// <example>
  2573. /// Append text to this Paragraph and then color it.
  2574. /// <code>
  2575. /// // Create a document.
  2576. /// using (DocX document = DocX.Create(@"Test.docx"))
  2577. /// {
  2578. /// // Insert a new Paragraph.
  2579. /// Paragraph p = document.InsertParagraph();
  2580. ///
  2581. /// p.Append("I am ")
  2582. /// .Append("Blue").Color(Color.Blue)
  2583. /// .Append(" I am not");
  2584. ///
  2585. /// // Save this document.
  2586. /// document.Save();
  2587. /// }// Release this document from memory.
  2588. /// </code>
  2589. /// </example>
  2590. public Paragraph Color(Color c)
  2591. {
  2592. ApplyTextFormattingProperty(XName.Get("color", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), c.ToHex()));
  2593. return this;
  2594. }
  2595. /// <summary>
  2596. /// For use with Append() and AppendLine()
  2597. /// </summary>
  2598. /// <param name="underlineStyle">The underline style to use for the appended text.</param>
  2599. /// <returns>This Paragraph with the last appended text underlined.</returns>
  2600. /// <example>
  2601. /// Append text to this Paragraph and then underline it.
  2602. /// <code>
  2603. /// // Create a document.
  2604. /// using (DocX document = DocX.Create(@"Test.docx"))
  2605. /// {
  2606. /// // Insert a new Paragraph.
  2607. /// Paragraph p = document.InsertParagraph();
  2608. ///
  2609. /// p.Append("I am ")
  2610. /// .Append("Underlined").UnderlineStyle(UnderlineStyle.doubleLine)
  2611. /// .Append(" I am not");
  2612. ///
  2613. /// // Save this document.
  2614. /// document.Save();
  2615. /// }// Release this document from memory.
  2616. /// </code>
  2617. /// </example>
  2618. public Paragraph UnderlineStyle(UnderlineStyle underlineStyle)
  2619. {
  2620. string value;
  2621. switch (underlineStyle)
  2622. {
  2623. case Novacode.UnderlineStyle.none: value = string.Empty; break;
  2624. case Novacode.UnderlineStyle.singleLine: value = "single"; break;
  2625. case Novacode.UnderlineStyle.doubleLine: value = "double"; break;
  2626. default: value = underlineStyle.ToString(); break;
  2627. }
  2628. ApplyTextFormattingProperty(XName.Get("u", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), value));
  2629. return this;
  2630. }
  2631. private Table followingTable;
  2632. ///<summary>
  2633. /// Returns table following the paragraph. Null if the following element isn't table.
  2634. ///</summary>
  2635. public Table FollowingTable
  2636. {
  2637. get
  2638. {
  2639. return followingTable;
  2640. }
  2641. internal set
  2642. {
  2643. followingTable = value;
  2644. }
  2645. }
  2646. /// <summary>
  2647. /// For use with Append() and AppendLine()
  2648. /// </summary>
  2649. /// <param name="fontSize">The font size to use for the appended text.</param>
  2650. /// <returns>This Paragraph with the last appended text resized.</returns>
  2651. /// <example>
  2652. /// Append text to this Paragraph and then resize it.
  2653. /// <code>
  2654. /// // Create a document.
  2655. /// using (DocX document = DocX.Create(@"Test.docx"))
  2656. /// {
  2657. /// // Insert a new Paragraph.
  2658. /// Paragraph p = document.InsertParagraph();
  2659. ///
  2660. /// p.Append("I am ")
  2661. /// .Append("Big").FontSize(20)
  2662. /// .Append(" I am not");
  2663. ///
  2664. /// // Save this document.
  2665. /// document.Save();
  2666. /// }// Release this document from memory.
  2667. /// </code>
  2668. /// </example>
  2669. public Paragraph FontSize(double fontSize)
  2670. {
  2671. double temp = fontSize * 2;
  2672. if (temp - (int)temp == 0)
  2673. {
  2674. if (!(fontSize > 0 && fontSize < 1639))
  2675. throw new ArgumentException("Size", "Value must be in the range 0 - 1638");
  2676. }
  2677. else
  2678. throw new ArgumentException("Size", "Value must be either a whole or half number, examples: 32, 32.5");
  2679. ApplyTextFormattingProperty(XName.Get("sz", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), fontSize * 2));
  2680. ApplyTextFormattingProperty(XName.Get("szCs", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), fontSize * 2));
  2681. return this;
  2682. }
  2683. /// <summary>
  2684. /// For use with Append() and AppendLine()
  2685. /// </summary>
  2686. /// <param name="fontName">The font to use for the appended text.</param>
  2687. /// <returns>This Paragraph with the last appended text's font changed.</returns>
  2688. public Paragraph Font(string fontName)
  2689. {
  2690. return Font(new Font(fontName));
  2691. }
  2692. /// <summary>
  2693. /// For use with Append() and AppendLine()
  2694. /// </summary>
  2695. /// <param name="fontFamily">The font to use for the appended text.</param>
  2696. /// <returns>This Paragraph with the last appended text's font changed.</returns>
  2697. /// <example>
  2698. /// Append text to this Paragraph and then change its font.
  2699. /// <code>
  2700. /// // Create a document.
  2701. /// using (DocX document = DocX.Create(@"Test.docx"))
  2702. /// {
  2703. /// // Insert a new Paragraph.
  2704. /// Paragraph p = document.InsertParagraph();
  2705. ///
  2706. /// p.Append("I am ")
  2707. /// .Append("Times new roman").Font(new FontFamily("Times new roman"))
  2708. /// .Append(" I am not");
  2709. ///
  2710. /// // Save this document.
  2711. /// document.Save();
  2712. /// }// Release this document from memory.
  2713. /// </code>
  2714. /// </example>
  2715. public Paragraph Font(Font fontFamily)
  2716. {
  2717. ApplyTextFormattingProperty
  2718. (
  2719. XName.Get("rFonts", DocX.w.NamespaceName),
  2720. string.Empty,
  2721. new[]
  2722. {
  2723. new XAttribute(XName.Get("ascii", DocX.w.NamespaceName), fontFamily.Name),
  2724. new XAttribute(XName.Get("hAnsi", DocX.w.NamespaceName), fontFamily.Name), // Added by Maurits Elbers to support non-standard characters. See http://docx.codeplex.com/Thread/View.aspx?ThreadId=70097&ANCHOR#Post453865
  2725. new XAttribute(XName.Get("cs", DocX.w.NamespaceName), fontFamily.Name), // Added by Maurits Elbers to support non-standard characters. See http://docx.codeplex.com/Thread/View.aspx?ThreadId=70097&ANCHOR#Post453865
  2726. new XAttribute(XName.Get("eastAsia", DocX.w.NamespaceName), fontFamily.Name) // DOCX in china #57
  2727. }
  2728. );
  2729. return this;
  2730. }
  2731. /// <summary>
  2732. /// For use with Append() and AppendLine()
  2733. /// </summary>
  2734. /// <param name="capsStyle">The caps style to apply to the last appended text.</param>
  2735. /// <returns>This Paragraph with the last appended text's caps style changed.</returns>
  2736. /// <example>
  2737. /// Append text to this Paragraph and then set it to full caps.
  2738. /// <code>
  2739. /// // Create a document.
  2740. /// using (DocX document = DocX.Create(@"Test.docx"))
  2741. /// {
  2742. /// // Insert a new Paragraph.
  2743. /// Paragraph p = document.InsertParagraph();
  2744. ///
  2745. /// p.Append("I am ")
  2746. /// .Append("Capitalized").CapsStyle(CapsStyle.caps)
  2747. /// .Append(" I am not");
  2748. ///
  2749. /// // Save this document.
  2750. /// document.Save();
  2751. /// }// Release this document from memory.
  2752. /// </code>
  2753. /// </example>
  2754. public Paragraph CapsStyle(CapsStyle capsStyle)
  2755. {
  2756. switch (capsStyle)
  2757. {
  2758. case Novacode.CapsStyle.none:
  2759. break;
  2760. default:
  2761. {
  2762. ApplyTextFormattingProperty(XName.Get(capsStyle.ToString(), DocX.w.NamespaceName), string.Empty, null);
  2763. break;
  2764. }
  2765. }
  2766. return this;
  2767. }
  2768. /// <summary>
  2769. /// For use with Append() and AppendLine()
  2770. /// </summary>
  2771. /// <param name="script">The script style to apply to the last appended text.</param>
  2772. /// <returns>This Paragraph with the last appended text's script style changed.</returns>
  2773. /// <example>
  2774. /// Append text to this Paragraph and then set it to superscript.
  2775. /// <code>
  2776. /// // Create a document.
  2777. /// using (DocX document = DocX.Create(@"Test.docx"))
  2778. /// {
  2779. /// // Insert a new Paragraph.
  2780. /// Paragraph p = document.InsertParagraph();
  2781. ///
  2782. /// p.Append("I am ")
  2783. /// .Append("superscript").Script(Script.superscript)
  2784. /// .Append(" I am not");
  2785. ///
  2786. /// // Save this document.
  2787. /// document.Save();
  2788. /// }// Release this document from memory.
  2789. /// </code>
  2790. /// </example>
  2791. public Paragraph Script(Script script)
  2792. {
  2793. switch (script)
  2794. {
  2795. case Novacode.Script.none:
  2796. break;
  2797. default:
  2798. {
  2799. ApplyTextFormattingProperty(XName.Get("vertAlign", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), script.ToString()));
  2800. break;
  2801. }
  2802. }
  2803. return this;
  2804. }
  2805. /// <summary>
  2806. /// For use with Append() and AppendLine()
  2807. /// </summary>
  2808. ///<param name="highlight">The highlight to apply to the last appended text.</param>
  2809. /// <returns>This Paragraph with the last appended text highlighted.</returns>
  2810. /// <example>
  2811. /// Append text to this Paragraph and then highlight it.
  2812. /// <code>
  2813. /// // Create a document.
  2814. /// using (DocX document = DocX.Create(@"Test.docx"))
  2815. /// {
  2816. /// // Insert a new Paragraph.
  2817. /// Paragraph p = document.InsertParagraph();
  2818. ///
  2819. /// p.Append("I am ")
  2820. /// .Append("highlighted").Highlight(Highlight.green)
  2821. /// .Append(" I am not");
  2822. ///
  2823. /// // Save this document.
  2824. /// document.Save();
  2825. /// }// Release this document from memory.
  2826. /// </code>
  2827. /// </example>
  2828. public Paragraph Highlight(Highlight highlight)
  2829. {
  2830. switch (highlight)
  2831. {
  2832. case Novacode.Highlight.none:
  2833. break;
  2834. default:
  2835. {
  2836. ApplyTextFormattingProperty(XName.Get("highlight", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), highlight.ToString()));
  2837. break;
  2838. }
  2839. }
  2840. return this;
  2841. }
  2842. /// <summary>
  2843. /// For use with Append() and AppendLine()
  2844. /// </summary>
  2845. /// <param name="misc">The miscellaneous property to set.</param>
  2846. /// <returns>This Paragraph with the last appended text changed by a miscellaneous property.</returns>
  2847. /// <example>
  2848. /// Append text to this Paragraph and then apply a miscellaneous property.
  2849. /// <code>
  2850. /// // Create a document.
  2851. /// using (DocX document = DocX.Create(@"Test.docx"))
  2852. /// {
  2853. /// // Insert a new Paragraph.
  2854. /// Paragraph p = document.InsertParagraph();
  2855. ///
  2856. /// p.Append("I am ")
  2857. /// .Append("outlined").Misc(Misc.outline)
  2858. /// .Append(" I am not");
  2859. ///
  2860. /// // Save this document.
  2861. /// document.Save();
  2862. /// }// Release this document from memory.
  2863. /// </code>
  2864. /// </example>
  2865. public Paragraph Misc(Misc misc)
  2866. {
  2867. switch (misc)
  2868. {
  2869. case Novacode.Misc.none:
  2870. break;
  2871. case Novacode.Misc.outlineShadow:
  2872. {
  2873. ApplyTextFormattingProperty(XName.Get("outline", DocX.w.NamespaceName), string.Empty, null);
  2874. ApplyTextFormattingProperty(XName.Get("shadow", DocX.w.NamespaceName), string.Empty, null);
  2875. break;
  2876. }
  2877. case Novacode.Misc.engrave:
  2878. {
  2879. ApplyTextFormattingProperty(XName.Get("imprint", DocX.w.NamespaceName), string.Empty, null);
  2880. break;
  2881. }
  2882. default:
  2883. {
  2884. ApplyTextFormattingProperty(XName.Get(misc.ToString(), DocX.w.NamespaceName), string.Empty, null);
  2885. break;
  2886. }
  2887. }
  2888. return this;
  2889. }
  2890. /// <summary>
  2891. /// For use with Append() and AppendLine()
  2892. /// </summary>
  2893. /// <param name="strikeThrough">The strike through style to used on the last appended text.</param>
  2894. /// <returns>This Paragraph with the last appended text striked.</returns>
  2895. /// <example>
  2896. /// Append text to this Paragraph and then strike it.
  2897. /// <code>
  2898. /// // Create a document.
  2899. /// using (DocX document = DocX.Create(@"Test.docx"))
  2900. /// {
  2901. /// // Insert a new Paragraph.
  2902. /// Paragraph p = document.InsertParagraph();
  2903. ///
  2904. /// p.Append("I am ")
  2905. /// .Append("striked").StrikeThrough(StrikeThrough.doubleStrike)
  2906. /// .Append(" I am not");
  2907. ///
  2908. /// // Save this document.
  2909. /// document.Save();
  2910. /// }// Release this document from memory.
  2911. /// </code>
  2912. /// </example>
  2913. public Paragraph StrikeThrough(StrikeThrough strikeThrough)
  2914. {
  2915. string value;
  2916. switch (strikeThrough)
  2917. {
  2918. case Novacode.StrikeThrough.strike: value = "strike"; break;
  2919. case Novacode.StrikeThrough.doubleStrike: value = "dstrike"; break;
  2920. default: return this;
  2921. }
  2922. ApplyTextFormattingProperty(XName.Get(value, DocX.w.NamespaceName), string.Empty, null);
  2923. return this;
  2924. }
  2925. /// <summary>
  2926. /// For use with Append() and AppendLine()
  2927. /// </summary>
  2928. /// <param name="underlineColor">The underline color to use, if no underline is set, a single line will be used.</param>
  2929. /// <returns>This Paragraph with the last appended text underlined in a color.</returns>
  2930. /// <example>
  2931. /// Append text to this Paragraph and then underline it using a color.
  2932. /// <code>
  2933. /// // Create a document.
  2934. /// using (DocX document = DocX.Create(@"Test.docx"))
  2935. /// {
  2936. /// // Insert a new Paragraph.
  2937. /// Paragraph p = document.InsertParagraph();
  2938. ///
  2939. /// p.Append("I am ")
  2940. /// .Append("color underlined").UnderlineStyle(UnderlineStyle.dotted).UnderlineColor(Color.Orange)
  2941. /// .Append(" I am not");
  2942. ///
  2943. /// // Save this document.
  2944. /// document.Save();
  2945. /// }// Release this document from memory.
  2946. /// </code>
  2947. /// </example>
  2948. public Paragraph UnderlineColor(Color underlineColor)
  2949. {
  2950. foreach (XElement run in runs)
  2951. {
  2952. XElement rPr = run.Element(XName.Get("rPr", DocX.w.NamespaceName));
  2953. if (rPr == null)
  2954. {
  2955. run.AddFirst(new XElement(XName.Get("rPr", DocX.w.NamespaceName)));
  2956. rPr = run.Element(XName.Get("rPr", DocX.w.NamespaceName));
  2957. }
  2958. XElement u = rPr.Element(XName.Get("u", DocX.w.NamespaceName));
  2959. if (u == null)
  2960. {
  2961. rPr.SetElementValue(XName.Get("u", DocX.w.NamespaceName), string.Empty);
  2962. u = rPr.Element(XName.Get("u", DocX.w.NamespaceName));
  2963. u.SetAttributeValue(XName.Get("val", DocX.w.NamespaceName), "single");
  2964. }
  2965. u.SetAttributeValue(XName.Get("color", DocX.w.NamespaceName), underlineColor.ToHex());
  2966. }
  2967. return this;
  2968. }
  2969. /// <summary>
  2970. /// For use with Append() and AppendLine()
  2971. /// </summary>
  2972. /// <returns>This Paragraph with the last appended text hidden.</returns>
  2973. /// <example>
  2974. /// Append text to this Paragraph and then hide it.
  2975. /// <code>
  2976. /// // Create a document.
  2977. /// using (DocX document = DocX.Create(@"Test.docx"))
  2978. /// {
  2979. /// // Insert a new Paragraph.
  2980. /// Paragraph p = document.InsertParagraph();
  2981. ///
  2982. /// p.Append("I am ")
  2983. /// .Append("hidden").Hide()
  2984. /// .Append(" I am not");
  2985. ///
  2986. /// // Save this document.
  2987. /// document.Save();
  2988. /// }// Release this document from memory.
  2989. /// </code>
  2990. /// </example>
  2991. public Paragraph Hide()
  2992. {
  2993. ApplyTextFormattingProperty(XName.Get("vanish", DocX.w.NamespaceName), string.Empty, null);
  2994. return this;
  2995. }
  2996. public float LineSpacing
  2997. {
  2998. get
  2999. {
  3000. XElement pPr = GetOrCreate_pPr();
  3001. XElement spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName));
  3002. if (spacing != null)
  3003. {
  3004. XAttribute line = spacing.Attribute(XName.Get("line", DocX.w.NamespaceName));
  3005. if (line != null)
  3006. {
  3007. float f;
  3008. if (float.TryParse(line.Value, out f))
  3009. return f / 20.0f;
  3010. }
  3011. }
  3012. return 1.1f * 20.0f;
  3013. }
  3014. set
  3015. {
  3016. Spacing(value);
  3017. }
  3018. }
  3019. /// <summary>
  3020. /// Set the linespacing for this paragraph manually.
  3021. /// </summary>
  3022. /// <param name="spacingType">The type of spacing to be set, can be either Before, After or Line (Standard line spacing).</param>
  3023. /// <param name="spacingFloat">A float value of the amount of spacing. Equals the value that van be set in Word using the "Line and Paragraph spacing" button.</param>
  3024. public void SetLineSpacing(LineSpacingType spacingType, float spacingFloat)
  3025. {
  3026. spacingFloat = spacingFloat * 240;
  3027. int spacingValue = (int)spacingFloat;
  3028. var pPr = this.GetOrCreate_pPr();
  3029. var spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName));
  3030. if (spacing == null)
  3031. {
  3032. pPr.Add(new XElement(XName.Get("spacing", DocX.w.NamespaceName)));
  3033. spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName));
  3034. }
  3035. string spacingTypeAttribute = "";
  3036. switch (spacingType)
  3037. {
  3038. case LineSpacingType.Line:
  3039. {
  3040. spacingTypeAttribute = "line";
  3041. break;
  3042. }
  3043. case LineSpacingType.Before:
  3044. {
  3045. spacingTypeAttribute = "before";
  3046. break;
  3047. }
  3048. case LineSpacingType.After:
  3049. {
  3050. spacingTypeAttribute = "after";
  3051. break;
  3052. }
  3053. }
  3054. spacing.SetAttributeValue(XName.Get(spacingTypeAttribute, DocX.w.NamespaceName), spacingValue);
  3055. }
  3056. /// <summary>
  3057. /// Set the linespacing for this paragraph using the Auto value.
  3058. /// </summary>
  3059. /// <param name="spacingType">The type of spacing to be set automatically. Using Auto will set both Before and After. None will remove any linespacing.</param>
  3060. public void SetLineSpacing(LineSpacingTypeAuto spacingType)
  3061. {
  3062. int spacingValue = 100;
  3063. var pPr = this.GetOrCreate_pPr();
  3064. var spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName));
  3065. if (spacingType.Equals(LineSpacingTypeAuto.None))
  3066. {
  3067. if (spacing != null)
  3068. {
  3069. spacing.Remove();
  3070. }
  3071. }
  3072. else
  3073. {
  3074. if (spacing == null)
  3075. {
  3076. pPr.Add(new XElement(XName.Get("spacing", DocX.w.NamespaceName)));
  3077. spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName));
  3078. }
  3079. string spacingTypeAttribute = "";
  3080. string autoSpacingTypeAttribute = "";
  3081. switch (spacingType)
  3082. {
  3083. case LineSpacingTypeAuto.AutoBefore:
  3084. {
  3085. spacingTypeAttribute = "before";
  3086. autoSpacingTypeAttribute = "beforeAutospacing";
  3087. break;
  3088. }
  3089. case LineSpacingTypeAuto.AutoAfter:
  3090. {
  3091. spacingTypeAttribute = "after";
  3092. autoSpacingTypeAttribute = "afterAutospacing";
  3093. break;
  3094. }
  3095. case LineSpacingTypeAuto.Auto:
  3096. {
  3097. spacingTypeAttribute = "before";
  3098. autoSpacingTypeAttribute = "beforeAutospacing";
  3099. spacing.SetAttributeValue(XName.Get("after", DocX.w.NamespaceName), spacingValue);
  3100. spacing.SetAttributeValue(XName.Get("afterAutospacing", DocX.w.NamespaceName), 1);
  3101. break;
  3102. }
  3103. }
  3104. spacing.SetAttributeValue(XName.Get(autoSpacingTypeAttribute, DocX.w.NamespaceName), 1);
  3105. spacing.SetAttributeValue(XName.Get(spacingTypeAttribute, DocX.w.NamespaceName), spacingValue);
  3106. }
  3107. }
  3108. public Paragraph Spacing(double spacing)
  3109. {
  3110. spacing *= 20;
  3111. if (spacing - (int)spacing == 0)
  3112. {
  3113. if (!(spacing > -1585 && spacing < 1585))
  3114. throw new ArgumentException("Spacing", "Value must be in the range: -1584 - 1584");
  3115. }
  3116. else
  3117. throw new ArgumentException("Spacing", "Value must be either a whole or acurate to one decimal, examples: 32, 32.1, 32.2, 32.9");
  3118. ApplyTextFormattingProperty(XName.Get("spacing", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), spacing));
  3119. return this;
  3120. }
  3121. public Paragraph SpacingBefore(double spacingBefore)
  3122. {
  3123. spacingBefore *= 20;
  3124. var pPr = GetOrCreate_pPr();
  3125. var spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName));
  3126. if (spacingBefore > 0)
  3127. {
  3128. if (spacing == null)
  3129. {
  3130. spacing = new XElement(XName.Get("spacing", DocX.w.NamespaceName));
  3131. pPr.Add(spacing);
  3132. }
  3133. var attr = spacing.Attribute(XName.Get("before", DocX.w.NamespaceName));
  3134. if (attr == null)
  3135. spacing.SetAttributeValue(XName.Get("before", DocX.w.NamespaceName), spacingBefore);
  3136. else
  3137. attr.SetValue(spacingBefore);
  3138. }
  3139. if (Math.Abs(spacingBefore) < 0.1f && spacing != null)
  3140. {
  3141. var attr = spacing.Attribute(XName.Get("before", DocX.w.NamespaceName));
  3142. attr.Remove();
  3143. if (!spacing.HasAttributes)
  3144. spacing.Remove();
  3145. }
  3146. return this;
  3147. }
  3148. public Paragraph SpacingAfter(double spacingAfter)
  3149. {
  3150. spacingAfter *= 20;
  3151. var pPr = GetOrCreate_pPr();
  3152. var spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName));
  3153. if (spacingAfter > 0)
  3154. {
  3155. if (spacing == null)
  3156. {
  3157. spacing = new XElement(XName.Get("spacing", DocX.w.NamespaceName));
  3158. pPr.Add(spacing);
  3159. }
  3160. var attr = spacing.Attribute(XName.Get("after", DocX.w.NamespaceName));
  3161. if (attr == null)
  3162. spacing.SetAttributeValue(XName.Get("after", DocX.w.NamespaceName), spacingAfter);
  3163. else
  3164. attr.SetValue(spacingAfter);
  3165. }
  3166. if (Math.Abs(spacingAfter) < 0.1f && spacing != null)
  3167. {
  3168. var attr = spacing.Attribute(XName.Get("after", DocX.w.NamespaceName));
  3169. attr.Remove();
  3170. if (!spacing.HasAttributes)
  3171. spacing.Remove();
  3172. }
  3173. //ApplyTextFormattingProperty(XName.Get("after", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), spacingAfter));
  3174. return this;
  3175. }
  3176. public Paragraph Kerning(int kerning)
  3177. {
  3178. if (!new int?[] { 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72 }.Contains(kerning))
  3179. throw new ArgumentOutOfRangeException("Kerning", "Value must be one of the following: 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48 or 72");
  3180. ApplyTextFormattingProperty(XName.Get("kern", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), kerning * 2));
  3181. return this;
  3182. }
  3183. public Paragraph Position(double position)
  3184. {
  3185. if (!(position > -1585 && position < 1585))
  3186. throw new ArgumentOutOfRangeException("Position", "Value must be in the range -1585 - 1585");
  3187. ApplyTextFormattingProperty(XName.Get("position", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), position * 2));
  3188. return this;
  3189. }
  3190. public Paragraph PercentageScale(int percentageScale)
  3191. {
  3192. if (!(new int?[] { 200, 150, 100, 90, 80, 66, 50, 33 }).Contains(percentageScale))
  3193. throw new ArgumentOutOfRangeException("PercentageScale", "Value must be one of the following: 200, 150, 100, 90, 80, 66, 50 or 33");
  3194. ApplyTextFormattingProperty(XName.Get("w", DocX.w.NamespaceName), string.Empty, new XAttribute(XName.Get("val", DocX.w.NamespaceName), percentageScale));
  3195. return this;
  3196. }
  3197. /// <summary>
  3198. /// Append a field of type document property, this field will display the custom property cp, at the end of this paragraph.
  3199. /// </summary>
  3200. /// <param name="cp">The custom property to display.</param>
  3201. /// <param name="trackChanges"></param>
  3202. /// <param name="f">The formatting to use for this text.</param>
  3203. /// <example>
  3204. /// Create, add and display a custom property in a document.
  3205. /// <code>
  3206. /// // Load a document.
  3207. ///using (DocX document = DocX.Create("CustomProperty_Add.docx"))
  3208. ///{
  3209. /// // Add a few Custom Properties to this document.
  3210. /// document.AddCustomProperty(new CustomProperty("fname", "cathal"));
  3211. /// document.AddCustomProperty(new CustomProperty("age", 24));
  3212. /// document.AddCustomProperty(new CustomProperty("male", true));
  3213. /// document.AddCustomProperty(new CustomProperty("newyear2012", new DateTime(2012, 1, 1)));
  3214. /// document.AddCustomProperty(new CustomProperty("fav_num", 3.141592));
  3215. ///
  3216. /// // Insert a new Paragraph and append a load of DocProperties.
  3217. /// Paragraph p = document.InsertParagraph("fname: ")
  3218. /// .AppendDocProperty(document.CustomProperties["fname"])
  3219. /// .Append(", age: ")
  3220. /// .AppendDocProperty(document.CustomProperties["age"])
  3221. /// .Append(", male: ")
  3222. /// .AppendDocProperty(document.CustomProperties["male"])
  3223. /// .Append(", newyear2012: ")
  3224. /// .AppendDocProperty(document.CustomProperties["newyear2012"])
  3225. /// .Append(", fav_num: ")
  3226. /// .AppendDocProperty(document.CustomProperties["fav_num"]);
  3227. ///
  3228. /// // Save the changes to the document.
  3229. /// document.Save();
  3230. ///}
  3231. /// </code>
  3232. /// </example>
  3233. public Paragraph AppendDocProperty(CustomProperty cp, bool trackChanges = false, Formatting f = null)
  3234. {
  3235. this.InsertDocProperty(cp, trackChanges, f);
  3236. return this;
  3237. }
  3238. /// <summary>
  3239. /// Insert a field of type document property, this field will display the custom property cp, at the end of this paragraph.
  3240. /// </summary>
  3241. /// <param name="cp">The custom property to display.</param>
  3242. /// <param name="trackChanges"></param>
  3243. /// <param name="f">The formatting to use for this text.</param>
  3244. /// <example>
  3245. /// Create, add and display a custom property in a document.
  3246. /// <code>
  3247. /// // Load a document
  3248. /// using (DocX document = DocX.Create(@"Test.docx"))
  3249. /// {
  3250. /// // Create a custom property.
  3251. /// CustomProperty name = new CustomProperty("name", "Cathal Coffey");
  3252. ///
  3253. /// // Add this custom property to this document.
  3254. /// document.AddCustomProperty(name);
  3255. ///
  3256. /// // Create a text formatting.
  3257. /// Formatting f = new Formatting();
  3258. /// f.Bold = true;
  3259. /// f.Size = 14;
  3260. /// f.StrikeThrough = StrickThrough.strike;
  3261. ///
  3262. /// // Insert a new paragraph.
  3263. /// Paragraph p = document.InsertParagraph("Author: ", false, f);
  3264. ///
  3265. /// // Insert a field of type document property to display the custom property name and track this change.
  3266. /// p.InsertDocProperty(name, true, f);
  3267. ///
  3268. /// // Save all changes made to this document.
  3269. /// document.Save();
  3270. /// }// Release this document from memory.
  3271. /// </code>
  3272. /// </example>
  3273. public DocProperty InsertDocProperty(CustomProperty cp, bool trackChanges = false, Formatting f = null)
  3274. {
  3275. XElement f_xml = null;
  3276. if (f != null)
  3277. f_xml = f.Xml;
  3278. XElement e = new XElement
  3279. (
  3280. XName.Get("fldSimple", DocX.w.NamespaceName),
  3281. new XAttribute(XName.Get("instr", DocX.w.NamespaceName), string.Format(@"DOCPROPERTY {0} \* MERGEFORMAT", cp.Name)),
  3282. new XElement(XName.Get("r", DocX.w.NamespaceName),
  3283. new XElement(XName.Get("t", DocX.w.NamespaceName), f_xml, cp.Value))
  3284. );
  3285. XElement xml = e;
  3286. if (trackChanges)
  3287. {
  3288. DateTime now = DateTime.Now;
  3289. DateTime insert_datetime = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0, DateTimeKind.Utc);
  3290. e = CreateEdit(EditType.ins, insert_datetime, e);
  3291. }
  3292. Xml.Add(e);
  3293. return new DocProperty(Document, xml);
  3294. }
  3295. /// <summary>
  3296. /// Removes characters from a Novacode.DocX.Paragraph.
  3297. /// </summary>
  3298. /// <example>
  3299. /// <code>
  3300. /// // Create a document using a relative filename.
  3301. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  3302. /// {
  3303. /// // Iterate through the paragraphs
  3304. /// foreach (Paragraph p in document.Paragraphs)
  3305. /// {
  3306. /// // Remove the first two characters from every paragraph
  3307. /// p.RemoveText(0, 2, false);
  3308. /// }
  3309. ///
  3310. /// // Save all changes made to this document.
  3311. /// document.Save();
  3312. /// }// Release this document from memory.
  3313. /// </code>
  3314. /// </example>
  3315. /// <seealso cref="Paragraph.InsertText(int, string, bool, Formatting)"/>
  3316. /// <seealso cref="Paragraph.InsertText(string, bool, Formatting)"/>
  3317. /// <param name="index">The position to begin deleting characters.</param>
  3318. /// <param name="count">The number of characters to delete</param>
  3319. /// <param name="trackChanges">Track changes</param>
  3320. /// <param name="removeEmptyParagraph">Remove empty paragraph</param>
  3321. public void RemoveText(int index, int count, bool trackChanges = false, bool removeEmptyParagraph = true)
  3322. {
  3323. // Timestamp to mark the start of insert
  3324. DateTime now = DateTime.Now;
  3325. DateTime remove_datetime = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0, DateTimeKind.Utc);
  3326. // The number of characters processed so far
  3327. int processed = 0;
  3328. do
  3329. {
  3330. // Get the first run effected by this Remove
  3331. Run run = GetFirstRunEffectedByEdit(index, EditType.del);
  3332. // The parent of this Run
  3333. XElement parentElement = run.Xml.Parent;
  3334. switch (parentElement.Name.LocalName)
  3335. {
  3336. case "ins":
  3337. {
  3338. XElement[] splitEditBefore = SplitEdit(parentElement, index, EditType.del);
  3339. int min = Math.Min(count - processed, run.Xml.ElementsAfterSelf().Sum(e => GetElementTextLength(e)));
  3340. XElement[] splitEditAfter = SplitEdit(parentElement, index + min, EditType.del);
  3341. XElement temp = SplitEdit(splitEditBefore[1], index + min, EditType.del)[0];
  3342. object middle = CreateEdit(EditType.del, remove_datetime, temp.Elements());
  3343. processed += GetElementTextLength(middle as XElement);
  3344. if (!trackChanges)
  3345. middle = null;
  3346. parentElement.ReplaceWith
  3347. (
  3348. splitEditBefore[0],
  3349. middle,
  3350. splitEditAfter[1]
  3351. );
  3352. processed += GetElementTextLength(middle as XElement);
  3353. break;
  3354. }
  3355. case "del":
  3356. {
  3357. if (trackChanges)
  3358. {
  3359. // You cannot delete from a deletion, advance processed to the end of this del
  3360. processed += GetElementTextLength(parentElement);
  3361. }
  3362. else
  3363. goto case "ins";
  3364. break;
  3365. }
  3366. default:
  3367. {
  3368. XElement[] splitRunBefore = Run.SplitRun(run, index, EditType.del);
  3369. //int min = Math.Min(index + processed + (count - processed), run.EndIndex);
  3370. int min = Math.Min(index + (count - processed), run.EndIndex);
  3371. XElement[] splitRunAfter = Run.SplitRun(run, min, EditType.del);
  3372. object middle = CreateEdit(EditType.del, remove_datetime, new List<XElement>() { Run.SplitRun(new Run(Document, splitRunBefore[1], run.StartIndex + GetElementTextLength(splitRunBefore[0])), min, EditType.del)[0] });
  3373. processed += GetElementTextLength(middle as XElement);
  3374. if (!trackChanges)
  3375. middle = null;
  3376. run.Xml.ReplaceWith
  3377. (
  3378. splitRunBefore[0],
  3379. middle,
  3380. splitRunAfter[1]
  3381. );
  3382. break;
  3383. }
  3384. }
  3385. // Removing of empty paragraph is allowed if text is empty and removeEmptyParagraph=true
  3386. bool removeEmpty = removeEmptyParagraph && GetElementTextLength( parentElement ) == 0;
  3387. if( parentElement.Parent != null )
  3388. {
  3389. // Need to make sure there is another paragraph in parent cell
  3390. removeEmpty &= parentElement.Parent.Name.LocalName == "tc" &&
  3391. parentElement.Parent.Elements( XName.Get( "p", DocX.w.NamespaceName ) ).Count() > 1;
  3392. // Need to make sure there is no drawing element within the parent element.
  3393. // Picture elements contain no text length but they are still content.
  3394. removeEmpty &= parentElement.Descendants( XName.Get( "drawing", DocX.w.NamespaceName ) ).Count() == 0;
  3395. }
  3396. if( removeEmpty )
  3397. parentElement.Remove();
  3398. }
  3399. while (processed < count);
  3400. HelperFunctions.RenumberIDs(Document);
  3401. }
  3402. /// <summary>
  3403. /// Removes characters from a Novacode.DocX.Paragraph.
  3404. /// </summary>
  3405. /// <example>
  3406. /// <code>
  3407. /// // Create a document using a relative filename.
  3408. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  3409. /// {
  3410. /// // Iterate through the paragraphs
  3411. /// foreach (Paragraph p in document.Paragraphs)
  3412. /// {
  3413. /// // Remove all but the first 2 characters from this Paragraph.
  3414. /// p.RemoveText(2, false);
  3415. /// }
  3416. ///
  3417. /// // Save all changes made to this document.
  3418. /// document.Save();
  3419. /// }// Release this document from memory.
  3420. /// </code>
  3421. /// </example>
  3422. /// <seealso cref="Paragraph.InsertText(int, string, bool, Formatting)"/>
  3423. /// <seealso cref="Paragraph.InsertText(string, bool, Formatting)"/>
  3424. /// <param name="index">The position to begin deleting characters.</param>
  3425. /// <param name="trackChanges">Track changes</param>
  3426. public void RemoveText(int index, bool trackChanges = false)
  3427. {
  3428. RemoveText(index, Text.Length - index, trackChanges);
  3429. }
  3430. /// <summary>
  3431. /// Replaces all occurrences of a specified System.String in this instance, with another specified System.String.
  3432. /// </summary>
  3433. /// <example>
  3434. /// <code>
  3435. /// // Load a document using a relative filename.
  3436. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  3437. /// {
  3438. /// // The formatting to match.
  3439. /// Formatting matchFormatting = new Formatting();
  3440. /// matchFormatting.Size = 10;
  3441. /// matchFormatting.Italic = true;
  3442. /// matchFormatting.FontFamily = new FontFamily("Times New Roman");
  3443. ///
  3444. /// // The formatting to apply to the inserted text.
  3445. /// Formatting newFormatting = new Formatting();
  3446. /// newFormatting.Size = 22;
  3447. /// newFormatting.UnderlineStyle = UnderlineStyle.dotted;
  3448. /// newFormatting.Bold = true;
  3449. ///
  3450. /// // Iterate through the paragraphs in this document.
  3451. /// foreach (Paragraph p in document.Paragraphs)
  3452. /// {
  3453. /// /*
  3454. /// * Replace all instances of the string "wrong" with the string "right" and ignore case.
  3455. /// * Each inserted instance of "wrong" should use the Formatting newFormatting.
  3456. /// * Only replace an instance of "wrong" if it is Size 10, Italic and Times New Roman.
  3457. /// * SubsetMatch means that the formatting must contain all elements of the match formatting,
  3458. /// * but it can also contain additional formatting for example Color, UnderlineStyle, etc.
  3459. /// * ExactMatch means it must not contain additional formatting.
  3460. /// */
  3461. /// p.ReplaceText("wrong", "right", false, RegexOptions.IgnoreCase, newFormatting, matchFormatting, MatchFormattingOptions.SubsetMatch);
  3462. /// }
  3463. ///
  3464. /// // Save all changes made to this document.
  3465. /// document.Save();
  3466. /// }// Release this document from memory.
  3467. /// </code>
  3468. /// </example>
  3469. /// <seealso cref="Paragraph.RemoveText(int, int, bool, bool)"/>
  3470. /// <seealso cref="Paragraph.RemoveText(int, bool)"/>
  3471. /// <seealso cref="Paragraph.InsertText(int, string, bool, Formatting)"/>
  3472. /// <seealso cref="Paragraph.InsertText(string, bool, Formatting)"/>
  3473. /// <param name="newValue">A System.String to replace all occurrences of oldValue.</param>
  3474. /// <param name="oldValue">A System.String to be replaced.</param>
  3475. /// <param name="options">A bitwise OR combination of RegexOption enumeration options.</param>
  3476. /// <param name="trackChanges">Track changes</param>
  3477. /// <param name="newFormatting">The formatting to apply to the text being inserted.</param>
  3478. /// <param name="matchFormatting">The formatting that the text must match in order to be replaced.</param>
  3479. /// <param name="fo">How should formatting be matched?</param>
  3480. /// <param name="escapeRegEx">True if the oldValue needs to be escaped, otherwise false. If it represents a valid RegEx pattern this should be false.</param>
  3481. /// <param name="useRegExSubstitutions">True if RegEx-like replace should be performed, i.e. if newValue contains RegEx substitutions. Does not perform named-group substitutions (only numbered groups).</param>
  3482. /// <param name="removeEmptyParagraph">Remove empty paragraph</param>
  3483. public void ReplaceText(string oldValue, string newValue, bool trackChanges = false, RegexOptions options = RegexOptions.None, Formatting newFormatting = null, Formatting matchFormatting = null, MatchFormattingOptions fo = MatchFormattingOptions.SubsetMatch, bool escapeRegEx = true, bool useRegExSubstitutions = false, bool removeEmptyParagraph = true)
  3484. {
  3485. string tText = Text;
  3486. MatchCollection mc = Regex.Matches(tText, escapeRegEx ? Regex.Escape(oldValue) : oldValue, options);
  3487. // Loop through the matches in reverse order
  3488. foreach (Match m in mc.Cast<Match>().Reverse())
  3489. {
  3490. // Assume the formatting matches until proven otherwise.
  3491. bool formattingMatch = true;
  3492. // Does the user want to match formatting?
  3493. if (matchFormatting != null)
  3494. {
  3495. // The number of characters processed so far
  3496. int processed = 0;
  3497. do
  3498. {
  3499. // Get the next run effected
  3500. Run run = GetFirstRunEffectedByEdit(m.Index + processed);
  3501. // Get this runs properties
  3502. XElement rPr = run.Xml.Element(XName.Get("rPr", DocX.w.NamespaceName));
  3503. if (rPr == null)
  3504. rPr = new Formatting().Xml;
  3505. /*
  3506. * Make sure that every formatting element in f.xml is also in this run,
  3507. * if this is not true, then their formatting does not match.
  3508. */
  3509. if (!HelperFunctions.ContainsEveryChildOf(matchFormatting.Xml, rPr, fo))
  3510. {
  3511. formattingMatch = false;
  3512. break;
  3513. }
  3514. // We have processed some characters, so update the counter.
  3515. processed += run.Value.Length;
  3516. } while (processed < m.Length);
  3517. }
  3518. // If the formatting matches, do the replace.
  3519. if (formattingMatch)
  3520. {
  3521. string repl = newValue;
  3522. //perform RegEx substitutions. Only named groups are not supported. Everything else is supported. However character escapes are not covered.
  3523. if (useRegExSubstitutions && !String.IsNullOrEmpty(repl))
  3524. {
  3525. repl = repl.Replace("$&", m.Value);
  3526. if (m.Groups.Count > 0)
  3527. {
  3528. int lastcap = 0;
  3529. for (int k = 0; k < m.Groups.Count; k++)
  3530. {
  3531. var g = m.Groups[k];
  3532. if ((g == null) || (g.Value == ""))
  3533. continue;
  3534. repl = repl.Replace("$" + k.ToString(), g.Value);
  3535. lastcap = k;
  3536. //cannot get named groups ATM
  3537. }
  3538. repl = repl.Replace("$+", m.Groups[lastcap].Value);
  3539. }
  3540. if (m.Index > 0)
  3541. {
  3542. repl = repl.Replace("$`", tText.Substring(0, m.Index));
  3543. }
  3544. if ((m.Index + m.Length) < tText.Length)
  3545. {
  3546. repl = repl.Replace("$'", tText.Substring(m.Index + m.Length));
  3547. }
  3548. repl = repl.Replace("$_", tText);
  3549. repl = repl.Replace("$$", "$");
  3550. }
  3551. if (!String.IsNullOrEmpty(repl))
  3552. InsertText(m.Index + m.Length, repl, trackChanges, newFormatting);
  3553. if (m.Length > 0)
  3554. RemoveText(m.Index, m.Length, trackChanges, removeEmptyParagraph);
  3555. }
  3556. }
  3557. }
  3558. /// <summary>
  3559. /// Find pattern regex must return a group match.
  3560. /// </summary>
  3561. /// <param name="findPattern">Regex pattern that must include one group match. ie (.*)</param>
  3562. /// <param name="regexMatchHandler">A func that accepts the matching find grouping text and returns a replacement value</param>
  3563. /// <param name="trackChanges"></param>
  3564. /// <param name="options"></param>
  3565. /// <param name="newFormatting"></param>
  3566. /// <param name="matchFormatting"></param>
  3567. /// <param name="fo"></param>
  3568. /// <param name="removeEmptyParagraph">Remove empty paragraph</param>
  3569. public void ReplaceText(string findPattern, Func<string, string> regexMatchHandler, bool trackChanges = false, RegexOptions options = RegexOptions.None, Formatting newFormatting = null, Formatting matchFormatting = null, MatchFormattingOptions fo = MatchFormattingOptions.SubsetMatch, bool removeEmptyParagraph = true)
  3570. {
  3571. var matchCollection = Regex.Matches(Text, findPattern, options);
  3572. // Loop through the matches in reverse order
  3573. foreach (var match in matchCollection.Cast<Match>().Reverse())
  3574. {
  3575. // Assume the formatting matches until proven otherwise.
  3576. bool formattingMatch = true;
  3577. // Does the user want to match formatting?
  3578. if (matchFormatting != null)
  3579. {
  3580. // The number of characters processed so far
  3581. int processed = 0;
  3582. do
  3583. {
  3584. // Get the next run effected
  3585. Run run = GetFirstRunEffectedByEdit(match.Index + processed);
  3586. // Get this runs properties
  3587. XElement rPr = run.Xml.Element(XName.Get("rPr", DocX.w.NamespaceName));
  3588. if (rPr == null)
  3589. rPr = new Formatting().Xml;
  3590. /*
  3591. * Make sure that every formatting element in f.xml is also in this run,
  3592. * if this is not true, then their formatting does not match.
  3593. */
  3594. if (!HelperFunctions.ContainsEveryChildOf(matchFormatting.Xml, rPr, fo))
  3595. {
  3596. formattingMatch = false;
  3597. break;
  3598. }
  3599. // We have processed some characters, so update the counter.
  3600. processed += run.Value.Length;
  3601. } while (processed < match.Length);
  3602. }
  3603. // If the formatting matches, do the replace.
  3604. if (formattingMatch)
  3605. {
  3606. var newValue = regexMatchHandler.Invoke(match.Groups[1].Value);
  3607. InsertText(match.Index + match.Value.Length, newValue, trackChanges, newFormatting);
  3608. RemoveText(match.Index, match.Value.Length, trackChanges, removeEmptyParagraph);
  3609. }
  3610. }
  3611. }
  3612. /// <summary>
  3613. /// Find all instances of a string in this paragraph and return their indexes in a List.
  3614. /// </summary>
  3615. /// <param name="str">The string to find</param>
  3616. /// <returns>A list of indexes.</returns>
  3617. /// <example>
  3618. /// Find all instances of Hello in this document and insert 'don't' in frount of them.
  3619. /// <code>
  3620. /// // Load a document
  3621. /// using (DocX document = DocX.Load(@"Test.docx"))
  3622. /// {
  3623. /// // Loop through the paragraphs in this document.
  3624. /// foreach(Paragraph p in document.Paragraphs)
  3625. /// {
  3626. /// // Find all instances of 'go' in this paragraph.
  3627. /// <![CDATA[ List<int> ]]> gos = document.FindAll("go");
  3628. ///
  3629. /// /*
  3630. /// * Insert 'don't' in frount of every instance of 'go' in this document to produce 'don't go'.
  3631. /// * An important trick here is to do the inserting in reverse document order. If you inserted
  3632. /// * in document order, every insert would shift the index of the remaining matches.
  3633. /// */
  3634. /// gos.Reverse();
  3635. /// foreach (int index in gos)
  3636. /// {
  3637. /// p.InsertText(index, "don't ", false);
  3638. /// }
  3639. /// }
  3640. ///
  3641. /// // Save all changes made to this document.
  3642. /// document.Save();
  3643. /// }// Release this document from memory.
  3644. /// </code>
  3645. /// </example>
  3646. public List<int> FindAll(string str)
  3647. {
  3648. return FindAll(str, RegexOptions.None);
  3649. }
  3650. /// <summary>
  3651. /// Find all instances of a string in this paragraph and return their indexes in a List.
  3652. /// </summary>
  3653. /// <param name="str">The string to find</param>
  3654. /// <param name="options">The options to use when finding a string match.</param>
  3655. /// <returns>A list of indexes.</returns>
  3656. /// <example>
  3657. /// Find all instances of Hello in this document and insert 'don't' in frount of them.
  3658. /// <code>
  3659. /// // Load a document
  3660. /// using (DocX document = DocX.Load(@"Test.docx"))
  3661. /// {
  3662. /// // Loop through the paragraphs in this document.
  3663. /// foreach(Paragraph p in document.Paragraphs)
  3664. /// {
  3665. /// // Find all instances of 'go' in this paragraph (Ignore case).
  3666. /// <![CDATA[ List<int> ]]> gos = document.FindAll("go", RegexOptions.IgnoreCase);
  3667. ///
  3668. /// /*
  3669. /// * Insert 'don't' in frount of every instance of 'go' in this document to produce 'don't go'.
  3670. /// * An important trick here is to do the inserting in reverse document order. If you inserted
  3671. /// * in document order, every insert would shift the index of the remaining matches.
  3672. /// */
  3673. /// gos.Reverse();
  3674. /// foreach (int index in gos)
  3675. /// {
  3676. /// p.InsertText(index, "don't ", false);
  3677. /// }
  3678. /// }
  3679. ///
  3680. /// // Save all changes made to this document.
  3681. /// document.Save();
  3682. /// }// Release this document from memory.
  3683. /// </code>
  3684. /// </example>
  3685. public List<int> FindAll(string str, RegexOptions options)
  3686. {
  3687. MatchCollection mc = Regex.Matches(this.Text, Regex.Escape(str), options);
  3688. var query =
  3689. (
  3690. from m in mc.Cast<Match>()
  3691. select m.Index
  3692. ).ToList();
  3693. return query;
  3694. }
  3695. /// <summary>
  3696. /// Find all unique instances of the given Regex Pattern
  3697. /// </summary>
  3698. /// <param name="str"></param>
  3699. /// <param name="options"></param>
  3700. /// <returns></returns>
  3701. public List<string> FindAllByPattern(string str, RegexOptions options)
  3702. {
  3703. MatchCollection mc = Regex.Matches(this.Text, str, options);
  3704. var query =
  3705. (
  3706. from m in mc.Cast<Match>()
  3707. select m.Value
  3708. ).ToList();
  3709. return query;
  3710. }
  3711. /// <summary>
  3712. /// Insert a PageNumber place holder into a Paragraph.
  3713. /// This place holder should only be inserted into a Header or Footer Paragraph.
  3714. /// Word will not automatically update this field if it is inserted into a document level Paragraph.
  3715. /// </summary>
  3716. /// <param name="pnf">The PageNumberFormat can be normal: (1, 2, ...) or Roman: (I, II, ...)</param>
  3717. /// <param name="index">The text index to insert this PageNumber place holder at.</param>
  3718. /// <example>
  3719. /// <code>
  3720. /// // Create a new document.
  3721. /// using (DocX document = DocX.Create(@"Test.docx"))
  3722. /// {
  3723. /// // Add Headers to the document.
  3724. /// document.AddHeaders();
  3725. ///
  3726. /// // Get the default Header.
  3727. /// Header header = document.Headers.odd;
  3728. ///
  3729. /// // Insert a Paragraph into the Header.
  3730. /// Paragraph p0 = header.InsertParagraph("Page ( of )");
  3731. ///
  3732. /// // Insert place holders for PageNumber and PageCount into the Header.
  3733. /// // Word will replace these with the correct value for each Page.
  3734. /// p0.InsertPageNumber(PageNumberFormat.normal, 6);
  3735. /// p0.InsertPageCount(PageNumberFormat.normal, 11);
  3736. ///
  3737. /// // Save the document.
  3738. /// document.Save();
  3739. /// }
  3740. /// </code>
  3741. /// </example>
  3742. /// <seealso cref="AppendPageCount"/>
  3743. /// <seealso cref="AppendPageNumber"/>
  3744. /// <seealso cref="InsertPageCount"/>
  3745. public void InsertPageNumber(PageNumberFormat pnf, int index = 0)
  3746. {
  3747. XElement fldSimple = new XElement(XName.Get("fldSimple", DocX.w.NamespaceName));
  3748. if (pnf == PageNumberFormat.normal)
  3749. fldSimple.Add(new XAttribute(XName.Get("instr", DocX.w.NamespaceName), @" PAGE \* MERGEFORMAT "));
  3750. else
  3751. fldSimple.Add(new XAttribute(XName.Get("instr", DocX.w.NamespaceName), @" PAGE \* ROMAN \* MERGEFORMAT "));
  3752. XElement content = XElement.Parse
  3753. (
  3754. @"<w:r w:rsidR='001D0226' xmlns:w=""http://schemas.openxmlformats.org/wordprocessingml/2006/main"">
  3755. <w:rPr>
  3756. <w:noProof />
  3757. </w:rPr>
  3758. <w:t>1</w:t>
  3759. </w:r>"
  3760. );
  3761. fldSimple.Add(content);
  3762. if (index == 0)
  3763. Xml.AddFirst(fldSimple);
  3764. else
  3765. {
  3766. Run r = GetFirstRunEffectedByEdit(index, EditType.ins);
  3767. XElement[] splitEdit = SplitEdit(r.Xml, index, EditType.ins);
  3768. r.Xml.ReplaceWith
  3769. (
  3770. splitEdit[0],
  3771. fldSimple,
  3772. splitEdit[1]
  3773. );
  3774. }
  3775. }
  3776. /// <summary>
  3777. /// Append a PageNumber place holder onto the end of a Paragraph.
  3778. /// </summary>
  3779. /// <param name="pnf">The PageNumberFormat can be normal: (1, 2, ...) or Roman: (I, II, ...)</param>
  3780. /// <example>
  3781. /// <code>
  3782. /// // Create a new document.
  3783. /// using (DocX document = DocX.Create(@"Test.docx"))
  3784. /// {
  3785. /// // Add Headers to the document.
  3786. /// document.AddHeaders();
  3787. ///
  3788. /// // Get the default Header.
  3789. /// Header header = document.Headers.odd;
  3790. ///
  3791. /// // Insert a Paragraph into the Header.
  3792. /// Paragraph p0 = header.InsertParagraph();
  3793. ///
  3794. /// // Appemd place holders for PageNumber and PageCount into the Header.
  3795. /// // Word will replace these with the correct value for each Page.
  3796. /// p0.Append("Page (");
  3797. /// p0.AppendPageNumber(PageNumberFormat.normal);
  3798. /// p0.Append(" of ");
  3799. /// p0.AppendPageCount(PageNumberFormat.normal);
  3800. /// p0.Append(")");
  3801. ///
  3802. /// // Save the document.
  3803. /// document.Save();
  3804. /// }
  3805. /// </code>
  3806. /// </example>
  3807. /// <seealso cref="AppendPageCount"/>
  3808. /// <seealso cref="InsertPageNumber"/>
  3809. /// <seealso cref="InsertPageCount"/>
  3810. public void AppendPageNumber(PageNumberFormat pnf)
  3811. {
  3812. XElement fldSimple = new XElement(XName.Get("fldSimple", DocX.w.NamespaceName));
  3813. if (pnf == PageNumberFormat.normal)
  3814. fldSimple.Add(new XAttribute(XName.Get("instr", DocX.w.NamespaceName), @" PAGE \* MERGEFORMAT "));
  3815. else
  3816. fldSimple.Add(new XAttribute(XName.Get("instr", DocX.w.NamespaceName), @" PAGE \* ROMAN \* MERGEFORMAT "));
  3817. XElement content = XElement.Parse
  3818. (
  3819. @"<w:r w:rsidR='001D0226' xmlns:w=""http://schemas.openxmlformats.org/wordprocessingml/2006/main"">
  3820. <w:rPr>
  3821. <w:noProof />
  3822. </w:rPr>
  3823. <w:t>1</w:t>
  3824. </w:r>"
  3825. );
  3826. fldSimple.Add(content);
  3827. Xml.Add(fldSimple);
  3828. }
  3829. /// <summary>
  3830. /// Insert a PageCount place holder into a Paragraph.
  3831. /// This place holder should only be inserted into a Header or Footer Paragraph.
  3832. /// Word will not automatically update this field if it is inserted into a document level Paragraph.
  3833. /// </summary>
  3834. /// <param name="pnf">The PageNumberFormat can be normal: (1, 2, ...) or Roman: (I, II, ...)</param>
  3835. /// <param name="index">The text index to insert this PageCount place holder at.</param>
  3836. /// <example>
  3837. /// <code>
  3838. /// // Create a new document.
  3839. /// using (DocX document = DocX.Create(@"Test.docx"))
  3840. /// {
  3841. /// // Add Headers to the document.
  3842. /// document.AddHeaders();
  3843. ///
  3844. /// // Get the default Header.
  3845. /// Header header = document.Headers.odd;
  3846. ///
  3847. /// // Insert a Paragraph into the Header.
  3848. /// Paragraph p0 = header.InsertParagraph("Page ( of )");
  3849. ///
  3850. /// // Insert place holders for PageNumber and PageCount into the Header.
  3851. /// // Word will replace these with the correct value for each Page.
  3852. /// p0.InsertPageNumber(PageNumberFormat.normal, 6);
  3853. /// p0.InsertPageCount(PageNumberFormat.normal, 11);
  3854. ///
  3855. /// // Save the document.
  3856. /// document.Save();
  3857. /// }
  3858. /// </code>
  3859. /// </example>
  3860. /// <seealso cref="AppendPageCount"/>
  3861. /// <seealso cref="AppendPageNumber"/>
  3862. /// <seealso cref="InsertPageNumber"/>
  3863. public void InsertPageCount(PageNumberFormat pnf, int index = 0)
  3864. {
  3865. XElement fldSimple = new XElement(XName.Get("fldSimple", DocX.w.NamespaceName));
  3866. if (pnf == PageNumberFormat.normal)
  3867. fldSimple.Add(new XAttribute(XName.Get("instr", DocX.w.NamespaceName), @" NUMPAGES \* MERGEFORMAT "));
  3868. else
  3869. fldSimple.Add(new XAttribute(XName.Get("instr", DocX.w.NamespaceName), @" NUMPAGES \* ROMAN \* MERGEFORMAT "));
  3870. XElement content = XElement.Parse
  3871. (
  3872. @"<w:r w:rsidR='001D0226' xmlns:w=""http://schemas.openxmlformats.org/wordprocessingml/2006/main"">
  3873. <w:rPr>
  3874. <w:noProof />
  3875. </w:rPr>
  3876. <w:t>1</w:t>
  3877. </w:r>"
  3878. );
  3879. fldSimple.Add(content);
  3880. if (index == 0)
  3881. Xml.AddFirst(fldSimple);
  3882. else
  3883. {
  3884. Run r = GetFirstRunEffectedByEdit(index, EditType.ins);
  3885. XElement[] splitEdit = SplitEdit(r.Xml, index, EditType.ins);
  3886. r.Xml.ReplaceWith
  3887. (
  3888. splitEdit[0],
  3889. fldSimple,
  3890. splitEdit[1]
  3891. );
  3892. }
  3893. }
  3894. /// <summary>
  3895. /// Append a PageCount place holder onto the end of a Paragraph.
  3896. /// </summary>
  3897. /// <param name="pnf">The PageNumberFormat can be normal: (1, 2, ...) or Roman: (I, II, ...)</param>
  3898. /// <example>
  3899. /// <code>
  3900. /// // Create a new document.
  3901. /// using (DocX document = DocX.Create(@"Test.docx"))
  3902. /// {
  3903. /// // Add Headers to the document.
  3904. /// document.AddHeaders();
  3905. ///
  3906. /// // Get the default Header.
  3907. /// Header header = document.Headers.odd;
  3908. ///
  3909. /// // Insert a Paragraph into the Header.
  3910. /// Paragraph p0 = header.InsertParagraph();
  3911. ///
  3912. /// // Appemd place holders for PageNumber and PageCount into the Header.
  3913. /// // Word will replace these with the correct value for each Page.
  3914. /// p0.Append("Page (");
  3915. /// p0.AppendPageNumber(PageNumberFormat.normal);
  3916. /// p0.Append(" of ");
  3917. /// p0.AppendPageCount(PageNumberFormat.normal);
  3918. /// p0.Append(")");
  3919. ///
  3920. /// // Save the document.
  3921. /// document.Save();
  3922. /// }
  3923. /// </code>
  3924. /// </example>
  3925. /// <seealso cref="AppendPageNumber"/>
  3926. /// <seealso cref="InsertPageNumber"/>
  3927. /// <seealso cref="InsertPageCount"/>
  3928. public void AppendPageCount(PageNumberFormat pnf)
  3929. {
  3930. XElement fldSimple = new XElement(XName.Get("fldSimple", DocX.w.NamespaceName));
  3931. if (pnf == PageNumberFormat.normal)
  3932. fldSimple.Add(new XAttribute(XName.Get("instr", DocX.w.NamespaceName), @" NUMPAGES \* MERGEFORMAT "));
  3933. else
  3934. fldSimple.Add(new XAttribute(XName.Get("instr", DocX.w.NamespaceName), @" NUMPAGES \* ROMAN \* MERGEFORMAT "));
  3935. XElement content = XElement.Parse
  3936. (
  3937. @"<w:r w:rsidR='001D0226' xmlns:w=""http://schemas.openxmlformats.org/wordprocessingml/2006/main"">
  3938. <w:rPr>
  3939. <w:noProof />
  3940. </w:rPr>
  3941. <w:t>1</w:t>
  3942. </w:r>"
  3943. );
  3944. fldSimple.Add(content);
  3945. Xml.Add(fldSimple);
  3946. }
  3947. public float LineSpacingBefore
  3948. {
  3949. get
  3950. {
  3951. XElement pPr = GetOrCreate_pPr();
  3952. XElement spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName));
  3953. if (spacing != null)
  3954. {
  3955. XAttribute line = spacing.Attribute(XName.Get("before", DocX.w.NamespaceName));
  3956. if (line != null)
  3957. {
  3958. float f;
  3959. if (float.TryParse(line.Value, out f))
  3960. return f / 20.0f;
  3961. }
  3962. }
  3963. return 0.0f;
  3964. }
  3965. set
  3966. {
  3967. SpacingBefore(value);
  3968. }
  3969. }
  3970. public float LineSpacingAfter
  3971. {
  3972. get
  3973. {
  3974. XElement pPr = GetOrCreate_pPr();
  3975. XElement spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName));
  3976. if (spacing != null)
  3977. {
  3978. XAttribute line = spacing.Attribute(XName.Get("after", DocX.w.NamespaceName));
  3979. if (line != null)
  3980. {
  3981. float f;
  3982. if (float.TryParse(line.Value, out f))
  3983. return f / 20.0f;
  3984. }
  3985. }
  3986. return 10.0f;
  3987. }
  3988. set
  3989. {
  3990. SpacingAfter(value);
  3991. }
  3992. }
  3993. }
  3994. public class Run : DocXElement
  3995. {
  3996. // A lookup for the text elements in this paragraph
  3997. Dictionary<int, Text> textLookup = new Dictionary<int, Text>();
  3998. private int startIndex;
  3999. private int endIndex;
  4000. private string text;
  4001. /// <summary>
  4002. /// Gets the start index of this Text (text length before this text)
  4003. /// </summary>
  4004. public int StartIndex { get { return startIndex; } }
  4005. /// <summary>
  4006. /// Gets the end index of this Text (text length before this text + this texts length)
  4007. /// </summary>
  4008. public int EndIndex { get { return endIndex; } }
  4009. /// <summary>
  4010. /// The text value of this text element
  4011. /// </summary>
  4012. internal string Value { set { text = value; } get { return text; } }
  4013. internal Run(DocX document, XElement xml, int startIndex)
  4014. : base(document, xml)
  4015. {
  4016. this.startIndex = startIndex;
  4017. // Get the text elements in this run
  4018. IEnumerable<XElement> texts = xml.Descendants();
  4019. int start = startIndex;
  4020. // Loop through each text in this run
  4021. foreach (XElement te in texts)
  4022. {
  4023. switch (te.Name.LocalName)
  4024. {
  4025. case "tab":
  4026. {
  4027. textLookup.Add(start + 1, new Text(Document, te, start));
  4028. text += "\t";
  4029. start++;
  4030. break;
  4031. }
  4032. case "br":
  4033. {
  4034. textLookup.Add(start + 1, new Text(Document, te, start));
  4035. text += "\n";
  4036. start++;
  4037. break;
  4038. }
  4039. case "t": goto case "delText";
  4040. case "delText":
  4041. {
  4042. // Only add strings which are not empty
  4043. if (te.Value.Length > 0)
  4044. {
  4045. textLookup.Add(start + te.Value.Length, new Text(Document, te, start));
  4046. text += te.Value;
  4047. start += te.Value.Length;
  4048. }
  4049. break;
  4050. }
  4051. default: break;
  4052. }
  4053. }
  4054. endIndex = start;
  4055. }
  4056. static internal XElement[] SplitRun(Run r, int index, EditType type = EditType.ins)
  4057. {
  4058. index = index - r.StartIndex;
  4059. Text t = r.GetFirstTextEffectedByEdit(index, type);
  4060. XElement[] splitText = Text.SplitText(t, index);
  4061. XElement splitLeft = new XElement(r.Xml.Name, r.Xml.Attributes(), r.Xml.Element(XName.Get("rPr", DocX.w.NamespaceName)), t.Xml.ElementsBeforeSelf().Where(n => n.Name.LocalName != "rPr"), splitText[0]);
  4062. if (Paragraph.GetElementTextLength(splitLeft) == 0)
  4063. splitLeft = null;
  4064. XElement splitRight = new XElement(r.Xml.Name, r.Xml.Attributes(), r.Xml.Element(XName.Get("rPr", DocX.w.NamespaceName)), splitText[1], t.Xml.ElementsAfterSelf().Where(n => n.Name.LocalName != "rPr"));
  4065. if (Paragraph.GetElementTextLength(splitRight) == 0)
  4066. splitRight = null;
  4067. return
  4068. (
  4069. new XElement[]
  4070. {
  4071. splitLeft,
  4072. splitRight
  4073. }
  4074. );
  4075. }
  4076. internal Text GetFirstTextEffectedByEdit(int index, EditType type = EditType.ins)
  4077. {
  4078. // Make sure we are looking within an acceptable index range.
  4079. if (index < 0 || index > HelperFunctions.GetText(Xml).Length)
  4080. throw new ArgumentOutOfRangeException();
  4081. // Need some memory that can be updated by the recursive search for the XElement to Split.
  4082. int count = 0;
  4083. Text theOne = null;
  4084. GetFirstTextEffectedByEditRecursive(Xml, index, ref count, ref theOne, type);
  4085. return theOne;
  4086. }
  4087. internal void GetFirstTextEffectedByEditRecursive(XElement Xml, int index, ref int count, ref Text theOne, EditType type = EditType.ins)
  4088. {
  4089. count += HelperFunctions.GetSize(Xml);
  4090. if (count > 0 && ((type == EditType.del && count > index) || (type == EditType.ins && count >= index)))
  4091. {
  4092. theOne = new Text(Document, Xml, count - HelperFunctions.GetSize(Xml));
  4093. return;
  4094. }
  4095. if (Xml.HasElements)
  4096. foreach (XElement e in Xml.Elements())
  4097. if (theOne == null)
  4098. GetFirstTextEffectedByEditRecursive(e, index, ref count, ref theOne);
  4099. }
  4100. }
  4101. internal class Text : DocXElement
  4102. {
  4103. private int startIndex;
  4104. private int endIndex;
  4105. private string text;
  4106. /// <summary>
  4107. /// Gets the start index of this Text (text length before this text)
  4108. /// </summary>
  4109. public int StartIndex { get { return startIndex; } }
  4110. /// <summary>
  4111. /// Gets the end index of this Text (text length before this text + this texts length)
  4112. /// </summary>
  4113. public int EndIndex { get { return endIndex; } }
  4114. /// <summary>
  4115. /// The text value of this text element
  4116. /// </summary>
  4117. public string Value { get { return text; } }
  4118. internal Text(DocX document, XElement xml, int startIndex)
  4119. : base(document, xml)
  4120. {
  4121. this.startIndex = startIndex;
  4122. switch (Xml.Name.LocalName)
  4123. {
  4124. case "t":
  4125. {
  4126. goto case "delText";
  4127. }
  4128. case "delText":
  4129. {
  4130. endIndex = startIndex + xml.Value.Length;
  4131. text = xml.Value;
  4132. break;
  4133. }
  4134. case "br":
  4135. {
  4136. text = "\n";
  4137. endIndex = startIndex + 1;
  4138. break;
  4139. }
  4140. case "tab":
  4141. {
  4142. text = "\t";
  4143. endIndex = startIndex + 1;
  4144. break;
  4145. }
  4146. default:
  4147. {
  4148. break;
  4149. }
  4150. }
  4151. }
  4152. internal static XElement[] SplitText(Text t, int index)
  4153. {
  4154. if (index < t.startIndex || index > t.EndIndex)
  4155. throw new ArgumentOutOfRangeException(nameof(index));
  4156. XElement splitLeft = null, splitRight = null;
  4157. if (t.Xml.Name.LocalName == "t" || t.Xml.Name.LocalName == "delText")
  4158. {
  4159. // The origional text element, now containing only the text before the index point.
  4160. splitLeft = new XElement(t.Xml.Name, t.Xml.Attributes(), t.Xml.Value.Substring(0, index - t.startIndex));
  4161. if (splitLeft.Value.Length == 0)
  4162. splitLeft = null;
  4163. else
  4164. PreserveSpace(splitLeft);
  4165. // The origional text element, now containing only the text after the index point.
  4166. splitRight = new XElement(t.Xml.Name, t.Xml.Attributes(), t.Xml.Value.Substring(index - t.startIndex, t.Xml.Value.Length - (index - t.startIndex)));
  4167. if (splitRight.Value.Length == 0)
  4168. splitRight = null;
  4169. else
  4170. PreserveSpace(splitRight);
  4171. }
  4172. else
  4173. {
  4174. if (index == t.EndIndex)
  4175. splitLeft = t.Xml;
  4176. else
  4177. splitRight = t.Xml;
  4178. }
  4179. return
  4180. (
  4181. new XElement[]
  4182. {
  4183. splitLeft,
  4184. splitRight
  4185. }
  4186. );
  4187. }
  4188. /// <summary>
  4189. /// If a text element or delText element, starts or ends with a space,
  4190. /// it must have the attribute space, otherwise it must not have it.
  4191. /// </summary>
  4192. /// <param name="e">The (t or delText) element check</param>
  4193. public static void PreserveSpace(XElement e)
  4194. {
  4195. // PreserveSpace should only be used on (t or delText) elements
  4196. if (!e.Name.Equals(DocX.w + "t") && !e.Name.Equals(DocX.w + "delText"))
  4197. throw new ArgumentException("SplitText can only split elements of type t or delText", "e");
  4198. // Check if this w:t contains a space atribute
  4199. XAttribute space = e.Attributes().Where(a => a.Name.Equals(XNamespace.Xml + "space")).SingleOrDefault();
  4200. // This w:t's text begins or ends with whitespace
  4201. if (e.Value.StartsWith(" ") || e.Value.EndsWith(" "))
  4202. {
  4203. // If this w:t contains no space attribute, add one.
  4204. if (space == null)
  4205. e.Add(new XAttribute(XNamespace.Xml + "space", "preserve"));
  4206. }
  4207. // This w:t's text does not begin or end with a space
  4208. else
  4209. {
  4210. // If this w:r contains a space attribute, remove it.
  4211. if (space != null)
  4212. space.Remove();
  4213. }
  4214. }
  4215. }
  4216. }