| /* ==================================================================== |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| ==================================================================== */ |
| package org.apache.poi.xslf.usermodel; |
| |
| import static org.apache.logging.log4j.util.Unbox.box; |
| import static org.apache.poi.ooxml.POIXMLTypeLoader.DEFAULT_XML_OPTIONS; |
| |
| import java.awt.*; |
| import java.awt.geom.Rectangle2D; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import javax.xml.namespace.QName; |
| |
| import com.zaxxer.sparsebits.SparseBitSet; |
| import org.apache.logging.log4j.LogManager; |
| import org.apache.logging.log4j.Logger; |
| import org.apache.poi.ooxml.POIXMLDocumentPart; |
| import org.apache.poi.ooxml.POIXMLException; |
| import org.apache.poi.openxml4j.opc.OPCPackage; |
| import org.apache.poi.openxml4j.opc.PackageNamespaces; |
| import org.apache.poi.openxml4j.opc.PackagePart; |
| import org.apache.poi.openxml4j.opc.PackagePartName; |
| import org.apache.poi.openxml4j.opc.PackageRelationship; |
| import org.apache.poi.openxml4j.opc.TargetMode; |
| import org.apache.poi.sl.draw.DrawFactory; |
| import org.apache.poi.sl.draw.DrawPictureShape; |
| import org.apache.poi.sl.draw.Drawable; |
| import org.apache.poi.sl.usermodel.PictureData; |
| import org.apache.poi.sl.usermodel.Placeholder; |
| import org.apache.poi.sl.usermodel.Sheet; |
| import org.apache.poi.util.Beta; |
| import org.apache.poi.util.IOUtils; |
| import org.apache.poi.util.Internal; |
| import org.apache.poi.util.Units; |
| import org.apache.poi.xddf.usermodel.chart.XDDFChart; |
| import org.apache.xmlbeans.XmlCursor; |
| import org.apache.xmlbeans.XmlException; |
| import org.apache.xmlbeans.XmlObject; |
| import org.apache.xmlbeans.XmlOptions; |
| import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl; |
| import org.openxmlformats.schemas.drawingml.x2006.main.CTColorMapping; |
| import org.openxmlformats.schemas.drawingml.x2006.main.CTColorMappingOverride; |
| import org.openxmlformats.schemas.drawingml.x2006.main.STColorSchemeIndex; |
| import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector; |
| import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame; |
| import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape; |
| import org.openxmlformats.schemas.presentationml.x2006.main.CTOleObject; |
| import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture; |
| import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; |
| import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; |
| |
| @Beta |
| public abstract class XSLFSheet extends POIXMLDocumentPart |
| implements XSLFShapeContainer, Sheet<XSLFShape,XSLFTextParagraph> { |
| private static Logger LOG = LogManager.getLogger(XSLFSheet.class); |
| |
| private XSLFDrawing _drawing; |
| private List<XSLFShape> _shapes; |
| private CTGroupShape _spTree; |
| private XSLFTheme _theme; |
| |
| private List<XSLFTextShape>_placeholders; |
| private Map<Integer, XSLFSimpleShape> _placeholderByIdMap; |
| private Map<Integer, XSLFSimpleShape> _placeholderByTypeMap; |
| |
| private final SparseBitSet shapeIds = new SparseBitSet(); |
| |
| protected XSLFSheet() { |
| super(); |
| } |
| |
| /** |
| * @since POI 3.14-Beta1 |
| */ |
| protected XSLFSheet(PackagePart part) { |
| super(part); |
| } |
| |
| /** |
| * @return the XMLSlideShow this sheet belongs to |
| */ |
| @Override |
| public XMLSlideShow getSlideShow() { |
| POIXMLDocumentPart p = getParent(); |
| while(p != null) { |
| if(p instanceof XMLSlideShow){ |
| return (XMLSlideShow)p; |
| } |
| p = p.getParent(); |
| } |
| throw new IllegalStateException("SlideShow was not found"); |
| } |
| |
| @SuppressWarnings("WeakerAccess") |
| protected int allocateShapeId() { |
| final int nextId = shapeIds.nextClearBit(1); |
| shapeIds.set(nextId); |
| return nextId; |
| } |
| |
| @SuppressWarnings("WeakerAccess") |
| protected void registerShapeId(final int shapeId) { |
| if (shapeIds.get(shapeId)) { |
| LOG.atWarn().log("shape id {} has been already used.", box(shapeId)); |
| } |
| shapeIds.set(shapeId); |
| } |
| |
| @SuppressWarnings("WeakerAccess") |
| protected void deregisterShapeId(final int shapeId) { |
| if (!shapeIds.get(shapeId)) { |
| LOG.atWarn().log("shape id {} hasn't been registered.", box(shapeId)); |
| } |
| shapeIds.clear(shapeId); |
| } |
| |
| @SuppressWarnings("WeakerAccess") |
| protected static List<XSLFShape> buildShapes(CTGroupShape spTree, XSLFShapeContainer parent){ |
| final XSLFSheet sheet = (parent instanceof XSLFSheet) ? (XSLFSheet)parent : ((XSLFShape)parent).getSheet(); |
| |
| List<XSLFShape> shapes = new ArrayList<>(); |
| XmlCursor cur = spTree.newCursor(); |
| try { |
| for (boolean b=cur.toFirstChild();b;b=cur.toNextSibling()) { |
| XmlObject ch = cur.getObject(); |
| if(ch instanceof CTShape){ |
| // simple shape |
| XSLFAutoShape shape = XSLFAutoShape.create((CTShape)ch, sheet); |
| shapes.add(shape); |
| } else if (ch instanceof CTGroupShape){ |
| shapes.add(new XSLFGroupShape((CTGroupShape)ch, sheet)); |
| } else if (ch instanceof CTConnector){ |
| shapes.add(new XSLFConnectorShape((CTConnector)ch, sheet)); |
| } else if (ch instanceof CTPicture){ |
| shapes.add(new XSLFPictureShape((CTPicture)ch, sheet)); |
| } else if (ch instanceof CTGraphicalObjectFrame){ |
| XSLFGraphicFrame shape = XSLFGraphicFrame.create((CTGraphicalObjectFrame)ch, sheet); |
| shapes.add(shape); |
| } else if (ch instanceof XmlAnyTypeImpl) { |
| // TODO: the link of the XLSF classes to the xml beans objects will |
| // be broken, when the elements are parsed a second time. |
| // Unfortunately, the xml schema type can't be set of the alternate |
| // content element |
| cur.push(); |
| if (cur.toChild(PackageNamespaces.MARKUP_COMPATIBILITY, "Choice") && cur.toFirstChild()) { |
| try { |
| CTGroupShape grp = CTGroupShape.Factory.parse(cur.newXMLStreamReader()); |
| shapes.addAll(buildShapes(grp, parent)); |
| } catch (XmlException e) { |
| LOG.atDebug().withThrowable(e).log("unparsable alternate content"); |
| } |
| } |
| cur.pop(); |
| } |
| } |
| } finally { |
| cur.dispose(); |
| } |
| |
| for (final XSLFShape s : shapes) { |
| s.setParent(parent); |
| } |
| |
| return shapes; |
| } |
| |
| /** |
| * @return top-level Xml bean representing this sheet |
| */ |
| public abstract XmlObject getXmlObject(); |
| |
| private XSLFDrawing getDrawing(){ |
| initDrawingAndShapes(); |
| return _drawing; |
| } |
| |
| /** |
| * Returns an array containing all of the shapes in this sheet |
| * |
| * @return an array of all shapes in this sheet |
| */ |
| @Override |
| public List<XSLFShape> getShapes(){ |
| initDrawingAndShapes(); |
| return _shapes; |
| } |
| |
| /** |
| * Helper method for initializing drawing and shapes in one go. |
| * If they are initialized separately, there's a risk that shapes |
| * get added twice, e.g. a shape is added to the drawing, then |
| * buildShapes is called and at last the shape is added to shape list |
| */ |
| private void initDrawingAndShapes() { |
| CTGroupShape cgs = getSpTree(); |
| if(_drawing == null) { |
| _drawing = new XSLFDrawing(this, cgs); |
| } |
| if (_shapes == null) { |
| _shapes = buildShapes(cgs, this); |
| } |
| } |
| |
| // shape factory methods |
| |
| @Override |
| public XSLFAutoShape createAutoShape(){ |
| XSLFAutoShape sh = getDrawing().createAutoShape(); |
| getShapes().add(sh); |
| sh.setParent(this); |
| return sh; |
| } |
| |
| @Override |
| public XSLFFreeformShape createFreeform(){ |
| XSLFFreeformShape sh = getDrawing().createFreeform(); |
| getShapes().add(sh); |
| sh.setParent(this); |
| return sh; |
| } |
| |
| @Override |
| public XSLFTextBox createTextBox(){ |
| XSLFTextBox sh = getDrawing().createTextBox(); |
| getShapes().add(sh); |
| sh.setParent(this); |
| return sh; |
| } |
| |
| @Override |
| public XSLFConnectorShape createConnector(){ |
| XSLFConnectorShape sh = getDrawing().createConnector(); |
| getShapes().add(sh); |
| sh.setParent(this); |
| return sh; |
| } |
| |
| @Override |
| public XSLFGroupShape createGroup(){ |
| XSLFGroupShape sh = getDrawing().createGroup(); |
| getShapes().add(sh); |
| sh.setParent(this); |
| return sh; |
| } |
| |
| @Override |
| public XSLFPictureShape createPicture(PictureData pictureData){ |
| if (!(pictureData instanceof XSLFPictureData)) { |
| throw new IllegalArgumentException("pictureData needs to be of type XSLFPictureData"); |
| } |
| |
| RelationPart rp = addRelation(null, XSLFRelation.IMAGES, (XSLFPictureData)pictureData); |
| |
| XSLFPictureShape sh = getDrawing().createPicture(rp.getRelationship().getId()); |
| new DrawPictureShape(sh).resize(); |
| getShapes().add(sh); |
| sh.setParent(this); |
| return sh; |
| } |
| |
| public XSLFTable createTable(){ |
| XSLFTable sh = getDrawing().createTable(); |
| getShapes().add(sh); |
| sh.setParent(this); |
| return sh; |
| } |
| |
| @Override |
| public XSLFTable createTable(int numRows, int numCols){ |
| if (numRows < 1 || numCols < 1) { |
| throw new IllegalArgumentException("numRows and numCols must be greater than 0"); |
| } |
| XSLFTable sh = getDrawing().createTable(); |
| getShapes().add(sh); |
| sh.setParent(this); |
| for (int r=0; r<numRows; r++) { |
| XSLFTableRow row = sh.addRow(); |
| for (int c=0; c<numCols; c++) { |
| row.addCell(); |
| } |
| } |
| return sh; |
| } |
| |
| |
| @Override |
| public XSLFObjectShape createOleShape(PictureData pictureData) { |
| if (!(pictureData instanceof XSLFPictureData)) { |
| throw new IllegalArgumentException("pictureData needs to be of type XSLFPictureData"); |
| } |
| RelationPart rp = addRelation(null, XSLFRelation.IMAGES, (XSLFPictureData)pictureData); |
| |
| XSLFObjectShape sh = getDrawing().createOleShape(rp.getRelationship().getId()); |
| CTOleObject oleObj = sh.getCTOleObject(); |
| Dimension dim = pictureData.getImageDimension(); |
| oleObj.setImgW(Units.toEMU(dim.getWidth())); |
| oleObj.setImgH(Units.toEMU(dim.getHeight())); |
| |
| getShapes().add(sh); |
| sh.setParent(this); |
| return sh; |
| } |
| |
| /** |
| * Returns an iterator over the shapes in this sheet |
| * |
| * @return an iterator over the shapes in this sheet |
| */ |
| @Override |
| public Iterator<XSLFShape> iterator(){ |
| return getShapes().iterator(); |
| } |
| |
| @Override |
| public void addShape(XSLFShape shape) { |
| throw new UnsupportedOperationException( |
| "Adding a shape from a different container is not supported -" |
| + " create it from scratch witht XSLFSheet.create* methods"); |
| } |
| |
| /** |
| * Removes the specified shape from this sheet, if it is present |
| * (optional operation). If this sheet does not contain the element, |
| * it is unchanged. |
| * |
| * @param xShape shape to be removed from this sheet, if present |
| * @return <tt>true</tt> if this sheet contained the specified element |
| * @throws IllegalArgumentException if the type of the specified shape |
| * is incompatible with this sheet (optional) |
| */ |
| @Override |
| public boolean removeShape(XSLFShape xShape) { |
| XmlObject obj = xShape.getXmlObject(); |
| CTGroupShape spTree = getSpTree(); |
| deregisterShapeId(xShape.getShapeId()); |
| if(obj instanceof CTShape){ |
| spTree.getSpList().remove(obj); |
| } else if (obj instanceof CTGroupShape) { |
| XSLFGroupShape gs = (XSLFGroupShape)xShape; |
| new ArrayList<>(gs.getShapes()).forEach(gs::removeShape); |
| spTree.getGrpSpList().remove(obj); |
| } else if (obj instanceof CTConnector) { |
| spTree.getCxnSpList().remove(obj); |
| } else if (obj instanceof CTGraphicalObjectFrame) { |
| spTree.getGraphicFrameList().remove(obj); |
| } else if (obj instanceof CTPicture) { |
| XSLFPictureShape ps = (XSLFPictureShape)xShape; |
| removePictureRelation(ps); |
| spTree.getPicList().remove(obj); |
| } else { |
| throw new IllegalArgumentException("Unsupported shape: " + xShape); |
| } |
| return getShapes().remove(xShape); |
| } |
| |
| /** |
| * Removes all of the elements from this container (optional operation). |
| * The container will be empty after this call returns. |
| */ |
| @Override |
| public void clear() { |
| List<XSLFShape> shapes = new ArrayList<>(getShapes()); |
| for(XSLFShape shape : shapes){ |
| removeShape(shape); |
| } |
| } |
| |
| protected abstract String getRootElementName(); |
| |
| @SuppressWarnings("WeakerAccess") |
| protected CTGroupShape getSpTree(){ |
| if(_spTree == null) { |
| XmlObject root = getXmlObject(); |
| XmlObject[] sp = root.selectPath( |
| "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//*/p:spTree"); |
| if(sp.length == 0) { |
| throw new IllegalStateException("CTGroupShape was not found"); |
| } |
| _spTree = (CTGroupShape)sp[0]; |
| } |
| return _spTree; |
| } |
| |
| @Override |
| protected final void commit() throws IOException { |
| XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS); |
| String docName = getRootElementName(); |
| if(docName != null) { |
| xmlOptions.setSaveSyntheticDocumentElement( |
| new QName("http://schemas.openxmlformats.org/presentationml/2006/main", docName)); |
| } |
| |
| PackagePart part = getPackagePart(); |
| OutputStream out = part.getOutputStream(); |
| getXmlObject().save(out, xmlOptions); |
| out.close(); |
| } |
| |
| /** |
| * Set the contents of this sheet to be a copy of the source sheet. |
| * This method erases any existing shapes and replaces them with |
| * object from the source sheet. |
| * |
| * @param src the source sheet to copy data from |
| * @return modified 'this' |
| */ |
| public XSLFSheet importContent(XSLFSheet src){ |
| _spTree = null; |
| |
| // first copy the source xml |
| getSpTree().set(src.getSpTree().copy()); |
| |
| wipeAndReinitialize(src, 0); |
| |
| return this; |
| } |
| |
| private void wipeAndReinitialize(XSLFSheet src, int offset) { |
| // explicitly initialize drawing and shapes from _spTree |
| _shapes = null; |
| _drawing = null; |
| initDrawingAndShapes(); |
| |
| // placeholders will be implicitly initialized when requested |
| _placeholders = null; |
| |
| // update each shape according to its own additional copy rules |
| List<XSLFShape> tgtShapes = getShapes(); |
| List<XSLFShape> srcShapes = src.getShapes(); |
| for(int i = 0; i < srcShapes.size(); i++){ |
| XSLFShape s1 = srcShapes.get(i); |
| XSLFShape s2 = tgtShapes.get(offset + i); |
| |
| s2.copy(s1); |
| } |
| |
| } |
| |
| /** |
| * Append content to this sheet. |
| * |
| * @param src the source sheet |
| * @return modified <code>this</code>. |
| */ |
| @SuppressWarnings("unused") |
| public XSLFSheet appendContent(XSLFSheet src){ |
| int numShapes = getShapes().size(); |
| CTGroupShape spTree = getSpTree(); |
| CTGroupShape srcTree = src.getSpTree(); |
| |
| for(XmlObject ch : srcTree.selectPath("*")){ |
| if(ch instanceof CTShape){ // simple shape |
| spTree.addNewSp().set(ch.copy()); |
| } else if (ch instanceof CTGroupShape){ |
| spTree.addNewGrpSp().set(ch.copy()); |
| } else if (ch instanceof CTConnector){ |
| spTree.addNewCxnSp().set(ch.copy()); |
| } else if (ch instanceof CTPicture){ |
| spTree.addNewPic().set(ch.copy()); |
| } else if (ch instanceof CTGraphicalObjectFrame){ |
| spTree.addNewGraphicFrame().set(ch.copy()); |
| } |
| } |
| |
| wipeAndReinitialize(src, numShapes); |
| |
| return this; |
| } |
| |
| /** |
| * @return theme (shared styles) associated with this theme. |
| * By default returns <code>null</code> which means that this sheet is theme-less. |
| * Sheets that support the notion of themes (slides, masters, layouts, etc.) should override this |
| * method and return the corresponding package part. |
| */ |
| public XSLFTheme getTheme() { |
| if (_theme != null || !isSupportTheme()) { |
| return _theme; |
| } |
| |
| getRelations().stream() |
| .filter(p -> p instanceof XSLFTheme) |
| .findAny() |
| .ifPresent(p -> _theme = (XSLFTheme)p); |
| |
| return _theme; |
| } |
| |
| |
| |
| /** |
| * @return {@code true} if this class supports themes |
| */ |
| boolean isSupportTheme() { |
| return false; |
| } |
| |
| /** |
| * @return the color mapping for this slide type |
| */ |
| String mapSchemeColor(String schemeColor) { |
| return null; |
| } |
| |
| @SuppressWarnings("WeakerAccess") |
| protected XSLFTextShape getTextShapeByType(Placeholder type){ |
| for(XSLFShape shape : this.getShapes()){ |
| if(shape instanceof XSLFTextShape) { |
| XSLFTextShape txt = (XSLFTextShape)shape; |
| if(txt.getTextType() == type) { |
| return txt; |
| } |
| } |
| } |
| return null; |
| } |
| |
| @SuppressWarnings("WeakerAccess") |
| public XSLFSimpleShape getPlaceholder(Placeholder ph) { |
| return getPlaceholderByType(ph.ooxmlId); |
| } |
| |
| @Internal |
| public XSLFSimpleShape getPlaceholder(CTPlaceholder ph) { |
| XSLFSimpleShape shape = null; |
| if(ph.isSetIdx()) { |
| shape = getPlaceholderById((int)ph.getIdx()); |
| } |
| |
| if (shape == null && ph.isSetType()) { |
| shape = getPlaceholderByType(ph.getType().intValue()); |
| } |
| return shape; |
| } |
| |
| private void initPlaceholders() { |
| if(_placeholders == null) { |
| _placeholders = new ArrayList<>(); |
| _placeholderByIdMap = new HashMap<>(); |
| _placeholderByTypeMap = new HashMap<>(); |
| |
| for(final XSLFShape sh : getShapes()){ |
| if(sh instanceof XSLFTextShape){ |
| final XSLFTextShape sShape = (XSLFTextShape)sh; |
| final CTPlaceholder ph = sShape.getPlaceholderDetails().getCTPlaceholder(false); |
| if(ph != null) { |
| _placeholders.add(sShape); |
| if(ph.isSetIdx()) { |
| int idx = (int)ph.getIdx(); |
| _placeholderByIdMap.put(idx, sShape); |
| } |
| if(ph.isSetType()){ |
| _placeholderByTypeMap.put(ph.getType().intValue(), sShape); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| private XSLFSimpleShape getPlaceholderById(int id) { |
| initPlaceholders(); |
| return _placeholderByIdMap.get(id); |
| } |
| |
| XSLFSimpleShape getPlaceholderByType(int ordinal) { |
| initPlaceholders(); |
| return _placeholderByTypeMap.get(ordinal); |
| } |
| |
| /** |
| * |
| * @param idx 0-based index of a placeholder in the sheet |
| * @return placeholder |
| */ |
| public XSLFTextShape getPlaceholder(int idx) { |
| initPlaceholders(); |
| return _placeholders.get(idx); |
| } |
| |
| /** |
| * |
| * @return all placeholder shapes in this sheet |
| */ |
| @SuppressWarnings("WeakerAccess") |
| public XSLFTextShape[] getPlaceholders() { |
| initPlaceholders(); |
| return _placeholders.toArray(new XSLFTextShape[0]); |
| } |
| |
| /** |
| * |
| * @return whether shapes on the master sheet should be shown. By default master graphics is turned off. |
| * Sheets that support the notion of master (slide, slideLayout) should override it and |
| * check this setting in the sheet XML |
| */ |
| @Override |
| public boolean getFollowMasterGraphics(){ |
| return false; |
| } |
| |
| /** |
| * @return background for this sheet |
| */ |
| @Override |
| public XSLFBackground getBackground() { |
| return null; |
| } |
| |
| /** |
| * Render this sheet into the supplied graphics object |
| * |
| * @param graphics the graphics context to draw to |
| */ |
| @Override |
| public void draw(Graphics2D graphics){ |
| DrawFactory drawFact = DrawFactory.getInstance(graphics); |
| Drawable draw = drawFact.getDrawable(this); |
| draw.draw(graphics); |
| } |
| |
| /** |
| * Import a picture data from another document. |
| * |
| * @param blipId ID of the package relationship to retrieve. |
| * @param parent parent document containing the data to import |
| * @return ID of the created relationship |
| */ |
| String importBlip(String blipId, POIXMLDocumentPart parent) { |
| final XSLFPictureData parData = parent.getRelationPartById(blipId).getDocumentPart(); |
| final XSLFPictureData pictureData; |
| if (getPackagePart().getPackage() == parent.getPackagePart().getPackage()) { |
| // handle ref counter correct, if the parent document is the same as this |
| pictureData = parData; |
| } else { |
| XMLSlideShow ppt = getSlideShow(); |
| pictureData = ppt.addPicture(parData.getData(), parData.getType()); |
| } |
| |
| RelationPart rp = addRelation(blipId, XSLFRelation.IMAGES, pictureData); |
| return rp.getRelationship().getId(); |
| } |
| |
| /** |
| * Import a package part into this sheet. |
| */ |
| void importPart(PackageRelationship srcRel, PackagePart srcPafrt) { |
| PackagePart destPP = getPackagePart(); |
| PackagePartName srcPPName = srcPafrt.getPartName(); |
| |
| OPCPackage pkg = destPP.getPackage(); |
| if(pkg.containPart(srcPPName)){ |
| // already exists |
| return; |
| } |
| |
| destPP.addRelationship(srcPPName, TargetMode.INTERNAL, srcRel.getRelationshipType()); |
| |
| PackagePart part = pkg.createPart(srcPPName, srcPafrt.getContentType()); |
| try { |
| OutputStream out = part.getOutputStream(); |
| InputStream is = srcPafrt.getInputStream(); |
| IOUtils.copy(is, out); |
| is.close(); |
| out.close(); |
| } catch (IOException e){ |
| throw new POIXMLException(e); |
| } |
| } |
| |
| /** |
| * Helper method for sheet and group shapes |
| * |
| * @param pictureShape the picture shapes whose relation is to be removed, |
| * only if there are no more relations on its sheet to that picture |
| */ |
| void removePictureRelation(XSLFPictureShape pictureShape) { |
| int numberOfRelations = 0; |
| String targetBlipId = pictureShape.getBlipId(); |
| for (XSLFShape shape : pictureShape.getSheet().getShapes()) { |
| if (shape instanceof XSLFPictureShape) { |
| XSLFPictureShape currentPictureShape = ((XSLFPictureShape) shape); |
| String currentBlipId = currentPictureShape.getBlipId(); |
| if (currentBlipId != null && currentBlipId.equals(targetBlipId)) { |
| numberOfRelations++; |
| } |
| } |
| } |
| if (numberOfRelations <= 1) { |
| removeRelation(pictureShape.getBlipId()); |
| } |
| } |
| |
| |
| @Override |
| public XSLFPlaceholderDetails getPlaceholderDetails(Placeholder placeholder) { |
| final XSLFSimpleShape ph = getPlaceholder(placeholder); |
| return (ph == null) ? null : new XSLFPlaceholderDetails(ph); |
| } |
| |
| /** |
| * this method will add chart into slide |
| * with default height, width, x and y |
| * @param chart xslf chart object |
| * @since POI 4.1.0 |
| */ |
| public void addChart(XSLFChart chart) { |
| Rectangle2D rect2D = new Rectangle(XDDFChart.DEFAULT_X, XDDFChart.DEFAULT_Y, |
| XDDFChart.DEFAULT_WIDTH, XDDFChart.DEFAULT_HEIGHT); |
| |
| this.addChart(chart, rect2D); |
| } |
| |
| /** |
| * this method will add chart into slide |
| * with given height, width, x and y |
| * @param chart xslf chart object |
| * @since POI 4.1.0 |
| */ |
| public void addChart(XSLFChart chart, Rectangle2D rect2D) { |
| RelationPart rp = addRelation(null, XSLFRelation.CHART, chart); |
| getDrawing().addChart(rp.getRelationship().getId(), rect2D); |
| } |
| |
| protected String mapSchemeColor(CTColorMappingOverride cmapOver, String schemeColor) { |
| String slideColor = mapSchemeColor((cmapOver == null) ? null : cmapOver.getOverrideClrMapping(), schemeColor); |
| if (slideColor != null) { |
| return slideColor; |
| } |
| XSLFSheet master = (XSLFSheet)getMasterSheet(); |
| String masterColor = (master == null) ? null : master.mapSchemeColor(schemeColor); |
| return (masterColor == null) ? schemeColor : masterColor; |
| } |
| |
| protected String mapSchemeColor(CTColorMapping cmap, String schemeColor) { |
| STColorSchemeIndex.Enum schemeMap = null; |
| if (cmap != null && schemeColor != null) { |
| switch (schemeColor) { |
| case "accent1": |
| schemeMap = cmap.getAccent1(); |
| break; |
| case "accent2": |
| schemeMap = cmap.getAccent2(); |
| break; |
| case "accent3": |
| schemeMap = cmap.getAccent3(); |
| break; |
| case "accent4": |
| schemeMap = cmap.getAccent4(); |
| break; |
| case "accent5": |
| schemeMap = cmap.getAccent5(); |
| break; |
| case "accent6": |
| schemeMap = cmap.getAccent6(); |
| break; |
| case "bg1": |
| schemeMap = cmap.getBg1(); |
| break; |
| case "bg2": |
| schemeMap = cmap.getBg2(); |
| break; |
| case "folHlink": |
| schemeMap = cmap.getFolHlink(); |
| break; |
| case "hlink": |
| schemeMap = cmap.getHlink(); |
| break; |
| case "tx1": |
| schemeMap = cmap.getTx1(); |
| break; |
| case "tx2": |
| schemeMap = cmap.getTx2(); |
| break; |
| default: |
| break; |
| } |
| } |
| return (schemeMap == null) ? null : schemeMap.toString(); |
| } |
| } |