Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

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