PageRenderTime 128ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/pptx/src/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java

https://github.com/minstrelsy/POI-Android
Java | 971 lines | 731 code | 111 blank | 129 comment | 200 complexity | 90e9bcad3d44264dac9d11db9a001e3f MD5 | raw file
  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.util.ArrayList;
  21. import java.util.List;
  22. import net.pbdavey.awt.Graphics2D;
  23. import org.apache.poi.util.Beta;
  24. import org.apache.poi.util.Units;
  25. import org.apache.poi.xslf.model.PropertyFetcher;
  26. import org.apache.poi.xslf.model.geom.CustomGeometry;
  27. import org.apache.poi.xslf.model.geom.Outline;
  28. import org.apache.poi.xslf.model.geom.Path;
  29. import org.apache.poi.xslf.model.geom.PresetGeometries;
  30. import org.apache.xmlbeans.XmlObject;
  31. import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;
  32. import org.openxmlformats.schemas.drawingml.x2006.main.CTLineEndProperties;
  33. import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties;
  34. import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
  35. //import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
  36. import org.openxmlformats.schemas.drawingml.x2006.main.CTOuterShadowEffect;
  37. import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
  38. import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
  39. import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetLineDashProperties;
  40. import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;
  41. import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
  42. import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle;
  43. import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
  44. import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrix;
  45. import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
  46. import org.openxmlformats.schemas.drawingml.x2006.main.STLineCap;
  47. import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndLength;
  48. import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndType;
  49. import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndWidth;
  50. import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal;
  51. import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;
  52. import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
  53. import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
  54. import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
  55. import and.awt.Color;
  56. import and.awt.Paint;
  57. import and.awt.Shape;
  58. import and.awt.geom.AffineTransform;
  59. import and.awt.geom.Ellipse2D;
  60. import and.awt.geom.GeneralPath;
  61. import and.awt.geom.Rectangle2D;
  62. /**
  63. * Represents a single (non-group) shape in a .pptx slide show
  64. *
  65. * @author Yegor Kozlov
  66. */
  67. @Beta
  68. public abstract class XSLFSimpleShape extends XSLFShape {
  69. private static CTOuterShadowEffect NO_SHADOW = CTOuterShadowEffect.Factory.newInstance();
  70. private final XmlObject _shape;
  71. private final XSLFSheet _sheet;
  72. private CTShapeProperties _spPr;
  73. private CTShapeStyle _spStyle;
  74. private CTNonVisualDrawingProps _nvPr;
  75. private CTPlaceholder _ph;
  76. /* package */XSLFSimpleShape(XmlObject shape, XSLFSheet sheet) {
  77. _shape = shape;
  78. _sheet = sheet;
  79. }
  80. @Override
  81. public XmlObject getXmlObject() {
  82. return _shape;
  83. }
  84. /**
  85. *
  86. * @return the sheet this shape belongs to
  87. */
  88. public XSLFSheet getSheet() {
  89. return _sheet;
  90. }
  91. /**
  92. *
  93. * @param type
  94. */
  95. public void setShapeType(XSLFShapeType type){
  96. CTShape shape = (CTShape) getXmlObject();
  97. STShapeType.Enum geom = STShapeType.Enum.forInt(type.getIndex());
  98. shape.getSpPr().getPrstGeom().setPrst(geom);
  99. }
  100. public XSLFShapeType getShapeType(){
  101. CTShape shape = (CTShape) getXmlObject();
  102. STShapeType.Enum geom = shape.getSpPr().getPrstGeom().getPrst();
  103. return XSLFShapeType.forInt(geom.intValue());
  104. }
  105. @Override
  106. public String getShapeName() {
  107. return getNvPr().getName();
  108. }
  109. @Override
  110. public int getShapeId() {
  111. return (int) getNvPr().getId();
  112. }
  113. protected CTNonVisualDrawingProps getNvPr() {
  114. if (_nvPr == null) {
  115. XmlObject[] rs = _shape
  116. .selectPath("declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//*/p:cNvPr");
  117. if (rs.length != 0) {
  118. _nvPr = (CTNonVisualDrawingProps) rs[0];
  119. }
  120. }
  121. return _nvPr;
  122. }
  123. protected CTShapeProperties getSpPr() {
  124. if (_spPr == null) {
  125. for (XmlObject obj : _shape.selectPath("*")) {
  126. if (obj instanceof CTShapeProperties) {
  127. _spPr = (CTShapeProperties) obj;
  128. }
  129. }
  130. }
  131. if (_spPr == null) {
  132. throw new IllegalStateException("CTShapeProperties was not found.");
  133. }
  134. return _spPr;
  135. }
  136. protected CTShapeStyle getSpStyle() {
  137. if (_spStyle == null) {
  138. for (XmlObject obj : _shape.selectPath("*")) {
  139. if (obj instanceof CTShapeStyle) {
  140. _spStyle = (CTShapeStyle) obj;
  141. }
  142. }
  143. }
  144. return _spStyle;
  145. }
  146. protected CTPlaceholder getCTPlaceholder() {
  147. if (_ph == null) {
  148. XmlObject[] obj = _shape.selectPath(
  149. "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//*/p:nvPr/p:ph");
  150. if (obj.length == 1) {
  151. _ph = (CTPlaceholder) obj[0];
  152. }
  153. }
  154. return _ph;
  155. }
  156. CTTransform2D getXfrm() {
  157. PropertyFetcher<CTTransform2D> fetcher = new PropertyFetcher<CTTransform2D>() {
  158. public boolean fetch(XSLFSimpleShape shape) {
  159. CTShapeProperties pr = shape.getSpPr();
  160. if (pr.isSetXfrm()) {
  161. setValue(pr.getXfrm());
  162. return true;
  163. }
  164. return false;
  165. }
  166. };
  167. fetchShapeProperty(fetcher);
  168. return fetcher.getValue();
  169. }
  170. @Override
  171. public Rectangle2D getAnchor() {
  172. CTTransform2D xfrm = getXfrm();
  173. CTPoint2D off = xfrm.getOff();
  174. long x = off.getX();
  175. long y = off.getY();
  176. CTPositiveSize2D ext = xfrm.getExt();
  177. long cx = ext.getCx();
  178. long cy = ext.getCy();
  179. return new Rectangle2D.Double(
  180. Units.toPoints(x), Units.toPoints(y),
  181. Units.toPoints(cx), Units.toPoints(cy));
  182. }
  183. @Override
  184. public void setAnchor(Rectangle2D anchor) {
  185. CTShapeProperties spPr = getSpPr();
  186. CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm();
  187. CTPoint2D off = xfrm.isSetOff() ? xfrm.getOff() : xfrm.addNewOff();
  188. long x = Units.toEMU(anchor.getX());
  189. long y = Units.toEMU(anchor.getY());
  190. off.setX(x);
  191. off.setY(y);
  192. CTPositiveSize2D ext = xfrm.isSetExt() ? xfrm.getExt() : xfrm
  193. .addNewExt();
  194. long cx = Units.toEMU(anchor.getWidth());
  195. long cy = Units.toEMU(anchor.getHeight());
  196. ext.setCx(cx);
  197. ext.setCy(cy);
  198. }
  199. @Override
  200. public void setRotation(double theta) {
  201. CTShapeProperties spPr = getSpPr();
  202. CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm();
  203. xfrm.setRot((int) (theta * 60000));
  204. }
  205. @Override
  206. public double getRotation() {
  207. CTTransform2D xfrm = getXfrm();
  208. return (double) xfrm.getRot() / 60000;
  209. }
  210. @Override
  211. public void setFlipHorizontal(boolean flip) {
  212. CTShapeProperties spPr = getSpPr();
  213. CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm();
  214. xfrm.setFlipH(flip);
  215. }
  216. @Override
  217. public void setFlipVertical(boolean flip) {
  218. CTShapeProperties spPr = getSpPr();
  219. CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm();
  220. xfrm.setFlipV(flip);
  221. }
  222. @Override
  223. public boolean getFlipHorizontal() {
  224. return getXfrm().getFlipH();
  225. }
  226. @Override
  227. public boolean getFlipVertical() {
  228. return getXfrm().getFlipV();
  229. }
  230. /**
  231. * Get default line properties defined in the theme (if any).
  232. * Used internally to resolve shape properties.
  233. *
  234. * @return line propeties from the theme of null
  235. */
  236. CTLineProperties getDefaultLineProperties() {
  237. CTLineProperties ln = null;
  238. CTShapeStyle style = getSpStyle();
  239. if (style != null) {
  240. // 1-based index of a line style within the style matrix
  241. int idx = (int) style.getLnRef().getIdx();
  242. CTStyleMatrix styleMatrix = _sheet.getTheme().getXmlObject().getThemeElements().getFmtScheme();
  243. ln = styleMatrix.getLnStyleLst().getLnArray(idx - 1);
  244. }
  245. return ln;
  246. }
  247. /**
  248. * @param color the color to paint the shape outline.
  249. * A <code>null</code> value turns off the shape outline.
  250. */
  251. public void setLineColor(Color color) {
  252. CTShapeProperties spPr = getSpPr();
  253. if (color == null) {
  254. if (spPr.isSetLn() && spPr.getLn().isSetSolidFill())
  255. spPr.getLn().unsetSolidFill();
  256. } else {
  257. CTLineProperties ln = spPr.isSetLn() ? spPr.getLn() : spPr
  258. .addNewLn();
  259. CTSRgbColor rgb = CTSRgbColor.Factory.newInstance();
  260. rgb.setVal(new byte[]{(byte) color.getRed(),
  261. (byte) color.getGreen(), (byte) color.getBlue()});
  262. CTSolidColorFillProperties fill = ln.isSetSolidFill() ? ln
  263. .getSolidFill() : ln.addNewSolidFill();
  264. fill.setSrgbClr(rgb);
  265. if(fill.isSetHslClr()) fill.unsetHslClr();
  266. if(fill.isSetPrstClr()) fill.unsetPrstClr();
  267. if(fill.isSetSchemeClr()) fill.unsetSchemeClr();
  268. if(fill.isSetScrgbClr()) fill.unsetScrgbClr();
  269. if(fill.isSetSysClr()) fill.unsetSysClr();
  270. }
  271. }
  272. /**
  273. *
  274. * @return the color of the shape outline or <code>null</code>
  275. * if outline is turned off
  276. */
  277. public Color getLineColor() {
  278. RenderableShape rShape = new RenderableShape(this);
  279. Paint paint = rShape.getLinePaint(null);
  280. if (paint instanceof Color) {
  281. return (Color) paint;
  282. }
  283. return null;
  284. }
  285. /**
  286. *
  287. * @param width line width in points. <code>0</code> means no line
  288. */
  289. public void setLineWidth(double width) {
  290. CTShapeProperties spPr = getSpPr();
  291. if (width == 0.) {
  292. if (spPr.isSetLn())
  293. spPr.getLn().unsetW();
  294. } else {
  295. CTLineProperties ln = spPr.isSetLn() ? spPr.getLn() : spPr
  296. .addNewLn();
  297. ln.setW(Units.toEMU(width));
  298. }
  299. }
  300. /**
  301. *
  302. * @return line width in points. <code>0</code> means no line.
  303. */
  304. public double getLineWidth() {
  305. PropertyFetcher<Double> fetcher = new PropertyFetcher<Double>() {
  306. public boolean fetch(XSLFSimpleShape shape) {
  307. CTShapeProperties spPr = shape.getSpPr();
  308. CTLineProperties ln = spPr.getLn();
  309. if (ln != null) {
  310. if (ln.isSetNoFill()) {
  311. setValue(0.);
  312. return true;
  313. }
  314. if (ln.isSetW()) {
  315. setValue(Units.toPoints(ln.getW()));
  316. return true;
  317. }
  318. }
  319. return false;
  320. }
  321. };
  322. fetchShapeProperty(fetcher);
  323. double lineWidth = 0;
  324. if (fetcher.getValue() == null) {
  325. CTLineProperties defaultLn = getDefaultLineProperties();
  326. if (defaultLn != null) {
  327. if (defaultLn.isSetW()) lineWidth = Units.toPoints(defaultLn.getW());
  328. }
  329. } else {
  330. lineWidth = fetcher.getValue();
  331. }
  332. return lineWidth;
  333. }
  334. /**
  335. *
  336. * @param dash a preset line dashing scheme to stroke thr shape outline
  337. */
  338. public void setLineDash(LineDash dash) {
  339. CTShapeProperties spPr = getSpPr();
  340. if (dash == null) {
  341. if (spPr.isSetLn())
  342. spPr.getLn().unsetPrstDash();
  343. } else {
  344. CTPresetLineDashProperties val = CTPresetLineDashProperties.Factory
  345. .newInstance();
  346. val.setVal(STPresetLineDashVal.Enum.forInt(dash.ordinal() + 1));
  347. CTLineProperties ln = spPr.isSetLn() ? spPr.getLn() : spPr
  348. .addNewLn();
  349. ln.setPrstDash(val);
  350. }
  351. }
  352. /**
  353. * @return a preset line dashing scheme to stroke thr shape outline
  354. */
  355. public LineDash getLineDash() {
  356. PropertyFetcher<LineDash> fetcher = new PropertyFetcher<LineDash>() {
  357. public boolean fetch(XSLFSimpleShape shape) {
  358. CTShapeProperties spPr = shape.getSpPr();
  359. CTLineProperties ln = spPr.getLn();
  360. if (ln != null) {
  361. CTPresetLineDashProperties ctDash = ln.getPrstDash();
  362. if (ctDash != null) {
  363. setValue(LineDash.values()[ctDash.getVal().intValue() - 1]);
  364. return true;
  365. }
  366. }
  367. return false;
  368. }
  369. };
  370. fetchShapeProperty(fetcher);
  371. LineDash dash = fetcher.getValue();
  372. if (dash == null) {
  373. CTLineProperties defaultLn = getDefaultLineProperties();
  374. if (defaultLn != null) {
  375. CTPresetLineDashProperties ctDash = defaultLn.getPrstDash();
  376. if (ctDash != null) {
  377. dash = LineDash.values()[ctDash.getVal().intValue() - 1];
  378. }
  379. }
  380. }
  381. return dash;
  382. }
  383. /**
  384. *
  385. * @param cap the line end cap style
  386. */
  387. public void setLineCap(LineCap cap) {
  388. CTShapeProperties spPr = getSpPr();
  389. if (cap == null) {
  390. if (spPr.isSetLn())
  391. spPr.getLn().unsetCap();
  392. } else {
  393. CTLineProperties ln = spPr.isSetLn() ? spPr.getLn() : spPr
  394. .addNewLn();
  395. ln.setCap(STLineCap.Enum.forInt(cap.ordinal() + 1));
  396. }
  397. }
  398. /**
  399. *
  400. * @return the line end cap style
  401. */
  402. public LineCap getLineCap() {
  403. PropertyFetcher<LineCap> fetcher = new PropertyFetcher<LineCap>() {
  404. public boolean fetch(XSLFSimpleShape shape) {
  405. CTShapeProperties spPr = shape.getSpPr();
  406. CTLineProperties ln = spPr.getLn();
  407. if (ln != null) {
  408. STLineCap.Enum stCap = ln.getCap();
  409. if (stCap != null) {
  410. setValue(LineCap.values()[stCap.intValue() - 1]);
  411. return true;
  412. }
  413. }
  414. return false;
  415. }
  416. };
  417. fetchShapeProperty(fetcher);
  418. LineCap cap = fetcher.getValue();
  419. if (cap == null) {
  420. CTLineProperties defaultLn = getDefaultLineProperties();
  421. if (defaultLn != null) {
  422. STLineCap.Enum stCap = defaultLn.getCap();
  423. if (stCap != null) {
  424. cap = LineCap.values()[stCap.intValue() - 1];
  425. }
  426. }
  427. }
  428. return cap;
  429. }
  430. /**
  431. * Specifies a solid color fill. The shape is filled entirely with the
  432. * specified color.
  433. *
  434. * @param color the solid color fill. The value of <code>null</code> unsets
  435. * the solidFIll attribute from the underlying xml
  436. */
  437. public void setFillColor(Color color) {
  438. CTShapeProperties spPr = getSpPr();
  439. if (color == null) {
  440. if (spPr.isSetSolidFill()) spPr.unsetSolidFill();
  441. if (!spPr.isSetNoFill()) spPr.addNewNoFill();
  442. } else {
  443. if (spPr.isSetNoFill()) spPr.unsetNoFill();
  444. CTSolidColorFillProperties fill = spPr.isSetSolidFill() ? spPr
  445. .getSolidFill() : spPr.addNewSolidFill();
  446. CTSRgbColor rgb = CTSRgbColor.Factory.newInstance();
  447. rgb.setVal(new byte[]{(byte) color.getRed(),
  448. (byte) color.getGreen(), (byte) color.getBlue()});
  449. fill.setSrgbClr(rgb);
  450. if(fill.isSetHslClr()) fill.unsetHslClr();
  451. if(fill.isSetPrstClr()) fill.unsetPrstClr();
  452. if(fill.isSetSchemeClr()) fill.unsetSchemeClr();
  453. if(fill.isSetScrgbClr()) fill.unsetScrgbClr();
  454. if(fill.isSetSysClr()) fill.unsetSysClr();
  455. }
  456. }
  457. /**
  458. * @return solid fill color of null if not set or fill color
  459. * is not solid (pattern or gradient)
  460. */
  461. public Color getFillColor() {
  462. RenderableShape rShape = new RenderableShape(this);
  463. Paint paint = rShape.getFillPaint(null);
  464. if (paint instanceof Color) {
  465. return (Color) paint;
  466. }
  467. return null;
  468. }
  469. /**
  470. * @return shadow of this shape or null if shadow is disabled
  471. */
  472. public XSLFShadow getShadow() {
  473. PropertyFetcher<CTOuterShadowEffect> fetcher = new PropertyFetcher<CTOuterShadowEffect>() {
  474. public boolean fetch(XSLFSimpleShape shape) {
  475. CTShapeProperties spPr = shape.getSpPr();
  476. if (spPr.isSetEffectLst()) {
  477. CTOuterShadowEffect obj = spPr.getEffectLst().getOuterShdw();
  478. setValue(obj == null ? NO_SHADOW : obj);
  479. return true;
  480. }
  481. return false;
  482. }
  483. };
  484. fetchShapeProperty(fetcher);
  485. CTOuterShadowEffect obj = fetcher.getValue();
  486. if (obj == null) {
  487. // fill color was not found, check if it is defined in the theme
  488. CTShapeStyle style = getSpStyle();
  489. if (style != null) {
  490. // 1-based index of a shadow style within the style matrix
  491. int idx = (int) style.getEffectRef().getIdx();
  492. if(idx != 0) {
  493. CTStyleMatrix styleMatrix = _sheet.getTheme().getXmlObject().getThemeElements().getFmtScheme();
  494. // CTEffectStyleItem ef = styleMatrix.getEffectStyleLst().getEffectStyleArray(idx - 1);
  495. // obj = ef.getEffectLst().getOuterShdw();
  496. }
  497. }
  498. }
  499. return (obj == null || obj == NO_SHADOW) ? null : new XSLFShadow(obj, this);
  500. }
  501. @Override
  502. public void draw(Graphics2D graphics) {
  503. RenderableShape rShape = new RenderableShape(this);
  504. rShape.render(graphics);
  505. // draw line decorations
  506. Color lineColor = getLineColor();
  507. if(lineColor != null) {
  508. graphics.setPaint(lineColor);
  509. for(Outline o : getDecorationOutlines(graphics)){
  510. if(o.getPath().isFilled()){
  511. graphics.fill(o.getOutline());
  512. }
  513. if(o.getPath().isStroked()){
  514. graphics.draw(o.getOutline());
  515. }
  516. }
  517. }
  518. }
  519. /**
  520. * Walk up the inheritance tree and fetch shape properties.
  521. *
  522. * The following order of inheritance is assumed:
  523. * <p>
  524. * slide <-- slideLayout <-- slideMaster
  525. * </p>
  526. *
  527. * @param visitor the object that collects the desired property
  528. * @return true if the property was fetched
  529. */
  530. boolean fetchShapeProperty(PropertyFetcher visitor) {
  531. boolean ok = visitor.fetch(this);
  532. XSLFSimpleShape masterShape;
  533. XSLFSheet masterSheet = getSheet().getMasterSheet();
  534. CTPlaceholder ph = getCTPlaceholder();
  535. if (masterSheet != null && ph != null) {
  536. if (!ok) {
  537. masterShape = masterSheet.getPlaceholder(ph);
  538. if (masterShape != null) {
  539. ok = visitor.fetch(masterShape);
  540. }
  541. }
  542. // try slide master
  543. if (!ok ) {
  544. int textType;
  545. if ( !ph.isSetType()) textType = STPlaceholderType.INT_BODY;
  546. else {
  547. switch (ph.getType().intValue()) {
  548. case STPlaceholderType.INT_TITLE:
  549. case STPlaceholderType.INT_CTR_TITLE:
  550. textType = STPlaceholderType.INT_TITLE;
  551. break;
  552. case STPlaceholderType.INT_FTR:
  553. case STPlaceholderType.INT_SLD_NUM:
  554. case STPlaceholderType.INT_DT:
  555. textType = ph.getType().intValue();
  556. break;
  557. default:
  558. textType = STPlaceholderType.INT_BODY;
  559. break;
  560. }
  561. }
  562. XSLFSheet master = masterSheet.getMasterSheet();
  563. if (master != null) {
  564. masterShape = master.getPlaceholderByType(textType);
  565. if (masterShape != null) {
  566. ok = visitor.fetch(masterShape);
  567. }
  568. }
  569. }
  570. }
  571. return ok;
  572. }
  573. /**
  574. *
  575. * @return definition of the shape geometry
  576. */
  577. CustomGeometry getGeometry(){
  578. CTShapeProperties spPr = getSpPr();
  579. CustomGeometry geom;
  580. PresetGeometries dict = PresetGeometries.getInstance();
  581. if(spPr.isSetPrstGeom()){
  582. String name = spPr.getPrstGeom().getPrst().toString();
  583. geom = dict.get(name);
  584. if(geom == null) {
  585. throw new IllegalStateException("Unknown shape geometry: " + name);
  586. }
  587. } else if (spPr.isSetCustGeom()){
  588. geom = new CustomGeometry(spPr.getCustGeom());
  589. } else {
  590. geom = dict.get("rect");
  591. }
  592. return geom;
  593. }
  594. /**
  595. * draw any content within this shape (image, text, etc.).
  596. *
  597. * @param graphics the graphics to draw into
  598. */
  599. public void drawContent(Graphics2D graphics){
  600. }
  601. @Override
  602. void copy(XSLFShape sh){
  603. super.copy(sh);
  604. XSLFSimpleShape s = (XSLFSimpleShape)sh;
  605. Color srsSolidFill = s.getFillColor();
  606. Color tgtSoliFill = getFillColor();
  607. if(srsSolidFill != null && !srsSolidFill.equals(tgtSoliFill)){
  608. setFillColor(srsSolidFill);
  609. }
  610. if(getSpPr().isSetBlipFill()){
  611. CTBlip blip = getSpPr().getBlipFill().getBlip();
  612. String blipId = blip.getEmbed();
  613. String relId = getSheet().importBlip(blipId, s.getSheet().getPackagePart());
  614. blip.setEmbed(relId);
  615. }
  616. Color srcLineColor = s.getLineColor();
  617. Color tgtLineColor = getLineColor();
  618. if(srcLineColor != null && !srcLineColor.equals(tgtLineColor)) {
  619. setLineColor(srcLineColor);
  620. }
  621. double srcLineWidth = s.getLineWidth();
  622. double tgtLineWidth = getLineWidth();
  623. if(srcLineWidth != tgtLineWidth) {
  624. setLineWidth(srcLineWidth);
  625. }
  626. LineDash srcLineDash = s.getLineDash();
  627. LineDash tgtLineDash = getLineDash();
  628. if(srcLineDash != null && srcLineDash != tgtLineDash) {
  629. setLineDash(srcLineDash);
  630. }
  631. LineCap srcLineCap = s.getLineCap();
  632. LineCap tgtLineCap = getLineCap();
  633. if(srcLineCap != null && srcLineCap != tgtLineCap) {
  634. setLineCap(srcLineCap);
  635. }
  636. }
  637. /**
  638. * Specifies the line end decoration, such as a triangle or arrowhead.
  639. */
  640. public void setLineHeadDecoration(LineDecoration style) {
  641. CTLineProperties ln = getSpPr().getLn();
  642. CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd();
  643. if (style == null) {
  644. if (lnEnd.isSetType()) lnEnd.unsetType();
  645. } else {
  646. lnEnd.setType(STLineEndType.Enum.forInt(style.ordinal() + 1));
  647. }
  648. }
  649. public LineDecoration getLineHeadDecoration() {
  650. CTLineProperties ln = getSpPr().getLn();
  651. if (ln == null || !ln.isSetHeadEnd()) return LineDecoration.NONE;
  652. STLineEndType.Enum end = ln.getHeadEnd().getType();
  653. return end == null ? LineDecoration.NONE : LineDecoration.values()[end.intValue() - 1];
  654. }
  655. /**
  656. * specifies decorations which can be added to the head of a line.
  657. */
  658. public void setLineHeadWidth(LineEndWidth style) {
  659. CTLineProperties ln = getSpPr().getLn();
  660. CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd();
  661. if (style == null) {
  662. if (lnEnd.isSetW()) lnEnd.unsetW();
  663. } else {
  664. lnEnd.setW(STLineEndWidth.Enum.forInt(style.ordinal() + 1));
  665. }
  666. }
  667. public LineEndWidth getLineHeadWidth() {
  668. CTLineProperties ln = getSpPr().getLn();
  669. if (ln == null || !ln.isSetHeadEnd()) return LineEndWidth.MEDIUM;
  670. STLineEndWidth.Enum w = ln.getHeadEnd().getW();
  671. return w == null ? LineEndWidth.MEDIUM : LineEndWidth.values()[w.intValue() - 1];
  672. }
  673. /**
  674. * Specifies the line end width in relation to the line width.
  675. */
  676. public void setLineHeadLength(LineEndLength style) {
  677. CTLineProperties ln = getSpPr().getLn();
  678. CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd();
  679. if (style == null) {
  680. if (lnEnd.isSetLen()) lnEnd.unsetLen();
  681. } else {
  682. lnEnd.setLen(STLineEndLength.Enum.forInt(style.ordinal() + 1));
  683. }
  684. }
  685. public LineEndLength getLineHeadLength() {
  686. CTLineProperties ln = getSpPr().getLn();
  687. if (ln == null || !ln.isSetHeadEnd()) return LineEndLength.MEDIUM;
  688. STLineEndLength.Enum len = ln.getHeadEnd().getLen();
  689. return len == null ? LineEndLength.MEDIUM : LineEndLength.values()[len.intValue() - 1];
  690. }
  691. /**
  692. * Specifies the line end decoration, such as a triangle or arrowhead.
  693. */
  694. public void setLineTailDecoration(LineDecoration style) {
  695. CTLineProperties ln = getSpPr().getLn();
  696. CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd();
  697. if (style == null) {
  698. if (lnEnd.isSetType()) lnEnd.unsetType();
  699. } else {
  700. lnEnd.setType(STLineEndType.Enum.forInt(style.ordinal() + 1));
  701. }
  702. }
  703. public LineDecoration getLineTailDecoration() {
  704. CTLineProperties ln = getSpPr().getLn();
  705. if (ln == null || !ln.isSetTailEnd()) return LineDecoration.NONE;
  706. STLineEndType.Enum end = ln.getTailEnd().getType();
  707. return end == null ? LineDecoration.NONE : LineDecoration.values()[end.intValue() - 1];
  708. }
  709. /**
  710. * specifies decorations which can be added to the tail of a line.
  711. */
  712. public void setLineTailWidth(LineEndWidth style) {
  713. CTLineProperties ln = getSpPr().getLn();
  714. CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd();
  715. if (style == null) {
  716. if (lnEnd.isSetW()) lnEnd.unsetW();
  717. } else {
  718. lnEnd.setW(STLineEndWidth.Enum.forInt(style.ordinal() + 1));
  719. }
  720. }
  721. public LineEndWidth getLineTailWidth() {
  722. CTLineProperties ln = getSpPr().getLn();
  723. if (ln == null || !ln.isSetTailEnd()) return LineEndWidth.MEDIUM;
  724. STLineEndWidth.Enum w = ln.getTailEnd().getW();
  725. return w == null ? LineEndWidth.MEDIUM : LineEndWidth.values()[w.intValue() - 1];
  726. }
  727. /**
  728. * Specifies the line end width in relation to the line width.
  729. */
  730. public void setLineTailLength(LineEndLength style) {
  731. CTLineProperties ln = getSpPr().getLn();
  732. CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd();
  733. if (style == null) {
  734. if (lnEnd.isSetLen()) lnEnd.unsetLen();
  735. } else {
  736. lnEnd.setLen(STLineEndLength.Enum.forInt(style.ordinal() + 1));
  737. }
  738. }
  739. public LineEndLength getLineTailLength() {
  740. CTLineProperties ln = getSpPr().getLn();
  741. if (ln == null || !ln.isSetTailEnd()) return LineEndLength.MEDIUM;
  742. STLineEndLength.Enum len = ln.getTailEnd().getLen();
  743. return len == null ? LineEndLength.MEDIUM : LineEndLength.values()[len.intValue() - 1];
  744. }
  745. Outline getTailDecoration(Graphics2D graphics) {
  746. LineEndLength tailLength = getLineTailLength();
  747. LineEndWidth tailWidth = getLineTailWidth();
  748. double lineWidth = Math.max(2.5, getLineWidth());
  749. Rectangle2D anchor = new RenderableShape(this).getAnchor(graphics);
  750. double x2 = anchor.getX() + anchor.getWidth(),
  751. y2 = anchor.getY() + anchor.getHeight();
  752. double alpha = Math.atan(anchor.getHeight() / anchor.getWidth());
  753. AffineTransform at = new AffineTransform();
  754. Shape shape = null;
  755. Path p = null;
  756. Rectangle2D bounds;
  757. double scaleY = Math.pow(2, tailWidth.ordinal());
  758. double scaleX = Math.pow(2, tailLength.ordinal());
  759. switch (getLineTailDecoration()) {
  760. case OVAL:
  761. p = new Path();
  762. shape = new Ellipse2D.Double(0, 0, lineWidth * scaleX, lineWidth * scaleY);
  763. bounds = shape.getBounds2D();
  764. at.translate(x2 - bounds.getWidth() / 2, y2 - bounds.getHeight() / 2);
  765. at.rotate(alpha, bounds.getX() + bounds.getWidth() / 2, bounds.getY() + bounds.getHeight() / 2);
  766. break;
  767. case ARROW:
  768. p = new Path();
  769. GeneralPath arrow = new GeneralPath();
  770. arrow.moveTo((float) (-lineWidth * 3), (float) (-lineWidth * 2));
  771. arrow.lineTo(0, 0);
  772. arrow.lineTo((float) (-lineWidth * 3), (float) (lineWidth * 2));
  773. shape = arrow;
  774. at.translate(x2, y2);
  775. at.rotate(alpha);
  776. break;
  777. case TRIANGLE:
  778. p = new Path();
  779. scaleY = tailWidth.ordinal() + 1;
  780. scaleX = tailLength.ordinal() + 1;
  781. GeneralPath triangle = new GeneralPath();
  782. triangle.moveTo((float) (-lineWidth * scaleX), (float) (-lineWidth * scaleY / 2));
  783. triangle.lineTo(0, 0);
  784. triangle.lineTo((float) (-lineWidth * scaleX), (float) (lineWidth * scaleY / 2));
  785. triangle.closePath();
  786. shape = triangle;
  787. at.translate(x2, y2);
  788. at.rotate(alpha);
  789. break;
  790. default:
  791. break;
  792. }
  793. if (shape != null) {
  794. shape = at.createTransformedShape(shape);
  795. }
  796. return shape == null ? null : new Outline(shape, p);
  797. }
  798. Outline getHeadDecoration(Graphics2D graphics) {
  799. LineEndLength headLength = getLineHeadLength();
  800. LineEndWidth headWidth = getLineHeadWidth();
  801. double lineWidth = Math.max(2.5, getLineWidth());
  802. Rectangle2D anchor = new RenderableShape(this).getAnchor(graphics);
  803. double x1 = anchor.getX(),
  804. y1 = anchor.getY();
  805. double alpha = Math.atan(anchor.getHeight() / anchor.getWidth());
  806. AffineTransform at = new AffineTransform();
  807. Shape shape = null;
  808. Path p = null;
  809. Rectangle2D bounds;
  810. double scaleY = 1;
  811. double scaleX = 1;
  812. switch (getLineHeadDecoration()) {
  813. case OVAL:
  814. p = new Path();
  815. shape = new Ellipse2D.Double(0, 0, lineWidth * scaleX, lineWidth * scaleY);
  816. bounds = shape.getBounds2D();
  817. at.translate(x1 - bounds.getWidth() / 2, y1 - bounds.getHeight() / 2);
  818. at.rotate(alpha, bounds.getX() + bounds.getWidth() / 2, bounds.getY() + bounds.getHeight() / 2);
  819. break;
  820. case STEALTH:
  821. case ARROW:
  822. p = new Path(false, true);
  823. GeneralPath arrow = new GeneralPath();
  824. arrow.moveTo((float) (lineWidth * 3 * scaleX), (float) (-lineWidth * scaleY * 2));
  825. arrow.lineTo(0, 0);
  826. arrow.lineTo((float) (lineWidth * 3 * scaleX), (float) (lineWidth * scaleY * 2));
  827. shape = arrow;
  828. at.translate(x1, y1);
  829. at.rotate(alpha);
  830. break;
  831. case TRIANGLE:
  832. p = new Path();
  833. scaleY = headWidth.ordinal() + 1;
  834. scaleX = headLength.ordinal() + 1;
  835. GeneralPath triangle = new GeneralPath();
  836. triangle.moveTo((float) (lineWidth * scaleX), (float) (-lineWidth * scaleY / 2));
  837. triangle.lineTo(0, 0);
  838. triangle.lineTo((float) (lineWidth * scaleX), (float) (lineWidth * scaleY / 2));
  839. triangle.closePath();
  840. shape = triangle;
  841. at.translate(x1, y1);
  842. at.rotate(alpha);
  843. break;
  844. default:
  845. break;
  846. }
  847. if (shape != null) {
  848. shape = at.createTransformedShape(shape);
  849. }
  850. return shape == null ? null : new Outline(shape, p);
  851. }
  852. private List<Outline> getDecorationOutlines(Graphics2D graphics){
  853. List<Outline> lst = new ArrayList<Outline>();
  854. Outline head = getHeadDecoration(graphics);
  855. if(head != null) lst.add(head);
  856. Outline tail = getTailDecoration(graphics);
  857. if(tail != null) lst.add(tail);
  858. return lst;
  859. }
  860. }