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

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