All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.poi.xslf.usermodel.XSLFSimpleShape Maven / Gradle / Ivy

Go to download

The Apache Commons Codec package contains simple encoder and decoders for various formats such as Base64 and Hexadecimal. In addition to these widely used encoders and decoders, the codec package also maintains a collection of phonetic encoding utilities.

The newest version!
/*
 *  ====================================================================
 *    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 java.awt.Color;
import java.awt.geom.Rectangle2D;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.sl.draw.geom.CustomGeometry;
import org.apache.poi.sl.draw.geom.Guide;
import org.apache.poi.sl.draw.geom.PresetGeometries;
import org.apache.poi.sl.usermodel.FillStyle;
import org.apache.poi.sl.usermodel.LineDecoration;
import org.apache.poi.sl.usermodel.LineDecoration.DecorationShape;
import org.apache.poi.sl.usermodel.LineDecoration.DecorationSize;
import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.ShapeType;
import org.apache.poi.sl.usermodel.SimpleShape;
import org.apache.poi.sl.usermodel.StrokeStyle;
import org.apache.poi.sl.usermodel.StrokeStyle.LineCap;
import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound;
import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;
import org.apache.poi.util.Beta;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.Units;
import org.apache.poi.xslf.model.PropertyFetcher;
import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFEffectProperties;
import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFFillProperties;
import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFGeometryProperties;
import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.drawingml.x2006.main.CTBaseStyles;
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;
import org.openxmlformats.schemas.drawingml.x2006.main.CTEffectStyleItem;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomGuide;
import org.openxmlformats.schemas.drawingml.x2006.main.CTLineEndProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTLineStyleList;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTOuterShadowEffect;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetLineDashProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrix;
import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrixReference;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
import org.openxmlformats.schemas.drawingml.x2006.main.STCompoundLine;
import org.openxmlformats.schemas.drawingml.x2006.main.STLineCap;
import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndLength;
import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndType;
import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndWidth;
import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal;
import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;

/**
 * Represents a single (non-group) shape in a .pptx slide show
 */
