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 25KB

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