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.

XSLFTextShape.java 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. /*
  2. * ====================================================================
  3. * Licensed to the Apache Software Foundation (ASF) under one or more
  4. * contributor license agreements. See the NOTICE file distributed with
  5. * this work for additional information regarding copyright ownership.
  6. * The ASF licenses this file to You under the Apache License, Version 2.0
  7. * (the "License"); you may not use this file except in compliance with
  8. * the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. * ====================================================================
  18. */
  19. package org.apache.poi.xslf.usermodel;
  20. import java.awt.geom.Rectangle2D;
  21. import java.util.ArrayList;
  22. import java.util.Iterator;
  23. import java.util.List;
  24. import org.apache.poi.POIXMLException;
  25. import org.apache.poi.sl.draw.DrawFactory;
  26. import org.apache.poi.sl.draw.DrawTextShape;
  27. import org.apache.poi.sl.usermodel.Insets2D;
  28. import org.apache.poi.sl.usermodel.Placeholder;
  29. import org.apache.poi.sl.usermodel.TextShape;
  30. import org.apache.poi.sl.usermodel.VerticalAlignment;
  31. import org.apache.poi.util.Beta;
  32. import org.apache.poi.util.Units;
  33. import org.apache.poi.xslf.model.PropertyFetcher;
  34. import org.apache.poi.xslf.model.TextBodyPropertyFetcher;
  35. import org.apache.xmlbeans.XmlObject;
  36. import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody;
  37. import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBodyProperties;
  38. import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
  39. import org.openxmlformats.schemas.drawingml.x2006.main.CTTextListStyle;
  40. import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;
  41. import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
  42. import org.openxmlformats.schemas.drawingml.x2006.main.STTextAnchoringType;
  43. import org.openxmlformats.schemas.drawingml.x2006.main.STTextVerticalType;
  44. import org.openxmlformats.schemas.drawingml.x2006.main.STTextWrappingType;
  45. import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
  46. /**
  47. * Represents a shape that can hold text.
  48. */
  49. @Beta
  50. public abstract class XSLFTextShape extends XSLFSimpleShape
  51. implements TextShape<XSLFShape,XSLFTextParagraph> {
  52. private final List<XSLFTextParagraph> _paragraphs;
  53. /*package*/ XSLFTextShape(XmlObject shape, XSLFSheet sheet) {
  54. super(shape, sheet);
  55. _paragraphs = new ArrayList<XSLFTextParagraph>();
  56. CTTextBody txBody = getTextBody(false);
  57. if (txBody != null) {
  58. for (CTTextParagraph p : txBody.getPArray()) {
  59. _paragraphs.add(newTextParagraph(p));
  60. }
  61. }
  62. }
  63. public Iterator<XSLFTextParagraph> iterator(){
  64. return getTextParagraphs().iterator();
  65. }
  66. @Override
  67. public String getText() {
  68. StringBuilder out = new StringBuilder();
  69. for (XSLFTextParagraph p : _paragraphs) {
  70. if (out.length() > 0) out.append('\n');
  71. out.append(p.getText());
  72. }
  73. return out.toString();
  74. }
  75. /**
  76. * unset text from this shape
  77. */
  78. public void clearText(){
  79. _paragraphs.clear();
  80. CTTextBody txBody = getTextBody(true);
  81. txBody.setPArray(null); // remove any existing paragraphs
  82. }
  83. @Override
  84. public XSLFTextRun setText(String text) {
  85. // calling clearText or setting to a new Array leads to a XmlValueDisconnectedException
  86. if (!_paragraphs.isEmpty()) {
  87. CTTextBody txBody = getTextBody(false);
  88. int cntPs = txBody.sizeOfPArray();
  89. for (int i = cntPs; i > 1; i--) {
  90. txBody.removeP(i-1);
  91. _paragraphs.remove(i-1);
  92. }
  93. _paragraphs.get(0).clearButKeepProperties();
  94. }
  95. return appendText(text, false);
  96. }
  97. @Override
  98. public XSLFTextRun appendText(String text, boolean newParagraph) {
  99. if (text == null) return null;
  100. // copy properties from last paragraph / textrun or paragraph end marker
  101. CTTextParagraphProperties otherPPr = null;
  102. CTTextCharacterProperties otherRPr = null;
  103. boolean firstPara;
  104. XSLFTextParagraph para;
  105. if (_paragraphs.isEmpty()) {
  106. firstPara = false;
  107. para = null;
  108. } else {
  109. firstPara = !newParagraph;
  110. para = _paragraphs.get(_paragraphs.size()-1);
  111. CTTextParagraph ctp = para.getXmlObject();
  112. otherPPr = ctp.getPPr();
  113. List<XSLFTextRun> runs = para.getTextRuns();
  114. if (!runs.isEmpty()) {
  115. XSLFTextRun r0 = runs.get(runs.size()-1);
  116. otherRPr = r0.getRPr(false);
  117. if (otherRPr == null) {
  118. otherRPr = ctp.getEndParaRPr();
  119. }
  120. }
  121. // don't copy endParaRPr to the run in case there aren't any other runs
  122. // this is the case when setText() was called initially
  123. // otherwise the master style will be overridden/ignored
  124. }
  125. XSLFTextRun run = null;
  126. for (String lineTxt : text.split("\\r\\n?|\\n")) {
  127. if (!firstPara) {
  128. if (para != null) {
  129. CTTextParagraph ctp = para.getXmlObject();
  130. CTTextCharacterProperties unexpectedRPr = ctp.getEndParaRPr();
  131. if (unexpectedRPr != null && unexpectedRPr != otherRPr) {
  132. ctp.unsetEndParaRPr();
  133. }
  134. }
  135. para = addNewTextParagraph();
  136. if (otherPPr != null) {
  137. para.getXmlObject().setPPr(otherPPr);
  138. }
  139. }
  140. boolean firstRun = true;
  141. for (String runText : lineTxt.split("[\u000b]")) {
  142. if (!firstRun) {
  143. para.addLineBreak();
  144. }
  145. run = para.addNewTextRun();
  146. run.setText(runText);
  147. if (otherRPr != null) {
  148. run.getRPr(true).set(otherRPr);
  149. }
  150. firstRun = false;
  151. }
  152. firstPara = false;
  153. }
  154. assert(run != null);
  155. return run;
  156. }
  157. @Override
  158. public List<XSLFTextParagraph> getTextParagraphs() {
  159. return _paragraphs;
  160. }
  161. /**
  162. * add a new paragraph run to this shape
  163. *
  164. * @return created paragraph run
  165. */
  166. public XSLFTextParagraph addNewTextParagraph() {
  167. CTTextBody txBody = getTextBody(false);
  168. CTTextParagraph p;
  169. if (txBody == null) {
  170. txBody = getTextBody(true);
  171. p = txBody.getPArray(0);
  172. p.removeR(0);
  173. } else {
  174. p = txBody.addNewP();
  175. }
  176. XSLFTextParagraph paragraph = newTextParagraph(p);
  177. _paragraphs.add(paragraph);
  178. return paragraph;
  179. }
  180. @Override
  181. public void setVerticalAlignment(VerticalAlignment anchor){
  182. CTTextBodyProperties bodyPr = getTextBodyPr(true);
  183. if (bodyPr != null) {
  184. if(anchor == null) {
  185. if(bodyPr.isSetAnchor()) bodyPr.unsetAnchor();
  186. } else {
  187. bodyPr.setAnchor(STTextAnchoringType.Enum.forInt(anchor.ordinal() + 1));
  188. }
  189. }
  190. }
  191. @Override
  192. public VerticalAlignment getVerticalAlignment(){
  193. PropertyFetcher<VerticalAlignment> fetcher = new TextBodyPropertyFetcher<VerticalAlignment>(){
  194. public boolean fetch(CTTextBodyProperties props){
  195. if(props.isSetAnchor()){
  196. int val = props.getAnchor().intValue();
  197. setValue(VerticalAlignment.values()[val - 1]);
  198. return true;
  199. }
  200. return false;
  201. }
  202. };
  203. fetchShapeProperty(fetcher);
  204. return fetcher.getValue() == null ? VerticalAlignment.TOP : fetcher.getValue();
  205. }
  206. @Override
  207. public void setHorizontalCentered(Boolean isCentered){
  208. CTTextBodyProperties bodyPr = getTextBodyPr(true);
  209. if (bodyPr != null) {
  210. if (isCentered == null) {
  211. if (bodyPr.isSetAnchorCtr()) bodyPr.unsetAnchorCtr();
  212. } else {
  213. bodyPr.setAnchorCtr(isCentered);
  214. }
  215. }
  216. }
  217. @Override
  218. public boolean isHorizontalCentered(){
  219. PropertyFetcher<Boolean> fetcher = new TextBodyPropertyFetcher<Boolean>(){
  220. public boolean fetch(CTTextBodyProperties props){
  221. if(props.isSetAnchorCtr()){
  222. setValue(props.getAnchorCtr());
  223. return true;
  224. }
  225. return false;
  226. }
  227. };
  228. fetchShapeProperty(fetcher);
  229. return fetcher.getValue() == null ? false : fetcher.getValue();
  230. }
  231. @Override
  232. public void setTextDirection(TextDirection orientation){
  233. CTTextBodyProperties bodyPr = getTextBodyPr(true);
  234. if (bodyPr != null) {
  235. if(orientation == null) {
  236. if(bodyPr.isSetVert()) bodyPr.unsetVert();
  237. } else {
  238. bodyPr.setVert(STTextVerticalType.Enum.forInt(orientation.ordinal() + 1));
  239. }
  240. }
  241. }
  242. @Override
  243. public TextDirection getTextDirection(){
  244. CTTextBodyProperties bodyPr = getTextBodyPr();
  245. if (bodyPr != null) {
  246. STTextVerticalType.Enum val = bodyPr.getVert();
  247. if(val != null) {
  248. switch (val.intValue()) {
  249. default:
  250. case STTextVerticalType.INT_HORZ:
  251. return TextDirection.HORIZONTAL;
  252. case STTextVerticalType.INT_EA_VERT:
  253. case STTextVerticalType.INT_MONGOLIAN_VERT:
  254. case STTextVerticalType.INT_VERT:
  255. return TextDirection.VERTICAL;
  256. case STTextVerticalType.INT_VERT_270:
  257. return TextDirection.VERTICAL_270;
  258. case STTextVerticalType.INT_WORD_ART_VERT_RTL:
  259. case STTextVerticalType.INT_WORD_ART_VERT:
  260. return TextDirection.STACKED;
  261. }
  262. }
  263. }
  264. return TextDirection.HORIZONTAL;
  265. }
  266. @Override
  267. public Double getTextRotation() {
  268. CTTextBodyProperties bodyPr = getTextBodyPr();
  269. if (bodyPr != null && bodyPr.isSetRot()) {
  270. return bodyPr.getRot() / 60000.;
  271. }
  272. return null;
  273. }
  274. @Override
  275. public void setTextRotation(Double rotation) {
  276. CTTextBodyProperties bodyPr = getTextBodyPr(true);
  277. if (bodyPr != null) {
  278. bodyPr.setRot((int)(rotation * 60000.));
  279. }
  280. }
  281. /**
  282. * Returns the distance (in points) between the bottom of the text frame
  283. * and the bottom of the inscribed rectangle of the shape that contains the text.
  284. *
  285. * @return the bottom inset in points
  286. */
  287. public double getBottomInset(){
  288. PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){
  289. public boolean fetch(CTTextBodyProperties props){
  290. if(props.isSetBIns()){
  291. double val = Units.toPoints(props.getBIns());
  292. setValue(val);
  293. return true;
  294. }
  295. return false;
  296. }
  297. };
  298. fetchShapeProperty(fetcher);
  299. // If this attribute is omitted, then a value of 0.05 inches is implied
  300. return fetcher.getValue() == null ? 3.6 : fetcher.getValue();
  301. }
  302. /**
  303. * Returns the distance (in points) between the left edge of the text frame
  304. * and the left edge of the inscribed rectangle of the shape that contains
  305. * the text.
  306. *
  307. * @return the left inset in points
  308. */
  309. public double getLeftInset(){
  310. PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){
  311. public boolean fetch(CTTextBodyProperties props){
  312. if(props.isSetLIns()){
  313. double val = Units.toPoints(props.getLIns());
  314. setValue(val);
  315. return true;
  316. }
  317. return false;
  318. }
  319. };
  320. fetchShapeProperty(fetcher);
  321. // If this attribute is omitted, then a value of 0.1 inches is implied
  322. return fetcher.getValue() == null ? 7.2 : fetcher.getValue();
  323. }
  324. /**
  325. * Returns the distance (in points) between the right edge of the
  326. * text frame and the right edge of the inscribed rectangle of the shape
  327. * that contains the text.
  328. *
  329. * @return the right inset in points
  330. */
  331. public double getRightInset(){
  332. PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){
  333. public boolean fetch(CTTextBodyProperties props){
  334. if(props.isSetRIns()){
  335. double val = Units.toPoints(props.getRIns());
  336. setValue(val);
  337. return true;
  338. }
  339. return false;
  340. }
  341. };
  342. fetchShapeProperty(fetcher);
  343. // If this attribute is omitted, then a value of 0.1 inches is implied
  344. return fetcher.getValue() == null ? 7.2 : fetcher.getValue();
  345. }
  346. /**
  347. * Returns the distance (in points) between the top of the text frame
  348. * and the top of the inscribed rectangle of the shape that contains the text.
  349. *
  350. * @return the top inset in points
  351. */
  352. public double getTopInset(){
  353. PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){
  354. public boolean fetch(CTTextBodyProperties props){
  355. if(props.isSetTIns()){
  356. double val = Units.toPoints(props.getTIns());
  357. setValue(val);
  358. return true;
  359. }
  360. return false;
  361. }
  362. };
  363. fetchShapeProperty(fetcher);
  364. // If this attribute is omitted, then a value of 0.05 inches is implied
  365. return fetcher.getValue() == null ? 3.6 : fetcher.getValue();
  366. }
  367. /**
  368. * Sets the bottom margin.
  369. * @see #getBottomInset()
  370. *
  371. * @param margin the bottom margin
  372. */
  373. public void setBottomInset(double margin){
  374. CTTextBodyProperties bodyPr = getTextBodyPr(true);
  375. if (bodyPr != null) {
  376. if(margin == -1) bodyPr.unsetBIns();
  377. else bodyPr.setBIns(Units.toEMU(margin));
  378. }
  379. }
  380. /**
  381. * Sets the left margin.
  382. * @see #getLeftInset()
  383. *
  384. * @param margin the left margin
  385. */
  386. public void setLeftInset(double margin){
  387. CTTextBodyProperties bodyPr = getTextBodyPr(true);
  388. if (bodyPr != null) {
  389. if(margin == -1) bodyPr.unsetLIns();
  390. else bodyPr.setLIns(Units.toEMU(margin));
  391. }
  392. }
  393. /**
  394. * Sets the right margin.
  395. * @see #getRightInset()
  396. *
  397. * @param margin the right margin
  398. */
  399. public void setRightInset(double margin){
  400. CTTextBodyProperties bodyPr = getTextBodyPr(true);
  401. if (bodyPr != null) {
  402. if(margin == -1) bodyPr.unsetRIns();
  403. else bodyPr.setRIns(Units.toEMU(margin));
  404. }
  405. }
  406. /**
  407. * Sets the top margin.
  408. * @see #getTopInset()
  409. *
  410. * @param margin the top margin
  411. */
  412. public void setTopInset(double margin){
  413. CTTextBodyProperties bodyPr = getTextBodyPr(true);
  414. if (bodyPr != null) {
  415. if(margin == -1) bodyPr.unsetTIns();
  416. else bodyPr.setTIns(Units.toEMU(margin));
  417. }
  418. }
  419. @Override
  420. public Insets2D getInsets() {
  421. Insets2D insets = new Insets2D(getTopInset(), getLeftInset(), getBottomInset(), getRightInset());
  422. return insets;
  423. }
  424. @Override
  425. public void setInsets(Insets2D insets) {
  426. setTopInset(insets.top);
  427. setLeftInset(insets.left);
  428. setBottomInset(insets.bottom);
  429. setRightInset(insets.right);
  430. }
  431. @Override
  432. public boolean getWordWrap(){
  433. PropertyFetcher<Boolean> fetcher = new TextBodyPropertyFetcher<Boolean>(){
  434. public boolean fetch(CTTextBodyProperties props){
  435. if(props.isSetWrap()){
  436. setValue(props.getWrap() == STTextWrappingType.SQUARE);
  437. return true;
  438. }
  439. return false;
  440. }
  441. };
  442. fetchShapeProperty(fetcher);
  443. return fetcher.getValue() == null ? true : fetcher.getValue();
  444. }
  445. @Override
  446. public void setWordWrap(boolean wrap){
  447. CTTextBodyProperties bodyPr = getTextBodyPr(true);
  448. if (bodyPr != null) {
  449. bodyPr.setWrap(wrap ? STTextWrappingType.SQUARE : STTextWrappingType.NONE);
  450. }
  451. }
  452. /**
  453. *
  454. * Specifies that a shape should be auto-fit to fully contain the text described within it.
  455. * Auto-fitting is when text within a shape is scaled in order to contain all the text inside
  456. *
  457. * @param value type of autofit
  458. */
  459. public void setTextAutofit(TextAutofit value){
  460. CTTextBodyProperties bodyPr = getTextBodyPr(true);
  461. if (bodyPr != null) {
  462. if(bodyPr.isSetSpAutoFit()) bodyPr.unsetSpAutoFit();
  463. if(bodyPr.isSetNoAutofit()) bodyPr.unsetNoAutofit();
  464. if(bodyPr.isSetNormAutofit()) bodyPr.unsetNormAutofit();
  465. switch(value){
  466. case NONE: bodyPr.addNewNoAutofit(); break;
  467. case NORMAL: bodyPr.addNewNormAutofit(); break;
  468. case SHAPE: bodyPr.addNewSpAutoFit(); break;
  469. }
  470. }
  471. }
  472. /**
  473. *
  474. * @return type of autofit
  475. */
  476. public TextAutofit getTextAutofit(){
  477. CTTextBodyProperties bodyPr = getTextBodyPr();
  478. if (bodyPr != null) {
  479. if(bodyPr.isSetNoAutofit()) return TextAutofit.NONE;
  480. else if (bodyPr.isSetNormAutofit()) return TextAutofit.NORMAL;
  481. else if (bodyPr.isSetSpAutoFit()) return TextAutofit.SHAPE;
  482. }
  483. return TextAutofit.NORMAL;
  484. }
  485. protected CTTextBodyProperties getTextBodyPr(){
  486. return getTextBodyPr(false);
  487. }
  488. protected CTTextBodyProperties getTextBodyPr(boolean create) {
  489. CTTextBody textBody = getTextBody(create);
  490. if (textBody == null) {
  491. return null;
  492. }
  493. CTTextBodyProperties textBodyPr = textBody.getBodyPr();
  494. if (textBodyPr == null && create) {
  495. textBodyPr = textBody.addNewBodyPr();
  496. }
  497. return textBodyPr;
  498. }
  499. protected abstract CTTextBody getTextBody(boolean create);
  500. @Override
  501. public void setPlaceholder(Placeholder placeholder) {
  502. super.setPlaceholder(placeholder);
  503. }
  504. public Placeholder getTextType(){
  505. CTPlaceholder ph = getCTPlaceholder();
  506. if (ph == null) return null;
  507. int val = ph.getType().intValue();
  508. return Placeholder.lookupOoxml(val);
  509. }
  510. @Override
  511. public double getTextHeight(){
  512. DrawFactory drawFact = DrawFactory.getInstance(null);
  513. DrawTextShape dts = drawFact.getDrawable(this);
  514. return dts.getTextHeight();
  515. }
  516. /**
  517. * Adjust the size of the shape so it encompasses the text inside it.
  518. *
  519. * @return a <code>Rectangle2D</code> that is the bounds of this shape.
  520. */
  521. public Rectangle2D resizeToFitText(){
  522. Rectangle2D anchor = getAnchor();
  523. if(anchor.getWidth() == 0.) throw new POIXMLException(
  524. "Anchor of the shape was not set.");
  525. double height = getTextHeight();
  526. height += 1; // add a pixel to compensate rounding errors
  527. anchor.setRect(anchor.getX(), anchor.getY(), anchor.getWidth(), height);
  528. setAnchor(anchor);
  529. return anchor;
  530. }
  531. @Override
  532. void copy(XSLFShape other){
  533. super.copy(other);
  534. XSLFTextShape otherTS = (XSLFTextShape)other;
  535. CTTextBody otherTB = otherTS.getTextBody(false);
  536. CTTextBody thisTB = getTextBody(true);
  537. if (otherTB == null) {
  538. return;
  539. }
  540. thisTB.setBodyPr((CTTextBodyProperties)otherTB.getBodyPr().copy());
  541. if (thisTB.isSetLstStyle()) thisTB.unsetLstStyle();
  542. if (otherTB.isSetLstStyle()) {
  543. thisTB.setLstStyle((CTTextListStyle)otherTB.getLstStyle().copy());
  544. }
  545. boolean srcWordWrap = otherTS.getWordWrap();
  546. if(srcWordWrap != getWordWrap()){
  547. setWordWrap(srcWordWrap);
  548. }
  549. double leftInset = otherTS.getLeftInset();
  550. if(leftInset != getLeftInset()) {
  551. setLeftInset(leftInset);
  552. }
  553. double rightInset = otherTS.getRightInset();
  554. if(rightInset != getRightInset()) {
  555. setRightInset(rightInset);
  556. }
  557. double topInset = otherTS.getTopInset();
  558. if(topInset != getTopInset()) {
  559. setTopInset(topInset);
  560. }
  561. double bottomInset = otherTS.getBottomInset();
  562. if(bottomInset != getBottomInset()) {
  563. setBottomInset(bottomInset);
  564. }
  565. VerticalAlignment vAlign = otherTS.getVerticalAlignment();
  566. if(vAlign != getVerticalAlignment()) {
  567. setVerticalAlignment(vAlign);
  568. }
  569. clearText();
  570. for (XSLFTextParagraph srcP : otherTS.getTextParagraphs()) {
  571. XSLFTextParagraph tgtP = addNewTextParagraph();
  572. tgtP.copy(srcP);
  573. }
  574. }
  575. @Override
  576. public void setTextPlaceholder(TextPlaceholder placeholder) {
  577. switch (placeholder) {
  578. default:
  579. case NOTES:
  580. case HALF_BODY:
  581. case QUARTER_BODY:
  582. case BODY:
  583. setPlaceholder(Placeholder.BODY);
  584. break;
  585. case TITLE:
  586. setPlaceholder(Placeholder.TITLE);
  587. break;
  588. case CENTER_BODY:
  589. setPlaceholder(Placeholder.BODY);
  590. setHorizontalCentered(true);
  591. break;
  592. case CENTER_TITLE:
  593. setPlaceholder(Placeholder.CENTERED_TITLE);
  594. break;
  595. case OTHER:
  596. setPlaceholder(Placeholder.CONTENT);
  597. break;
  598. }
  599. }
  600. @Override
  601. public TextPlaceholder getTextPlaceholder() {
  602. Placeholder ph = getTextType();
  603. if (ph == null) return TextPlaceholder.BODY;
  604. switch (ph) {
  605. case BODY: return TextPlaceholder.BODY;
  606. case TITLE: return TextPlaceholder.TITLE;
  607. case CENTERED_TITLE: return TextPlaceholder.CENTER_TITLE;
  608. default:
  609. case CONTENT: return TextPlaceholder.OTHER;
  610. }
  611. }
  612. /**
  613. * Helper method to allow subclasses to provide their own text paragraph
  614. *
  615. * @param p the xml reference
  616. *
  617. * @return a new text paragraph
  618. *
  619. * @since POI 3.15-beta2
  620. */
  621. protected XSLFTextParagraph newTextParagraph(CTTextParagraph p) {
  622. return new XSLFTextParagraph(p, this);
  623. }
  624. }