Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

XSSFSimpleShape.java 30KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860
  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.xssf.usermodel;
  16. import java.util.ArrayList;
  17. import java.util.Iterator;
  18. import java.util.List;
  19. import org.apache.poi.hssf.util.HSSFColor;
  20. import org.openxmlformats.schemas.drawingml.x2006.main.*;
  21. import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShape;
  22. import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShapeNonVisual;
  23. import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRElt;
  24. import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRPrElt;
  25. import org.apache.poi.util.Internal;
  26. import org.apache.poi.util.Units;
  27. import org.apache.poi.ss.usermodel.VerticalAlignment;
  28. import org.openxmlformats.schemas.spreadsheetml.x2006.main.STUnderlineValues;
  29. /**
  30. * Represents a shape with a predefined geometry in a SpreadsheetML drawing.
  31. * Possible shape types are defined in {@link org.apache.poi.ss.usermodel.ShapeTypes}
  32. */
  33. public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParagraph> { // TODO - instantiable superclass
  34. /**
  35. * List of the paragraphs that make up the text in this shape
  36. */
  37. private final List<XSSFTextParagraph> _paragraphs;
  38. /**
  39. * A default instance of CTShape used for creating new shapes.
  40. */
  41. private static CTShape prototype = null;
  42. /**
  43. * Xml bean that stores properties of this shape
  44. */
  45. private CTShape ctShape;
  46. protected XSSFSimpleShape(XSSFDrawing drawing, CTShape ctShape) {
  47. this.drawing = drawing;
  48. this.ctShape = ctShape;
  49. _paragraphs = new ArrayList<XSSFTextParagraph>();
  50. // initialize any existing paragraphs - this will be the default body paragraph in a new shape,
  51. // or existing paragraphs that have been loaded from the file
  52. CTTextBody body = ctShape.getTxBody();
  53. for(int i = 0; i < body.sizeOfPArray(); i++) {
  54. _paragraphs.add(new XSSFTextParagraph(body.getPArray(i), ctShape));
  55. }
  56. }
  57. /**
  58. * Prototype with the default structure of a new auto-shape.
  59. */
  60. protected static CTShape prototype() {
  61. if(prototype == null) {
  62. CTShape shape = CTShape.Factory.newInstance();
  63. CTShapeNonVisual nv = shape.addNewNvSpPr();
  64. CTNonVisualDrawingProps nvp = nv.addNewCNvPr();
  65. nvp.setId(1);
  66. nvp.setName("Shape 1");
  67. nv.addNewCNvSpPr();
  68. CTShapeProperties sp = shape.addNewSpPr();
  69. CTTransform2D t2d = sp.addNewXfrm();
  70. CTPositiveSize2D p1 = t2d.addNewExt();
  71. p1.setCx(0);
  72. p1.setCy(0);
  73. CTPoint2D p2 = t2d.addNewOff();
  74. p2.setX(0);
  75. p2.setY(0);
  76. CTPresetGeometry2D geom = sp.addNewPrstGeom();
  77. geom.setPrst(STShapeType.RECT);
  78. geom.addNewAvLst();
  79. CTTextBody body = shape.addNewTxBody();
  80. CTTextBodyProperties bodypr = body.addNewBodyPr();
  81. bodypr.setAnchor(STTextAnchoringType.T);
  82. bodypr.setRtlCol(false);
  83. CTTextParagraph p = body.addNewP();
  84. p.addNewPPr().setAlgn(STTextAlignType.L);
  85. CTTextCharacterProperties endPr = p.addNewEndParaRPr();
  86. endPr.setLang("en-US");
  87. endPr.setSz(1100);
  88. CTSolidColorFillProperties scfpr = endPr.addNewSolidFill();
  89. scfpr.addNewSrgbClr().setVal(new byte[] { 0, 0, 0 });
  90. body.addNewLstStyle();
  91. prototype = shape;
  92. }
  93. return prototype;
  94. }
  95. @Internal
  96. public CTShape getCTShape(){
  97. return ctShape;
  98. }
  99. public Iterator<XSSFTextParagraph> iterator(){
  100. return _paragraphs.iterator();
  101. }
  102. /**
  103. * Returns the text from all paragraphs in the shape. Paragraphs are separated by new lines.
  104. *
  105. * @return text contained within this shape or empty string
  106. */
  107. public String getText() {
  108. final int MAX_LEVELS = 9;
  109. StringBuilder out = new StringBuilder();
  110. List<Integer> levelCount = new ArrayList<Integer>(MAX_LEVELS); // maximum 9 levels
  111. XSSFTextParagraph p = null;
  112. // initialise the levelCount array - this maintains a record of the numbering to be used at each level
  113. for (int k = 0; k < MAX_LEVELS; k++){
  114. levelCount.add(0);
  115. }
  116. for(int i = 0; i < _paragraphs.size(); i++) {
  117. if (out.length() > 0) out.append('\n');
  118. p = _paragraphs.get(i);
  119. if(p.isBullet() && p.getText().length() > 0){
  120. int level = Math.min(p.getLevel(), MAX_LEVELS - 1);
  121. if(p.isBulletAutoNumber()){
  122. i = processAutoNumGroup(i, level, levelCount, out);
  123. } else {
  124. // indent appropriately for the level
  125. for(int j = 0; j < level; j++){
  126. out.append('\t');
  127. }
  128. String character = p.getBulletCharacter();
  129. out.append(character.length() > 0 ? character + " " : "- ");
  130. out.append(p.getText());
  131. }
  132. } else {
  133. out.append(p.getText());
  134. // this paragraph is not a bullet, so reset the count array
  135. for (int k = 0; k < MAX_LEVELS; k++){
  136. levelCount.set(k, 0);
  137. }
  138. }
  139. }
  140. return out.toString();
  141. }
  142. /**
  143. *
  144. */
  145. private int processAutoNumGroup(int index, int level, List<Integer> levelCount, StringBuilder out){
  146. XSSFTextParagraph p = null;
  147. XSSFTextParagraph nextp = null;
  148. ListAutoNumber scheme, nextScheme;
  149. int startAt, nextStartAt;
  150. p = _paragraphs.get(index);
  151. // The rules for generating the auto numbers are as follows. If the following paragraph is also
  152. // an auto-number, has the same type/scheme (and startAt if defined on this paragraph) then they are
  153. // considered part of the same group. An empty bullet paragraph is counted as part of the same
  154. // group but does not increment the count for the group. A change of type, startAt or the paragraph
  155. // not being a bullet resets the count for that level to 1.
  156. // first auto-number paragraph so initialise to 1 or the bullets startAt if present
  157. startAt = p.getBulletAutoNumberStart();
  158. scheme = p.getBulletAutoNumberScheme();
  159. if(levelCount.get(level) == 0) {
  160. levelCount.set(level, startAt == 0 ? 1 : startAt);
  161. }
  162. // indent appropriately for the level
  163. for(int j = 0; j < level; j++){
  164. out.append('\t');
  165. }
  166. if (p.getText().length() > 0){
  167. out.append(getBulletPrefix(scheme, levelCount.get(level)));
  168. out.append(p.getText());
  169. }
  170. while(true) {
  171. nextp = (index + 1) == _paragraphs.size() ? null : _paragraphs.get(index + 1);
  172. if(nextp == null) break; // out of paragraphs
  173. if(!(nextp.isBullet() && p.isBulletAutoNumber())) break; // not an auto-number bullet
  174. if(nextp.getLevel() > level) {
  175. // recurse into the new level group
  176. if (out.length() > 0) out.append('\n');
  177. index = processAutoNumGroup(index + 1, nextp.getLevel(), levelCount, out);
  178. continue; // restart the loop given the new index
  179. } else if(nextp.getLevel() < level) {
  180. break; // changed level
  181. }
  182. nextScheme = nextp.getBulletAutoNumberScheme();
  183. nextStartAt = nextp.getBulletAutoNumberStart();
  184. if(nextScheme == scheme && nextStartAt == startAt) {
  185. // bullet is valid, so increment i
  186. ++index;
  187. if (out.length() > 0) out.append('\n');
  188. // indent for the level
  189. for(int j = 0; j < level; j++){
  190. out.append('\t');
  191. }
  192. // check for empty text - only output a bullet if there is text, but it is still part of the group
  193. if(nextp.getText().length() > 0) {
  194. // increment the count for this level
  195. levelCount.set(level, levelCount.get(level) + 1);
  196. out.append(getBulletPrefix(nextScheme, levelCount.get(level)));
  197. out.append(nextp.getText());
  198. }
  199. } else {
  200. // something doesn't match so stop
  201. break;
  202. }
  203. }
  204. // end of the group so reset the count for this level
  205. levelCount.set(level, 0);
  206. return index;
  207. }
  208. /**
  209. * Returns a string containing an appropriate prefix for an auto-numbering bullet
  210. * @param scheme the auto-numbering scheme used by the bullet
  211. * @param value the value of the bullet
  212. * @return
  213. */
  214. private String getBulletPrefix(ListAutoNumber scheme, int value){
  215. StringBuilder out = new StringBuilder();
  216. switch(scheme) {
  217. case ALPHA_LC_PARENT_BOTH:
  218. case ALPHA_LC_PARENT_R:
  219. if(scheme == ListAutoNumber.ALPHA_LC_PARENT_BOTH) out.append('(');
  220. out.append(valueToAlpha(value).toLowerCase());
  221. out.append(')');
  222. break;
  223. case ALPHA_UC_PARENT_BOTH:
  224. case ALPHA_UC_PARENT_R:
  225. if(scheme == ListAutoNumber.ALPHA_UC_PARENT_BOTH) out.append('(');
  226. out.append(valueToAlpha(value));
  227. out.append(')');
  228. break;
  229. case ALPHA_LC_PERIOD:
  230. out.append(valueToAlpha(value).toLowerCase());
  231. out.append('.');
  232. break;
  233. case ALPHA_UC_PERIOD:
  234. out.append(valueToAlpha(value));
  235. out.append('.');
  236. break;
  237. case ARABIC_PARENT_BOTH:
  238. case ARABIC_PARENT_R:
  239. if(scheme == ListAutoNumber.ARABIC_PARENT_BOTH) out.append('(');
  240. out.append(value);
  241. out.append(')');
  242. break;
  243. case ARABIC_PERIOD:
  244. out.append(value);
  245. out.append('.');
  246. break;
  247. case ARABIC_PLAIN:
  248. out.append(value);
  249. break;
  250. case ROMAN_LC_PARENT_BOTH:
  251. case ROMAN_LC_PARENT_R:
  252. if(scheme == ListAutoNumber.ROMAN_LC_PARENT_BOTH) out.append('(');
  253. out.append(valueToRoman(value).toLowerCase());
  254. out.append(')');
  255. break;
  256. case ROMAN_UC_PARENT_BOTH:
  257. case ROMAN_UC_PARENT_R:
  258. if(scheme == ListAutoNumber.ROMAN_UC_PARENT_BOTH) out.append('(');
  259. out.append(valueToRoman(value));
  260. out.append(')');
  261. break;
  262. case ROMAN_LC_PERIOD:
  263. out.append(valueToRoman(value).toLowerCase());
  264. out.append('.');
  265. break;
  266. case ROMAN_UC_PERIOD:
  267. out.append(valueToRoman(value));
  268. out.append('.');
  269. break;
  270. default:
  271. out.append('\u2022'); // can't set the font to wingdings so use the default bullet character
  272. break;
  273. }
  274. out.append(" ");
  275. return out.toString();
  276. }
  277. /**
  278. * Convert an integer to its alpha equivalent e.g. 1 = A, 2 = B, 27 = AA etc
  279. */
  280. private String valueToAlpha(int value) {
  281. String alpha = "";
  282. int modulo;
  283. while (value > 0) {
  284. modulo = (value - 1) % 26;
  285. alpha = (char)(65 + modulo) + alpha;
  286. value = (int)((value - modulo) / 26);
  287. }
  288. return alpha;
  289. }
  290. private static String[] _romanChars = new String[] { "M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I" };
  291. private static int[] _romanAlphaValues = new int[] { 1000,900,500,400,100,90,50,40,10,9,5,4,1 };
  292. /**
  293. * Convert an integer to its roman equivalent e.g. 1 = I, 9 = IX etc
  294. */
  295. private String valueToRoman(int value) {
  296. StringBuilder out = new StringBuilder();
  297. for(int i = 0; value > 0 && i < _romanChars.length; i++) {
  298. while(_romanAlphaValues[i] <= value) {
  299. out.append(_romanChars[i]);
  300. value -= _romanAlphaValues[i];
  301. }
  302. }
  303. return out.toString();
  304. }
  305. /**
  306. * Clear all text from this shape
  307. */
  308. public void clearText(){
  309. _paragraphs.clear();
  310. CTTextBody txBody = ctShape.getTxBody();
  311. txBody.setPArray(null); // remove any existing paragraphs
  312. }
  313. /**
  314. * Set a single paragraph of text on the shape. Note this will replace all existing paragraphs created on the shape.
  315. * @param text string representing the paragraph text
  316. */
  317. public void setText(String text){
  318. clearText();
  319. addNewTextParagraph().addNewTextRun().setText(text);
  320. }
  321. /**
  322. * Set a single paragraph of text on the shape. Note this will replace all existing paragraphs created on the shape.
  323. * @param str rich text string representing the paragraph text
  324. */
  325. public void setText(XSSFRichTextString str){
  326. XSSFWorkbook wb = (XSSFWorkbook)getDrawing().getParent().getParent();
  327. str.setStylesTableReference(wb.getStylesSource());
  328. CTTextParagraph p = CTTextParagraph.Factory.newInstance();
  329. if(str.numFormattingRuns() == 0){
  330. CTRegularTextRun r = p.addNewR();
  331. CTTextCharacterProperties rPr = r.addNewRPr();
  332. rPr.setLang("en-US");
  333. rPr.setSz(1100);
  334. r.setT(str.getString());
  335. } else {
  336. for (int i = 0; i < str.getCTRst().sizeOfRArray(); i++) {
  337. CTRElt lt = str.getCTRst().getRArray(i);
  338. CTRPrElt ltPr = lt.getRPr();
  339. if(ltPr == null) ltPr = lt.addNewRPr();
  340. CTRegularTextRun r = p.addNewR();
  341. CTTextCharacterProperties rPr = r.addNewRPr();
  342. rPr.setLang("en-US");
  343. applyAttributes(ltPr, rPr);
  344. r.setT(lt.getT());
  345. }
  346. }
  347. clearText();
  348. ctShape.getTxBody().setPArray(new CTTextParagraph[]{p});
  349. _paragraphs.add(new XSSFTextParagraph(ctShape.getTxBody().getPArray(0), ctShape));
  350. }
  351. /**
  352. * Returns a collection of the XSSFTextParagraphs that are attached to this shape
  353. *
  354. * @return text paragraphs in this shape
  355. */
  356. public List<XSSFTextParagraph> getTextParagraphs() {
  357. return _paragraphs;
  358. }
  359. /**
  360. * Add a new paragraph run to this shape
  361. *
  362. * @return created paragraph run
  363. */
  364. public XSSFTextParagraph addNewTextParagraph() {
  365. CTTextBody txBody = ctShape.getTxBody();
  366. CTTextParagraph p = txBody.addNewP();
  367. XSSFTextParagraph paragraph = new XSSFTextParagraph(p, ctShape);
  368. _paragraphs.add(paragraph);
  369. return paragraph;
  370. }
  371. /**
  372. * Add a new paragraph run to this shape, set to the provided string
  373. *
  374. * @return created paragraph run
  375. */
  376. public XSSFTextParagraph addNewTextParagraph(String text) {
  377. XSSFTextParagraph paragraph = addNewTextParagraph();
  378. paragraph.addNewTextRun().setText(text);
  379. return paragraph;
  380. }
  381. /**
  382. * Add a new paragraph run to this shape, set to the provided rich text string
  383. *
  384. * @return created paragraph run
  385. */
  386. public XSSFTextParagraph addNewTextParagraph(XSSFRichTextString str) {
  387. CTTextBody txBody = ctShape.getTxBody();
  388. CTTextParagraph p = txBody.addNewP();
  389. if(str.numFormattingRuns() == 0){
  390. CTRegularTextRun r = p.addNewR();
  391. CTTextCharacterProperties rPr = r.addNewRPr();
  392. rPr.setLang("en-US");
  393. rPr.setSz(1100);
  394. r.setT(str.getString());
  395. } else {
  396. for (int i = 0; i < str.getCTRst().sizeOfRArray(); i++) {
  397. CTRElt lt = str.getCTRst().getRArray(i);
  398. CTRPrElt ltPr = lt.getRPr();
  399. if(ltPr == null) ltPr = lt.addNewRPr();
  400. CTRegularTextRun r = p.addNewR();
  401. CTTextCharacterProperties rPr = r.addNewRPr();
  402. rPr.setLang("en-US");
  403. applyAttributes(ltPr, rPr);
  404. r.setT(lt.getT());
  405. }
  406. }
  407. // Note: the XSSFTextParagraph constructor will create its required XSSFTextRuns from the provided CTTextParagraph
  408. XSSFTextParagraph paragraph = new XSSFTextParagraph(p, ctShape);
  409. _paragraphs.add(paragraph);
  410. return paragraph;
  411. }
  412. /**
  413. * Sets the type of horizontal overflow for the text.
  414. *
  415. * @param overflow - the type of horizontal overflow.
  416. * A <code>null</code> values unsets this property.
  417. */
  418. public void setTextHorizontalOverflow(TextHorizontalOverflow overflow){
  419. CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
  420. if (bodyPr != null) {
  421. if(anchor == null) {
  422. if(bodyPr.isSetHorzOverflow()) bodyPr.unsetHorzOverflow();
  423. } else {
  424. bodyPr.setHorzOverflow(STTextHorzOverflowType.Enum.forInt(overflow.ordinal() + 1));
  425. }
  426. }
  427. }
  428. /**
  429. * Returns the type of horizontal overflow for the text.
  430. *
  431. * @return the type of horizontal overflow
  432. */
  433. public TextHorizontalOverflow getTextHorizontalOverflow(){
  434. CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
  435. if(bodyPr != null) {
  436. if(bodyPr.isSetHorzOverflow()){
  437. return TextHorizontalOverflow.values()[bodyPr.getVertOverflow().intValue() - 1];
  438. }
  439. }
  440. return TextHorizontalOverflow.OVERFLOW;
  441. }
  442. /**
  443. * Sets the type of vertical overflow for the text.
  444. *
  445. * @param overflow - the type of vertical overflow.
  446. * A <code>null</code> values unsets this property.
  447. */
  448. public void setTextVerticalOverflow(TextVerticalOverflow overflow){
  449. CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
  450. if (bodyPr != null) {
  451. if(anchor == null) {
  452. if(bodyPr.isSetVertOverflow()) bodyPr.unsetVertOverflow();
  453. } else {
  454. bodyPr.setVertOverflow(STTextVertOverflowType.Enum.forInt(overflow.ordinal() + 1));
  455. }
  456. }
  457. }
  458. /**
  459. * Returns the type of vertical overflow for the text.
  460. *
  461. * @return the type of vertical overflow
  462. */
  463. public TextVerticalOverflow getTextVerticalOverflow(){
  464. CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
  465. if(bodyPr != null) {
  466. if(bodyPr.isSetVertOverflow()){
  467. return TextVerticalOverflow.values()[bodyPr.getVertOverflow().intValue() - 1];
  468. }
  469. }
  470. return TextVerticalOverflow.OVERFLOW;
  471. }
  472. /**
  473. * Sets the type of vertical alignment for the text within the shape.
  474. *
  475. * @param anchor - the type of alignment.
  476. * A <code>null</code> values unsets this property.
  477. */
  478. public void setVerticalAlignment(VerticalAlignment anchor){
  479. CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
  480. if (bodyPr != null) {
  481. if(anchor == null) {
  482. if(bodyPr.isSetAnchor()) bodyPr.unsetAnchor();
  483. } else {
  484. bodyPr.setAnchor(STTextAnchoringType.Enum.forInt(anchor.ordinal() + 1));
  485. }
  486. }
  487. }
  488. /**
  489. * Returns the type of vertical alignment for the text within the shape.
  490. *
  491. * @return the type of vertical alignment
  492. */
  493. public VerticalAlignment getVerticalAlignment(){
  494. CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
  495. if(bodyPr != null) {
  496. if(bodyPr.isSetAnchor()){
  497. return VerticalAlignment.values()[bodyPr.getAnchor().intValue() - 1];
  498. }
  499. }
  500. return VerticalAlignment.TOP;
  501. }
  502. /**
  503. * Sets the vertical orientation of the text
  504. *
  505. * @param orientation vertical orientation of the text
  506. * A <code>null</code> values unsets this property.
  507. */
  508. public void setTextDirection(TextDirection orientation){
  509. CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
  510. if (bodyPr != null) {
  511. if(orientation == null) {
  512. if(bodyPr.isSetVert()) bodyPr.unsetVert();
  513. } else {
  514. bodyPr.setVert(STTextVerticalType.Enum.forInt(orientation.ordinal() + 1));
  515. }
  516. }
  517. }
  518. /**
  519. * Gets the vertical orientation of the text
  520. *
  521. * @return vertical orientation of the text
  522. */
  523. public TextDirection getTextDirection(){
  524. CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
  525. if (bodyPr != null) {
  526. STTextVerticalType.Enum val = bodyPr.getVert();
  527. if(val != null){
  528. return TextDirection.values()[val.intValue() - 1];
  529. }
  530. }
  531. return TextDirection.HORIZONTAL;
  532. }
  533. /**
  534. * Returns the distance (in points) between the bottom of the text frame
  535. * and the bottom of the inscribed rectangle of the shape that contains the text.
  536. *
  537. * @return the bottom inset in points
  538. */
  539. public double getBottomInset(){
  540. CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
  541. if (bodyPr != null) {
  542. if(bodyPr.isSetBIns()){
  543. return Units.toPoints(bodyPr.getBIns());
  544. }
  545. }
  546. // If this attribute is omitted, then a value of 0.05 inches is implied
  547. return 3.6;
  548. }
  549. /**
  550. * Returns the distance (in points) between the left edge of the text frame
  551. * and the left edge of the inscribed rectangle of the shape that contains
  552. * the text.
  553. *
  554. * @return the left inset in points
  555. */
  556. public double getLeftInset(){
  557. CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
  558. if (bodyPr != null) {
  559. if(bodyPr.isSetLIns()){
  560. return Units.toPoints(bodyPr.getLIns());
  561. }
  562. }
  563. // If this attribute is omitted, then a value of 0.05 inches is implied
  564. return 3.6;
  565. }
  566. /**
  567. * Returns the distance (in points) between the right edge of the
  568. * text frame and the right edge of the inscribed rectangle of the shape
  569. * that contains the text.
  570. *
  571. * @return the right inset in points
  572. */
  573. public double getRightInset(){
  574. CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
  575. if (bodyPr != null) {
  576. if(bodyPr.isSetRIns()){
  577. return Units.toPoints(bodyPr.getRIns());
  578. }
  579. }
  580. // If this attribute is omitted, then a value of 0.05 inches is implied
  581. return 3.6;
  582. }
  583. /**
  584. * Returns the distance (in points) between the top of the text frame
  585. * and the top of the inscribed rectangle of the shape that contains the text.
  586. *
  587. * @return the top inset in points
  588. */
  589. public double getTopInset(){
  590. CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
  591. if (bodyPr != null) {
  592. if(bodyPr.isSetTIns()){
  593. return Units.toPoints(bodyPr.getTIns());
  594. }
  595. }
  596. // If this attribute is omitted, then a value of 0.05 inches is implied
  597. return 3.6;
  598. }
  599. /**
  600. * Sets the bottom inset.
  601. * @see #getBottomInset()
  602. *
  603. * @param margin the bottom margin
  604. */
  605. public void setBottomInset(double margin){
  606. CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
  607. if (bodyPr != null) {
  608. if(margin == -1) bodyPr.unsetBIns();
  609. else bodyPr.setBIns(Units.toEMU(margin));
  610. }
  611. }
  612. /**
  613. * Sets the left inset.
  614. * @see #getLeftInset()
  615. *
  616. * @param margin the left margin
  617. */
  618. public void setLeftInset(double margin){
  619. CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
  620. if (bodyPr != null) {
  621. if(margin == -1) bodyPr.unsetLIns();
  622. else bodyPr.setLIns(Units.toEMU(margin));
  623. }
  624. }
  625. /**
  626. * Sets the right inset.
  627. * @see #getRightInset()
  628. *
  629. * @param margin the right margin
  630. */
  631. public void setRightInset(double margin){
  632. CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
  633. if (bodyPr != null) {
  634. if(margin == -1) bodyPr.unsetRIns();
  635. else bodyPr.setRIns(Units.toEMU(margin));
  636. }
  637. }
  638. /**
  639. * Sets the top inset.
  640. * @see #getTopInset()
  641. *
  642. * @param margin the top margin
  643. */
  644. public void setTopInset(double margin){
  645. CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
  646. if (bodyPr != null) {
  647. if(margin == -1) bodyPr.unsetTIns();
  648. else bodyPr.setTIns(Units.toEMU(margin));
  649. }
  650. }
  651. /**
  652. * @return whether to wrap words within the bounding rectangle
  653. */
  654. public boolean getWordWrap(){
  655. CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
  656. if (bodyPr != null) {
  657. if(bodyPr.isSetWrap()){
  658. return bodyPr.getWrap() == STTextWrappingType.SQUARE;
  659. }
  660. }
  661. return true;
  662. }
  663. /**
  664. *
  665. * @param wrap whether to wrap words within the bounding rectangle
  666. */
  667. public void setWordWrap(boolean wrap){
  668. CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
  669. if (bodyPr != null) {
  670. bodyPr.setWrap(wrap ? STTextWrappingType.SQUARE : STTextWrappingType.NONE);
  671. }
  672. }
  673. /**
  674. *
  675. * Specifies that a shape should be auto-fit to fully contain the text described within it.
  676. * Auto-fitting is when text within a shape is scaled in order to contain all the text inside
  677. *
  678. * @param value type of autofit
  679. */
  680. public void setTextAutofit(TextAutofit value){
  681. CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
  682. if (bodyPr != null) {
  683. if(bodyPr.isSetSpAutoFit()) bodyPr.unsetSpAutoFit();
  684. if(bodyPr.isSetNoAutofit()) bodyPr.unsetNoAutofit();
  685. if(bodyPr.isSetNormAutofit()) bodyPr.unsetNormAutofit();
  686. switch(value){
  687. case NONE: bodyPr.addNewNoAutofit(); break;
  688. case NORMAL: bodyPr.addNewNormAutofit(); break;
  689. case SHAPE: bodyPr.addNewSpAutoFit(); break;
  690. }
  691. }
  692. }
  693. /**
  694. *
  695. * @return type of autofit
  696. */
  697. public TextAutofit getTextAutofit(){
  698. CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
  699. if (bodyPr != null) {
  700. if(bodyPr.isSetNoAutofit()) return TextAutofit.NONE;
  701. else if (bodyPr.isSetNormAutofit()) return TextAutofit.NORMAL;
  702. else if (bodyPr.isSetSpAutoFit()) return TextAutofit.SHAPE;
  703. }
  704. return TextAutofit.NORMAL;
  705. }
  706. /**
  707. * Gets the shape type, one of the constants defined in {@link org.apache.poi.ss.usermodel.ShapeTypes}.
  708. *
  709. * @return the shape type
  710. * @see org.apache.poi.ss.usermodel.ShapeTypes
  711. */
  712. public int getShapeType() {
  713. return ctShape.getSpPr().getPrstGeom().getPrst().intValue();
  714. }
  715. /**
  716. * Sets the shape types.
  717. *
  718. * @param type the shape type, one of the constants defined in {@link org.apache.poi.ss.usermodel.ShapeTypes}.
  719. * @see org.apache.poi.ss.usermodel.ShapeTypes
  720. */
  721. public void setShapeType(int type) {
  722. ctShape.getSpPr().getPrstGeom().setPrst(STShapeType.Enum.forInt(type));
  723. }
  724. protected CTShapeProperties getShapeProperties(){
  725. return ctShape.getSpPr();
  726. }
  727. /**
  728. * org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRPrElt to
  729. * org.openxmlformats.schemas.drawingml.x2006.main.CTFont adapter
  730. */
  731. private static void applyAttributes(CTRPrElt pr, CTTextCharacterProperties rPr){
  732. if(pr.sizeOfBArray() > 0) rPr.setB(pr.getBArray(0).getVal());
  733. if(pr.sizeOfUArray() > 0) {
  734. STUnderlineValues.Enum u1 = pr.getUArray(0).getVal();
  735. if(u1 == STUnderlineValues.SINGLE) rPr.setU(STTextUnderlineType.SNG);
  736. else if(u1 == STUnderlineValues.DOUBLE) rPr.setU(STTextUnderlineType.DBL);
  737. else if(u1 == STUnderlineValues.NONE) rPr.setU(STTextUnderlineType.NONE);
  738. }
  739. if(pr.sizeOfIArray() > 0) rPr.setI(pr.getIArray(0).getVal());
  740. if(pr.sizeOfRFontArray() > 0) {
  741. CTTextFont rFont = rPr.isSetLatin() ? rPr.getLatin() : rPr.addNewLatin();
  742. rFont.setTypeface(pr.getRFontArray(0).getVal());
  743. }
  744. if(pr.sizeOfSzArray() > 0) {
  745. int sz = (int)(pr.getSzArray(0).getVal()*100);
  746. rPr.setSz(sz);
  747. }
  748. if(pr.sizeOfColorArray() > 0) {
  749. CTSolidColorFillProperties fill = rPr.isSetSolidFill() ? rPr.getSolidFill() : rPr.addNewSolidFill();
  750. org.openxmlformats.schemas.spreadsheetml.x2006.main.CTColor xlsColor = pr.getColorArray(0);
  751. if(xlsColor.isSetRgb()) {
  752. CTSRgbColor clr = fill.isSetSrgbClr() ? fill.getSrgbClr() : fill.addNewSrgbClr();
  753. clr.setVal(xlsColor.getRgb());
  754. }
  755. else if(xlsColor.isSetIndexed()) {
  756. HSSFColor indexed = HSSFColor.getIndexHash().get((int) xlsColor.getIndexed());
  757. if (indexed != null) {
  758. byte[] rgb = new byte[3];
  759. rgb[0] = (byte) indexed.getTriplet()[0];
  760. rgb[1] = (byte) indexed.getTriplet()[1];
  761. rgb[2] = (byte) indexed.getTriplet()[2];
  762. CTSRgbColor clr = fill.isSetSrgbClr() ? fill.getSrgbClr() : fill.addNewSrgbClr();
  763. clr.setVal(rgb);
  764. }
  765. }
  766. }
  767. }
  768. }