@Beta
public abstract class XSLFSimpleShape extends XSLFShape
    implements SimpleShape {
    private static CTOuterShadowEffect NO_SHADOW = CTOuterShadowEffect.Factory.newInstance();
    private static final POILogger LOG = POILogFactory.getLogger(XSLFSimpleShape.class);

    /* package */XSLFSimpleShape(XmlObject shape, XSLFSheet sheet) {
        super(shape,sheet);
    }

    @Override
    public void setShapeType(ShapeType type) {
        XSLFGeometryProperties gp = XSLFPropertiesDelegate.getGeometryDelegate(getShapeProperties());
        if (gp == null) {
            return;
        }
        if (gp.isSetCustGeom()) {
            gp.unsetCustGeom();
        }
        CTPresetGeometry2D prst = (gp.isSetPrstGeom()) ? gp.getPrstGeom() : gp.addNewPrstGeom();
        prst.setPrst(STShapeType.Enum.forInt(type.ooxmlId));
    }

    @Override
    public ShapeType getShapeType(){
        XSLFGeometryProperties gp = XSLFPropertiesDelegate.getGeometryDelegate(getShapeProperties());
        if (gp != null && gp.isSetPrstGeom()) {
            STShapeType.Enum geom = gp.getPrstGeom().getPrst();
            if (geom != null) {
                return ShapeType.forId(geom.intValue(), true);
            }
        }
        return null;
    }

    protected CTTransform2D getXfrm(boolean create) {
        PropertyFetcher fetcher = new PropertyFetcher() {
            @Override
            public boolean fetch(XSLFShape shape) {
                XmlObject xo = shape.getShapeProperties();
                if (xo instanceof CTShapeProperties && ((CTShapeProperties)xo).isSetXfrm()) {
                    setValue(((CTShapeProperties)xo).getXfrm());
                    return true;
                }
                return false;
            }
        };
        fetchShapeProperty(fetcher);
        
        CTTransform2D xfrm = fetcher.getValue();
        if (!create || xfrm != null) {
            return xfrm;
        } else {
            XmlObject xo = getShapeProperties();
            if (xo instanceof CTShapeProperties) {
                return ((CTShapeProperties)xo).addNewXfrm();
            } else {
                // ... group shapes have their own getXfrm()
                LOG.log(POILogger.WARN, getClass() +" doesn't have xfrm element.");
                return null;
            }
        }
    }

    @Override
    public Rectangle2D getAnchor() {

        CTTransform2D xfrm = getXfrm(false);
        if (xfrm == null) {
            return null;
        }

        CTPoint2D off = xfrm.getOff();
        double x = Units.toPoints(off.getX());
        double y = Units.toPoints(off.getY());
        CTPositiveSize2D ext = xfrm.getExt();
        double cx = Units.toPoints(ext.getCx());
        double cy = Units.toPoints(ext.getCy());
        return new Rectangle2D.Double(x, y, cx, cy);
    }

    @Override
    public void setAnchor(Rectangle2D anchor) {
        CTTransform2D xfrm = getXfrm(true);
        if (xfrm == null) {
            return;
        }
        CTPoint2D off = xfrm.isSetOff() ? xfrm.getOff() : xfrm.addNewOff();
        long x = Units.toEMU(anchor.getX());
        long y = Units.toEMU(anchor.getY());
        off.setX(x);
        off.setY(y);
        CTPositiveSize2D ext = xfrm.isSetExt() ? xfrm.getExt() : xfrm
                .addNewExt();
        long cx = Units.toEMU(anchor.getWidth());
        long cy = Units.toEMU(anchor.getHeight());
        ext.setCx(cx);
        ext.setCy(cy);
    }

    @Override
    public void setRotation(double theta) {
        CTTransform2D xfrm = getXfrm(true);
        if (xfrm != null) {
            xfrm.setRot((int) (theta * 60000));
        }
    }

    @Override
    public double getRotation() {
        CTTransform2D xfrm = getXfrm(false);
        return (xfrm == null || !xfrm.isSetRot()) ? 0 : (xfrm.getRot() / 60000.d);
    }

    @Override
    public void setFlipHorizontal(boolean flip) {
        CTTransform2D xfrm = getXfrm(true);
        if (xfrm != null) {
            xfrm.setFlipH(flip);
        }
    }

    @Override
    public void setFlipVertical(boolean flip) {
        CTTransform2D xfrm = getXfrm(true);
        if (xfrm != null) {
            xfrm.setFlipV(flip);
        }
    }

    @Override
    public boolean getFlipHorizontal() {
        CTTransform2D xfrm = getXfrm(false);
        return (xfrm != null && xfrm.isSetFlipH()) && xfrm.getFlipH();
    }

    @Override
    public boolean getFlipVertical() {
        CTTransform2D xfrm = getXfrm(false);
        return (xfrm != null && xfrm.isSetFlipV()) && xfrm.getFlipV();
    }


    /**
     * Get default line properties defined in the theme (if any).
     * Used internally to resolve shape properties.
     *
     * @return line properties from the theme of null
     */
    private CTLineProperties getDefaultLineProperties() {
        CTShapeStyle style = getSpStyle();
        if (style == null) {
            return null;
        }
        CTStyleMatrixReference lnRef = style.getLnRef();
        if (lnRef == null) {
            return null;
        }
        // 1-based index of a line style within the style matrix
        int idx = (int)lnRef.getIdx();

        XSLFTheme theme = getSheet().getTheme();
        if (theme == null) {
            return null;
        }
        CTBaseStyles styles = theme.getXmlObject().getThemeElements();
        if (styles == null) {
            return null;
        }
        CTStyleMatrix styleMatrix = styles.getFmtScheme();
        if (styleMatrix == null) {
            return null;
        }
        CTLineStyleList lineStyles = styleMatrix.getLnStyleLst();
        if (lineStyles == null || lineStyles.sizeOfLnArray() < idx) {
            return null;
        }

        return lineStyles.getLnArray(idx - 1);
    }

    /**
    * @param color  the color to paint the shape outline.
     * A null value turns off the shape outline.
     */
    public void setLineColor(Color color) {
        CTLineProperties ln = getLn(this, true);
        if (ln == null) {
            return;
        }

        if (ln.isSetSolidFill()) {
            ln.unsetSolidFill();
        }
        if (ln.isSetGradFill()) {
            ln.unsetGradFill();
        }
        if (ln.isSetPattFill()) {
            ln.unsetPattFill();
        }
        if (ln.isSetNoFill()) {
            ln.unsetNoFill();
        }

        
        if (color == null) {
            ln.addNewNoFill();
        } else {
            CTSolidColorFillProperties fill = ln.addNewSolidFill();
            XSLFColor col = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr());
            col.setColor(color);
        }
    }

    /**
     *
     * @return the color of the shape outline or null
     * if outline is turned off
     */
    @SuppressWarnings("WeakerAccess")
    public Color getLineColor() {
        PaintStyle ps = getLinePaint();
        if (ps instanceof SolidPaint) {
            return ((SolidPaint)ps).getSolidColor().getColor();
        }
        return null;
    }

    @SuppressWarnings("WeakerAccess")
    protected PaintStyle getLinePaint() {
        XSLFSheet sheet = getSheet();
        final XSLFTheme theme = sheet.getTheme();
        final boolean hasPlaceholder = getPlaceholder() != null;
        PropertyFetcher fetcher = new PropertyFetcher() {
            @Override
            public boolean fetch(XSLFShape shape) {
                CTLineProperties spPr = getLn(shape, false);
                XSLFFillProperties fp = XSLFPropertiesDelegate.getFillDelegate(spPr);

                if (fp != null && fp.isSetNoFill()) {
                    setValue(null);
                    return true;
                }
                
                PackagePart pp = shape.getSheet().getPackagePart();
                PaintStyle paint = selectPaint(fp, null, pp, theme, hasPlaceholder);
                if (paint != null) {
                    setValue(paint);
                    return true;
                }

                CTShapeStyle style = shape.getSpStyle();
                if (style != null) {
                    fp = XSLFPropertiesDelegate.getFillDelegate(style.getLnRef());
                    paint = selectPaint(fp, null, pp, theme, hasPlaceholder);

                    // line color was not found, check if it is defined in the theme
                    if (paint == null) {
                        paint = getThemePaint(style, pp);
                    }
                }
                
                if (paint != null) {
                    setValue(paint);
                    return true;
                }
                
                return false;
            }

            PaintStyle getThemePaint(CTShapeStyle style, PackagePart pp) {
                // get a reference to a line style within the style matrix.
                CTStyleMatrixReference lnRef = style.getLnRef();
                if (lnRef == null) {
                    return null;
                }
                int idx = (int)lnRef.getIdx();
                CTSchemeColor phClr = lnRef.getSchemeClr();
                if(idx <= 0){
                    return null;
                }

                CTLineProperties props = theme.getXmlObject().getThemeElements().getFmtScheme().getLnStyleLst().getLnArray(idx - 1);
                XSLFFillProperties fp = XSLFPropertiesDelegate.getFillDelegate(props);
                return selectPaint(fp, phClr, pp, theme, hasPlaceholder);
            }
        };
        fetchShapeProperty(fetcher);

        return fetcher.getValue();
    }

    /**
     *
     * @param width line width in points. 0 means no line
     */
    @SuppressWarnings("WeakerAccess")
    public void setLineWidth(double width) {
        CTLineProperties lnPr = getLn(this, true);
        if (lnPr == null) {
            return;
        }
        
        if (width == 0.) {
            if (lnPr.isSetW()) {
                lnPr.unsetW();
            }
            if (!lnPr.isSetNoFill()) {
                lnPr.addNewNoFill();
            }
            if (lnPr.isSetSolidFill()) {
                lnPr.unsetSolidFill();
            }
            if (lnPr.isSetGradFill()) {
                lnPr.unsetGradFill();
            }
            if (lnPr.isSetPattFill()) {
                lnPr.unsetPattFill();
            }
        } else {
            if (lnPr.isSetNoFill()) {
                lnPr.unsetNoFill();
            }

            lnPr.setW(Units.toEMU(width));
        }
    }

    /**
     * @return line width in points. 0 means no line.
     */
    @SuppressWarnings("WeakerAccess")
    public double getLineWidth() {
        PropertyFetcher fetcher = new PropertyFetcher() {
            @Override
            public boolean fetch(XSLFShape shape) {
                CTLineProperties ln = getLn(shape, false);
                if (ln != null) {
                    if (ln.isSetNoFill()) {
                        setValue(0.);
                        return true;
                    }

                    if (ln.isSetW()) {
                        setValue(Units.toPoints(ln.getW()));
                        return true;
                    }
                }
                return false;
            }
        };
        fetchShapeProperty(fetcher);

        double lineWidth = 0;
        if (fetcher.getValue() == null) {
            CTLineProperties defaultLn = getDefaultLineProperties();
            if (defaultLn != null) {
                if (defaultLn.isSetW()) {
                    lineWidth = Units.toPoints(defaultLn.getW());
                }
            }
        } else {
            lineWidth = fetcher.getValue();
        }

        return lineWidth;
    }


    /**
     * @param compound set the line compound style
     */
    @SuppressWarnings("WeakerAccess")
    public void setLineCompound(LineCompound compound) {
        CTLineProperties ln = getLn(this, true);
        if (ln == null) {
            return;
        }
        if (compound == null) {
            if (ln.isSetCmpd()) {
                ln.unsetCmpd();
            }
        } else {
            STCompoundLine.Enum xCmpd;
            switch (compound) {
                default:
                case SINGLE:
                    xCmpd = STCompoundLine.SNG;
                    break;
                case DOUBLE:
                    xCmpd = STCompoundLine.DBL;
                    break;
                case THICK_THIN:
                    xCmpd = STCompoundLine.THICK_THIN;
                    break;
                case THIN_THICK:
                    xCmpd = STCompoundLine.THIN_THICK;
                    break;
                case TRIPLE:
                    xCmpd = STCompoundLine.TRI;
                    break;
            }
            ln.setCmpd(xCmpd);
        }
    }

    /**
     * @return the line compound
     */
    @SuppressWarnings("WeakerAccess")
    public LineCompound getLineCompound() {
        PropertyFetcher fetcher = new PropertyFetcher() {
            @Override
            public boolean fetch(XSLFShape shape) {
                CTLineProperties ln = getLn(shape, false);
                if (ln != null) {
                    STCompoundLine.Enum stCmpd = ln.getCmpd();
                    if (stCmpd != null) {
                        setValue(stCmpd.intValue());
                        return true;
                    }
                }
                return false;
            }
        };
        fetchShapeProperty(fetcher);

        Integer cmpd = fetcher.getValue();
        if (cmpd == null) {
            CTLineProperties defaultLn = getDefaultLineProperties();
            if (defaultLn != null && defaultLn.isSetCmpd()) {
                switch (defaultLn.getCmpd().intValue()) {
                default:
                case STCompoundLine.INT_SNG:
                    return LineCompound.SINGLE;
                case STCompoundLine.INT_DBL:
                    return LineCompound.DOUBLE;
                case STCompoundLine.INT_THICK_THIN:
                    return LineCompound.THICK_THIN;
                case STCompoundLine.INT_THIN_THICK:
                    return LineCompound.THIN_THICK;
                case STCompoundLine.INT_TRI:
                    return LineCompound.TRIPLE;
                }
            }
        }

        return null;
    }

    /**
     *
     * @param dash a preset line dashing scheme to stroke thr shape outline
     */
    @SuppressWarnings("WeakerAccess")
    public void setLineDash(LineDash dash) {
        CTLineProperties ln = getLn(this, true);
        if (ln == null) {
            return;
        }
        if (dash == null) {
            if (ln.isSetPrstDash()) {
                ln.unsetPrstDash();
            }
        } else {
            CTPresetLineDashProperties ldp = ln.isSetPrstDash() ? ln.getPrstDash() : ln.addNewPrstDash();
            ldp.setVal(STPresetLineDashVal.Enum.forInt(dash.ooxmlId));
        }
    }

    /**
     * @return  a preset line dashing scheme to stroke the shape outline
     */
    @SuppressWarnings("WeakerAccess")
    public LineDash getLineDash() {

        PropertyFetcher fetcher = new PropertyFetcher() {
            @Override
            public boolean fetch(XSLFShape shape) {
                CTLineProperties ln = getLn(shape, false);
                if (ln == null || !ln.isSetPrstDash()) {
                    return false;
                }

                setValue(LineDash.fromOoxmlId(ln.getPrstDash().getVal().intValue()));
                return true;
            }
        };
        fetchShapeProperty(fetcher);

        LineDash dash = fetcher.getValue();
        if (dash == null) {
            CTLineProperties defaultLn = getDefaultLineProperties();
            if (defaultLn != null && defaultLn.isSetPrstDash()) {
                dash = LineDash.fromOoxmlId(defaultLn.getPrstDash().getVal().intValue());
            }
        }
        return dash;
    }

    /**
     *
     * @param cap the line end cap style
     */
    @SuppressWarnings("WeakerAccess")
    public void setLineCap(LineCap cap) {
        CTLineProperties ln = getLn(this, true);
        if (ln == null) {
            return;
        }
        
        if (cap == null) {
            if (ln.isSetCap()) {
                ln.unsetCap();
            }
        } else {
            ln.setCap(STLineCap.Enum.forInt(cap.ooxmlId));
        }
    }

    /**
     *
     * @return the line end cap style
     */
    @SuppressWarnings("WeakerAccess")
    public LineCap getLineCap() {
        PropertyFetcher fetcher = new PropertyFetcher() {
            @Override
            public boolean fetch(XSLFShape shape) {
                CTLineProperties ln = getLn(shape, false);
                if (ln != null && ln.isSetCap()) {
                    setValue(LineCap.fromOoxmlId(ln.getCap().intValue()));
                    return true;
                }
                return false;
            }
        };
        fetchShapeProperty(fetcher);

        LineCap cap = fetcher.getValue();
        if (cap == null) {
            CTLineProperties defaultLn = getDefaultLineProperties();
            if (defaultLn != null && defaultLn.isSetCap()) {
                cap = LineCap.fromOoxmlId(defaultLn.getCap().intValue());
            }
        }
        return cap;
    }

    @Override
    public void setFillColor(Color color) {
        XSLFFillProperties fp = XSLFPropertiesDelegate.getFillDelegate(getShapeProperties());
        if (fp == null) {
            return;
        }
        if (color == null) {
            if (fp.isSetSolidFill()) {
                fp.unsetSolidFill();
            }
            
            if (fp.isSetGradFill()) {
                fp.unsetGradFill();
            }

            if (fp.isSetPattFill()) {
                fp.unsetGradFill();
            }
            
            if (fp.isSetBlipFill()) {
                fp.unsetBlipFill();
            }
            
            if (!fp.isSetNoFill()) {
                fp.addNewNoFill();
            }
        } else {
            if (fp.isSetNoFill()) {
                fp.unsetNoFill();
            }

            CTSolidColorFillProperties fill = fp.isSetSolidFill() ? fp.getSolidFill() : fp.addNewSolidFill();
                    
            XSLFColor col = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr());
            col.setColor(color);
        }
    }

    @Override
    public Color getFillColor() {
        PaintStyle ps = getFillPaint();
        if (ps instanceof SolidPaint) {
            return DrawPaint.applyColorTransform(((SolidPaint)ps).getSolidColor());
        }
        return null;
    }

    /**
     * @return shadow of this shape or null if shadow is disabled
     */
    @Override
    public XSLFShadow getShadow() {
        PropertyFetcher fetcher = new PropertyFetcher() {
            @Override
            public boolean fetch(XSLFShape shape) {
                XSLFEffectProperties ep = XSLFPropertiesDelegate.getEffectDelegate(shape.getShapeProperties());
                if (ep != null && ep.isSetEffectLst()) {
                    CTOuterShadowEffect obj = ep.getEffectLst().getOuterShdw();
                    setValue(obj == null ? NO_SHADOW : obj);
                    return true;
                }
                return false;
            }
        };
        fetchShapeProperty(fetcher);

        CTOuterShadowEffect obj = fetcher.getValue();
        if (obj == null) {
            // fill color was not found, check if it is defined in the theme
            CTShapeStyle style = getSpStyle();
            if (style != null && style.getEffectRef() != null) {
                // 1-based index of a shadow style within the style matrix
                int idx = (int) style.getEffectRef().getIdx();
                if(idx != 0) {
                    CTStyleMatrix styleMatrix = getSheet().getTheme().getXmlObject().getThemeElements().getFmtScheme();
                    CTEffectStyleItem ef = styleMatrix.getEffectStyleLst().getEffectStyleArray(idx - 1);
                    obj = ef.getEffectLst().getOuterShdw();
                }
            }
        }
        return (obj == null || obj == NO_SHADOW) ? null : new XSLFShadow(obj, this);
    }

    /**
     * @return definition of the shape geometry
     */
    @Override
    public CustomGeometry getGeometry() {
        XSLFGeometryProperties gp = XSLFPropertiesDelegate.getGeometryDelegate(getShapeProperties());
        
        if (gp == null) {
            return null;
        }
        
        CustomGeometry geom;
        PresetGeometries dict = PresetGeometries.getInstance();
        if(gp.isSetPrstGeom()){
            String name = gp.getPrstGeom().getPrst().toString();
            geom = dict.get(name);
            if(geom == null) {
                throw new IllegalStateException("Unknown shape geometry: " + name + ", available geometries are: " + dict.keySet());
            }
        } else if (gp.isSetCustGeom()){
            XMLStreamReader staxReader = gp.getCustGeom().newXMLStreamReader();
            geom = PresetGeometries.convertCustomGeometry(staxReader);
            try {
                staxReader.close();
            }
            catch (XMLStreamException e) {
                LOG.log(POILogger.WARN,
                        "An error occurred while closing a Custom Geometry XML Stream Reader: " + e.getMessage());
            }
        } else {
            geom = dict.get("rect");
        }
        return geom;
    }

    @Override
    void copy(XSLFShape sh){
        super.copy(sh);

        XSLFSimpleShape s = (XSLFSimpleShape)sh;

        Color srsSolidFill = s.getFillColor();
        Color tgtSoliFill = getFillColor();
        if(srsSolidFill != null && !srsSolidFill.equals(tgtSoliFill)){
            setFillColor(srsSolidFill);
        }

        XSLFFillProperties fp = XSLFPropertiesDelegate.getFillDelegate(getShapeProperties());
        if(fp != null && fp.isSetBlipFill()){
            CTBlip blip = fp.getBlipFill().getBlip();
            String blipId = blip.getEmbed();

            String relId = getSheet().importBlip(blipId, s.getSheet());
            blip.setEmbed(relId);
        }

        Color srcLineColor = s.getLineColor();
        Color tgtLineColor = getLineColor();
        if(srcLineColor != null && !srcLineColor.equals(tgtLineColor)) {
            setLineColor(srcLineColor);
        }

        double srcLineWidth = s.getLineWidth();
        double tgtLineWidth = getLineWidth();
        if(srcLineWidth != tgtLineWidth) {
            setLineWidth(srcLineWidth);
        }

        LineDash srcLineDash = s.getLineDash();
        LineDash tgtLineDash = getLineDash();
        if(srcLineDash != null && srcLineDash != tgtLineDash) {
            setLineDash(srcLineDash);
        }

        LineCap srcLineCap = s.getLineCap();
        LineCap tgtLineCap = getLineCap();
        if(srcLineCap != null && srcLineCap != tgtLineCap) {
            setLineCap(srcLineCap);
        }

    }

    /**
     * Specifies the line end decoration, such as a triangle or arrowhead.
     * 
     * @param style the line end docoration style
     */
    @SuppressWarnings("WeakerAccess")
    public void setLineHeadDecoration(DecorationShape style) {
        CTLineProperties ln = getLn(this, true);
        if (ln == null) {
            return;
        }
        CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd();
        if (style == null) {
            if (lnEnd.isSetType()) {
                lnEnd.unsetType();
            }
        } else {
            lnEnd.setType(STLineEndType.Enum.forInt(style.ooxmlId));
        }
    }

    /**
     * @return the line end decoration shape
     */
    @SuppressWarnings("WeakerAccess")
    public DecorationShape getLineHeadDecoration() {
        CTLineProperties ln = getLn(this, false);
        DecorationShape ds = DecorationShape.NONE;
        if (ln != null && ln.isSetHeadEnd() && ln.getHeadEnd().isSetType()) {
            ds = DecorationShape.fromOoxmlId(ln.getHeadEnd().getType().intValue());
        }
        return ds;
    }

    /**
     * specifies decoration width of the head of a line.
     * 
     * @param style the decoration width 
     */
    @SuppressWarnings("WeakerAccess")
    public void setLineHeadWidth(DecorationSize style) {
        CTLineProperties ln = getLn(this, true);
        if (ln == null) {
            return;
        }
        CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd();
        if (style == null) {
            if (lnEnd.isSetW()) {
                lnEnd.unsetW();
            }
        } else {
            lnEnd.setW(STLineEndWidth.Enum.forInt(style.ooxmlId));
        }
    }

    /**
     * @return the line end decoration width
     */
    @SuppressWarnings("WeakerAccess")
    public DecorationSize getLineHeadWidth() {
        CTLineProperties ln = getLn(this, false);
        DecorationSize ds = DecorationSize.MEDIUM;
        if (ln != null && ln.isSetHeadEnd() && ln.getHeadEnd().isSetW()) {
            ds = DecorationSize.fromOoxmlId(ln.getHeadEnd().getW().intValue());
        }
        return ds;
    }

    /**
     * Specifies the line end width in relation to the line width.
     */
    @SuppressWarnings("WeakerAccess")
    public void setLineHeadLength(DecorationSize style) {
        CTLineProperties ln = getLn(this, true);
        if (ln == null) {
            return;
        }
        
        CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd();
        if (style == null) {
            if (lnEnd.isSetLen()) {
                lnEnd.unsetLen();
            }
        } else {
            lnEnd.setLen(STLineEndLength.Enum.forInt(style.ooxmlId));
        }
    }

    /**
     * @return the line end decoration length
     */
    @SuppressWarnings("WeakerAccess")
    public DecorationSize getLineHeadLength() {
        CTLineProperties ln = getLn(this, false);
        
        DecorationSize ds = DecorationSize.MEDIUM;
        if (ln != null && ln.isSetHeadEnd() && ln.getHeadEnd().isSetLen()) {
            ds = DecorationSize.fromOoxmlId(ln.getHeadEnd().getLen().intValue());
        }
        return ds; 
    }

    /**
     * Specifies the line end decoration, such as a triangle or arrowhead.
     */
    @SuppressWarnings("WeakerAccess")
    public void setLineTailDecoration(DecorationShape style) {
        CTLineProperties ln = getLn(this, true);
        if (ln == null) {
            return;
        }

        CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd();
        if (style == null) {
            if (lnEnd.isSetType()) {
                lnEnd.unsetType();
            }
        } else {
            lnEnd.setType(STLineEndType.Enum.forInt(style.ooxmlId));
        }
    }

    /**
     * @return the line end decoration shape
     */
    @SuppressWarnings("WeakerAccess")
    public DecorationShape getLineTailDecoration() {
        CTLineProperties ln = getLn(this, false);
        
        DecorationShape ds = DecorationShape.NONE;
        if (ln != null && ln.isSetTailEnd() && ln.getTailEnd().isSetType()) {
            ds = DecorationShape.fromOoxmlId(ln.getTailEnd().getType().intValue());
        }
        return ds;
    }

    /**
     * specifies decorations which can be added to the tail of a line.
     */
    @SuppressWarnings("WeakerAccess")
    public void setLineTailWidth(DecorationSize style) {
        CTLineProperties ln = getLn(this, true);
        if (ln == null) {
            return;
        }
        
        CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd();
        if (style == null) {
            if (lnEnd.isSetW()) {
                lnEnd.unsetW();
            }
        } else {
            lnEnd.setW(STLineEndWidth.Enum.forInt(style.ooxmlId));
        }
    }

    /**
     * @return the line end decoration width
     */
    @SuppressWarnings("WeakerAccess")
    public DecorationSize getLineTailWidth() {
        CTLineProperties ln = getLn(this, false);
        DecorationSize ds = DecorationSize.MEDIUM;
        if (ln != null && ln.isSetTailEnd() && ln.getTailEnd().isSetW()) {
            ds = DecorationSize.fromOoxmlId(ln.getTailEnd().getW().intValue());
        }
        return ds;
    }

    /**
     * Specifies the line end width in relation to the line width.
     */
    @SuppressWarnings("WeakerAccess")
    public void setLineTailLength(DecorationSize style) {
        CTLineProperties ln = getLn(this, true);
        if (ln == null) {
            return;
        }
        
        CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd();
        if (style == null) {
            if (lnEnd.isSetLen()) {
                lnEnd.unsetLen();
            }
        } else {
            lnEnd.setLen(STLineEndLength.Enum.forInt(style.ooxmlId));
        }
    }

    /**
     * @return the line end decoration length
     */
    @SuppressWarnings("WeakerAccess")
    public DecorationSize getLineTailLength() {
        CTLineProperties ln = getLn(this, false);
        
        DecorationSize ds = DecorationSize.MEDIUM;
        if (ln != null && ln.isSetTailEnd() && ln.getTailEnd().isSetLen()) {
            ds = DecorationSize.fromOoxmlId(ln.getTailEnd().getLen().intValue());
        }
        return ds; 
    }

    @Override
    public Guide getAdjustValue(String name) {
        XSLFGeometryProperties gp = XSLFPropertiesDelegate.getGeometryDelegate(getShapeProperties());
        
        if (gp != null && gp.isSetPrstGeom() && gp.getPrstGeom().isSetAvLst()) {
            //noinspection deprecation
            for (CTGeomGuide g : gp.getPrstGeom().getAvLst().getGdArray()) {
                if (g.getName().equals(name)) {
                    return new Guide(g.getName(), g.getFmla());
                }
            }
        }

        return null;
    }

    @Override
    public LineDecoration getLineDecoration() {
        return new LineDecoration() {
            @Override
            public DecorationShape getHeadShape() {
                return getLineHeadDecoration();
            }

            @Override
            public DecorationSize getHeadWidth() {
                return getLineHeadWidth();
            }

            @Override
            public DecorationSize getHeadLength() {
                return getLineHeadLength();
            }

            @Override
            public DecorationShape getTailShape() {
                return getLineTailDecoration();
            }

            @Override
            public DecorationSize getTailWidth() {
                return getLineTailWidth();
            }

            @Override
            public DecorationSize getTailLength() {
                return getLineTailLength();
            }
        };
    }

    /**
     * fetch shape fill as a java.awt.Paint
     *
     * @return either Color or GradientPaint or TexturePaint or null
     */
    @Override
    public FillStyle getFillStyle() {
        return XSLFSimpleShape.this::getFillPaint;
    }

    @Override
    public StrokeStyle getStrokeStyle() {
        return new StrokeStyle() {
            @Override
            public PaintStyle getPaint() {
                return XSLFSimpleShape.this.getLinePaint();
            }

            @Override
            public LineCap getLineCap() {
                return XSLFSimpleShape.this.getLineCap();
            }

            @Override
            public LineDash getLineDash() {
                return XSLFSimpleShape.this.getLineDash();
            }

            @Override
            public double getLineWidth() {
                return XSLFSimpleShape.this.getLineWidth();
            }

            @Override
            public LineCompound getLineCompound() {
                return XSLFSimpleShape.this.getLineCompound();
            }

        };
    }

    @Override
    public void setStrokeStyle(Object... styles) {
        if (styles.length == 0) {
            // remove stroke
            setLineColor(null);
            return;
        }
        
        // TODO: handle PaintStyle
        for (Object st : styles) {
            if (st instanceof Number) {
                setLineWidth(((Number)st).doubleValue());
            } else if (st instanceof LineCap) {
                setLineCap((LineCap)st);
            } else if (st instanceof LineDash) {
                setLineDash((LineDash)st);
            } else if (st instanceof LineCompound) {
                setLineCompound((LineCompound)st);
            } else if (st instanceof Color) {
                setLineColor((Color)st);
            }
        }
    }
    
    @Override
    public XSLFHyperlink getHyperlink() {
        CTNonVisualDrawingProps cNvPr = getCNvPr();
        if (!cNvPr.isSetHlinkClick()) {
            return null;
        }
        return new XSLFHyperlink(cNvPr.getHlinkClick(), getSheet());
    }
    
    @Override
    public XSLFHyperlink createHyperlink() {
        XSLFHyperlink hl = getHyperlink();
        if (hl == null) {
            CTNonVisualDrawingProps cNvPr = getCNvPr();
            hl = new XSLFHyperlink(cNvPr.addNewHlinkClick(), getSheet());
        }
        return hl;
    }

    private static CTLineProperties getLn(XSLFShape shape, boolean create) {
        XmlObject pr = shape.getShapeProperties();
        if (!(pr instanceof CTShapeProperties)) {
            LOG.log(POILogger.WARN, shape.getClass() +" doesn't have line properties");
            return null;
        }
        
        CTShapeProperties spr = (CTShapeProperties)pr;
        return (spr.isSetLn() || !create) ? spr.getLn() : spr.addNewLn();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy