Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

Paragraph.cs 166KB

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