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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  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.geom.Rectangle2D;
  21. import java.util.Iterator;
  22. import java.util.List;
  23. import java.util.regex.Pattern;
  24. import org.apache.poi.openxml4j.opc.*;
  25. import org.apache.poi.sl.usermodel.GroupShape;
  26. import org.apache.poi.util.*;
  27. import org.apache.xmlbeans.XmlObject;
  28. import org.openxmlformats.schemas.drawingml.x2006.main.*;
  29. import org.openxmlformats.schemas.presentationml.x2006.main.*;
  30. /**
  31. * Represents a group shape that consists of many shapes grouped together.
  32. *
  33. * @author Yegor Kozlov
  34. */
  35. @Beta
  36. public class XSLFGroupShape extends XSLFShape implements XSLFShapeContainer, GroupShape<XSLFShape> {
  37. private static POILogger _logger = POILogFactory.getLogger(XSLFGroupShape.class);
  38. private final List<XSLFShape> _shapes;
  39. private final CTGroupShapeProperties _grpSpPr;
  40. private XSLFDrawing _drawing;
  41. protected XSLFGroupShape(CTGroupShape shape, XSLFSheet sheet){
  42. super(shape,sheet);
  43. _shapes = sheet.buildShapes(shape);
  44. _grpSpPr = shape.getGrpSpPr();
  45. }
  46. protected CTGroupShapeProperties getGrpSpPr() {
  47. return _grpSpPr;
  48. }
  49. protected CTGroupTransform2D getSafeXfrm() {
  50. CTGroupTransform2D xfrm = getXfrm();
  51. return (xfrm == null ? getGrpSpPr().addNewXfrm() : xfrm);
  52. }
  53. protected CTGroupTransform2D getXfrm() {
  54. return getGrpSpPr().getXfrm();
  55. }
  56. @Override
  57. public Rectangle2D getAnchor(){
  58. CTGroupTransform2D xfrm = getXfrm();
  59. CTPoint2D off = xfrm.getOff();
  60. long x = off.getX();
  61. long y = off.getY();
  62. CTPositiveSize2D ext = xfrm.getExt();
  63. long cx = ext.getCx();
  64. long cy = ext.getCy();
  65. return new Rectangle2D.Double(
  66. Units.toPoints(x), Units.toPoints(y),
  67. Units.toPoints(cx), Units.toPoints(cy));
  68. }
  69. @Override
  70. public void setAnchor(Rectangle2D anchor){
  71. CTGroupTransform2D xfrm = getSafeXfrm();
  72. CTPoint2D off = xfrm.isSetOff() ? xfrm.getOff() : xfrm.addNewOff();
  73. long x = Units.toEMU(anchor.getX());
  74. long y = Units.toEMU(anchor.getY());
  75. off.setX(x);
  76. off.setY(y);
  77. CTPositiveSize2D ext = xfrm.isSetExt() ? xfrm.getExt() : xfrm.addNewExt();
  78. long cx = Units.toEMU(anchor.getWidth());
  79. long cy = Units.toEMU(anchor.getHeight());
  80. ext.setCx(cx);
  81. ext.setCy(cy);
  82. }
  83. /**
  84. *
  85. * @return the coordinates of the child extents rectangle
  86. * used for calculations of grouping, scaling, and rotation
  87. * behavior of shapes placed within a group.
  88. */
  89. public Rectangle2D getInteriorAnchor(){
  90. CTGroupTransform2D xfrm = getXfrm();
  91. CTPoint2D off = xfrm.getChOff();
  92. long x = off.getX();
  93. long y = off.getY();
  94. CTPositiveSize2D ext = xfrm.getChExt();
  95. long cx = ext.getCx();
  96. long cy = ext.getCy();
  97. return new Rectangle2D.Double(
  98. Units.toPoints(x), Units.toPoints(y),
  99. Units.toPoints(cx), Units.toPoints(cy));
  100. }
  101. /**
  102. *
  103. * @param anchor the coordinates of the child extents rectangle
  104. * used for calculations of grouping, scaling, and rotation
  105. * behavior of shapes placed within a group.
  106. */
  107. public void setInteriorAnchor(Rectangle2D anchor) {
  108. CTGroupTransform2D xfrm = getSafeXfrm();
  109. CTPoint2D off = xfrm.isSetChOff() ? xfrm.getChOff() : xfrm.addNewChOff();
  110. long x = Units.toEMU(anchor.getX());
  111. long y = Units.toEMU(anchor.getY());
  112. off.setX(x);
  113. off.setY(y);
  114. CTPositiveSize2D ext = xfrm.isSetChExt() ? xfrm.getChExt() : xfrm.addNewChExt();
  115. long cx = Units.toEMU(anchor.getWidth());
  116. long cy = Units.toEMU(anchor.getHeight());
  117. ext.setCx(cx);
  118. ext.setCy(cy);
  119. }
  120. /**
  121. *
  122. * @return child shapes contained witin this group
  123. */
  124. @Override
  125. public List<XSLFShape> getShapes(){
  126. return _shapes;
  127. }
  128. /**
  129. * Returns an iterator over the shapes in this sheet
  130. *
  131. * @return an iterator over the shapes in this sheet
  132. */
  133. public Iterator<XSLFShape> iterator(){
  134. return _shapes.iterator();
  135. }
  136. /**
  137. * Remove the specified shape from this group
  138. */
  139. public boolean removeShape(XSLFShape xShape) {
  140. XmlObject obj = xShape.getXmlObject();
  141. CTGroupShape grpSp = (CTGroupShape)getXmlObject();
  142. if(obj instanceof CTShape){
  143. grpSp.getSpList().remove(obj);
  144. } else if (obj instanceof CTGroupShape){
  145. grpSp.getGrpSpList().remove(obj);
  146. } else if (obj instanceof CTConnector){
  147. grpSp.getCxnSpList().remove(obj);
  148. } else {
  149. throw new IllegalArgumentException("Unsupported shape: " + xShape);
  150. }
  151. return _shapes.remove(xShape);
  152. }
  153. /**
  154. * @param shapeId 1-based shapeId
  155. */
  156. static CTGroupShape prototype(int shapeId) {
  157. CTGroupShape ct = CTGroupShape.Factory.newInstance();
  158. CTGroupShapeNonVisual nvSpPr = ct.addNewNvGrpSpPr();
  159. CTNonVisualDrawingProps cnv = nvSpPr.addNewCNvPr();
  160. cnv.setName("Group " + shapeId);
  161. cnv.setId(shapeId + 1);
  162. nvSpPr.addNewCNvGrpSpPr();
  163. nvSpPr.addNewNvPr();
  164. ct.addNewGrpSpPr();
  165. return ct;
  166. }
  167. // shape factory methods
  168. private XSLFDrawing getDrawing(){
  169. if(_drawing == null) {
  170. _drawing = new XSLFDrawing(getSheet(), (CTGroupShape)getXmlObject());
  171. }
  172. return _drawing;
  173. }
  174. public XSLFAutoShape createAutoShape(){
  175. XSLFAutoShape sh = getDrawing().createAutoShape();
  176. _shapes.add(sh);
  177. sh.setParent(this);
  178. return sh;
  179. }
  180. public XSLFFreeformShape createFreeform(){
  181. XSLFFreeformShape sh = getDrawing().createFreeform();
  182. _shapes.add(sh);
  183. sh.setParent(this);
  184. return sh;
  185. }
  186. public XSLFTextBox createTextBox(){
  187. XSLFTextBox sh = getDrawing().createTextBox();
  188. _shapes.add(sh);
  189. sh.setParent(this);
  190. return sh;
  191. }
  192. public XSLFConnectorShape createConnector(){
  193. XSLFConnectorShape sh = getDrawing().createConnector();
  194. _shapes.add(sh);
  195. sh.setParent(this);
  196. return sh;
  197. }
  198. public XSLFGroupShape createGroup(){
  199. XSLFGroupShape sh = getDrawing().createGroup();
  200. _shapes.add(sh);
  201. sh.setParent(this);
  202. return sh;
  203. }
  204. public XSLFPictureShape createPicture(int pictureIndex){
  205. List<PackagePart> pics = getSheet().getPackagePart().getPackage()
  206. .getPartsByName(Pattern.compile("/ppt/media/image" + (pictureIndex + 1) + ".*?"));
  207. if(pics.size() == 0) {
  208. throw new IllegalArgumentException("Picture with index=" + pictureIndex + " was not found");
  209. }
  210. PackagePart pic = pics.get(0);
  211. PackageRelationship rel = getSheet().getPackagePart().addRelationship(
  212. pic.getPartName(), TargetMode.INTERNAL, XSLFRelation.IMAGES.getRelation());
  213. XSLFPictureShape sh = getDrawing().createPicture(rel.getId());
  214. sh.resize();
  215. _shapes.add(sh);
  216. sh.setParent(this);
  217. return sh;
  218. }
  219. public XSLFTable createTable(){
  220. XSLFTable sh = getDrawing().createTable();
  221. _shapes.add(sh);
  222. sh.setParent(this);
  223. return sh;
  224. }
  225. @Override
  226. public void setFlipHorizontal(boolean flip){
  227. getSafeXfrm().setFlipH(flip);
  228. }
  229. @Override
  230. public void setFlipVertical(boolean flip){
  231. getSafeXfrm().setFlipV(flip);
  232. }
  233. @Override
  234. public boolean getFlipHorizontal(){
  235. CTGroupTransform2D xfrm = getXfrm();
  236. return (xfrm == null || !xfrm.isSetFlipH()) ? false : xfrm.getFlipH();
  237. }
  238. @Override
  239. public boolean getFlipVertical(){
  240. CTGroupTransform2D xfrm = getXfrm();
  241. return (xfrm == null || !xfrm.isSetFlipV()) ? false : xfrm.getFlipV();
  242. }
  243. @Override
  244. public void setRotation(double theta){
  245. getSafeXfrm().setRot((int) (theta * 60000));
  246. }
  247. @Override
  248. public double getRotation(){
  249. CTGroupTransform2D xfrm = getXfrm();
  250. return (xfrm == null || !xfrm.isSetRot()) ? 0 : (xfrm.getRot() / 60000.d);
  251. }
  252. @Override
  253. void copy(XSLFShape src){
  254. XSLFGroupShape gr = (XSLFGroupShape)src;
  255. // clear shapes
  256. clear();
  257. // recursively update each shape
  258. for(XSLFShape shape : gr.getShapes()) {
  259. XSLFShape newShape = null;
  260. if (shape instanceof XSLFTextBox) {
  261. newShape = createTextBox();
  262. } else if (shape instanceof XSLFAutoShape) {
  263. newShape = createAutoShape();
  264. } else if (shape instanceof XSLFConnectorShape) {
  265. newShape = createConnector();
  266. } else if (shape instanceof XSLFFreeformShape) {
  267. newShape = createFreeform();
  268. } else if (shape instanceof XSLFPictureShape) {
  269. XSLFPictureShape p = (XSLFPictureShape)shape;
  270. XSLFPictureData pd = p.getPictureData();
  271. int picId = getSheet().getSlideShow().addPicture(pd.getData(), pd.getPictureType());
  272. newShape = createPicture(picId);
  273. } else if (shape instanceof XSLFGroupShape) {
  274. newShape = createGroup();
  275. } else if (shape instanceof XSLFTable) {
  276. newShape = createTable();
  277. } else {
  278. _logger.log(POILogger.WARN, "copying of class "+shape.getClass()+" not supported.");
  279. continue;
  280. }
  281. newShape.copy(shape);
  282. }
  283. }
  284. /**
  285. * Removes all of the elements from this container (optional operation).
  286. * The container will be empty after this call returns.
  287. */
  288. public void clear() {
  289. for(XSLFShape shape : getShapes()){
  290. removeShape(shape);
  291. }
  292. }
  293. public void addShape(XSLFShape shape) {
  294. throw new UnsupportedOperationException(
  295. "Adding a shape from a different container is not supported -"
  296. + " create it from scratch with XSLFGroupShape.create* methods");
  297. }
  298. }