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

Paragraph.cs 177KB

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