Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

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