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.

XSLFSimpleShape.java 38KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148
  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.Color;
  21. import java.awt.geom.Rectangle2D;
  22. import javax.xml.stream.XMLStreamException;
  23. import javax.xml.stream.XMLStreamReader;
  24. import org.apache.poi.openxml4j.opc.PackagePart;
  25. import org.apache.poi.sl.draw.DrawPaint;
  26. import org.apache.poi.sl.draw.geom.CustomGeometry;
  27. import org.apache.poi.sl.draw.geom.Guide;
  28. import org.apache.poi.sl.draw.geom.PresetGeometries;
  29. import org.apache.poi.sl.usermodel.FillStyle;
  30. import org.apache.poi.sl.usermodel.LineDecoration;
  31. import org.apache.poi.sl.usermodel.LineDecoration.DecorationShape;
  32. import org.apache.poi.sl.usermodel.LineDecoration.DecorationSize;
  33. import org.apache.poi.sl.usermodel.PaintStyle;
  34. import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
  35. import org.apache.poi.sl.usermodel.ShapeType;
  36. import org.apache.poi.sl.usermodel.SimpleShape;
  37. import org.apache.poi.sl.usermodel.StrokeStyle;
  38. import org.apache.poi.sl.usermodel.StrokeStyle.LineCap;
  39. import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound;
  40. import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;
  41. import org.apache.poi.util.Beta;
  42. import org.apache.poi.util.POILogFactory;
  43. import org.apache.poi.util.POILogger;
  44. import org.apache.poi.util.Units;
  45. import org.apache.poi.xslf.model.PropertyFetcher;
  46. import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFEffectProperties;
  47. import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFFillProperties;
  48. import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFGeometryProperties;
  49. import org.apache.xmlbeans.XmlObject;
  50. import org.openxmlformats.schemas.drawingml.x2006.main.CTBaseStyles;
  51. import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;
  52. import org.openxmlformats.schemas.drawingml.x2006.main.CTEffectStyleItem;
  53. import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomGuide;
  54. import org.openxmlformats.schemas.drawingml.x2006.main.CTLineEndProperties;
  55. import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties;
  56. import org.openxmlformats.schemas.drawingml.x2006.main.CTLineStyleList;
  57. import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
  58. import org.openxmlformats.schemas.drawingml.x2006.main.CTOuterShadowEffect;
  59. import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
  60. import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
  61. import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D;
  62. import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetLineDashProperties;
  63. import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;
  64. import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
  65. import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle;
  66. import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
  67. import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrix;
  68. import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrixReference;
  69. import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
  70. import org.openxmlformats.schemas.drawingml.x2006.main.STCompoundLine;
  71. import org.openxmlformats.schemas.drawingml.x2006.main.STLineCap;
  72. import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndLength;
  73. import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndType;
  74. import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndWidth;
  75. import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal;
  76. import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;
  77. import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
  78. /**
  79. * Represents a single (non-group) shape in a .pptx slide show
  80. */
  81. @Beta
  82. public abstract class XSLFSimpleShape extends XSLFShape
  83. implements SimpleShape<XSLFShape,XSLFTextParagraph> {
  84. private static CTOuterShadowEffect NO_SHADOW = CTOuterShadowEffect.Factory.newInstance();
  85. private static final POILogger LOG = POILogFactory.getLogger(XSLFSimpleShape.class);
  86. /* package */XSLFSimpleShape(XmlObject shape, XSLFSheet sheet) {
  87. super(shape,sheet);
  88. }
  89. @Override
  90. public void setShapeType(ShapeType type) {
  91. XSLFGeometryProperties gp = XSLFPropertiesDelegate.getGeometryDelegate(getShapeProperties());
  92. if (gp == null) {
  93. return;
  94. }
  95. if (gp.isSetCustGeom()) {
  96. gp.unsetCustGeom();
  97. }
  98. CTPresetGeometry2D prst = (gp.isSetPrstGeom()) ? gp.getPrstGeom() : gp.addNewPrstGeom();
  99. prst.setPrst(STShapeType.Enum.forInt(type.ooxmlId));
  100. }
  101. @Override
  102. public ShapeType getShapeType(){
  103. XSLFGeometryProperties gp = XSLFPropertiesDelegate.getGeometryDelegate(getShapeProperties());
  104. if (gp != null && gp.isSetPrstGeom()) {
  105. STShapeType.Enum geom = gp.getPrstGeom().getPrst();
  106. if (geom != null) {
  107. return ShapeType.forId(geom.intValue(), true);
  108. }
  109. }
  110. return null;
  111. }
  112. protected CTTransform2D getXfrm(boolean create) {
  113. PropertyFetcher<CTTransform2D> fetcher = new PropertyFetcher<CTTransform2D>() {
  114. @Override
  115. public boolean fetch(XSLFShape shape) {
  116. XmlObject xo = shape.getShapeProperties();
  117. if (xo instanceof CTShapeProperties && ((CTShapeProperties)xo).isSetXfrm()) {
  118. setValue(((CTShapeProperties)xo).getXfrm());
  119. return true;
  120. }
  121. return false;
  122. }
  123. };
  124. fetchShapeProperty(fetcher);
  125. CTTransform2D xfrm = fetcher.getValue();
  126. if (!create || xfrm != null) {
  127. return xfrm;
  128. } else {
  129. XmlObject xo = getShapeProperties();
  130. if (xo instanceof CTShapeProperties) {
  131. return ((CTShapeProperties)xo).addNewXfrm();
  132. } else {
  133. // ... group shapes have their own getXfrm()
  134. LOG.log(POILogger.WARN, getClass() +" doesn't have xfrm element.");
  135. return null;
  136. }
  137. }
  138. }
  139. @Override
  140. public Rectangle2D getAnchor() {
  141. CTTransform2D xfrm = getXfrm(false);
  142. if (xfrm == null || !xfrm.isSetOff()) {
  143. return null;
  144. }
  145. CTPoint2D off = xfrm.getOff();
  146. double x = Units.toPoints(off.getX());
  147. double y = Units.toPoints(off.getY());
  148. CTPositiveSize2D ext = xfrm.getExt();
  149. double cx = Units.toPoints(ext.getCx());
  150. double cy = Units.toPoints(ext.getCy());
  151. return new Rectangle2D.Double(x, y, cx, cy);
  152. }
  153. @Override
  154. public void setAnchor(Rectangle2D anchor) {
  155. CTTransform2D xfrm = getXfrm(true);
  156. if (xfrm == null) {
  157. return;
  158. }
  159. CTPoint2D off = xfrm.isSetOff() ? xfrm.getOff() : xfrm.addNewOff();
  160. long x = Units.toEMU(anchor.getX());
  161. long y = Units.toEMU(anchor.getY());
  162. off.setX(x);
  163. off.setY(y);
  164. CTPositiveSize2D ext = xfrm.isSetExt() ? xfrm.getExt() : xfrm
  165. .addNewExt();
  166. long cx = Units.toEMU(anchor.getWidth());
  167. long cy = Units.toEMU(anchor.getHeight());
  168. ext.setCx(cx);
  169. ext.setCy(cy);
  170. }
  171. @Override
  172. public void setRotation(double theta) {
  173. CTTransform2D xfrm = getXfrm(true);
  174. if (xfrm != null) {
  175. xfrm.setRot((int) (theta * 60000));
  176. }
  177. }
  178. @Override
  179. public double getRotation() {
  180. CTTransform2D xfrm = getXfrm(false);
  181. return (xfrm == null || !xfrm.isSetRot()) ? 0 : (xfrm.getRot() / 60000.d);
  182. }
  183. @Override
  184. public void setFlipHorizontal(boolean flip) {
  185. CTTransform2D xfrm = getXfrm(true);
  186. if (xfrm != null) {
  187. xfrm.setFlipH(flip);
  188. }
  189. }
  190. @Override
  191. public void setFlipVertical(boolean flip) {
  192. CTTransform2D xfrm = getXfrm(true);
  193. if (xfrm != null) {
  194. xfrm.setFlipV(flip);
  195. }
  196. }
  197. @Override
  198. public boolean getFlipHorizontal() {
  199. CTTransform2D xfrm = getXfrm(false);
  200. return (xfrm != null && xfrm.isSetFlipH()) && xfrm.getFlipH();
  201. }
  202. @Override
  203. public boolean getFlipVertical() {
  204. CTTransform2D xfrm = getXfrm(false);
  205. return (xfrm != null && xfrm.isSetFlipV()) && xfrm.getFlipV();
  206. }
  207. /**
  208. * Get default line properties defined in the theme (if any).
  209. * Used internally to resolve shape properties.
  210. *
  211. * @return line properties from the theme of null
  212. */
  213. private CTLineProperties getDefaultLineProperties() {
  214. CTShapeStyle style = getSpStyle();
  215. if (style == null) {
  216. return null;
  217. }
  218. CTStyleMatrixReference lnRef = style.getLnRef();
  219. if (lnRef == null) {
  220. return null;
  221. }
  222. // 1-based index of a line style within the style matrix
  223. int idx = (int)lnRef.getIdx();
  224. XSLFTheme theme = getSheet().getTheme();
  225. if (theme == null) {
  226. return null;
  227. }
  228. CTBaseStyles styles = theme.getXmlObject().getThemeElements();
  229. if (styles == null) {
  230. return null;
  231. }
  232. CTStyleMatrix styleMatrix = styles.getFmtScheme();
  233. if (styleMatrix == null) {
  234. return null;
  235. }
  236. CTLineStyleList lineStyles = styleMatrix.getLnStyleLst();
  237. if (lineStyles == null || lineStyles.sizeOfLnArray() < idx) {
  238. return null;
  239. }
  240. return lineStyles.getLnArray(idx - 1);
  241. }
  242. /**
  243. * @param color the color to paint the shape outline.
  244. * A <code>null</code> value turns off the shape outline.
  245. */
  246. public void setLineColor(Color color) {
  247. CTLineProperties ln = getLn(this, true);
  248. if (ln == null) {
  249. return;
  250. }
  251. if (ln.isSetSolidFill()) {
  252. ln.unsetSolidFill();
  253. }
  254. if (ln.isSetGradFill()) {
  255. ln.unsetGradFill();
  256. }
  257. if (ln.isSetPattFill()) {
  258. ln.unsetPattFill();
  259. }
  260. if (ln.isSetNoFill()) {
  261. ln.unsetNoFill();
  262. }
  263. if (color == null) {
  264. ln.addNewNoFill();
  265. } else {
  266. CTSolidColorFillProperties fill = ln.addNewSolidFill();
  267. XSLFColor col = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr());
  268. col.setColor(color);
  269. }
  270. }
  271. /**
  272. *
  273. * @return the color of the shape outline or <code>null</code>
  274. * if outline is turned off
  275. */
  276. @SuppressWarnings("WeakerAccess")
  277. public Color getLineColor() {
  278. PaintStyle ps = getLinePaint();
  279. if (ps instanceof SolidPaint) {
  280. return ((SolidPaint)ps).getSolidColor().getColor();
  281. }
  282. return null;
  283. }
  284. @SuppressWarnings("WeakerAccess")
  285. protected PaintStyle getLinePaint() {
  286. XSLFSheet sheet = getSheet();
  287. final XSLFTheme theme = sheet.getTheme();
  288. final boolean hasPlaceholder = getPlaceholder() != null;
  289. PropertyFetcher<PaintStyle> fetcher = new PropertyFetcher<PaintStyle>() {
  290. @Override
  291. public boolean fetch(XSLFShape shape) {
  292. CTLineProperties spPr = getLn(shape, false);
  293. XSLFFillProperties fp = XSLFPropertiesDelegate.getFillDelegate(spPr);
  294. if (fp != null && fp.isSetNoFill()) {
  295. setValue(null);
  296. return true;
  297. }
  298. PackagePart pp = shape.getSheet().getPackagePart();
  299. PaintStyle paint = selectPaint(fp, null, pp, theme, hasPlaceholder);
  300. if (paint != null) {
  301. setValue(paint);
  302. return true;
  303. }
  304. CTShapeStyle style = shape.getSpStyle();
  305. if (style != null) {
  306. fp = XSLFPropertiesDelegate.getFillDelegate(style.getLnRef());
  307. paint = selectPaint(fp, null, pp, theme, hasPlaceholder);
  308. // line color was not found, check if it is defined in the theme
  309. if (paint == null) {
  310. paint = getThemePaint(style, pp);
  311. }
  312. }
  313. if (paint != null) {
  314. setValue(paint);
  315. return true;
  316. }
  317. return false;
  318. }
  319. PaintStyle getThemePaint(CTShapeStyle style, PackagePart pp) {
  320. // get a reference to a line style within the style matrix.
  321. CTStyleMatrixReference lnRef = style.getLnRef();
  322. if (lnRef == null) {
  323. return null;
  324. }
  325. int idx = (int)lnRef.getIdx();
  326. CTSchemeColor phClr = lnRef.getSchemeClr();
  327. if(idx <= 0){
  328. return null;
  329. }
  330. CTLineProperties props = theme.getXmlObject().getThemeElements().getFmtScheme().getLnStyleLst().getLnArray(idx - 1);
  331. XSLFFillProperties fp = XSLFPropertiesDelegate.getFillDelegate(props);
  332. return selectPaint(fp, phClr, pp, theme, hasPlaceholder);
  333. }
  334. };
  335. fetchShapeProperty(fetcher);
  336. return fetcher.getValue();
  337. }
  338. /**
  339. *
  340. * @param width line width in points. <code>0</code> means no line
  341. */
  342. @SuppressWarnings("WeakerAccess")
  343. public void setLineWidth(double width) {
  344. CTLineProperties lnPr = getLn(this, true);
  345. if (lnPr == null) {
  346. return;
  347. }
  348. if (width == 0.) {
  349. if (lnPr.isSetW()) {
  350. lnPr.unsetW();
  351. }
  352. if (!lnPr.isSetNoFill()) {
  353. lnPr.addNewNoFill();
  354. }
  355. if (lnPr.isSetSolidFill()) {
  356. lnPr.unsetSolidFill();
  357. }
  358. if (lnPr.isSetGradFill()) {
  359. lnPr.unsetGradFill();
  360. }
  361. if (lnPr.isSetPattFill()) {
  362. lnPr.unsetPattFill();
  363. }
  364. } else {
  365. if (lnPr.isSetNoFill()) {
  366. lnPr.unsetNoFill();
  367. }
  368. lnPr.setW(Units.toEMU(width));
  369. }
  370. }
  371. /**
  372. * @return line width in points. <code>0</code> means no line.
  373. */
  374. @SuppressWarnings("WeakerAccess")
  375. public double getLineWidth() {
  376. PropertyFetcher<Double> fetcher = new PropertyFetcher<Double>() {
  377. @Override
  378. public boolean fetch(XSLFShape shape) {
  379. CTLineProperties ln = getLn(shape, false);
  380. if (ln != null) {
  381. if (ln.isSetNoFill()) {
  382. setValue(0.);
  383. return true;
  384. }
  385. if (ln.isSetW()) {
  386. setValue(Units.toPoints(ln.getW()));
  387. return true;
  388. }
  389. }
  390. return false;
  391. }
  392. };
  393. fetchShapeProperty(fetcher);
  394. double lineWidth = 0;
  395. if (fetcher.getValue() == null) {
  396. CTLineProperties defaultLn = getDefaultLineProperties();
  397. if (defaultLn != null) {
  398. if (defaultLn.isSetW()) {
  399. lineWidth = Units.toPoints(defaultLn.getW());
  400. }
  401. }
  402. } else {
  403. lineWidth = fetcher.getValue();
  404. }
  405. return lineWidth;
  406. }
  407. /**
  408. * @param compound set the line compound style
  409. */
  410. @SuppressWarnings("WeakerAccess")
  411. public void setLineCompound(LineCompound compound) {
  412. CTLineProperties ln = getLn(this, true);
  413. if (ln == null) {
  414. return;
  415. }
  416. if (compound == null) {
  417. if (ln.isSetCmpd()) {
  418. ln.unsetCmpd();
  419. }
  420. } else {
  421. STCompoundLine.Enum xCmpd;
  422. switch (compound) {
  423. default:
  424. case SINGLE:
  425. xCmpd = STCompoundLine.SNG;
  426. break;
  427. case DOUBLE:
  428. xCmpd = STCompoundLine.DBL;
  429. break;
  430. case THICK_THIN:
  431. xCmpd = STCompoundLine.THICK_THIN;
  432. break;
  433. case THIN_THICK:
  434. xCmpd = STCompoundLine.THIN_THICK;
  435. break;
  436. case TRIPLE:
  437. xCmpd = STCompoundLine.TRI;
  438. break;
  439. }
  440. ln.setCmpd(xCmpd);
  441. }
  442. }
  443. /**
  444. * @return the line compound
  445. */
  446. @SuppressWarnings("WeakerAccess")
  447. public LineCompound getLineCompound() {
  448. PropertyFetcher<Integer> fetcher = new PropertyFetcher<Integer>() {
  449. @Override
  450. public boolean fetch(XSLFShape shape) {
  451. CTLineProperties ln = getLn(shape, false);
  452. if (ln != null) {
  453. STCompoundLine.Enum stCmpd = ln.getCmpd();
  454. if (stCmpd != null) {
  455. setValue(stCmpd.intValue());
  456. return true;
  457. }
  458. }
  459. return false;
  460. }
  461. };
  462. fetchShapeProperty(fetcher);
  463. Integer cmpd = fetcher.getValue();
  464. if (cmpd == null) {
  465. CTLineProperties defaultLn = getDefaultLineProperties();
  466. if (defaultLn != null && defaultLn.isSetCmpd()) {
  467. switch (defaultLn.getCmpd().intValue()) {
  468. default:
  469. case STCompoundLine.INT_SNG:
  470. return LineCompound.SINGLE;
  471. case STCompoundLine.INT_DBL:
  472. return LineCompound.DOUBLE;
  473. case STCompoundLine.INT_THICK_THIN:
  474. return LineCompound.THICK_THIN;
  475. case STCompoundLine.INT_THIN_THICK:
  476. return LineCompound.THIN_THICK;
  477. case STCompoundLine.INT_TRI:
  478. return LineCompound.TRIPLE;
  479. }
  480. }
  481. }
  482. return null;
  483. }
  484. /**
  485. *
  486. * @param dash a preset line dashing scheme to stroke thr shape outline
  487. */
  488. @SuppressWarnings("WeakerAccess")
  489. public void setLineDash(LineDash dash) {
  490. CTLineProperties ln = getLn(this, true);
  491. if (ln == null) {
  492. return;
  493. }
  494. if (dash == null) {
  495. if (ln.isSetPrstDash()) {
  496. ln.unsetPrstDash();
  497. }
  498. } else {
  499. CTPresetLineDashProperties ldp = ln.isSetPrstDash() ? ln.getPrstDash() : ln.addNewPrstDash();
  500. ldp.setVal(STPresetLineDashVal.Enum.forInt(dash.ooxmlId));
  501. }
  502. }
  503. /**
  504. * @return a preset line dashing scheme to stroke the shape outline
  505. */
  506. @SuppressWarnings("WeakerAccess")
  507. public LineDash getLineDash() {
  508. PropertyFetcher<LineDash> fetcher = new PropertyFetcher<LineDash>() {
  509. @Override
  510. public boolean fetch(XSLFShape shape) {
  511. CTLineProperties ln = getLn(shape, false);
  512. if (ln == null || !ln.isSetPrstDash()) {
  513. return false;
  514. }
  515. setValue(LineDash.fromOoxmlId(ln.getPrstDash().getVal().intValue()));
  516. return true;
  517. }
  518. };
  519. fetchShapeProperty(fetcher);
  520. LineDash dash = fetcher.getValue();
  521. if (dash == null) {
  522. CTLineProperties defaultLn = getDefaultLineProperties();
  523. if (defaultLn != null && defaultLn.isSetPrstDash()) {
  524. dash = LineDash.fromOoxmlId(defaultLn.getPrstDash().getVal().intValue());
  525. }
  526. }
  527. return dash;
  528. }
  529. /**
  530. *
  531. * @param cap the line end cap style
  532. */
  533. @SuppressWarnings("WeakerAccess")
  534. public void setLineCap(LineCap cap) {
  535. CTLineProperties ln = getLn(this, true);
  536. if (ln == null) {
  537. return;
  538. }
  539. if (cap == null) {
  540. if (ln.isSetCap()) {
  541. ln.unsetCap();
  542. }
  543. } else {
  544. ln.setCap(STLineCap.Enum.forInt(cap.ooxmlId));
  545. }
  546. }
  547. /**
  548. *
  549. * @return the line end cap style
  550. */
  551. @SuppressWarnings("WeakerAccess")
  552. public LineCap getLineCap() {
  553. PropertyFetcher<LineCap> fetcher = new PropertyFetcher<LineCap>() {
  554. @Override
  555. public boolean fetch(XSLFShape shape) {
  556. CTLineProperties ln = getLn(shape, false);
  557. if (ln != null && ln.isSetCap()) {
  558. setValue(LineCap.fromOoxmlId(ln.getCap().intValue()));
  559. return true;
  560. }
  561. return false;
  562. }
  563. };
  564. fetchShapeProperty(fetcher);
  565. LineCap cap = fetcher.getValue();
  566. if (cap == null) {
  567. CTLineProperties defaultLn = getDefaultLineProperties();
  568. if (defaultLn != null && defaultLn.isSetCap()) {
  569. cap = LineCap.fromOoxmlId(defaultLn.getCap().intValue());
  570. }
  571. }
  572. return cap;
  573. }
  574. @Override
  575. public void setFillColor(Color color) {
  576. XSLFFillProperties fp = XSLFPropertiesDelegate.getFillDelegate(getShapeProperties());
  577. if (fp == null) {
  578. return;
  579. }
  580. if (color == null) {
  581. if (fp.isSetSolidFill()) {
  582. fp.unsetSolidFill();
  583. }
  584. if (fp.isSetGradFill()) {
  585. fp.unsetGradFill();
  586. }
  587. if (fp.isSetPattFill()) {
  588. fp.unsetGradFill();
  589. }
  590. if (fp.isSetBlipFill()) {
  591. fp.unsetBlipFill();
  592. }
  593. if (!fp.isSetNoFill()) {
  594. fp.addNewNoFill();
  595. }
  596. } else {
  597. if (fp.isSetNoFill()) {
  598. fp.unsetNoFill();
  599. }
  600. CTSolidColorFillProperties fill = fp.isSetSolidFill() ? fp.getSolidFill() : fp.addNewSolidFill();
  601. XSLFColor col = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr());
  602. col.setColor(color);
  603. }
  604. }
  605. @Override
  606. public Color getFillColor() {
  607. PaintStyle ps = getFillPaint();
  608. if (ps instanceof SolidPaint) {
  609. return DrawPaint.applyColorTransform(((SolidPaint)ps).getSolidColor());
  610. }
  611. return null;
  612. }
  613. /**
  614. * @return shadow of this shape or null if shadow is disabled
  615. */
  616. @Override
  617. public XSLFShadow getShadow() {
  618. PropertyFetcher<CTOuterShadowEffect> fetcher = new PropertyFetcher<CTOuterShadowEffect>() {
  619. @Override
  620. public boolean fetch(XSLFShape shape) {
  621. XSLFEffectProperties ep = XSLFPropertiesDelegate.getEffectDelegate(shape.getShapeProperties());
  622. if (ep != null && ep.isSetEffectLst()) {
  623. CTOuterShadowEffect obj = ep.getEffectLst().getOuterShdw();
  624. setValue(obj == null ? NO_SHADOW : obj);
  625. return true;
  626. }
  627. return false;
  628. }
  629. };
  630. fetchShapeProperty(fetcher);
  631. CTOuterShadowEffect obj = fetcher.getValue();
  632. if (obj == null) {
  633. // fill color was not found, check if it is defined in the theme
  634. CTShapeStyle style = getSpStyle();
  635. if (style != null && style.getEffectRef() != null) {
  636. // 1-based index of a shadow style within the style matrix
  637. int idx = (int) style.getEffectRef().getIdx();
  638. if(idx != 0) {
  639. CTStyleMatrix styleMatrix = getSheet().getTheme().getXmlObject().getThemeElements().getFmtScheme();
  640. CTEffectStyleItem ef = styleMatrix.getEffectStyleLst().getEffectStyleArray(idx - 1);
  641. obj = ef.getEffectLst().getOuterShdw();
  642. }
  643. }
  644. }
  645. return (obj == null || obj == NO_SHADOW) ? null : new XSLFShadow(obj, this);
  646. }
  647. /**
  648. * @return definition of the shape geometry
  649. */
  650. @Override
  651. public CustomGeometry getGeometry() {
  652. XSLFGeometryProperties gp = XSLFPropertiesDelegate.getGeometryDelegate(getShapeProperties());
  653. if (gp == null) {
  654. return null;
  655. }
  656. CustomGeometry geom;
  657. PresetGeometries dict = PresetGeometries.getInstance();
  658. if(gp.isSetPrstGeom()){
  659. String name = gp.getPrstGeom().getPrst().toString();
  660. geom = dict.get(name);
  661. if(geom == null) {
  662. throw new IllegalStateException("Unknown shape geometry: " + name + ", available geometries are: " + dict.keySet());
  663. }
  664. } else if (gp.isSetCustGeom()){
  665. XMLStreamReader staxReader = gp.getCustGeom().newXMLStreamReader();
  666. geom = PresetGeometries.convertCustomGeometry(staxReader);
  667. try {
  668. staxReader.close();
  669. }
  670. catch (XMLStreamException e) {
  671. LOG.log(POILogger.WARN,
  672. "An error occurred while closing a Custom Geometry XML Stream Reader: " + e.getMessage());
  673. }
  674. } else {
  675. geom = dict.get("rect");
  676. }
  677. return geom;
  678. }
  679. @Override
  680. void copy(XSLFShape sh){
  681. super.copy(sh);
  682. XSLFSimpleShape s = (XSLFSimpleShape)sh;
  683. Color srsSolidFill = s.getFillColor();
  684. Color tgtSoliFill = getFillColor();
  685. if(srsSolidFill != null && !srsSolidFill.equals(tgtSoliFill)){
  686. setFillColor(srsSolidFill);
  687. }
  688. XSLFFillProperties fp = XSLFPropertiesDelegate.getFillDelegate(getShapeProperties());
  689. if(fp != null && fp.isSetBlipFill()){
  690. CTBlip blip = fp.getBlipFill().getBlip();
  691. String blipId = blip.getEmbed();
  692. String relId = getSheet().importBlip(blipId, s.getSheet());
  693. blip.setEmbed(relId);
  694. }
  695. Color srcLineColor = s.getLineColor();
  696. Color tgtLineColor = getLineColor();
  697. if(srcLineColor != null && !srcLineColor.equals(tgtLineColor)) {
  698. setLineColor(srcLineColor);
  699. }
  700. double srcLineWidth = s.getLineWidth();
  701. double tgtLineWidth = getLineWidth();
  702. if(srcLineWidth != tgtLineWidth) {
  703. setLineWidth(srcLineWidth);
  704. }
  705. LineDash srcLineDash = s.getLineDash();
  706. LineDash tgtLineDash = getLineDash();
  707. if(srcLineDash != null && srcLineDash != tgtLineDash) {
  708. setLineDash(srcLineDash);
  709. }
  710. LineCap srcLineCap = s.getLineCap();
  711. LineCap tgtLineCap = getLineCap();
  712. if(srcLineCap != null && srcLineCap != tgtLineCap) {
  713. setLineCap(srcLineCap);
  714. }
  715. }
  716. /**
  717. * Specifies the line end decoration, such as a triangle or arrowhead.
  718. *
  719. * @param style the line end docoration style
  720. */
  721. @SuppressWarnings("WeakerAccess")
  722. public void setLineHeadDecoration(DecorationShape style) {
  723. CTLineProperties ln = getLn(this, true);
  724. if (ln == null) {
  725. return;
  726. }
  727. CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd();
  728. if (style == null) {
  729. if (lnEnd.isSetType()) {
  730. lnEnd.unsetType();
  731. }
  732. } else {
  733. lnEnd.setType(STLineEndType.Enum.forInt(style.ooxmlId));
  734. }
  735. }
  736. /**
  737. * @return the line end decoration shape
  738. */
  739. @SuppressWarnings("WeakerAccess")
  740. public DecorationShape getLineHeadDecoration() {
  741. CTLineProperties ln = getLn(this, false);
  742. DecorationShape ds = DecorationShape.NONE;
  743. if (ln != null && ln.isSetHeadEnd() && ln.getHeadEnd().isSetType()) {
  744. ds = DecorationShape.fromOoxmlId(ln.getHeadEnd().getType().intValue());
  745. }
  746. return ds;
  747. }
  748. /**
  749. * specifies decoration width of the head of a line.
  750. *
  751. * @param style the decoration width
  752. */
  753. @SuppressWarnings("WeakerAccess")
  754. public void setLineHeadWidth(DecorationSize style) {
  755. CTLineProperties ln = getLn(this, true);
  756. if (ln == null) {
  757. return;
  758. }
  759. CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd();
  760. if (style == null) {
  761. if (lnEnd.isSetW()) {
  762. lnEnd.unsetW();
  763. }
  764. } else {
  765. lnEnd.setW(STLineEndWidth.Enum.forInt(style.ooxmlId));
  766. }
  767. }
  768. /**
  769. * @return the line end decoration width
  770. */
  771. @SuppressWarnings("WeakerAccess")
  772. public DecorationSize getLineHeadWidth() {
  773. CTLineProperties ln = getLn(this, false);
  774. DecorationSize ds = DecorationSize.MEDIUM;
  775. if (ln != null && ln.isSetHeadEnd() && ln.getHeadEnd().isSetW()) {
  776. ds = DecorationSize.fromOoxmlId(ln.getHeadEnd().getW().intValue());
  777. }
  778. return ds;
  779. }
  780. /**
  781. * Specifies the line end width in relation to the line width.
  782. */
  783. @SuppressWarnings("WeakerAccess")
  784. public void setLineHeadLength(DecorationSize style) {
  785. CTLineProperties ln = getLn(this, true);
  786. if (ln == null) {
  787. return;
  788. }
  789. CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd();
  790. if (style == null) {
  791. if (lnEnd.isSetLen()) {
  792. lnEnd.unsetLen();
  793. }
  794. } else {
  795. lnEnd.setLen(STLineEndLength.Enum.forInt(style.ooxmlId));
  796. }
  797. }
  798. /**
  799. * @return the line end decoration length
  800. */
  801. @SuppressWarnings("WeakerAccess")
  802. public DecorationSize getLineHeadLength() {
  803. CTLineProperties ln = getLn(this, false);
  804. DecorationSize ds = DecorationSize.MEDIUM;
  805. if (ln != null && ln.isSetHeadEnd() && ln.getHeadEnd().isSetLen()) {
  806. ds = DecorationSize.fromOoxmlId(ln.getHeadEnd().getLen().intValue());
  807. }
  808. return ds;
  809. }
  810. /**
  811. * Specifies the line end decoration, such as a triangle or arrowhead.
  812. */
  813. @SuppressWarnings("WeakerAccess")
  814. public void setLineTailDecoration(DecorationShape style) {
  815. CTLineProperties ln = getLn(this, true);
  816. if (ln == null) {
  817. return;
  818. }
  819. CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd();
  820. if (style == null) {
  821. if (lnEnd.isSetType()) {
  822. lnEnd.unsetType();
  823. }
  824. } else {
  825. lnEnd.setType(STLineEndType.Enum.forInt(style.ooxmlId));
  826. }
  827. }
  828. /**
  829. * @return the line end decoration shape
  830. */
  831. @SuppressWarnings("WeakerAccess")
  832. public DecorationShape getLineTailDecoration() {
  833. CTLineProperties ln = getLn(this, false);
  834. DecorationShape ds = DecorationShape.NONE;
  835. if (ln != null && ln.isSetTailEnd() && ln.getTailEnd().isSetType()) {
  836. ds = DecorationShape.fromOoxmlId(ln.getTailEnd().getType().intValue());
  837. }
  838. return ds;
  839. }
  840. /**
  841. * specifies decorations which can be added to the tail of a line.
  842. */
  843. @SuppressWarnings("WeakerAccess")
  844. public void setLineTailWidth(DecorationSize style) {
  845. CTLineProperties ln = getLn(this, true);
  846. if (ln == null) {
  847. return;
  848. }
  849. CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd();
  850. if (style == null) {
  851. if (lnEnd.isSetW()) {
  852. lnEnd.unsetW();
  853. }
  854. } else {
  855. lnEnd.setW(STLineEndWidth.Enum.forInt(style.ooxmlId));
  856. }
  857. }
  858. /**
  859. * @return the line end decoration width
  860. */
  861. @SuppressWarnings("WeakerAccess")
  862. public DecorationSize getLineTailWidth() {
  863. CTLineProperties ln = getLn(this, false);
  864. DecorationSize ds = DecorationSize.MEDIUM;
  865. if (ln != null && ln.isSetTailEnd() && ln.getTailEnd().isSetW()) {
  866. ds = DecorationSize.fromOoxmlId(ln.getTailEnd().getW().intValue());
  867. }
  868. return ds;
  869. }
  870. /**
  871. * Specifies the line end width in relation to the line width.
  872. */
  873. @SuppressWarnings("WeakerAccess")
  874. public void setLineTailLength(DecorationSize style) {
  875. CTLineProperties ln = getLn(this, true);
  876. if (ln == null) {
  877. return;
  878. }
  879. CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd();
  880. if (style == null) {
  881. if (lnEnd.isSetLen()) {
  882. lnEnd.unsetLen();
  883. }
  884. } else {
  885. lnEnd.setLen(STLineEndLength.Enum.forInt(style.ooxmlId));
  886. }
  887. }
  888. /**
  889. * @return the line end decoration length
  890. */
  891. @SuppressWarnings("WeakerAccess")
  892. public DecorationSize getLineTailLength() {
  893. CTLineProperties ln = getLn(this, false);
  894. DecorationSize ds = DecorationSize.MEDIUM;
  895. if (ln != null && ln.isSetTailEnd() && ln.getTailEnd().isSetLen()) {
  896. ds = DecorationSize.fromOoxmlId(ln.getTailEnd().getLen().intValue());
  897. }
  898. return ds;
  899. }
  900. @Override
  901. public Guide getAdjustValue(String name) {
  902. XSLFGeometryProperties gp = XSLFPropertiesDelegate.getGeometryDelegate(getShapeProperties());
  903. if (gp != null && gp.isSetPrstGeom() && gp.getPrstGeom().isSetAvLst()) {
  904. //noinspection deprecation
  905. for (CTGeomGuide g : gp.getPrstGeom().getAvLst().getGdArray()) {
  906. if (g.getName().equals(name)) {
  907. return new Guide(g.getName(), g.getFmla());
  908. }
  909. }
  910. }
  911. return null;
  912. }
  913. @Override
  914. public LineDecoration getLineDecoration() {
  915. return new LineDecoration() {
  916. @Override
  917. public DecorationShape getHeadShape() {
  918. return getLineHeadDecoration();
  919. }
  920. @Override
  921. public DecorationSize getHeadWidth() {
  922. return getLineHeadWidth();
  923. }
  924. @Override
  925. public DecorationSize getHeadLength() {
  926. return getLineHeadLength();
  927. }
  928. @Override
  929. public DecorationShape getTailShape() {
  930. return getLineTailDecoration();
  931. }
  932. @Override
  933. public DecorationSize getTailWidth() {
  934. return getLineTailWidth();
  935. }
  936. @Override
  937. public DecorationSize getTailLength() {
  938. return getLineTailLength();
  939. }
  940. };
  941. }
  942. /**
  943. * fetch shape fill as a java.awt.Paint
  944. *
  945. * @return either Color or GradientPaint or TexturePaint or null
  946. */
  947. @Override
  948. public FillStyle getFillStyle() {
  949. return XSLFSimpleShape.this::getFillPaint;
  950. }
  951. @Override
  952. public StrokeStyle getStrokeStyle() {
  953. return new StrokeStyle() {
  954. @Override
  955. public PaintStyle getPaint() {
  956. return XSLFSimpleShape.this.getLinePaint();
  957. }
  958. @Override
  959. public LineCap getLineCap() {
  960. return XSLFSimpleShape.this.getLineCap();
  961. }
  962. @Override
  963. public LineDash getLineDash() {
  964. return XSLFSimpleShape.this.getLineDash();
  965. }
  966. @Override
  967. public double getLineWidth() {
  968. return XSLFSimpleShape.this.getLineWidth();
  969. }
  970. @Override
  971. public LineCompound getLineCompound() {
  972. return XSLFSimpleShape.this.getLineCompound();
  973. }
  974. };
  975. }
  976. @Override
  977. public void setStrokeStyle(Object... styles) {
  978. if (styles.length == 0) {
  979. // remove stroke
  980. setLineColor(null);
  981. return;
  982. }
  983. // TODO: handle PaintStyle
  984. for (Object st : styles) {
  985. if (st instanceof Number) {
  986. setLineWidth(((Number)st).doubleValue());
  987. } else if (st instanceof LineCap) {
  988. setLineCap((LineCap)st);
  989. } else if (st instanceof LineDash) {
  990. setLineDash((LineDash)st);
  991. } else if (st instanceof LineCompound) {
  992. setLineCompound((LineCompound)st);
  993. } else if (st instanceof Color) {
  994. setLineColor((Color)st);
  995. }
  996. }
  997. }
  998. @Override
  999. public XSLFHyperlink getHyperlink() {
  1000. CTNonVisualDrawingProps cNvPr = getCNvPr();
  1001. if (!cNvPr.isSetHlinkClick()) {
  1002. return null;
  1003. }
  1004. return new XSLFHyperlink(cNvPr.getHlinkClick(), getSheet());
  1005. }
  1006. @Override
  1007. public XSLFHyperlink createHyperlink() {
  1008. XSLFHyperlink hl = getHyperlink();
  1009. if (hl == null) {
  1010. CTNonVisualDrawingProps cNvPr = getCNvPr();
  1011. hl = new XSLFHyperlink(cNvPr.addNewHlinkClick(), getSheet());
  1012. }
  1013. return hl;
  1014. }
  1015. private static CTLineProperties getLn(XSLFShape shape, boolean create) {
  1016. XmlObject pr = shape.getShapeProperties();
  1017. if (!(pr instanceof CTShapeProperties)) {
  1018. LOG.log(POILogger.WARN, shape.getClass() +" doesn't have line properties");
  1019. return null;
  1020. }
  1021. CTShapeProperties spr = (CTShapeProperties)pr;
  1022. return (spr.isSetLn() || !create) ? spr.getLn() : spr.addNewLn();
  1023. }
  1024. }