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.

XSLFGroupShape.java 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  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.openxml4j.opc.PackagePart;
  21. import org.apache.poi.openxml4j.opc.PackageRelationship;
  22. import org.apache.poi.openxml4j.opc.TargetMode;
  23. import org.apache.poi.sl.usermodel.Shape;
  24. import org.apache.poi.sl.usermodel.ShapeContainer;
  25. import org.apache.poi.sl.usermodel.ShapeGroup;
  26. import org.apache.poi.util.Beta;
  27. import org.apache.poi.util.Units;
  28. import org.apache.xmlbeans.XmlObject;
  29. import org.openxmlformats.schemas.drawingml.x2006.main.CTGroupShapeProperties;
  30. import org.openxmlformats.schemas.drawingml.x2006.main.CTGroupTransform2D;
  31. import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
  32. import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
  33. import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
  34. import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
  35. import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector;
  36. import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;
  37. import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShapeNonVisual;
  38. import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
  39. import java.awt.Graphics2D;
  40. import java.awt.geom.AffineTransform;
  41. import java.awt.geom.Rectangle2D;
  42. import java.util.List;
  43. import java.util.regex.Pattern;
  44. /**
  45. * Represents a group shape that consists of many shapes grouped together.
  46. *
  47. * @author Yegor Kozlov
  48. */
  49. @Beta
  50. public class XSLFGroupShape extends XSLFShape {
  51. private final CTGroupShape _shape;
  52. private final XSLFSheet _sheet;
  53. private final List<XSLFShape> _shapes;
  54. private final CTGroupShapeProperties _spPr;
  55. private XSLFDrawing _drawing;
  56. /*package*/ XSLFGroupShape(CTGroupShape shape, XSLFSheet sheet){
  57. _shape = shape;
  58. _sheet = sheet;
  59. _shapes = _sheet.buildShapes(_shape);
  60. _spPr = shape.getGrpSpPr();
  61. }
  62. public CTGroupShape getXmlObject(){
  63. return _shape;
  64. }
  65. public Rectangle2D getAnchor(){
  66. CTGroupTransform2D xfrm = _spPr.getXfrm();
  67. CTPoint2D off = xfrm.getOff();
  68. long x = off.getX();
  69. long y = off.getY();
  70. CTPositiveSize2D ext = xfrm.getExt();
  71. long cx = ext.getCx();
  72. long cy = ext.getCy();
  73. return new Rectangle2D.Double(
  74. Units.toPoints(x), Units.toPoints(y),
  75. Units.toPoints(cx), Units.toPoints(cy));
  76. }
  77. public void setAnchor(Rectangle2D anchor){
  78. CTGroupTransform2D xfrm = _spPr.isSetXfrm() ? _spPr.getXfrm() : _spPr.addNewXfrm();
  79. CTPoint2D off = xfrm.isSetOff() ? xfrm.getOff() : xfrm.addNewOff();
  80. long x = Units.toEMU(anchor.getX());
  81. long y = Units.toEMU(anchor.getY());
  82. off.setX(x);
  83. off.setY(y);
  84. CTPositiveSize2D ext = xfrm.isSetExt() ? xfrm.getExt() : xfrm.addNewExt();
  85. long cx = Units.toEMU(anchor.getWidth());
  86. long cy = Units.toEMU(anchor.getHeight());
  87. ext.setCx(cx);
  88. ext.setCy(cy);
  89. }
  90. public Rectangle2D getInteriorAnchor(){
  91. CTGroupTransform2D xfrm = _spPr.getXfrm();
  92. CTPoint2D off = xfrm.getChOff();
  93. long x = off.getX();
  94. long y = off.getY();
  95. CTPositiveSize2D ext = xfrm.getChExt();
  96. long cx = ext.getCx();
  97. long cy = ext.getCy();
  98. return new Rectangle2D.Double(
  99. Units.toPoints(x), Units.toPoints(y),
  100. Units.toPoints(cx), Units.toPoints(cy));
  101. }
  102. public void setInteriorAnchor(Rectangle2D anchor){
  103. CTGroupTransform2D xfrm = _spPr.isSetXfrm() ? _spPr.getXfrm() : _spPr.addNewXfrm();
  104. CTPoint2D off = xfrm.isSetChOff() ? xfrm.getChOff() : xfrm.addNewChOff();
  105. long x = Units.toEMU(anchor.getX());
  106. long y = Units.toEMU(anchor.getY());
  107. off.setX(x);
  108. off.setY(y);
  109. CTPositiveSize2D ext = xfrm.isSetChExt() ? xfrm.getChExt() : xfrm.addNewChExt();
  110. long cx = Units.toEMU(anchor.getWidth());
  111. long cy = Units.toEMU(anchor.getHeight());
  112. ext.setCx(cx);
  113. ext.setCy(cy);
  114. }
  115. public XSLFShape[] getShapes(){
  116. return _shapes.toArray(new XSLFShape[_shapes.size()]);
  117. }
  118. public boolean removeShape(XSLFShape xShape) {
  119. XmlObject obj = xShape.getXmlObject();
  120. if(obj instanceof CTShape){
  121. _shape.getSpList().remove(obj);
  122. } else if (obj instanceof CTGroupShape){
  123. _shape.getGrpSpList().remove(obj);
  124. } else if (obj instanceof CTConnector){
  125. _shape.getCxnSpList().remove(obj);
  126. } else {
  127. throw new IllegalArgumentException("Unsupported shape: " + xShape);
  128. }
  129. return _shapes.remove(xShape);
  130. }
  131. public String getShapeName(){
  132. return _shape.getNvGrpSpPr().getCNvPr().getName();
  133. }
  134. public int getShapeId(){
  135. return (int)_shape.getNvGrpSpPr().getCNvPr().getId();
  136. }
  137. /**
  138. * @param shapeId 1-based shapeId
  139. */
  140. static CTGroupShape prototype(int shapeId) {
  141. CTGroupShape ct = CTGroupShape.Factory.newInstance();
  142. CTGroupShapeNonVisual nvSpPr = ct.addNewNvGrpSpPr();
  143. CTNonVisualDrawingProps cnv = nvSpPr.addNewCNvPr();
  144. cnv.setName("Group " + shapeId);
  145. cnv.setId(shapeId + 1);
  146. nvSpPr.addNewCNvGrpSpPr();
  147. nvSpPr.addNewNvPr();
  148. ct.addNewGrpSpPr();
  149. return ct;
  150. }
  151. // shape factory methods
  152. private XSLFDrawing getDrawing(){
  153. if(_drawing == null) {
  154. _drawing = new XSLFDrawing(_sheet, _shape);
  155. }
  156. return _drawing;
  157. }
  158. public XSLFAutoShape createAutoShape(){
  159. XSLFAutoShape sh = getDrawing().createAutoShape();
  160. _shapes.add(sh);
  161. return sh;
  162. }
  163. public XSLFFreeformShape createFreeform(){
  164. XSLFFreeformShape sh = getDrawing().createFreeform();
  165. _shapes.add(sh);
  166. return sh;
  167. }
  168. public XSLFTextBox createTextBox(){
  169. XSLFTextBox sh = getDrawing().createTextBox();
  170. _shapes.add(sh);
  171. return sh;
  172. }
  173. public XSLFConnectorShape createConnector(){
  174. XSLFConnectorShape sh = getDrawing().createConnector();
  175. _shapes.add(sh);
  176. return sh;
  177. }
  178. public XSLFGroupShape createGroup(){
  179. XSLFGroupShape sh = getDrawing().createGroup();
  180. _shapes.add(sh);
  181. return sh;
  182. }
  183. public XSLFPictureShape createPicture(int pictureIndex){
  184. List<PackagePart> pics = _sheet.getPackagePart().getPackage()
  185. .getPartsByName(Pattern.compile("/ppt/media/.*?"));
  186. PackagePart pic = pics.get(pictureIndex);
  187. PackageRelationship rel = _sheet.getPackagePart().addRelationship(
  188. pic.getPartName(), TargetMode.INTERNAL, XSLFRelation.IMAGES.getRelation());
  189. XSLFPictureShape sh = getDrawing().createPicture(rel.getId());
  190. sh.resize();
  191. _shapes.add(sh);
  192. return sh;
  193. }
  194. public void setFlipHorizontal(boolean flip){
  195. _spPr.getXfrm().setFlipH(flip);
  196. }
  197. public void setFlipVertical(boolean flip){
  198. _spPr.getXfrm().setFlipV(flip);
  199. }
  200. /**
  201. * Whether the shape is horizontally flipped
  202. *
  203. * @return whether the shape is horizontally flipped
  204. */
  205. public boolean getFlipHorizontal(){
  206. return _spPr.getXfrm().getFlipH();
  207. }
  208. public boolean getFlipVertical(){
  209. return _spPr.getXfrm().getFlipV();
  210. }
  211. /**
  212. * Rotate this shape.
  213. * <p>
  214. * Positive angles are clockwise (i.e., towards the positive y axis);
  215. * negative angles are counter-clockwise (i.e., towards the negative y axis).
  216. * </p>
  217. *
  218. * @param theta the rotation angle in degrees.
  219. */
  220. public void setRotation(double theta){
  221. _spPr.getXfrm().setRot((int)(theta*60000));
  222. }
  223. /**
  224. * Rotation angle in degrees
  225. * <p>
  226. * Positive angles are clockwise (i.e., towards the positive y axis);
  227. * negative angles are counter-clockwise (i.e., towards the negative y axis).
  228. * </p>
  229. *
  230. * @return rotation angle in degrees
  231. */
  232. public double getRotation(){
  233. return (double)_spPr.getXfrm().getRot()/60000;
  234. }
  235. public void draw(Graphics2D graphics){
  236. // the coordinate system of this group of shape
  237. Rectangle2D interior = getInteriorAnchor();
  238. // anchor of this group relative to the parent shape
  239. Rectangle2D exterior = getAnchor();
  240. graphics.translate(exterior.getX(), exterior.getY());
  241. double scaleX = exterior.getWidth() / interior.getWidth();
  242. double scaleY = exterior.getHeight() / interior.getHeight();
  243. graphics.scale(scaleX, scaleY);
  244. graphics.translate(-interior.getX(), -interior.getY());
  245. for (XSLFShape shape : getShapes()) {
  246. // remember the initial transform and restore it after we are done with the drawing
  247. AffineTransform at0 = graphics.getTransform();
  248. graphics.setRenderingHint(XSLFRenderingHint.GSAVE, true);
  249. // apply rotation and flipping
  250. shape.applyTransform(graphics);
  251. shape.draw(graphics);
  252. // restore the coordinate system
  253. graphics.setTransform(at0);
  254. graphics.setRenderingHint(XSLFRenderingHint.GRESTORE, true);
  255. }
  256. }
  257. }