You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

XWPFParagraph.java 68KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.xwpf.usermodel;
  16. import java.math.BigInteger;
  17. import java.util.ArrayList;
  18. import java.util.Collections;
  19. import java.util.List;
  20. import java.util.function.Function;
  21. import org.apache.poi.ooxml.POIXMLDocumentPart;
  22. import org.apache.poi.util.Internal;
  23. import org.apache.poi.wp.usermodel.Paragraph;
  24. import org.apache.xmlbeans.XmlCursor;
  25. import org.apache.xmlbeans.XmlObject;
  26. import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
  27. /**
  28. * <p>A Paragraph within a Document, Table, Header etc.</p>
  29. * <p>
  30. * <p>A paragraph has a lot of styling information, but the
  31. * actual text (possibly along with more styling) is held on
  32. * the child {@link XWPFRun}s.</p>
  33. */
  34. public class XWPFParagraph implements IBodyElement, IRunBody, ISDTContents, Paragraph {
  35. private final CTP paragraph;
  36. protected IBody part;
  37. /**
  38. * For access to the document's hyperlink, comments, tables etc
  39. */
  40. protected XWPFDocument document;
  41. protected List<XWPFRun> runs;
  42. protected List<IRunElement> iruns;
  43. private StringBuilder footnoteText = new StringBuilder(64);
  44. public XWPFParagraph(CTP prgrph, IBody part) {
  45. this.paragraph = prgrph;
  46. this.part = part;
  47. this.document = part.getXWPFDocument();
  48. if (document == null) {
  49. throw new NullPointerException();
  50. }
  51. // Build up the character runs
  52. runs = new ArrayList<>();
  53. iruns = new ArrayList<>();
  54. buildRunsInOrderFromXml(paragraph);
  55. // Look for bits associated with the runs
  56. for (XWPFRun run : runs) {
  57. CTR r = run.getCTR();
  58. // Check for bits that only apply when attached to a core document
  59. // TODO Make this nicer by tracking the XWPFFootnotes directly
  60. XmlCursor c = r.newCursor();
  61. c.selectPath("child::*");
  62. while (c.toNextSelection()) {
  63. XmlObject o = c.getObject();
  64. if (o instanceof CTFtnEdnRef) {
  65. CTFtnEdnRef ftn = (CTFtnEdnRef) o;
  66. footnoteText.append(" [").append(ftn.getId()).append(": ");
  67. XWPFAbstractFootnoteEndnote footnote =
  68. ftn.getDomNode().getLocalName().equals("footnoteReference") ?
  69. document.getFootnoteByID(ftn.getId().intValue()) :
  70. document.getEndnoteByID(ftn.getId().intValue());
  71. if (null != footnote) {
  72. boolean first = true;
  73. for (XWPFParagraph p : footnote.getParagraphs()) {
  74. if (!first) {
  75. footnoteText.append("\n");
  76. }
  77. first = false;
  78. footnoteText.append(p.getText());
  79. }
  80. } else {
  81. footnoteText.append("!!! End note with ID \"").append(ftn.getId()).append("\" not found in document.");
  82. }
  83. footnoteText.append("] ");
  84. }
  85. }
  86. c.dispose();
  87. }
  88. }
  89. /**
  90. * Identifies (in order) the parts of the paragraph /
  91. * sub-paragraph that correspond to character text
  92. * runs, and builds the appropriate runs for these.
  93. */
  94. @SuppressWarnings("deprecation")
  95. private void buildRunsInOrderFromXml(XmlObject object) {
  96. XmlCursor c = object.newCursor();
  97. c.selectPath("child::*");
  98. while (c.toNextSelection()) {
  99. XmlObject o = c.getObject();
  100. if (o instanceof CTR) {
  101. XWPFRun r = new XWPFRun((CTR) o, this);
  102. runs.add(r);
  103. iruns.add(r);
  104. }
  105. if (o instanceof CTHyperlink) {
  106. CTHyperlink link = (CTHyperlink)o;
  107. for (CTR r : link.getRArray()) {
  108. XWPFHyperlinkRun hr = new XWPFHyperlinkRun(link, r, this);
  109. runs.add(hr);
  110. iruns.add(hr);
  111. }
  112. }
  113. if (o instanceof CTSimpleField) {
  114. CTSimpleField field = (CTSimpleField)o;
  115. for (CTR r : field.getRArray()) {
  116. XWPFFieldRun fr = new XWPFFieldRun(field, r, this);
  117. runs.add(fr);
  118. iruns.add(fr);
  119. }
  120. }
  121. if (o instanceof CTSdtBlock) {
  122. XWPFSDT cc = new XWPFSDT((CTSdtBlock) o, part);
  123. iruns.add(cc);
  124. }
  125. if (o instanceof CTSdtRun) {
  126. XWPFSDT cc = new XWPFSDT((CTSdtRun) o, part);
  127. iruns.add(cc);
  128. }
  129. if (o instanceof CTRunTrackChange) {
  130. for (CTR r : ((CTRunTrackChange) o).getRArray()) {
  131. XWPFRun cr = new XWPFRun(r, this);
  132. runs.add(cr);
  133. iruns.add(cr);
  134. }
  135. }
  136. if (o instanceof CTSmartTagRun) {
  137. // Smart Tags can be nested many times.
  138. // This implementation does not preserve the tagging information
  139. buildRunsInOrderFromXml(o);
  140. }
  141. if (o instanceof CTRunTrackChange) {
  142. // add all the insertions as text
  143. for (CTRunTrackChange change : ((CTRunTrackChange) o).getInsArray()) {
  144. buildRunsInOrderFromXml(change);
  145. }
  146. }
  147. }
  148. c.dispose();
  149. }
  150. @Internal
  151. public CTP getCTP() {
  152. return paragraph;
  153. }
  154. public List<XWPFRun> getRuns() {
  155. return Collections.unmodifiableList(runs);
  156. }
  157. /**
  158. * Return literal runs and sdt/content control objects.
  159. *
  160. * @return List<IRunElement>
  161. */
  162. public List<IRunElement> getIRuns() {
  163. return Collections.unmodifiableList(iruns);
  164. }
  165. public boolean isEmpty() {
  166. return !paragraph.getDomNode().hasChildNodes();
  167. }
  168. @Override
  169. public XWPFDocument getDocument() {
  170. return document;
  171. }
  172. /**
  173. * Return the textual content of the paragraph, including text from pictures
  174. * and sdt elements in it.
  175. */
  176. public String getText() {
  177. StringBuilder out = new StringBuilder(64);
  178. for (IRunElement run : iruns) {
  179. if (run instanceof XWPFRun) {
  180. XWPFRun xRun = (XWPFRun) run;
  181. // don't include the text if reviewing is enabled and this is a deleted run
  182. if (xRun.getCTR().getDelTextArray().length == 0) {
  183. out.append(xRun);
  184. }
  185. } else if (run instanceof XWPFSDT) {
  186. out.append(((XWPFSDT) run).getContent().getText());
  187. } else {
  188. out.append(run);
  189. }
  190. }
  191. out.append(footnoteText);
  192. return out.toString();
  193. }
  194. /**
  195. * Return styleID of the paragraph if style exist for this paragraph
  196. * if not, null will be returned
  197. *
  198. * @return styleID as String
  199. */
  200. public String getStyleID() {
  201. if (paragraph.getPPr() != null) {
  202. if (paragraph.getPPr().getPStyle() != null) {
  203. if (paragraph.getPPr().getPStyle().getVal() != null) {
  204. return paragraph.getPPr().getPStyle().getVal();
  205. }
  206. }
  207. }
  208. return null;
  209. }
  210. /**
  211. * If style exist for this paragraph
  212. * NumId of the paragraph will be returned.
  213. * If style not exist null will be returned
  214. *
  215. * @return NumID as BigInteger
  216. */
  217. public BigInteger getNumID() {
  218. if (paragraph.getPPr() != null) {
  219. if (paragraph.getPPr().getNumPr() != null) {
  220. if (paragraph.getPPr().getNumPr().getNumId() != null) {
  221. return paragraph.getPPr().getNumPr().getNumId().getVal();
  222. }
  223. }
  224. }
  225. return null;
  226. }
  227. /**
  228. * setNumID of Paragraph
  229. *
  230. * @param numPos
  231. */
  232. public void setNumID(BigInteger numPos) {
  233. if (paragraph.getPPr() == null) {
  234. paragraph.addNewPPr();
  235. }
  236. if (paragraph.getPPr().getNumPr() == null) {
  237. paragraph.getPPr().addNewNumPr();
  238. }
  239. if (paragraph.getPPr().getNumPr().getNumId() == null) {
  240. paragraph.getPPr().getNumPr().addNewNumId();
  241. }
  242. paragraph.getPPr().getNumPr().getNumId().setVal(numPos);
  243. }
  244. /**
  245. * setNumILvl of Paragraph
  246. *
  247. * @param iLvl
  248. * @since 4.1.2
  249. */
  250. public void setNumILvl(BigInteger iLvl) {
  251. if (paragraph.getPPr() == null) {
  252. paragraph.addNewPPr();
  253. }
  254. if (paragraph.getPPr().getNumPr() == null) {
  255. paragraph.getPPr().addNewNumPr();
  256. }
  257. if (paragraph.getPPr().getNumPr().getIlvl() == null) {
  258. paragraph.getPPr().getNumPr().addNewIlvl();
  259. }
  260. paragraph.getPPr().getNumPr().getIlvl().setVal(iLvl);
  261. }
  262. /**
  263. * Returns Ilvl of the numeric style for this paragraph.
  264. * Returns null if this paragraph does not have numeric style.
  265. *
  266. * @return Ilvl as BigInteger
  267. */
  268. public BigInteger getNumIlvl() {
  269. if (paragraph.getPPr() != null) {
  270. if (paragraph.getPPr().getNumPr() != null) {
  271. if (paragraph.getPPr().getNumPr().getIlvl() != null) {
  272. return paragraph.getPPr().getNumPr().getIlvl().getVal();
  273. }
  274. }
  275. }
  276. return null;
  277. }
  278. /**
  279. * Returns numbering format for this paragraph, eg bullet or
  280. * lowerLetter.
  281. * Returns null if this paragraph does not have numeric style.
  282. */
  283. public String getNumFmt() {
  284. BigInteger numID = getNumID();
  285. XWPFNumbering numbering = document.getNumbering();
  286. if (numID != null && numbering != null) {
  287. XWPFNum num = numbering.getNum(numID);
  288. if (num != null) {
  289. BigInteger ilvl = getNumIlvl();
  290. BigInteger abstractNumId = num.getCTNum().getAbstractNumId().getVal();
  291. CTAbstractNum anum = numbering.getAbstractNum(abstractNumId).getAbstractNum();
  292. CTLvl level = null;
  293. for (int i = 0; i < anum.sizeOfLvlArray(); i++) {
  294. CTLvl lvl = anum.getLvlArray(i);
  295. if (lvl.getIlvl().equals(ilvl)) {
  296. level = lvl;
  297. break;
  298. }
  299. }
  300. if (level != null && level.getNumFmt() != null
  301. && level.getNumFmt().getVal() != null) {
  302. return level.getNumFmt().getVal().toString();
  303. }
  304. }
  305. }
  306. return null;
  307. }
  308. /**
  309. * Returns the text that should be used around the paragraph level numbers.
  310. *
  311. * @return a string (e.g. "%1.") or null if the value is not found.
  312. */
  313. public String getNumLevelText() {
  314. BigInteger numID = getNumID();
  315. XWPFNumbering numbering = document.getNumbering();
  316. if (numID != null && numbering != null) {
  317. XWPFNum num = numbering.getNum(numID);
  318. if (num != null) {
  319. BigInteger ilvl = getNumIlvl();
  320. CTNum ctNum = num.getCTNum();
  321. if (ctNum == null) {
  322. return null;
  323. }
  324. CTDecimalNumber ctDecimalNumber = ctNum.getAbstractNumId();
  325. if (ctDecimalNumber == null) {
  326. return null;
  327. }
  328. BigInteger abstractNumId = ctDecimalNumber.getVal();
  329. if (abstractNumId == null) {
  330. return null;
  331. }
  332. XWPFAbstractNum xwpfAbstractNum = numbering.getAbstractNum(abstractNumId);
  333. if (xwpfAbstractNum == null) {
  334. return null;
  335. }
  336. CTAbstractNum anum = xwpfAbstractNum.getCTAbstractNum();
  337. if (anum == null) {
  338. return null;
  339. }
  340. CTLvl level = null;
  341. for (int i = 0; i < anum.sizeOfLvlArray(); i++) {
  342. CTLvl lvl = anum.getLvlArray(i);
  343. if (lvl != null && lvl.getIlvl() != null && lvl.getIlvl().equals(ilvl)) {
  344. level = lvl;
  345. break;
  346. }
  347. }
  348. if (level != null && level.getLvlText() != null
  349. && level.getLvlText().getVal() != null) {
  350. return level.getLvlText().getVal();
  351. }
  352. }
  353. }
  354. return null;
  355. }
  356. /**
  357. * Gets the numstartOverride for the paragraph numbering for this paragraph.
  358. *
  359. * @return returns the overridden start number or null if there is no override for this paragraph.
  360. */
  361. public BigInteger getNumStartOverride() {
  362. BigInteger numID = getNumID();
  363. XWPFNumbering numbering = document.getNumbering();
  364. if (numID != null && numbering != null) {
  365. XWPFNum num = numbering.getNum(numID);
  366. if (num != null) {
  367. CTNum ctNum = num.getCTNum();
  368. if (ctNum == null) {
  369. return null;
  370. }
  371. BigInteger ilvl = getNumIlvl();
  372. CTNumLvl level = null;
  373. for (int i = 0; i < ctNum.sizeOfLvlOverrideArray(); i++) {
  374. CTNumLvl ctNumLvl = ctNum.getLvlOverrideArray(i);
  375. if (ctNumLvl != null && ctNumLvl.getIlvl() != null &&
  376. ctNumLvl.getIlvl().equals(ilvl)) {
  377. level = ctNumLvl;
  378. break;
  379. }
  380. }
  381. if (level != null && level.getStartOverride() != null) {
  382. return level.getStartOverride().getVal();
  383. }
  384. }
  385. }
  386. return null;
  387. }
  388. /**
  389. * Indicates whether this paragraph should be kept on the same page as the next one.
  390. *
  391. * @since POI 4.1.1
  392. */
  393. public boolean isKeepNext() {
  394. if (getCTP() != null && getCTP().getPPr() != null && getCTP().getPPr().isSetKeepNext()) {
  395. return getCTP().getPPr().getKeepNext().getVal() == STOnOff.ON;
  396. }
  397. return false;
  398. }
  399. /**
  400. * Sets this paragraph to be kept on the same page as the next one or not.
  401. *
  402. * @since POI 4.1.1
  403. */
  404. public void setKeepNext(boolean keepNext) {
  405. CTOnOff state = CTOnOff.Factory.newInstance();
  406. state.setVal(keepNext ? STOnOff.ON : STOnOff.OFF);
  407. getCTP().getPPr().setKeepNext(state);
  408. }
  409. /**
  410. * Returns the text of the paragraph, but not of any objects in the
  411. * paragraph
  412. */
  413. public String getParagraphText() {
  414. StringBuilder out = new StringBuilder(64);
  415. for (XWPFRun run : runs) {
  416. out.append(run);
  417. }
  418. return out.toString();
  419. }
  420. /**
  421. * Returns any text from any suitable pictures in the paragraph
  422. */
  423. public String getPictureText() {
  424. StringBuilder out = new StringBuilder(64);
  425. for (XWPFRun run : runs) {
  426. out.append(run.getPictureText());
  427. }
  428. return out.toString();
  429. }
  430. /**
  431. * Returns the footnote text of the paragraph
  432. *
  433. * @return the footnote text or empty string if the paragraph does not have footnotes
  434. */
  435. public String getFootnoteText() {
  436. return footnoteText.toString();
  437. }
  438. /**
  439. * Returns the paragraph alignment which shall be applied to text in this
  440. * paragraph.
  441. * <p>
  442. * <p>
  443. * If this element is not set on a given paragraph, its value is determined
  444. * by the setting previously set at any level of the style hierarchy (i.e.
  445. * that previous setting remains unchanged). If this setting is never
  446. * specified in the style hierarchy, then no alignment is applied to the
  447. * paragraph.
  448. * </p>
  449. *
  450. * @return the paragraph alignment of this paragraph.
  451. */
  452. public ParagraphAlignment getAlignment() {
  453. CTPPr pr = getCTPPr();
  454. return pr == null || !pr.isSetJc() ? ParagraphAlignment.LEFT
  455. : ParagraphAlignment.valueOf(pr.getJc().getVal().intValue());
  456. }
  457. /**
  458. * Specifies the paragraph alignment which shall be applied to text in this
  459. * paragraph.
  460. * <p>
  461. * <p>
  462. * If this element is not set on a given paragraph, its value is determined
  463. * by the setting previously set at any level of the style hierarchy (i.e.
  464. * that previous setting remains unchanged). If this setting is never
  465. * specified in the style hierarchy, then no alignment is applied to the
  466. * paragraph.
  467. * </p>
  468. *
  469. * @param align the paragraph alignment to apply to this paragraph.
  470. */
  471. public void setAlignment(ParagraphAlignment align) {
  472. CTPPr pr = getCTPPr();
  473. CTJc jc = pr.isSetJc() ? pr.getJc() : pr.addNewJc();
  474. STJc.Enum en = STJc.Enum.forInt(align.getValue());
  475. jc.setVal(en);
  476. }
  477. /**
  478. * @return The raw alignment value, {@link #getAlignment()} is suggested
  479. */
  480. @Override
  481. public int getFontAlignment() {
  482. return getAlignment().getValue();
  483. }
  484. @Override
  485. public void setFontAlignment(int align) {
  486. ParagraphAlignment pAlign = ParagraphAlignment.valueOf(align);
  487. setAlignment(pAlign);
  488. }
  489. /**
  490. * Returns the text vertical alignment which shall be applied to text in
  491. * this paragraph.
  492. * <p>
  493. * If the line height (before any added spacing) is larger than one or more
  494. * characters on the line, all characters will be aligned to each other as
  495. * specified by this element.
  496. * </p>
  497. * <p>
  498. * If this element is omitted on a given paragraph, its value is determined
  499. * by the setting previously set at any level of the style hierarchy (i.e.
  500. * that previous setting remains unchanged). If this setting is never
  501. * specified in the style hierarchy, then the vertical alignment of all
  502. * characters on the line shall be automatically determined by the consumer.
  503. * </p>
  504. *
  505. * @return the vertical alignment of this paragraph.
  506. */
  507. public TextAlignment getVerticalAlignment() {
  508. CTPPr pr = getCTPPr();
  509. return (pr == null || !pr.isSetTextAlignment()) ? TextAlignment.AUTO
  510. : TextAlignment.valueOf(pr.getTextAlignment().getVal()
  511. .intValue());
  512. }
  513. /**
  514. * Specifies the text vertical alignment which shall be applied to text in
  515. * this paragraph.
  516. * <p>
  517. * If the line height (before any added spacing) is larger than one or more
  518. * characters on the line, all characters will be aligned to each other as
  519. * specified by this element.
  520. * </p>
  521. * <p>
  522. * If this element is omitted on a given paragraph, its value is determined
  523. * by the setting previously set at any level of the style hierarchy (i.e.
  524. * that previous setting remains unchanged). If this setting is never
  525. * specified in the style hierarchy, then the vertical alignment of all
  526. * characters on the line shall be automatically determined by the consumer.
  527. * </p>
  528. *
  529. * @param valign the paragraph vertical alignment to apply to this
  530. * paragraph.
  531. */
  532. public void setVerticalAlignment(TextAlignment valign) {
  533. CTPPr pr = getCTPPr();
  534. CTTextAlignment textAlignment = pr.isSetTextAlignment() ? pr
  535. .getTextAlignment() : pr.addNewTextAlignment();
  536. STTextAlignment.Enum en = STTextAlignment.Enum
  537. .forInt(valign.getValue());
  538. textAlignment.setVal(en);
  539. }
  540. /**
  541. * Specifies the border which shall be displayed above a set of paragraphs
  542. * which have the same set of paragraph border settings.
  543. *
  544. * @return paragraphBorder - the top border for the paragraph
  545. * @see #setBorderTop(Borders)
  546. * @see Borders a list of all types of borders
  547. */
  548. public Borders getBorderTop() {
  549. CTPBdr border = getCTPBrd(false);
  550. CTBorder ct = null;
  551. if (border != null) {
  552. ct = border.getTop();
  553. }
  554. STBorder.Enum ptrn = (ct != null) ? ct.getVal() : STBorder.NONE;
  555. return Borders.valueOf(ptrn.intValue());
  556. }
  557. /**
  558. * Specifies the border which shall be displayed above a set of paragraphs
  559. * which have the same set of paragraph border settings.
  560. * <p>
  561. * <p>
  562. * To determine if any two adjoining paragraphs shall have an individual top
  563. * and bottom border or a between border, the set of borders on the two
  564. * adjoining paragraphs are compared. If the border information on those two
  565. * paragraphs is identical for all possible paragraphs borders, then the
  566. * between border is displayed. Otherwise, the final paragraph shall use its
  567. * bottom border and the following paragraph shall use its top border,
  568. * respectively. If this border specifies a space attribute, that value
  569. * determines the space above the text (ignoring any spacing above) which
  570. * should be left before this border is drawn, specified in points.
  571. * </p>
  572. * <p>
  573. * If this element is omitted on a given paragraph, its value is determined
  574. * by the setting previously set at any level of the style hierarchy (i.e.
  575. * that previous setting remains unchanged). If this setting is never
  576. * specified in the style hierarchy, then no between border shall be applied
  577. * above identical paragraphs.
  578. * </p>
  579. * <b>This border can only be a line border.</b>
  580. *
  581. * @param border one of the defined Border styles, see {@link Borders}
  582. * @see Borders for a list of all types of borders
  583. */
  584. public void setBorderTop(Borders border) {
  585. CTPBdr ct = getCTPBrd(true);
  586. if (ct == null) {
  587. throw new RuntimeException("invalid paragraph state");
  588. }
  589. CTBorder pr = (ct.isSetTop()) ? ct.getTop() : ct.addNewTop();
  590. if (border.getValue() == Borders.NONE.getValue()) {
  591. ct.unsetTop();
  592. } else {
  593. pr.setVal(STBorder.Enum.forInt(border.getValue()));
  594. }
  595. }
  596. /**
  597. * Specifies the border which shall be displayed below a set of
  598. * paragraphs which have the same set of paragraph border settings.
  599. *
  600. * @return paragraphBorder - the bottom border for the paragraph
  601. * @see #setBorderBottom(Borders)
  602. * @see Borders a list of all types of borders
  603. */
  604. public Borders getBorderBottom() {
  605. CTPBdr border = getCTPBrd(false);
  606. CTBorder ct = null;
  607. if (border != null) {
  608. ct = border.getBottom();
  609. }
  610. STBorder.Enum ptrn = ct != null ? ct.getVal() : STBorder.NONE;
  611. return Borders.valueOf(ptrn.intValue());
  612. }
  613. /**
  614. * Specifies the border which shall be displayed below a set of paragraphs
  615. * which have the same set of paragraph border settings.
  616. * <p>
  617. * To determine if any two adjoining paragraphs shall have an individual top
  618. * and bottom border or a between border, the set of borders on the two
  619. * adjoining paragraphs are compared. If the border information on those two
  620. * paragraphs is identical for all possible paragraphs borders, then the
  621. * between border is displayed. Otherwise, the final paragraph shall use its
  622. * bottom border and the following paragraph shall use its top border,
  623. * respectively. If this border specifies a space attribute, that value
  624. * determines the space after the bottom of the text (ignoring any space
  625. * below) which should be left before this border is drawn, specified in
  626. * points.
  627. * </p>
  628. * <p>
  629. * If this element is omitted on a given paragraph, its value is determined
  630. * by the setting previously set at any level of the style hierarchy (i.e.
  631. * that previous setting remains unchanged). If this setting is never
  632. * specified in the style hierarchy, then no between border shall be applied
  633. * below identical paragraphs.
  634. * </p>
  635. * <b>This border can only be a line border.</b>
  636. *
  637. * @param border one of the defined Border styles, see {@link Borders}
  638. * @see Borders a list of all types of borders
  639. */
  640. public void setBorderBottom(Borders border) {
  641. CTPBdr ct = getCTPBrd(true);
  642. CTBorder pr = ct.isSetBottom() ? ct.getBottom() : ct.addNewBottom();
  643. if (border.getValue() == Borders.NONE.getValue()) {
  644. ct.unsetBottom();
  645. } else {
  646. pr.setVal(STBorder.Enum.forInt(border.getValue()));
  647. }
  648. }
  649. /**
  650. * Specifies the border which shall be displayed on the left side of the
  651. * page around the specified paragraph.
  652. *
  653. * @return ParagraphBorder - the left border for the paragraph
  654. * @see #setBorderLeft(Borders)
  655. * @see Borders for a list of all possible borders
  656. */
  657. public Borders getBorderLeft() {
  658. CTPBdr border = getCTPBrd(false);
  659. CTBorder ct = null;
  660. if (border != null) {
  661. ct = border.getLeft();
  662. }
  663. STBorder.Enum ptrn = ct != null ? ct.getVal() : STBorder.NONE;
  664. return Borders.valueOf(ptrn.intValue());
  665. }
  666. /**
  667. * Specifies the border which shall be displayed on the left side of the
  668. * page around the specified paragraph.
  669. * <p>
  670. * To determine if any two adjoining paragraphs should have a left border
  671. * which spans the full line height or not, the left border shall be drawn
  672. * between the top border or between border at the top (whichever would be
  673. * rendered for the current paragraph), and the bottom border or between
  674. * border at the bottom (whichever would be rendered for the current
  675. * paragraph).
  676. * </p>
  677. * <p>
  678. * If this element is omitted on a given paragraph, its value is determined
  679. * by the setting previously set at any level of the style hierarchy (i.e.
  680. * that previous setting remains unchanged). If this setting is never
  681. * specified in the style hierarchy, then no left border shall be applied.
  682. * </p>
  683. * <b>This border can only be a line border.</b>
  684. *
  685. * @param border one of the defined Border styles, see {@link Borders}
  686. * @see Borders for a list of all possible borders
  687. */
  688. public void setBorderLeft(Borders border) {
  689. CTPBdr ct = getCTPBrd(true);
  690. CTBorder pr = ct.isSetLeft() ? ct.getLeft() : ct.addNewLeft();
  691. if (border.getValue() == Borders.NONE.getValue()) {
  692. ct.unsetLeft();
  693. } else {
  694. pr.setVal(STBorder.Enum.forInt(border.getValue()));
  695. }
  696. }
  697. /**
  698. * Specifies the border which shall be displayed on the right side of the
  699. * page around the specified paragraph.
  700. *
  701. * @return ParagraphBorder - the right border for the paragraph
  702. * @see #setBorderRight(Borders)
  703. * @see Borders for a list of all possible borders
  704. */
  705. public Borders getBorderRight() {
  706. CTPBdr border = getCTPBrd(false);
  707. CTBorder ct = null;
  708. if (border != null) {
  709. ct = border.getRight();
  710. }
  711. STBorder.Enum ptrn = ct != null ? ct.getVal() : STBorder.NONE;
  712. return Borders.valueOf(ptrn.intValue());
  713. }
  714. /**
  715. * Specifies the border which shall be displayed on the right side of the
  716. * page around the specified paragraph.
  717. * <p>
  718. * To determine if any two adjoining paragraphs should have a right border
  719. * which spans the full line height or not, the right border shall be drawn
  720. * between the top border or between border at the top (whichever would be
  721. * rendered for the current paragraph), and the bottom border or between
  722. * border at the bottom (whichever would be rendered for the current
  723. * paragraph).
  724. * </p>
  725. * <p>
  726. * If this element is omitted on a given paragraph, its value is determined
  727. * by the setting previously set at any level of the style hierarchy (i.e.
  728. * that previous setting remains unchanged). If this setting is never
  729. * specified in the style hierarchy, then no right border shall be applied.
  730. * </p>
  731. * <b>This border can only be a line border.</b>
  732. *
  733. * @param border one of the defined Border styles, see {@link Borders}
  734. * @see Borders for a list of all possible borders
  735. */
  736. public void setBorderRight(Borders border) {
  737. CTPBdr ct = getCTPBrd(true);
  738. CTBorder pr = ct.isSetRight() ? ct.getRight() : ct.addNewRight();
  739. if (border.getValue() == Borders.NONE.getValue()) {
  740. ct.unsetRight();
  741. } else {
  742. pr.setVal(STBorder.Enum.forInt(border.getValue()));
  743. }
  744. }
  745. /**
  746. * Specifies the border which shall be displayed between each paragraph in a
  747. * set of paragraphs which have the same set of paragraph border settings.
  748. *
  749. * @return ParagraphBorder - the between border for the paragraph
  750. * @see #setBorderBetween(Borders)
  751. * @see Borders for a list of all possible borders
  752. */
  753. public Borders getBorderBetween() {
  754. CTPBdr border = getCTPBrd(false);
  755. CTBorder ct = null;
  756. if (border != null) {
  757. ct = border.getBetween();
  758. }
  759. STBorder.Enum ptrn = ct != null ? ct.getVal() : STBorder.NONE;
  760. return Borders.valueOf(ptrn.intValue());
  761. }
  762. /**
  763. * Specifies the border which shall be displayed between each paragraph in a
  764. * set of paragraphs which have the same set of paragraph border settings.
  765. * <p>
  766. * To determine if any two adjoining paragraphs should have a between border
  767. * or an individual top and bottom border, the set of borders on the two
  768. * adjoining paragraphs are compared. If the border information on those two
  769. * paragraphs is identical for all possible paragraphs borders, then the
  770. * between border is displayed. Otherwise, each paragraph shall use its
  771. * bottom and top border, respectively. If this border specifies a space
  772. * attribute, that value is ignored - this border is always located at the
  773. * bottom of each paragraph with an identical following paragraph, taking
  774. * into account any space after the line pitch.
  775. * </p>
  776. * <p>
  777. * If this element is omitted on a given paragraph, its value is determined
  778. * by the setting previously set at any level of the style hierarchy (i.e.
  779. * that previous setting remains unchanged). If this setting is never
  780. * specified in the style hierarchy, then no between border shall be applied
  781. * between identical paragraphs.
  782. * </p>
  783. * <b>This border can only be a line border.</b>
  784. *
  785. * @param border one of the defined Border styles, see {@link Borders}
  786. * @see Borders for a list of all possible borders
  787. */
  788. public void setBorderBetween(Borders border) {
  789. CTPBdr ct = getCTPBrd(true);
  790. CTBorder pr = ct.isSetBetween() ? ct.getBetween() : ct.addNewBetween();
  791. if (border.getValue() == Borders.NONE.getValue()) {
  792. ct.unsetBetween();
  793. } else {
  794. pr.setVal(STBorder.Enum.forInt(border.getValue()));
  795. }
  796. }
  797. /**
  798. * Specifies that when rendering this document in a paginated
  799. * view, the contents of this paragraph are rendered on the start of a new
  800. * page in the document.
  801. * <p>
  802. * If this element is omitted on a given paragraph,
  803. * its value is determined by the setting previously set at any level of the
  804. * style hierarchy (i.e. that previous setting remains unchanged). If this
  805. * setting is never specified in the style hierarchy, then this property
  806. * shall not be applied. Since the paragraph is specified to start on a new
  807. * page, it begins page two even though it could have fit on page one.
  808. * </p>
  809. *
  810. * @return boolean - if page break is set
  811. */
  812. public boolean isPageBreak() {
  813. final CTPPr ppr = getCTPPr();
  814. final CTOnOff ctPageBreak = ppr.isSetPageBreakBefore() ? ppr.getPageBreakBefore() : null;
  815. if (ctPageBreak == null) {
  816. return false;
  817. }
  818. return isTruelike(ctPageBreak.getVal());
  819. }
  820. private static boolean isTruelike(final STOnOff.Enum value) {
  821. if (value == null) {
  822. return false;
  823. }
  824. switch (value.intValue()) {
  825. case STOnOff.INT_TRUE:
  826. case STOnOff.INT_X_1:
  827. case STOnOff.INT_ON:
  828. return true;
  829. /*STOnOff.INT_FALSE:
  830. STOnOff.INT_X_0:
  831. STOnOff.INT_OFF:*/
  832. default:
  833. return false;
  834. }
  835. }
  836. /**
  837. * Specifies that when rendering this document in a paginated
  838. * view, the contents of this paragraph are rendered on the start of a new
  839. * page in the document.
  840. * <p>
  841. * If this element is omitted on a given paragraph,
  842. * its value is determined by the setting previously set at any level of the
  843. * style hierarchy (i.e. that previous setting remains unchanged). If this
  844. * setting is never specified in the style hierarchy, then this property
  845. * shall not be applied. Since the paragraph is specified to start on a new
  846. * page, it begins page two even though it could have fit on page one.
  847. * </p>
  848. *
  849. * @param pageBreak -
  850. * boolean value
  851. */
  852. public void setPageBreak(boolean pageBreak) {
  853. CTPPr ppr = getCTPPr();
  854. CTOnOff ctPageBreak = ppr.isSetPageBreakBefore() ? ppr
  855. .getPageBreakBefore() : ppr.addNewPageBreakBefore();
  856. if (pageBreak) {
  857. ctPageBreak.setVal(STOnOff.TRUE);
  858. } else {
  859. ctPageBreak.setVal(STOnOff.FALSE);
  860. }
  861. }
  862. /**
  863. * Specifies the spacing that should be added after the last line in this
  864. * paragraph in the document in absolute units.
  865. *
  866. * @return int - value representing the spacing after the paragraph
  867. */
  868. public int getSpacingAfter() {
  869. CTSpacing spacing = getCTSpacing(false);
  870. return (spacing != null && spacing.isSetAfter()) ? spacing.getAfter().intValue() : -1;
  871. }
  872. /**
  873. * Specifies the spacing that should be added after the last line in this
  874. * paragraph in the document in absolute units.
  875. * <p>
  876. * If the afterLines attribute or the afterAutoSpacing attribute is also
  877. * specified, then this attribute value is ignored.
  878. * </p>
  879. *
  880. * @param spaces a positive whole number, whose contents consist of a
  881. * measurement in twentieths of a point.
  882. */
  883. public void setSpacingAfter(int spaces) {
  884. CTSpacing spacing = getCTSpacing(true);
  885. if (spacing != null) {
  886. BigInteger bi = new BigInteger(Integer.toString(spaces));
  887. spacing.setAfter(bi);
  888. }
  889. }
  890. /**
  891. * Specifies the spacing that should be added after the last line in this
  892. * paragraph in the document in absolute units.
  893. *
  894. * @return int - value representing the spacing after the paragraph
  895. * @see #setSpacingAfterLines(int)
  896. */
  897. public int getSpacingAfterLines() {
  898. CTSpacing spacing = getCTSpacing(false);
  899. return (spacing != null && spacing.isSetAfterLines()) ? spacing.getAfterLines().intValue() : -1;
  900. }
  901. /**
  902. * Specifies the spacing that should be added after the last line in this
  903. * paragraph in the document in line units.
  904. * <b>The value of this attribute is
  905. * specified in one hundredths of a line.
  906. * </b>
  907. * <p>
  908. * If the afterAutoSpacing attribute
  909. * is also specified, then this attribute value is ignored. If this setting
  910. * is never specified in the style hierarchy, then its value shall be zero
  911. * (if needed)
  912. * </p>
  913. *
  914. * @param spaces a positive whole number, whose contents consist of a
  915. * measurement in hundredths of a line
  916. */
  917. public void setSpacingAfterLines(int spaces) {
  918. CTSpacing spacing = getCTSpacing(true);
  919. BigInteger bi = new BigInteger(Integer.toString(spaces));
  920. spacing.setAfterLines(bi);
  921. }
  922. /**
  923. * Specifies the spacing that should be added above the first line in this
  924. * paragraph in the document in absolute units.
  925. *
  926. * @return the spacing that should be added above the first line
  927. * @see #setSpacingBefore(int)
  928. */
  929. public int getSpacingBefore() {
  930. CTSpacing spacing = getCTSpacing(false);
  931. return (spacing != null && spacing.isSetBefore()) ? spacing.getBefore().intValue() : -1;
  932. }
  933. /**
  934. * Specifies the spacing that should be added above the first line in this
  935. * paragraph in the document in absolute units.
  936. * <p>
  937. * If the beforeLines attribute or the beforeAutoSpacing attribute is also
  938. * specified, then this attribute value is ignored.
  939. * </p>
  940. *
  941. * @param spaces a positive whole number, whose contents consist of a
  942. * measurement in twentieths of a point.
  943. */
  944. public void setSpacingBefore(int spaces) {
  945. CTSpacing spacing = getCTSpacing(true);
  946. BigInteger bi = new BigInteger(Integer.toString(spaces));
  947. spacing.setBefore(bi);
  948. }
  949. /**
  950. * Specifies the spacing that should be added before the first line in this paragraph in the
  951. * document in line units.
  952. * The value of this attribute is specified in one hundredths of a line.
  953. *
  954. * @return the spacing that should be added before the first line in this paragraph
  955. * @see #setSpacingBeforeLines(int)
  956. */
  957. public int getSpacingBeforeLines() {
  958. CTSpacing spacing = getCTSpacing(false);
  959. return (spacing != null && spacing.isSetBeforeLines()) ? spacing.getBeforeLines().intValue() : -1;
  960. }
  961. /**
  962. * Specifies the spacing that should be added before the first line in this
  963. * paragraph in the document in line units. <b> The value of this attribute
  964. * is specified in one hundredths of a line. </b>
  965. * <p>
  966. * If the beforeAutoSpacing attribute is also specified, then this attribute
  967. * value is ignored. If this setting is never specified in the style
  968. * hierarchy, then its value shall be zero.
  969. * </p>
  970. *
  971. * @param spaces a positive whole number, whose contents consist of a
  972. * measurement in hundredths of a line
  973. */
  974. public void setSpacingBeforeLines(int spaces) {
  975. CTSpacing spacing = getCTSpacing(true);
  976. BigInteger bi = new BigInteger(Integer.toString(spaces));
  977. spacing.setBeforeLines(bi);
  978. }
  979. /**
  980. * Specifies how the spacing between lines is calculated as stored in the
  981. * line attribute. If this attribute is omitted, then it shall be assumed to
  982. * be of a value auto if a line attribute value is present.
  983. *
  984. * @return rule
  985. * @see LineSpacingRule
  986. * @see #setSpacingLineRule(LineSpacingRule)
  987. */
  988. public LineSpacingRule getSpacingLineRule() {
  989. CTSpacing spacing = getCTSpacing(false);
  990. return (spacing != null && spacing.isSetLineRule()) ? LineSpacingRule.valueOf(spacing
  991. .getLineRule().intValue()) : LineSpacingRule.AUTO;
  992. }
  993. /**
  994. * Specifies how the spacing between lines is calculated as stored in the
  995. * line attribute. If this attribute is omitted, then it shall be assumed to
  996. * be of a value auto if a line attribute value is present.
  997. *
  998. * @param rule one of the defined rules, see {@link LineSpacingRule}
  999. * @see LineSpacingRule
  1000. */
  1001. // TODO Fix this to convert line to equivalent value, or deprecate this in
  1002. // favor of setSpacingLine(double, LineSpacingRule)
  1003. public void setSpacingLineRule(LineSpacingRule rule) {
  1004. CTSpacing spacing = getCTSpacing(true);
  1005. spacing.setLineRule(STLineSpacingRule.Enum.forInt(rule.getValue()));
  1006. }
  1007. /**
  1008. * Return the spacing between lines of a paragraph. The units of the return value depends on the
  1009. * {@link LineSpacingRule}. If AUTO, the return value is in lines, otherwise the return
  1010. * value is in points
  1011. *
  1012. * @return a double specifying points or lines.
  1013. */
  1014. public double getSpacingBetween() {
  1015. CTSpacing spacing = getCTSpacing(false);
  1016. if (spacing == null || !spacing.isSetLine()) {
  1017. return -1;
  1018. } else if (spacing.getLineRule() == null || spacing.getLineRule() == STLineSpacingRule.AUTO) {
  1019. BigInteger[] val = spacing.getLine().divideAndRemainder(BigInteger.valueOf(240L));
  1020. return val[0].doubleValue() + (val[1].doubleValue() / 240L);
  1021. }
  1022. BigInteger[] val = spacing.getLine().divideAndRemainder(BigInteger.valueOf(20L));
  1023. return val[0].doubleValue() + (val[1].doubleValue() / 20L);
  1024. }
  1025. /**
  1026. * Sets the spacing between lines in a paragraph
  1027. *
  1028. * @param spacing - A double specifying spacing in inches or lines. If rule is
  1029. * AUTO, then spacing is in lines. Otherwise spacing is in points.
  1030. * @param rule - {@link LineSpacingRule} indicating how spacing is interpreted. If
  1031. * AUTO, then spacing value is in lines, and the height depends on the
  1032. * font size. If AT_LEAST, then spacing value is in inches, and is the
  1033. * minimum size of the line. If the line height is taller, then the
  1034. * line expands to match. If EXACT, then spacing is the exact line
  1035. * height. If the text is taller than the line height, then it is
  1036. * clipped at the top.
  1037. */
  1038. public void setSpacingBetween(double spacing, LineSpacingRule rule) {
  1039. CTSpacing ctSp = getCTSpacing(true);
  1040. if (rule == LineSpacingRule.AUTO) {
  1041. ctSp.setLine(new BigInteger(String.valueOf(Math.round(spacing * 240.0))));
  1042. } else {
  1043. ctSp.setLine(new BigInteger(String.valueOf(Math.round(spacing * 20.0))));
  1044. }
  1045. ctSp.setLineRule(STLineSpacingRule.Enum.forInt(rule.getValue()));
  1046. }
  1047. /**
  1048. * Sets the spacing between lines in a paragraph
  1049. *
  1050. * @param spacing - A double specifying spacing in lines.
  1051. */
  1052. public void setSpacingBetween(double spacing) {
  1053. setSpacingBetween(spacing, LineSpacingRule.AUTO);
  1054. }
  1055. /**
  1056. * Specifies the indentation which shall be placed between the left text
  1057. * margin for this paragraph and the left edge of that paragraph's content
  1058. * in a left to right paragraph, and the right text margin and the right
  1059. * edge of that paragraph's text in a right to left paragraph
  1060. * <p>
  1061. * If this attribute is omitted, its value shall be assumed to be zero.
  1062. * Negative values are defined such that the text is moved past the text margin,
  1063. * positive values move the text inside the text margin.
  1064. * </p>
  1065. *
  1066. * @return indentation in twips or null if indentation is not set
  1067. */
  1068. public int getIndentationLeft() {
  1069. CTInd indentation = getCTInd(false);
  1070. return (indentation != null && indentation.isSetLeft()) ? indentation.getLeft().intValue()
  1071. : -1;
  1072. }
  1073. /**
  1074. * Specifies the indentation which shall be placed between the left text
  1075. * margin for this paragraph and the left edge of that paragraph's content
  1076. * in a left to right paragraph, and the right text margin and the right
  1077. * edge of that paragraph's text in a right to left paragraph
  1078. * <p>
  1079. * If this attribute is omitted, its value shall be assumed to be zero.
  1080. * Negative values are defined such that the text is moved past the text margin,
  1081. * positive values move the text inside the text margin.
  1082. * </p>
  1083. *
  1084. * @param indentation in twips
  1085. */
  1086. public void setIndentationLeft(int indentation) {
  1087. CTInd indent = getCTInd(true);
  1088. BigInteger bi = new BigInteger(Integer.toString(indentation));
  1089. indent.setLeft(bi);
  1090. }
  1091. /**
  1092. * Specifies the indentation which shall be placed between the right text
  1093. * margin for this paragraph and the right edge of that paragraph's content
  1094. * in a left to right paragraph, and the right text margin and the right
  1095. * edge of that paragraph's text in a right to left paragraph
  1096. * <p>
  1097. * If this attribute is omitted, its value shall be assumed to be zero.
  1098. * Negative values are defined such that the text is moved past the text margin,
  1099. * positive values move the text inside the text margin.
  1100. * </p>
  1101. *
  1102. * @return indentation in twips or null if indentation is not set
  1103. */
  1104. public int getIndentationRight() {
  1105. CTInd indentation = getCTInd(false);
  1106. return (indentation != null && indentation.isSetRight()) ? indentation.getRight().intValue()
  1107. : -1;
  1108. }
  1109. /**
  1110. * Specifies the indentation which shall be placed between the right text
  1111. * margin for this paragraph and the right edge of that paragraph's content
  1112. * in a left to right paragraph, and the right text margin and the right
  1113. * edge of that paragraph's text in a right to left paragraph
  1114. * <p>
  1115. * If this attribute is omitted, its value shall be assumed to be zero.
  1116. * Negative values are defined such that the text is moved past the text margin,
  1117. * positive values move the text inside the text margin.
  1118. * </p>
  1119. *
  1120. * @param indentation in twips
  1121. */
  1122. public void setIndentationRight(int indentation) {
  1123. CTInd indent = getCTInd(true);
  1124. BigInteger bi = new BigInteger(Integer.toString(indentation));
  1125. indent.setRight(bi);
  1126. }
  1127. /**
  1128. * Specifies the indentation which shall be removed from the first line of
  1129. * the parent paragraph, by moving the indentation on the first line back
  1130. * towards the beginning of the direction of text flow.
  1131. * This indentation is
  1132. * specified relative to the paragraph indentation which is specified for
  1133. * all other lines in the parent paragraph.
  1134. * The firstLine and hanging
  1135. * attributes are mutually exclusive, if both are specified, then the
  1136. * firstLine value is ignored.
  1137. *
  1138. * @return indentation in twips or null if indentation is not set
  1139. */
  1140. public int getIndentationHanging() {
  1141. CTInd indentation = getCTInd(false);
  1142. return (indentation != null && indentation.isSetHanging()) ? indentation.getHanging().intValue() : -1;
  1143. }
  1144. /**
  1145. * Specifies the indentation which shall be removed from the first line of
  1146. * the parent paragraph, by moving the indentation on the first line back
  1147. * towards the beginning of the direction of text flow.
  1148. * This indentation is specified relative to the paragraph indentation which is specified for
  1149. * all other lines in the parent paragraph.
  1150. * <p>
  1151. * The firstLine and hanging attributes are mutually exclusive, if both are specified, then the
  1152. * firstLine value is ignored.
  1153. * </p>
  1154. *
  1155. * @param indentation in twips
  1156. */
  1157. public void setIndentationHanging(int indentation) {
  1158. CTInd indent = getCTInd(true);
  1159. BigInteger bi = new BigInteger(Integer.toString(indentation));
  1160. indent.setHanging(bi);
  1161. }
  1162. /**
  1163. * Specifies the additional indentation which shall be applied to the first
  1164. * line of the parent paragraph. This additional indentation is specified
  1165. * relative to the paragraph indentation which is specified for all other
  1166. * lines in the parent paragraph.
  1167. * The firstLine and hanging attributes are
  1168. * mutually exclusive, if both are specified, then the firstLine value is
  1169. * ignored.
  1170. * If the firstLineChars attribute is also specified, then this
  1171. * value is ignored.
  1172. * If this attribute is omitted, then its value shall be
  1173. * assumed to be zero (if needed).
  1174. *
  1175. * @return indentation in twips or null if indentation is not set
  1176. */
  1177. public int getIndentationFirstLine() {
  1178. CTInd indentation = getCTInd(false);
  1179. return (indentation != null && indentation.isSetFirstLine()) ? indentation.getFirstLine().intValue()
  1180. : -1;
  1181. }
  1182. /**
  1183. * Specifies the additional indentation which shall be applied to the first
  1184. * line of the parent paragraph. This additional indentation is specified
  1185. * relative to the paragraph indentation which is specified for all other
  1186. * lines in the parent paragraph.
  1187. * The firstLine and hanging attributes are
  1188. * mutually exclusive, if both are specified, then the firstLine value is
  1189. * ignored.
  1190. * If the firstLineChars attribute is also specified, then this
  1191. * value is ignored. If this attribute is omitted, then its value shall be
  1192. * assumed to be zero (if needed).
  1193. *
  1194. * @param indentation in twips
  1195. */
  1196. public void setIndentationFirstLine(int indentation) {
  1197. CTInd indent = getCTInd(true);
  1198. BigInteger bi = new BigInteger(Integer.toString(indentation));
  1199. indent.setFirstLine(bi);
  1200. }
  1201. @Override
  1202. public int getIndentFromLeft() {
  1203. return getIndentationLeft();
  1204. }
  1205. @Override
  1206. public void setIndentFromLeft(int dxaLeft) {
  1207. setIndentationLeft(dxaLeft);
  1208. }
  1209. @Override
  1210. public int getIndentFromRight() {
  1211. return getIndentationRight();
  1212. }
  1213. @Override
  1214. public void setIndentFromRight(int dxaRight) {
  1215. setIndentationRight(dxaRight);
  1216. }
  1217. @Override
  1218. public int getFirstLineIndent() {
  1219. return getIndentationFirstLine();
  1220. }
  1221. @Override
  1222. public void setFirstLineIndent(int first) {
  1223. setIndentationFirstLine(first);
  1224. }
  1225. /**
  1226. * This element specifies whether a consumer shall break Latin text which
  1227. * exceeds the text extents of a line by breaking the word across two lines
  1228. * (breaking on the character level) or by moving the word to the following
  1229. * line (breaking on the word level).
  1230. *
  1231. * @return boolean
  1232. */
  1233. @Override
  1234. public boolean isWordWrapped() {
  1235. CTOnOff wordWrap = getCTPPr().isSetWordWrap() ? getCTPPr()
  1236. .getWordWrap() : null;
  1237. if (wordWrap != null) {
  1238. return isTruelike(wordWrap.getVal());
  1239. }
  1240. return false;
  1241. }
  1242. /**
  1243. * This element specifies whether a consumer shall break Latin text which
  1244. * exceeds the text extents of a line by breaking the word across two lines
  1245. * (breaking on the character level) or by moving the word to the following
  1246. * line (breaking on the word level).
  1247. *
  1248. * @param wrap - boolean
  1249. */
  1250. @Override
  1251. public void setWordWrapped(boolean wrap) {
  1252. CTOnOff wordWrap = getCTPPr().isSetWordWrap() ? getCTPPr()
  1253. .getWordWrap() : getCTPPr().addNewWordWrap();
  1254. if (wrap) {
  1255. wordWrap.setVal(STOnOff.TRUE);
  1256. } else {
  1257. wordWrap.unsetVal();
  1258. }
  1259. }
  1260. public boolean isWordWrap() {
  1261. return isWordWrapped();
  1262. }
  1263. @Deprecated
  1264. public void setWordWrap(boolean wrap) {
  1265. setWordWrapped(wrap);
  1266. }
  1267. /**
  1268. * @return the style of the paragraph
  1269. */
  1270. public String getStyle() {
  1271. CTPPr pr = getCTPPr();
  1272. CTString style = pr.isSetPStyle() ? pr.getPStyle() : null;
  1273. return style != null ? style.getVal() : null;
  1274. }
  1275. /**
  1276. * Set the style ID for the paragraph
  1277. *
  1278. * @param styleId ID (not name) of the style to set for the paragraph, e.g. "Heading1" (not "Heading 1").
  1279. */
  1280. public void setStyle(String styleId) {
  1281. CTPPr pr = getCTPPr();
  1282. CTString style = pr.getPStyle() != null ? pr.getPStyle() : pr.addNewPStyle();
  1283. style.setVal(styleId);
  1284. }
  1285. /**
  1286. * Get a <b>copy</b> of the currently used CTPBrd, if none is used, return
  1287. * a new instance.
  1288. */
  1289. private CTPBdr getCTPBrd(boolean create) {
  1290. CTPPr pr = getCTPPr();
  1291. CTPBdr ct = pr.isSetPBdr() ? pr.getPBdr() : null;
  1292. if (create && ct == null) {
  1293. ct = pr.addNewPBdr();
  1294. }
  1295. return ct;
  1296. }
  1297. /**
  1298. * Get a <b>copy</b> of the currently used CTSpacing, if none is used,
  1299. * return a new instance.
  1300. */
  1301. private CTSpacing getCTSpacing(boolean create) {
  1302. CTPPr pr = getCTPPr();
  1303. CTSpacing ct = pr.getSpacing();
  1304. if (create && ct == null) {
  1305. ct = pr.addNewSpacing();
  1306. }
  1307. return ct;
  1308. }
  1309. /**
  1310. * Get a <b>copy</b> of the currently used CTPInd, if none is used, return
  1311. * a new instance.
  1312. */
  1313. private CTInd getCTInd(boolean create) {
  1314. CTPPr pr = getCTPPr();
  1315. CTInd ct = pr.getInd();
  1316. if (create && ct == null) {
  1317. ct = pr.addNewInd();
  1318. }
  1319. return ct;
  1320. }
  1321. /**
  1322. * Get a <b>copy</b> of the currently used CTPPr, if none is used, return
  1323. * a new instance.
  1324. */
  1325. private CTPPr getCTPPr() {
  1326. return paragraph.getPPr() == null ? paragraph.addNewPPr()
  1327. : paragraph.getPPr();
  1328. }
  1329. /**
  1330. * add a new run at the end of the position of
  1331. * the content of parameter run
  1332. *
  1333. * @param run
  1334. */
  1335. protected void addRun(CTR run) {
  1336. int pos;
  1337. pos = paragraph.sizeOfRArray();
  1338. paragraph.addNewR();
  1339. paragraph.setRArray(pos, run);
  1340. }
  1341. /**
  1342. * Appends a new run to this paragraph
  1343. *
  1344. * @return a new text run
  1345. */
  1346. public XWPFRun createRun() {
  1347. XWPFRun xwpfRun = new XWPFRun(paragraph.addNewR(), (IRunBody)this);
  1348. runs.add(xwpfRun);
  1349. iruns.add(xwpfRun);
  1350. return xwpfRun;
  1351. }
  1352. /**
  1353. * Appends a new hyperlink run to this paragraph
  1354. *
  1355. * @return a new hyperlink run
  1356. * @since POI 4.1.1
  1357. */
  1358. public XWPFHyperlinkRun createHyperlinkRun(String uri) {
  1359. // Create a relationship ID for this link.
  1360. String rId = getPart().getPackagePart().addExternalRelationship(
  1361. uri, XWPFRelation.HYPERLINK.getRelation()
  1362. ).getId();
  1363. // Create the run.
  1364. CTHyperlink ctHyperLink = getCTP().addNewHyperlink();
  1365. ctHyperLink.setId(rId);
  1366. ctHyperLink.addNewR();
  1367. // Append this run to the paragraph.
  1368. XWPFHyperlinkRun link = new XWPFHyperlinkRun(ctHyperLink, ctHyperLink.getRArray(0), this);
  1369. runs.add(link);
  1370. iruns.add(link);
  1371. return link;
  1372. }
  1373. /**
  1374. * Appends a new field run to this paragraph
  1375. *
  1376. * @return a new field run
  1377. */
  1378. public XWPFFieldRun createFieldRun() {
  1379. CTSimpleField ctSimpleField = paragraph.addNewFldSimple();
  1380. XWPFFieldRun newRun = new XWPFFieldRun(ctSimpleField, ctSimpleField.addNewR(), this);
  1381. runs.add(newRun);
  1382. iruns.add(newRun);
  1383. return newRun;
  1384. }
  1385. /**
  1386. * insert a new Run in all runs
  1387. *
  1388. * @param pos The position at which the new run should be added.
  1389. *
  1390. * @return the inserted run or null if the given pos is out of bounds.
  1391. */
  1392. public XWPFRun insertNewRun(int pos) {
  1393. if (pos == runs.size()) {
  1394. return createRun();
  1395. }
  1396. return insertNewProvidedRun(pos, newCursor -> {
  1397. String uri = CTR.type.getName().getNamespaceURI();
  1398. String localPart = "r";
  1399. // creates a new run, cursor is positioned inside the new
  1400. // element
  1401. newCursor.beginElement(localPart, uri);
  1402. // move the cursor to the START token to the run just created
  1403. newCursor.toParent();
  1404. CTR r = (CTR) newCursor.getObject();
  1405. return new XWPFRun(r, (IRunBody)this);
  1406. });
  1407. }
  1408. /**
  1409. * insert a new hyperlink Run in all runs
  1410. *
  1411. * @param pos The position at which the new run should be added.
  1412. * @param uri hyperlink uri
  1413. *
  1414. * @return the inserted run or null if the given pos is out of bounds.
  1415. */
  1416. public XWPFHyperlinkRun insertNewHyperlinkRun(int pos, String uri) {
  1417. if (pos == runs.size()) {
  1418. return createHyperlinkRun(uri);
  1419. }
  1420. XWPFHyperlinkRun newRun = insertNewProvidedRun(pos, newCursor -> {
  1421. String namespaceURI = CTHyperlink.type.getName().getNamespaceURI();
  1422. String localPart = "hyperlink";
  1423. newCursor.beginElement(localPart, namespaceURI);
  1424. // move the cursor to the START token to the hyperlink just created
  1425. newCursor.toParent();
  1426. CTHyperlink ctHyperLink = (CTHyperlink) newCursor.getObject();
  1427. return new XWPFHyperlinkRun(ctHyperLink, ctHyperLink.addNewR(), this);
  1428. });
  1429. if (newRun != null) {
  1430. String rId = getPart().getPackagePart().addExternalRelationship(
  1431. uri, XWPFRelation.HYPERLINK.getRelation()
  1432. ).getId();
  1433. newRun.getCTHyperlink().setId(rId);
  1434. }
  1435. return newRun;
  1436. }
  1437. /**
  1438. * insert a new field Run in all runs
  1439. *
  1440. * @param pos The position at which the new run should be added.
  1441. *
  1442. * @return the inserted run or null if the given pos is out of bounds.
  1443. */
  1444. public XWPFFieldRun insertNewFieldRun(int pos) {
  1445. if (pos == runs.size()) {
  1446. return createFieldRun();
  1447. }
  1448. return insertNewProvidedRun(pos, newCursor -> {
  1449. String uri = CTSimpleField.type.getName().getNamespaceURI();
  1450. String localPart = "fldSimple";
  1451. newCursor.beginElement(localPart, uri);
  1452. // move the cursor to the START token to the field just created
  1453. newCursor.toParent();
  1454. CTSimpleField ctSimpleField = (CTSimpleField) newCursor.getObject();
  1455. return new XWPFFieldRun(ctSimpleField, ctSimpleField.addNewR(), this);
  1456. });
  1457. }
  1458. /**
  1459. * insert a new run provided by in all runs
  1460. *
  1461. * @param <T> XWPFRun or XWPFHyperlinkRun or XWPFFieldRun
  1462. * @param pos The position at which the new run should be added.
  1463. * @param provider provide a new run at position of the given cursor.
  1464. * @return the inserted run or null if the given pos is out of bounds.
  1465. */
  1466. private <T extends XWPFRun> T insertNewProvidedRun(int pos, Function<XmlCursor, T> provider) {
  1467. if (pos >= 0 && pos < runs.size()) {
  1468. XWPFRun run = runs.get(pos);
  1469. CTR ctr = run.getCTR();
  1470. XmlCursor newCursor = ctr.newCursor();
  1471. if (!isCursorInParagraph(newCursor)) {
  1472. // look up correct position for CTP -> XXX -> R array
  1473. newCursor.toParent();
  1474. }
  1475. if (isCursorInParagraph(newCursor)) {
  1476. // provide a new run
  1477. T newRun = provider.apply(newCursor);
  1478. // To update the iruns, find where we're going
  1479. // in the normal runs, and go in there
  1480. int iPos = iruns.size();
  1481. int oldAt = iruns.indexOf(run);
  1482. if (oldAt != -1) {
  1483. iPos = oldAt;
  1484. }
  1485. iruns.add(iPos, newRun);
  1486. // Runs itself is easy to update
  1487. runs.add(pos, newRun);
  1488. return newRun;
  1489. }
  1490. newCursor.dispose();
  1491. }
  1492. return null;
  1493. }
  1494. /**
  1495. * verifies that cursor is on the right position
  1496. *
  1497. * @param cursor
  1498. * @return
  1499. */
  1500. private boolean isCursorInParagraph(XmlCursor cursor) {
  1501. XmlCursor verify = cursor.newCursor();
  1502. verify.toParent();
  1503. boolean result = (verify.getObject() == this.paragraph);
  1504. verify.dispose();
  1505. return result;
  1506. }
  1507. /**
  1508. * this methods parse the paragraph and search for the string searched.
  1509. * If it finds the string, it will return true and the position of the String
  1510. * will be saved in the parameter startPos.
  1511. *
  1512. * @param searched
  1513. * @param startPos
  1514. */
  1515. public TextSegment searchText(String searched, PositionInParagraph startPos) {
  1516. int startRun = startPos.getRun(),
  1517. startText = startPos.getText(),
  1518. startChar = startPos.getChar();
  1519. int beginRunPos = 0, candCharPos = 0;
  1520. boolean newList = false;
  1521. CTR[] rArray = paragraph.getRArray();
  1522. for (int runPos = startRun; runPos < rArray.length; runPos++) {
  1523. int beginTextPos = 0, beginCharPos = 0, textPos = 0, charPos;
  1524. CTR ctRun = rArray[runPos];
  1525. XmlCursor c = ctRun.newCursor();
  1526. c.selectPath("./*");
  1527. try {
  1528. while (c.toNextSelection()) {
  1529. XmlObject o = c.getObject();
  1530. if (o instanceof CTText) {
  1531. if (textPos >= startText) {
  1532. String candidate = ((CTText) o).getStringValue();
  1533. if (runPos == startRun) {
  1534. charPos = startChar;
  1535. } else {
  1536. charPos = 0;
  1537. }
  1538. for (; charPos < candidate.length(); charPos++) {
  1539. if ((candidate.charAt(charPos) == searched.charAt(0)) && (candCharPos == 0)) {
  1540. beginTextPos = textPos;
  1541. beginCharPos = charPos;
  1542. beginRunPos = runPos;
  1543. newList = true;
  1544. }
  1545. if (candidate.charAt(charPos) == searched.charAt(candCharPos)) {
  1546. if (candCharPos + 1 < searched.length()) {
  1547. candCharPos++;
  1548. } else if (newList) {
  1549. TextSegment segment = new TextSegment();
  1550. segment.setBeginRun(beginRunPos);
  1551. segment.setBeginText(beginTextPos);
  1552. segment.setBeginChar(beginCharPos);
  1553. segment.setEndRun(runPos);
  1554. segment.setEndText(textPos);
  1555. segment.setEndChar(charPos);
  1556. return segment;
  1557. }
  1558. } else {
  1559. candCharPos = 0;
  1560. }
  1561. }
  1562. }
  1563. textPos++;
  1564. } else if (o instanceof CTProofErr) {
  1565. c.removeXml();
  1566. } else if (o instanceof CTRPr) {
  1567. //do nothing
  1568. } else {
  1569. candCharPos = 0;
  1570. }
  1571. }
  1572. } finally {
  1573. c.dispose();
  1574. }
  1575. }
  1576. return null;
  1577. }
  1578. /**
  1579. * get a Text
  1580. *
  1581. * @param segment
  1582. */
  1583. public String getText(TextSegment segment) {
  1584. int runBegin = segment.getBeginRun();
  1585. int textBegin = segment.getBeginText();
  1586. int charBegin = segment.getBeginChar();
  1587. int runEnd = segment.getEndRun();
  1588. int textEnd = segment.getEndText();
  1589. int charEnd = segment.getEndChar();
  1590. StringBuilder out = new StringBuilder();
  1591. CTR[] rArray = paragraph.getRArray();
  1592. for (int i = runBegin; i <= runEnd; i++) {
  1593. CTText[] tArray = rArray[i].getTArray();
  1594. int startText = 0, endText = tArray.length - 1;
  1595. if (i == runBegin) {
  1596. startText = textBegin;
  1597. }
  1598. if (i == runEnd) {
  1599. endText = textEnd;
  1600. }
  1601. for (int j = startText; j <= endText; j++) {
  1602. String tmpText = tArray[j].getStringValue();
  1603. int startChar = 0, endChar = tmpText.length() - 1;
  1604. if ((j == textBegin) && (i == runBegin)) {
  1605. startChar = charBegin;
  1606. }
  1607. if ((j == textEnd) && (i == runEnd)) {
  1608. endChar = charEnd;
  1609. }
  1610. out.append(tmpText, startChar, endChar + 1);
  1611. }
  1612. }
  1613. return out.toString();
  1614. }
  1615. /**
  1616. * removes a Run at the position pos in the paragraph
  1617. *
  1618. * @param pos
  1619. * @return true if the run was removed
  1620. */
  1621. public boolean removeRun(int pos) {
  1622. if (pos >= 0 && pos < runs.size()) {
  1623. XWPFRun run = runs.get(pos);
  1624. // CTP -> CTHyperlink -> R array
  1625. if (run instanceof XWPFHyperlinkRun
  1626. && isTheOnlyCTHyperlinkInRuns((XWPFHyperlinkRun) run)) {
  1627. XmlCursor c = ((XWPFHyperlinkRun) run).getCTHyperlink()
  1628. .newCursor();
  1629. c.removeXml();
  1630. c.dispose();
  1631. runs.remove(pos);
  1632. iruns.remove(run);
  1633. return true;
  1634. }
  1635. // CTP -> CTField -> R array
  1636. if (run instanceof XWPFFieldRun
  1637. && isTheOnlyCTFieldInRuns((XWPFFieldRun) run)) {
  1638. XmlCursor c = ((XWPFFieldRun) run).getCTField().newCursor();
  1639. c.removeXml();
  1640. c.dispose();
  1641. runs.remove(pos);
  1642. iruns.remove(run);
  1643. return true;
  1644. }
  1645. XmlCursor c = run.getCTR().newCursor();
  1646. c.removeXml();
  1647. c.dispose();
  1648. runs.remove(pos);
  1649. iruns.remove(run);
  1650. return true;
  1651. }
  1652. return false;
  1653. }
  1654. /**
  1655. * Is there only one ctHyperlink in all runs
  1656. *
  1657. * @param run
  1658. * hyperlink run
  1659. * @return
  1660. */
  1661. private boolean isTheOnlyCTHyperlinkInRuns(XWPFHyperlinkRun run) {
  1662. CTHyperlink ctHyperlink = run.getCTHyperlink();
  1663. long count = runs.stream().filter(r -> (r instanceof XWPFHyperlinkRun
  1664. && ctHyperlink == ((XWPFHyperlinkRun) r).getCTHyperlink()))
  1665. .count();
  1666. return count <= 1;
  1667. }
  1668. /**
  1669. * Is there only one ctField in all runs
  1670. *
  1671. * @param run
  1672. * field run
  1673. * @return
  1674. */
  1675. private boolean isTheOnlyCTFieldInRuns(XWPFFieldRun run) {
  1676. CTSimpleField ctField = run.getCTField();
  1677. long count = runs.stream().filter(r -> (r instanceof XWPFFieldRun
  1678. && ctField == ((XWPFFieldRun) r).getCTField())).count();
  1679. return count <= 1;
  1680. }
  1681. /**
  1682. * returns the type of the BodyElement Paragraph
  1683. *
  1684. * @see org.apache.poi.xwpf.usermodel.IBodyElement#getElementType()
  1685. */
  1686. @Override
  1687. public BodyElementType getElementType() {
  1688. return BodyElementType.PARAGRAPH;
  1689. }
  1690. @Override
  1691. public IBody getBody() {
  1692. return part;
  1693. }
  1694. /**
  1695. * returns the part of the bodyElement
  1696. *
  1697. * @see org.apache.poi.xwpf.usermodel.IBody#getPart()
  1698. */
  1699. @Override
  1700. public POIXMLDocumentPart getPart() {
  1701. if (part != null) {
  1702. return part.getPart();
  1703. }
  1704. return null;
  1705. }
  1706. /**
  1707. * returns the partType of the bodyPart which owns the bodyElement
  1708. *
  1709. * @see org.apache.poi.xwpf.usermodel.IBody#getPartType()
  1710. */
  1711. @Override
  1712. public BodyType getPartType() {
  1713. return part.getPartType();
  1714. }
  1715. /**
  1716. * adds a new Run to the Paragraph
  1717. *
  1718. * @param r
  1719. */
  1720. public void addRun(XWPFRun r) {
  1721. if (!runs.contains(r)) {
  1722. runs.add(r);
  1723. }
  1724. }
  1725. /**
  1726. * return the XWPFRun-Element which owns the CTR run-Element
  1727. *
  1728. * @param r
  1729. */
  1730. public XWPFRun getRun(CTR r) {
  1731. for (int i = 0; i < getRuns().size(); i++) {
  1732. if (getRuns().get(i).getCTR() == r) {
  1733. return getRuns().get(i);
  1734. }
  1735. }
  1736. return null;
  1737. }
  1738. /**
  1739. * Add a new run with a reference to the specified footnote.
  1740. * The footnote reference run will have the style name "FootnoteReference".
  1741. *
  1742. * @param footnote Footnote to which to add a reference.
  1743. * @since 4.0.0
  1744. */
  1745. public void addFootnoteReference(XWPFAbstractFootnoteEndnote footnote) {
  1746. XWPFRun run = createRun();
  1747. CTR ctRun = run.getCTR();
  1748. ctRun.addNewRPr().addNewRStyle().setVal("FootnoteReference");
  1749. if (footnote instanceof XWPFEndnote) {
  1750. ctRun.addNewEndnoteReference().setId(footnote.getId());
  1751. } else {
  1752. ctRun.addNewFootnoteReference().setId(footnote.getId());
  1753. }
  1754. }
  1755. }