git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1200330 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_8_BETA5
package org.apache.poi.xslf.usermodel; | package org.apache.poi.xslf.usermodel; | ||||
/** | /** | ||||
* | |||||
* | |||||
* @author Yegor Kozlov | * @author Yegor Kozlov | ||||
*/ | */ | ||||
public enum LineCap { | public enum LineCap { | ||||
/** | /** | ||||
* Rounded ends - the default | |||||
* Rounded ends | |||||
*/ | */ | ||||
ROUND, | ROUND, | ||||
/** | /** |
// first fill | // first fill | ||||
Paint fill = getFillPaint(graphics); | Paint fill = getFillPaint(graphics); | ||||
Paint line = getLinePaint(graphics); | |||||
applyStroke(graphics); // the stroke applies both to the shadow and the shape | |||||
// first paint the shadow | |||||
if(shadow != null) for(Outline o : elems){ | |||||
if(o.getPath().isFilled()){ | |||||
if(fill != null) shadow.fill(graphics, o.getOutline()); | |||||
if(line != null) shadow.draw(graphics, o.getOutline()); | |||||
} | |||||
} | |||||
// then fill the shape interior | |||||
if(fill != null) for(Outline o : elems){ | if(fill != null) for(Outline o : elems){ | ||||
if(o.getPath().isFilled()){ | if(o.getPath().isFilled()){ | ||||
if(shadow != null) shadow.fill(graphics, o.getOutline()); | |||||
graphics.setPaint(fill); | graphics.setPaint(fill); | ||||
graphics.fill(o.getOutline()); | graphics.fill(o.getOutline()); | ||||
} | } | ||||
_shape.drawContent(graphics); | _shape.drawContent(graphics); | ||||
// then stroke the shape outline | // then stroke the shape outline | ||||
Paint line = getLinePaint(graphics); | |||||
if(line != null) for(Outline o : elems){ | if(line != null) for(Outline o : elems){ | ||||
if(o.getPath().isStroked()){ | if(o.getPath().isStroked()){ | ||||
applyStroke(graphics); // the stroke applies both to the shadow and the shape | |||||
if(shadow != null) shadow.draw(graphics, o.getOutline()); | |||||
graphics.setPaint(line); | graphics.setPaint(line); | ||||
graphics.draw(o.getOutline()); | graphics.draw(o.getOutline()); | ||||
} | } |
return lst; | return lst; | ||||
} | } | ||||
/** | |||||
* YK: dashing of lines is suppressed for now. | |||||
* @return | |||||
*/ | |||||
@Override | |||||
public XSLFShadow getShadow() { | |||||
return null; | |||||
} | |||||
} | } |
import org.apache.poi.POIXMLException; | import org.apache.poi.POIXMLException; | ||||
import org.apache.poi.openxml4j.opc.PackagePart; | import org.apache.poi.openxml4j.opc.PackagePart; | ||||
import org.apache.poi.openxml4j.opc.PackageRelationship; | import org.apache.poi.openxml4j.opc.PackageRelationship; | ||||
import org.apache.poi.openxml4j.opc.TargetMode; | |||||
import org.apache.poi.util.Beta; | import org.apache.poi.util.Beta; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip; | import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties; | import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties; | ||||
public XSLFPictureData getPictureData() { | public XSLFPictureData getPictureData() { | ||||
if(_data == null){ | if(_data == null){ | ||||
CTPicture ct = (CTPicture)getXmlObject(); | |||||
String blipId = ct.getBlipFill().getBlip().getEmbed(); | |||||
String blipId = getBlipId(); | |||||
PackagePart p = getSheet().getPackagePart(); | PackagePart p = getSheet().getPackagePart(); | ||||
PackageRelationship rel = p.getRelationship(blipId); | PackageRelationship rel = p.getRelationship(blipId); | ||||
return _data; | return _data; | ||||
} | } | ||||
private String getBlipId(){ | |||||
CTPicture ct = (CTPicture)getXmlObject(); | |||||
return ct.getBlipFill().getBlip().getEmbed(); | |||||
} | |||||
@Override | @Override | ||||
public void drawContent(Graphics2D graphics) { | public void drawContent(Graphics2D graphics) { | ||||
renderer.drawImage(graphics, data, getAnchor()); | renderer.drawImage(graphics, data, getAnchor()); | ||||
} | } | ||||
@Override | |||||
void copy(XSLFShape sh){ | |||||
super.copy(sh); | |||||
XSLFPictureShape p = (XSLFPictureShape)sh; | |||||
String blipId = p.getBlipId(); | |||||
String relId = getSheet().importBlip(blipId, p.getSheet().getPackagePart()); | |||||
CTPicture ct = (CTPicture)getXmlObject(); | |||||
CTBlip blip = ct.getBlipFill().getBlip(); | |||||
blip.setEmbed(relId); | |||||
} | |||||
} | } |
* @author Yegor Kozlov | * @author Yegor Kozlov | ||||
*/ | */ | ||||
public class XSLFShadow extends XSLFSimpleShape { | public class XSLFShadow extends XSLFSimpleShape { | ||||
private XSLFSimpleShape _parent; | private XSLFSimpleShape _parent; | ||||
/* package */XSLFShadow(CTOuterShadowEffect shape, XSLFSimpleShape parentShape) { | /* package */XSLFShadow(CTOuterShadowEffect shape, XSLFSimpleShape parentShape) { |
package org.apache.poi.xslf.usermodel; | package org.apache.poi.xslf.usermodel; | ||||
import org.apache.poi.util.Beta; | import org.apache.poi.util.Beta; | ||||
import org.apache.poi.util.Internal; | |||||
import org.apache.xmlbeans.XmlObject; | import org.apache.xmlbeans.XmlObject; | ||||
import java.awt.Graphics2D; | import java.awt.Graphics2D; | ||||
public abstract class XSLFShape { | public abstract class XSLFShape { | ||||
/** | /** | ||||
* | |||||
* @return the position of this shape within the drawing canvas. | * @return the position of this shape within the drawing canvas. | ||||
* The coordinates are expressed in points | |||||
* The coordinates are expressed in points | |||||
*/ | */ | ||||
public abstract Rectangle2D getAnchor(); | public abstract Rectangle2D getAnchor(); | ||||
/** | /** | ||||
* | |||||
* @param anchor the position of this shape within the drawing canvas. | * @param anchor the position of this shape within the drawing canvas. | ||||
* The coordinates are expressed in points | |||||
* The coordinates are expressed in points | |||||
*/ | */ | ||||
public abstract void setAnchor(Rectangle2D anchor); | public abstract void setAnchor(Rectangle2D anchor); | ||||
/** | /** | ||||
* | |||||
* @return the xml bean holding this shape's data | * @return the xml bean holding this shape's data | ||||
*/ | */ | ||||
public abstract XmlObject getXmlObject(); | public abstract XmlObject getXmlObject(); | ||||
/** | /** | ||||
* | |||||
* @return human-readable name of this shape, e.g. "Rectange 3" | * @return human-readable name of this shape, e.g. "Rectange 3" | ||||
*/ | */ | ||||
public abstract String getShapeName(); | public abstract String getShapeName(); | ||||
* This ID may be used to assist in uniquely identifying this object so that it can | * This ID may be used to assist in uniquely identifying this object so that it can | ||||
* be referred to by other parts of the document. | * be referred to by other parts of the document. | ||||
* <p> | * <p> | ||||
* If multiple objects within the same document share the same id attribute value, | |||||
* then the document shall be considered non-conformant. | |||||
* If multiple objects within the same document share the same id attribute value, | |||||
* then the document shall be considered non-conformant. | |||||
* </p> | * </p> | ||||
* | * | ||||
* @return unique id of this shape | * @return unique id of this shape | ||||
* @param theta the rotation angle in degrees. | * @param theta the rotation angle in degrees. | ||||
*/ | */ | ||||
public abstract void setRotation(double theta); | public abstract void setRotation(double theta); | ||||
/** | /** | ||||
* Rotation angle in degrees | * Rotation angle in degrees | ||||
* <p> | * <p> | ||||
* @param flip whether the shape is vertically flipped | * @param flip whether the shape is vertically flipped | ||||
*/ | */ | ||||
public abstract void setFlipVertical(boolean flip); | public abstract void setFlipVertical(boolean flip); | ||||
/** | /** | ||||
* Whether the shape is horizontally flipped | * Whether the shape is horizontally flipped | ||||
* | * | ||||
* | * | ||||
* @param graphics the graphics whos transform matrix will be modified | * @param graphics the graphics whos transform matrix will be modified | ||||
*/ | */ | ||||
protected void applyTransform(Graphics2D graphics){ | |||||
protected void applyTransform(Graphics2D graphics) { | |||||
Rectangle2D anchor = getAnchor(); | Rectangle2D anchor = getAnchor(); | ||||
// rotation | // rotation | ||||
double rotation = getRotation(); | double rotation = getRotation(); | ||||
if(rotation != 0.) { | |||||
// PowerPoint rotates shapes relative to the geometric center | |||||
double centerX = anchor.getX() + anchor.getWidth()/2; | |||||
double centerY = anchor.getY() + anchor.getHeight()/2; | |||||
if (rotation != 0.) { | |||||
// PowerPoint rotates shapes relative to the geometric center | |||||
double centerX = anchor.getX() + anchor.getWidth() / 2; | |||||
double centerY = anchor.getY() + anchor.getHeight() / 2; | |||||
graphics.translate(centerX, centerY); | graphics.translate(centerX, centerY); | ||||
graphics.rotate(Math.toRadians(rotation)); | graphics.rotate(Math.toRadians(rotation)); | ||||
} | } | ||||
//flip horizontal | //flip horizontal | ||||
if(getFlipHorizontal()){ | |||||
if (getFlipHorizontal()) { | |||||
graphics.translate(anchor.getX() + anchor.getWidth(), anchor.getY()); | graphics.translate(anchor.getX() + anchor.getWidth(), anchor.getY()); | ||||
graphics.scale(-1, 1); | graphics.scale(-1, 1); | ||||
graphics.translate(-anchor.getX() , -anchor.getY()); | |||||
graphics.translate(-anchor.getX(), -anchor.getY()); | |||||
} | } | ||||
//flip vertical | //flip vertical | ||||
if(getFlipVertical()){ | |||||
if (getFlipVertical()) { | |||||
graphics.translate(anchor.getX(), anchor.getY() + anchor.getHeight()); | graphics.translate(anchor.getX(), anchor.getY() + anchor.getHeight()); | ||||
graphics.scale(1, -1); | graphics.scale(1, -1); | ||||
graphics.translate(-anchor.getX(), -anchor.getY()); | graphics.translate(-anchor.getX(), -anchor.getY()); | ||||
} | } | ||||
} | } | ||||
/** | |||||
* Set the contents of this shape to be a copy of the source shape. | |||||
* This method is called recursively for each shape when merging slides | |||||
* | |||||
* @param sh the source shape | |||||
* @see org.apache.poi.xslf.usermodel.XSLFSlide#importContent(XSLFSheet) | |||||
*/ | |||||
@Internal | |||||
void copy(XSLFShape sh) { | |||||
if (!getClass().isInstance(sh)) { | |||||
throw new IllegalArgumentException( | |||||
"Can't copy " + sh.getClass().getSimpleName() + " into " + getClass().getSimpleName()); | |||||
} | |||||
setAnchor(sh.getAnchor()); | |||||
} | |||||
} | } |
package org.apache.poi.xslf.usermodel; | package org.apache.poi.xslf.usermodel; | ||||
import org.apache.poi.POIXMLDocumentPart; | import org.apache.poi.POIXMLDocumentPart; | ||||
import org.apache.poi.POIXMLException; | |||||
import org.apache.poi.openxml4j.opc.PackagePart; | import org.apache.poi.openxml4j.opc.PackagePart; | ||||
import org.apache.poi.openxml4j.opc.PackageRelationship; | import org.apache.poi.openxml4j.opc.PackageRelationship; | ||||
import org.apache.poi.openxml4j.opc.TargetMode; | import org.apache.poi.openxml4j.opc.TargetMode; | ||||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException; | |||||
import org.apache.poi.util.Beta; | import org.apache.poi.util.Beta; | ||||
import org.apache.poi.util.Internal; | import org.apache.poi.util.Internal; | ||||
import org.apache.xmlbeans.XmlObject; | import org.apache.xmlbeans.XmlObject; | ||||
/** | /** | ||||
* Set the contents of this sheet to be a copy of the source sheet. | * 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 | * @param src the source sheet to copy data from | ||||
* @return modified 'this' | |||||
*/ | */ | ||||
public void copy(XSLFSheet src){ | |||||
public XSLFSheet importContent(XSLFSheet src){ | |||||
_shapes = null; | _shapes = null; | ||||
_spTree = null; | _spTree = null; | ||||
_drawing = null; | _drawing = null; | ||||
// first copy the source xml | |||||
getXmlObject().set(src.getXmlObject()); | getXmlObject().set(src.getXmlObject()); | ||||
// recursively update each shape | |||||
List<XSLFShape> tgtShapes = getShapeList(); | |||||
List<XSLFShape> srcShapes = src.getShapeList(); | |||||
for(int i = 0; i < tgtShapes.size(); i++){ | |||||
XSLFShape s1 = srcShapes.get(i); | |||||
XSLFShape s2 = tgtShapes.get(i); | |||||
s2.copy(s1); | |||||
} | |||||
return this; | |||||
} | } | ||||
/** | /** | ||||
} | } | ||||
} | } | ||||
/** | |||||
* Import a picture data from another document. | |||||
* | |||||
* @param blipId ID of the package relationship to retrieve. | |||||
* @param packagePart package part containing the data to import | |||||
* @return ID of the created relationship | |||||
*/ | |||||
String importBlip(String blipId, PackagePart packagePart) { | |||||
PackageRelationship blipRel = packagePart.getRelationship(blipId); | |||||
PackagePart blipPart; | |||||
try { | |||||
blipPart = packagePart.getRelatedPart(blipRel); | |||||
} catch (InvalidFormatException e){ | |||||
throw new POIXMLException(e); | |||||
} | |||||
XSLFPictureData data = new XSLFPictureData(blipPart, null); | |||||
XMLSlideShow ppt = getSlideShow(); | |||||
int pictureIdx = ppt.addPicture(data.getData(), data.getPictureType()); | |||||
PackagePart pic = ppt.getAllPictures().get(pictureIdx).getPackagePart(); | |||||
PackageRelationship rel = getPackagePart().addRelationship( | |||||
pic.getPartName(), TargetMode.INTERNAL, blipRel.getRelationshipType()); | |||||
addRelation(rel.getId(), new XSLFPictureData(pic, rel)); | |||||
return rel.getId(); | |||||
} | |||||
} | } |
import org.apache.poi.xslf.model.geom.Outline; | import org.apache.poi.xslf.model.geom.Outline; | ||||
import org.apache.poi.xslf.model.geom.Path; | import org.apache.poi.xslf.model.geom.Path; | ||||
import org.apache.poi.xslf.model.geom.PresetGeometries; | import org.apache.poi.xslf.model.geom.PresetGeometries; | ||||
import org.apache.poi.openxml4j.opc.PackageRelationship; | |||||
import org.apache.poi.openxml4j.opc.PackagePart; | |||||
import org.apache.poi.openxml4j.opc.TargetMode; | |||||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException; | |||||
import org.apache.poi.POIXMLException; | |||||
import org.apache.xmlbeans.XmlObject; | import org.apache.xmlbeans.XmlObject; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTEffectStyleItem; | import org.openxmlformats.schemas.drawingml.x2006.main.CTEffectStyleItem; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomGuide; | import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomGuide; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.STLineCap; | import org.openxmlformats.schemas.drawingml.x2006.main.STLineCap; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal; | import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType; | import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip; | |||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; | import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType; | import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture; | |||||
import java.awt.Color; | import java.awt.Color; | ||||
import java.awt.Graphics2D; | import java.awt.Graphics2D; | ||||
*/ | */ | ||||
@Beta | @Beta | ||||
public abstract class XSLFSimpleShape extends XSLFShape { | public abstract class XSLFSimpleShape extends XSLFShape { | ||||
private static CTOuterShadowEffect NO_SHADOW = CTOuterShadowEffect.Factory.newInstance(); | |||||
private final XmlObject _shape; | private final XmlObject _shape; | ||||
private final XSLFSheet _sheet; | private final XSLFSheet _sheet; | ||||
CTSolidColorFillProperties fill = ln.isSetSolidFill() ? ln | CTSolidColorFillProperties fill = ln.isSetSolidFill() ? ln | ||||
.getSolidFill() : ln.addNewSolidFill(); | .getSolidFill() : ln.addNewSolidFill(); | ||||
fill.setSrgbClr(rgb); | fill.setSrgbClr(rgb); | ||||
if(fill.isSetHslClr()) fill.unsetHslClr(); | |||||
if(fill.isSetPrstClr()) fill.unsetPrstClr(); | |||||
if(fill.isSetSchemeClr()) fill.unsetSchemeClr(); | |||||
if(fill.isSetScrgbClr()) fill.unsetScrgbClr(); | |||||
if(fill.isSetSysClr()) fill.unsetSysClr(); | |||||
} | } | ||||
} | } | ||||
(byte) color.getGreen(), (byte) color.getBlue()}); | (byte) color.getGreen(), (byte) color.getBlue()}); | ||||
fill.setSrgbClr(rgb); | fill.setSrgbClr(rgb); | ||||
if(fill.isSetHslClr()) fill.unsetHslClr(); | |||||
if(fill.isSetPrstClr()) fill.unsetPrstClr(); | |||||
if(fill.isSetSchemeClr()) fill.unsetSchemeClr(); | |||||
if(fill.isSetScrgbClr()) fill.unsetScrgbClr(); | |||||
if(fill.isSetSysClr()) fill.unsetSysClr(); | |||||
} | } | ||||
} | } | ||||
CTShapeProperties spPr = shape.getSpPr(); | CTShapeProperties spPr = shape.getSpPr(); | ||||
if (spPr.isSetEffectLst()) { | if (spPr.isSetEffectLst()) { | ||||
CTOuterShadowEffect obj = spPr.getEffectLst().getOuterShdw(); | CTOuterShadowEffect obj = spPr.getEffectLst().getOuterShdw(); | ||||
setValue(obj); | |||||
setValue(obj == null ? NO_SHADOW : obj); | |||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return obj == null ? null : new XSLFShadow(obj, this); | |||||
return (obj == null || obj == NO_SHADOW) ? null : new XSLFShadow(obj, this); | |||||
} | } | ||||
@Override | @Override | ||||
public void drawContent(Graphics2D graphics){ | public void drawContent(Graphics2D graphics){ | ||||
} | } | ||||
@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); | |||||
} | |||||
if(getSpPr().isSetBlipFill()){ | |||||
CTBlip blip = getSpPr().getBlipFill().getBlip(); | |||||
String blipId = blip.getEmbed(); | |||||
String relId = getSheet().importBlip(blipId, s.getSheet().getPackagePart()); | |||||
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); | |||||
} | |||||
} | |||||
} | } |
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps; | import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D; | import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D; | import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip; | |||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTCommonSlideData; | import org.openxmlformats.schemas.presentationml.x2006.main.CTCommonSlideData; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape; | import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShapeNonVisual; | import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShapeNonVisual; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlide; | import org.openxmlformats.schemas.presentationml.x2006.main.CTSlide; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.SldDocument; | import org.openxmlformats.schemas.presentationml.x2006.main.SldDocument; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTBackground; | |||||
import java.awt.Graphics2D; | import java.awt.Graphics2D; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
} | } | ||||
@Override | |||||
public XSLFSlide importContent(XSLFSheet src){ | |||||
super.importContent(src); | |||||
CTBackground bg = ((CTSlide)src.getXmlObject()).getCSld().getBg(); | |||||
if(bg != null) { | |||||
if(bg.isSetBgPr() && bg.getBgPr().isSetBlipFill()){ | |||||
CTBlip blip = bg.getBgPr().getBlipFill().getBlip(); | |||||
String blipId = blip.getEmbed(); | |||||
String relId = importBlip(blipId, src.getPackagePart()); | |||||
blip.setEmbed(relId); | |||||
} | |||||
} | |||||
return this; | |||||
} | |||||
} | } |
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties; | import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextSpacing; | import org.openxmlformats.schemas.drawingml.x2006.main.CTTextSpacing; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.STTextAlignType; | import org.openxmlformats.schemas.drawingml.x2006.main.STTextAlignType; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharBullet; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTColor; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBulletSizePoint; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextLineBreak; | |||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; | import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType; | import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType; | ||||
private final XSLFTextShape _shape; | private final XSLFTextShape _shape; | ||||
private List<TextFragment> _lines; | private List<TextFragment> _lines; | ||||
private TextFragment _bullet; | private TextFragment _bullet; | ||||
/** | |||||
* the highest line in this paragraph. Used for line spacing. | |||||
*/ | |||||
private double _maxLineHeight; | |||||
XSLFTextParagraph(CTTextParagraph p, XSLFTextShape shape){ | XSLFTextParagraph(CTTextParagraph p, XSLFTextShape shape){ | ||||
_p = p; | _p = p; | ||||
_runs = new ArrayList<XSLFTextRun>(); | _runs = new ArrayList<XSLFTextRun>(); | ||||
_shape = shape; | _shape = shape; | ||||
for (CTRegularTextRun r : _p.getRList()) { | |||||
_runs.add(new XSLFTextRun(r, this)); | |||||
} | |||||
for (CTTextField f : _p.getFldList()) { | |||||
CTRegularTextRun r = CTRegularTextRun.Factory.newInstance(); | |||||
r.setT(f.getT()); | |||||
_runs.add(new XSLFTextRun(r, this)); | |||||
for(XmlObject ch : _p.selectPath("*")){ | |||||
if(ch instanceof CTRegularTextRun){ | |||||
CTRegularTextRun r = (CTRegularTextRun)ch; | |||||
_runs.add(new XSLFTextRun(r, this)); | |||||
} else if (ch instanceof CTTextLineBreak){ | |||||
CTTextLineBreak br = (CTTextLineBreak)ch; | |||||
CTRegularTextRun r = CTRegularTextRun.Factory.newInstance(); | |||||
r.setRPr(br.getRPr()); | |||||
r.setT("\n"); | |||||
_runs.add(new XSLFTextRun(r, this)); | |||||
} else if (ch instanceof CTTextField){ | |||||
CTTextField f = (CTTextField)ch; | |||||
CTRegularTextRun r = CTRegularTextRun.Factory.newInstance(); | |||||
r.setRPr(f.getRPr()); | |||||
r.setT(f.getT()); | |||||
_runs.add(new XSLFTextRun(r, this)); | |||||
} | |||||
} | } | ||||
} | } | ||||
return out.toString(); | return out.toString(); | ||||
} | } | ||||
private String getVisibleText(){ | |||||
String getRenderableText(){ | |||||
StringBuilder out = new StringBuilder(); | StringBuilder out = new StringBuilder(); | ||||
for (XSLFTextRun r : _runs) { | for (XSLFTextRun r : _runs) { | ||||
String txt = r.getText(); | |||||
switch (r.getTextCap()){ | |||||
case ALL: | |||||
txt = txt.toUpperCase(); | |||||
break; | |||||
case SMALL: | |||||
txt = txt.toLowerCase(); | |||||
break; | |||||
} | |||||
out.append(txt); | |||||
out.append(r.getRenderableText()); | |||||
} | } | ||||
return out.toString(); | return out.toString(); | ||||
} | } | ||||
return fetcher.getValue(); | return fetcher.getValue(); | ||||
} | } | ||||
public void setBulletFont(String typeface){ | |||||
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); | |||||
CTTextFont font = pr.isSetBuFont() ? pr.getBuFont() : pr.addNewBuFont(); | |||||
font.setTypeface(typeface); | |||||
} | |||||
/** | /** | ||||
* @return the character to be used in place of the standard bullet point | * @return the character to be used in place of the standard bullet point | ||||
*/ | */ | ||||
return fetcher.getValue(); | return fetcher.getValue(); | ||||
} | } | ||||
public void setBulletCharacter(String str){ | |||||
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); | |||||
CTTextCharBullet c = pr.isSetBuChar() ? pr.getBuChar() : pr.addNewBuChar(); | |||||
c.setChar(str); | |||||
} | |||||
public Color getBulletFontColor(){ | public Color getBulletFontColor(){ | ||||
final XSLFTheme theme = getParentShape().getSheet().getTheme(); | final XSLFTheme theme = getParentShape().getSheet().getTheme(); | ||||
ParagraphPropertyFetcher<Color> fetcher = new ParagraphPropertyFetcher<Color>(getLevel()){ | ParagraphPropertyFetcher<Color> fetcher = new ParagraphPropertyFetcher<Color>(getLevel()){ | ||||
return fetcher.getValue(); | return fetcher.getValue(); | ||||
} | } | ||||
public void setBulletFontColor(Color color){ | |||||
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); | |||||
CTColor c = pr.isSetBuClr() ? pr.getBuClr() : pr.addNewBuClr(); | |||||
CTSRgbColor clr = c.isSetSrgbClr() ? c.getSrgbClr() : c.addNewSrgbClr(); | |||||
clr.setVal(new byte[]{(byte)color.getRed(), (byte)color.getGreen(), (byte)color.getBlue()}); | |||||
} | |||||
public double getBulletFontSize(){ | public double getBulletFontSize(){ | ||||
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){ | ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){ | ||||
public boolean fetch(CTTextParagraphProperties props){ | public boolean fetch(CTTextParagraphProperties props){ | ||||
return fetcher.getValue() == null ? 100 : fetcher.getValue(); | return fetcher.getValue() == null ? 100 : fetcher.getValue(); | ||||
} | } | ||||
public void setBulletFontSize(double size){ | |||||
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); | |||||
CTTextBulletSizePoint pt = pr.isSetBuSzPts() ? pr.getBuSzPts() : pr.addNewBuSzPts(); | |||||
pt.setVal((int)(size*1000)); | |||||
if(pr.isSetBuSzPct()) pr.unsetBuSzPct(); | |||||
} | |||||
/** | /** | ||||
* Specifies the indent size that will be applied to the first line of text in the paragraph. | * Specifies the indent size that will be applied to the first line of text in the paragraph. | ||||
* | * | ||||
* @param value the indent in points. The value of -1 unsets the indent attribute | |||||
* from the underlying xml bean. | |||||
* @param value the indent in points. | |||||
*/ | */ | ||||
public void setIndent(double value){ | public void setIndent(double value){ | ||||
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); | CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); | ||||
} | } | ||||
}; | }; | ||||
fetchParagraphProperty(fetcher); | fetchParagraphProperty(fetcher); | ||||
return fetcher.getValue() == null ? 0 : fetcher.getValue(); | |||||
// if the marL attribute is omitted, then a value of 347663 is implied | |||||
return fetcher.getValue() == null ? Units.toPoints(347663) : fetcher.getValue(); | |||||
} | } | ||||
/** | /** | ||||
/** | /** | ||||
* | * | ||||
* @param isBullet whether text in this paragraph has bullets | |||||
* @param flag whether text in this paragraph has bullets | |||||
*/ | */ | ||||
public void setBullet(boolean flag) { | public void setBullet(boolean flag) { | ||||
if(isBullet() == flag) return; | if(isBullet() == flag) return; | ||||
return _lines; | return _lines; | ||||
} | } | ||||
/** | |||||
* Returns wrapping width to break lines in this paragraph | |||||
* | |||||
* @param firstLine whether the first line is breaking | |||||
* | |||||
* @return wrapping width in points | |||||
*/ | |||||
double getWrappingWidth(boolean firstLine){ | |||||
// internal margins for the text box | |||||
double leftInset = _shape.getLeftInset(); | |||||
double rightInset = _shape.getRightInset(); | |||||
Rectangle2D anchor = _shape.getAnchor(); | |||||
double leftMargin = getLeftMargin(); | |||||
double indent = getIndent(); | |||||
double width; | |||||
if(!_shape.getWordWrap()) { | |||||
// if wordWrap == false then we return the advance to the right border of the sheet | |||||
width = _shape.getSheet().getSlideShow().getPageSize().getWidth() - anchor.getX(); | |||||
} else { | |||||
width = anchor.getWidth() - leftInset - rightInset - leftMargin; | |||||
if(firstLine) { | |||||
if(isBullet()){ | |||||
width -= Math.abs(indent); | |||||
} else { | |||||
if(indent > 0) width -= indent; // first line indentation | |||||
else if (indent < 0) { // hanging indentation: the first line start at the left margin | |||||
width += leftMargin; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
return width; | |||||
} | |||||
public double draw(Graphics2D graphics, double x, double y){ | public double draw(Graphics2D graphics, double x, double y){ | ||||
double marginLeft = _shape.getLeftInset(); | |||||
double marginRight = _shape.getRightInset(); | |||||
double leftInset = _shape.getLeftInset(); | |||||
double rightInset = _shape.getRightInset(); | |||||
Rectangle2D anchor = _shape.getAnchor(); | Rectangle2D anchor = _shape.getAnchor(); | ||||
double penY = y; | double penY = y; | ||||
double textOffset = getLeftMargin(); | |||||
double leftMargin = getLeftMargin(); | |||||
boolean firstLine = true; | boolean firstLine = true; | ||||
double indent = getIndent(); | |||||
for(TextFragment line : _lines){ | for(TextFragment line : _lines){ | ||||
double penX = x; | double penX = x; | ||||
if(firstLine) { | |||||
if(_bullet != null){ | |||||
if(indent < 0) { | |||||
// a negative value means "Hanging" indentation and | |||||
// indicates the position of the actual bullet character. | |||||
// (the bullet is shifted to right relative to the text) | |||||
_bullet.draw(graphics, penX, penY); | |||||
penX -= indent; | |||||
} else if(indent > 0){ | |||||
penX += leftMargin; | |||||
// a positive value means the "First Line" indentation: | |||||
// the first line is indented and other lines start at the bullet ofset | |||||
_bullet.draw(graphics, penX, penY); | |||||
penX += indent; | |||||
} else { | |||||
// no special indent. The first line behaves like all others | |||||
penX += leftMargin; | |||||
// a zero indent means that the bullet and text have the same offset | |||||
_bullet.draw(graphics, penX, penY); | |||||
// don't let text overlay the bullet and advance by the bullet width | |||||
penX += _bullet._layout.getAdvance() + 1; | |||||
} | |||||
} else { | |||||
if(indent < 0) { | |||||
// if bullet=false and indentation=hanging then the first line | |||||
// starts at the left offset (penX is not incremented) | |||||
} else if(indent > 0) { | |||||
// first line indent shifts penX | |||||
penX += indent + leftMargin; | |||||
} else { | |||||
// no special indent. The first line behaves like all others | |||||
penX += leftMargin; | |||||
} | |||||
} | |||||
} else { | |||||
penX += leftMargin; | |||||
} | |||||
switch (getTextAlign()) { | switch (getTextAlign()) { | ||||
case CENTER: | case CENTER: | ||||
penX += textOffset + (anchor.getWidth() - textOffset - line.getWidth() - marginLeft - marginRight) / 2; | |||||
penX += (anchor.getWidth() - leftMargin - line.getWidth() - leftInset - rightInset) / 2; | |||||
break; | break; | ||||
case RIGHT: | case RIGHT: | ||||
penX += (anchor.getWidth() - line.getWidth() - marginLeft - marginRight); | |||||
penX += (anchor.getWidth() - line.getWidth() - leftInset - rightInset); | |||||
break; | break; | ||||
default: | default: | ||||
penX = x + textOffset; | |||||
//penX += leftInset; | |||||
break; | break; | ||||
} | } | ||||
if(_bullet != null && firstLine){ | |||||
_bullet.draw(graphics, penX + getIndent(), penY); | |||||
} | |||||
line.draw(graphics, penX, penY); | line.draw(graphics, penX, penY); | ||||
//The vertical line spacing | //The vertical line spacing | ||||
double spacing = getLineSpacing(); | double spacing = getLineSpacing(); | ||||
if(spacing > 0) { | if(spacing > 0) { | ||||
// If linespacing >= 0, then linespacing is a percentage of normal line height. | // If linespacing >= 0, then linespacing is a percentage of normal line height. | ||||
penY += spacing*0.01*line.getHeight(); | |||||
penY += spacing*0.01* _maxLineHeight; | |||||
} else { | } else { | ||||
// positive value means absolute spacing in points | // positive value means absolute spacing in points | ||||
penY += -spacing; | penY += -spacing; | ||||
} | } | ||||
AttributedString getAttributedString(Graphics2D graphics){ | AttributedString getAttributedString(Graphics2D graphics){ | ||||
String text = getVisibleText(); | |||||
String text = getRenderableText(); | |||||
AttributedString string = new AttributedString(text); | AttributedString string = new AttributedString(text); | ||||
int startIndex = 0; | int startIndex = 0; | ||||
for (XSLFTextRun run : _runs){ | for (XSLFTextRun run : _runs){ | ||||
int length = run.getText().length(); | |||||
int length = run.getRenderableText().length(); | |||||
if(length == 0) { | if(length == 0) { | ||||
// skip empty runs | // skip empty runs | ||||
continue; | continue; | ||||
void breakText(Graphics2D graphics){ | void breakText(Graphics2D graphics){ | ||||
_lines = new ArrayList<TextFragment>(); | _lines = new ArrayList<TextFragment>(); | ||||
String text = getRenderableText(); | |||||
AttributedString at = getAttributedString(graphics); | AttributedString at = getAttributedString(graphics); | ||||
AttributedCharacterIterator it = at.getIterator(); | AttributedCharacterIterator it = at.getIterator(); | ||||
if(it.getBeginIndex() == it.getEndIndex()) { | if(it.getBeginIndex() == it.getEndIndex()) { | ||||
LineBreakMeasurer measurer = new LineBreakMeasurer(it, graphics.getFontRenderContext()); | LineBreakMeasurer measurer = new LineBreakMeasurer(it, graphics.getFontRenderContext()); | ||||
for (;;) { | for (;;) { | ||||
int startIndex = measurer.getPosition(); | int startIndex = measurer.getPosition(); | ||||
double wrappingWidth = getWrappingWidth() + 1; // add a pixel to compensate rounding errors | |||||
TextLayout layout = measurer.nextLayout((float)wrappingWidth, it.getEndIndex(), true); | |||||
double wrappingWidth = getWrappingWidth(_lines.size() == 0) + 1; // add a pixel to compensate rounding errors | |||||
int nextBreak = text.indexOf('\n', startIndex + 1); | |||||
if(nextBreak == -1) nextBreak = it.getEndIndex(); | |||||
TextLayout layout = measurer.nextLayout((float)wrappingWidth, nextBreak, true); | |||||
if (layout == null) { | if (layout == null) { | ||||
// layout can be null if the entire word at the current position | // layout can be null if the entire word at the current position | ||||
// does not fit within the wrapping width. Try with requireNextWord=false. | // does not fit within the wrapping width. Try with requireNextWord=false. | ||||
layout = measurer.nextLayout((float)wrappingWidth, it.getEndIndex(), false); | |||||
layout = measurer.nextLayout((float)wrappingWidth, nextBreak, false); | |||||
} | } | ||||
int endIndex = measurer.getPosition(); | int endIndex = measurer.getPosition(); | ||||
TextFragment line = new TextFragment(layout, str); | TextFragment line = new TextFragment(layout, str); | ||||
_lines.add(line); | _lines.add(line); | ||||
_maxLineHeight = Math.max(_maxLineHeight, line.getHeight()); | |||||
if(endIndex == it.getEndIndex()) break; | if(endIndex == it.getEndIndex()) break; | ||||
} | } | ||||
} | } | ||||
double getWrappingWidth(){ | |||||
double width; | |||||
if(!_shape.getWordWrap()) { | |||||
width = _shape.getSheet().getSlideShow().getPageSize().getWidth(); | |||||
} else { | |||||
width = _shape.getAnchor().getWidth() - | |||||
_shape.getLeftInset() - _shape.getRightInset() - getLeftMargin(); | |||||
} | |||||
return width; | |||||
} | |||||
CTTextParagraphProperties getDefaultStyle(){ | CTTextParagraphProperties getDefaultStyle(){ | ||||
CTPlaceholder ph = _shape.getCTPlaceholder(); | CTPlaceholder ph = _shape.getCTPlaceholder(); | ||||
String defaultStyleSelector; | String defaultStyleSelector; | ||||
return ok; | return ok; | ||||
} | } | ||||
void copy(XSLFTextParagraph p){ | |||||
TextAlign srcAlign = p.getTextAlign(); | |||||
if(srcAlign != getTextAlign()){ | |||||
setTextAlign(srcAlign); | |||||
} | |||||
boolean isBullet = p.isBullet(); | |||||
if(isBullet != isBullet()){ | |||||
setBullet(isBullet); | |||||
if(isBullet) { | |||||
String buFont = p.getBulletFont(); | |||||
if(buFont != null && !buFont.equals(getBulletFont())){ | |||||
setBulletFont(buFont); | |||||
} | |||||
String buChar = p.getBulletCharacter(); | |||||
if(buChar != null && !buChar.equals(getBulletCharacter())){ | |||||
setBulletCharacter(buChar); | |||||
} | |||||
Color buColor = p.getBulletFontColor(); | |||||
if(buColor != null && !buColor.equals(getBulletFontColor())){ | |||||
setBulletFontColor(buColor); | |||||
} | |||||
double buSize = p.getBulletFontSize(); | |||||
if(buSize != getBulletFontSize()){ | |||||
setBulletFontSize(buSize); | |||||
} | |||||
} | |||||
} | |||||
double leftMargin = p.getLeftMargin(); | |||||
if(leftMargin != getLeftMargin()){ | |||||
setLeftMargin(leftMargin); | |||||
} | |||||
double indent = p.getIndent(); | |||||
if(indent != getIndent()){ | |||||
setIndent(indent); | |||||
} | |||||
double spaceAfter = p.getSpaceAfter(); | |||||
if(spaceAfter != getSpaceAfter()){ | |||||
setSpaceAfter(spaceAfter); | |||||
} | |||||
double spaceBefore = p.getSpaceBefore(); | |||||
if(spaceBefore != getSpaceBefore()){ | |||||
setSpaceBefore(spaceBefore); | |||||
} | |||||
double lineSpacing = p.getLineSpacing(); | |||||
if(lineSpacing != getLineSpacing()){ | |||||
setLineSpacing(lineSpacing); | |||||
} | |||||
List<XSLFTextRun> srcR = p.getTextRuns(); | |||||
List<XSLFTextRun> tgtR = getTextRuns(); | |||||
for(int i = 0; i < srcR.size(); i++){ | |||||
XSLFTextRun r1 = srcR.get(i); | |||||
XSLFTextRun r2 = tgtR.get(i); | |||||
r2.copy(r1); | |||||
} | |||||
} | |||||
} | } |
return _r.getT(); | return _r.getT(); | ||||
} | } | ||||
String getRenderableText(){ | |||||
String txt = _r.getT(); | |||||
switch (getTextCap()){ | |||||
case ALL: | |||||
txt = txt.toUpperCase(); | |||||
break; | |||||
case SMALL: | |||||
txt = txt.toLowerCase(); | |||||
break; | |||||
} | |||||
// TODO-1 is is the place to convert wingdings to unicode | |||||
// TODO-2 this is a temporary hack. Rendering text with tabs is not yet supported. | |||||
// for now tabs are replaced with some number of spaces. | |||||
return txt.replace("\t", " "); | |||||
} | |||||
public void setText(String text){ | public void setText(String text){ | ||||
_r.setT(text); | _r.setT(text); | ||||
} | } | ||||
CTSolidColorFillProperties fill = rPr.isSetSolidFill() ? rPr.getSolidFill() : rPr.addNewSolidFill(); | CTSolidColorFillProperties fill = rPr.isSetSolidFill() ? rPr.getSolidFill() : rPr.addNewSolidFill(); | ||||
CTSRgbColor clr = fill.isSetSrgbClr() ? fill.getSrgbClr() : fill.addNewSrgbClr(); | CTSRgbColor clr = fill.isSetSrgbClr() ? fill.getSrgbClr() : fill.addNewSrgbClr(); | ||||
clr.setVal(new byte[]{(byte)color.getRed(), (byte)color.getGreen(), (byte)color.getBlue()}); | clr.setVal(new byte[]{(byte)color.getRed(), (byte)color.getGreen(), (byte)color.getBlue()}); | ||||
if(fill.isSetHslClr()) fill.unsetHslClr(); | |||||
if(fill.isSetPrstClr()) fill.unsetPrstClr(); | |||||
if(fill.isSetSchemeClr()) fill.unsetSchemeClr(); | |||||
if(fill.isSetScrgbClr()) fill.unsetScrgbClr(); | |||||
if(fill.isSetSysClr()) fill.unsetSysClr(); | |||||
} | } | ||||
public Color getFontColor(){ | public Color getFontColor(){ | ||||
return ok; | return ok; | ||||
} | } | ||||
void copy(XSLFTextRun r){ | |||||
String srcFontFamily = r.getFontFamily(); | |||||
if(srcFontFamily != null && !srcFontFamily.equals(getFontFamily())){ | |||||
setFontFamily(srcFontFamily); | |||||
} | |||||
Color srcFontColor = r.getFontColor(); | |||||
if(srcFontColor != null && !srcFontColor.equals(getFontColor())){ | |||||
setFontColor(srcFontColor); | |||||
} | |||||
double srcFontSize = r.getFontSize(); | |||||
if(srcFontSize != getFontSize()){ | |||||
setFontSize(srcFontSize); | |||||
} | |||||
boolean bold = r.isBold(); | |||||
if(bold != isBold()) setBold(bold); | |||||
boolean italic = r.isItalic(); | |||||
if(italic != isItalic()) setItalic(italic); | |||||
boolean underline = r.isUnderline(); | |||||
if(underline != isUnderline()) setUnderline(underline); | |||||
boolean strike = r.isStrikethrough(); | |||||
if(strike != isStrikethrough()) setStrikethrough(strike); | |||||
} | |||||
} | } |
} | } | ||||
}; | }; | ||||
fetchShapeProperty(fetcher); | fetchShapeProperty(fetcher); | ||||
return fetcher.getValue() == null ? 0 : fetcher.getValue(); | |||||
// If this attribute is omitted, then a value of 0.05 inches is implied | |||||
return fetcher.getValue() == null ? 3.6 : fetcher.getValue(); | |||||
} | } | ||||
/** | /** | ||||
} | } | ||||
}; | }; | ||||
fetchShapeProperty(fetcher); | fetchShapeProperty(fetcher); | ||||
return fetcher.getValue() == null ? 0 : fetcher.getValue(); | |||||
// If this attribute is omitted, then a value of 0.1 inches is implied | |||||
return fetcher.getValue() == null ? 7.2 : fetcher.getValue(); | |||||
} | } | ||||
/** | /** | ||||
} | } | ||||
}; | }; | ||||
fetchShapeProperty(fetcher); | fetchShapeProperty(fetcher); | ||||
return fetcher.getValue() == null ? 0 : fetcher.getValue(); | |||||
// If this attribute is omitted, then a value of 0.1 inches is implied | |||||
return fetcher.getValue() == null ? 7.2 : fetcher.getValue(); | |||||
} | } | ||||
/** | /** | ||||
} | } | ||||
}; | }; | ||||
fetchShapeProperty(fetcher); | fetchShapeProperty(fetcher); | ||||
return fetcher.getValue() == null ? 0 : fetcher.getValue(); | |||||
// If this attribute is omitted, then a value of 0.05 inches is implied | |||||
return fetcher.getValue() == null ? 3.6 : fetcher.getValue(); | |||||
} | } | ||||
/** | /** | ||||
return y - y0; | return y - y0; | ||||
} | } | ||||
@Override | |||||
void copy(XSLFShape sh){ | |||||
super.copy(sh); | |||||
XSLFTextShape tsh = (XSLFTextShape)sh; | |||||
boolean srcWordWrap = tsh.getWordWrap(); | |||||
if(srcWordWrap != getWordWrap()){ | |||||
setWordWrap(srcWordWrap); | |||||
} | |||||
double leftInset = tsh.getLeftInset(); | |||||
if(leftInset != getLeftInset()) { | |||||
setLeftInset(leftInset); | |||||
} | |||||
double rightInset = tsh.getRightInset(); | |||||
if(rightInset != getRightInset()) { | |||||
setRightInset(rightInset); | |||||
} | |||||
double topInset = tsh.getTopInset(); | |||||
if(topInset != getTopInset()) { | |||||
setTopInset(topInset); | |||||
} | |||||
double bottomInset = tsh.getBottomInset(); | |||||
if(bottomInset != getBottomInset()) { | |||||
setBottomInset(bottomInset); | |||||
} | |||||
VerticalAlignment vAlign = tsh.getVerticalAlignment(); | |||||
if(vAlign != getVerticalAlignment()) { | |||||
setVerticalAlignment(vAlign); | |||||
} | |||||
List<XSLFTextParagraph> srcP = tsh.getTextParagraphs(); | |||||
List<XSLFTextParagraph> tgtP = getTextParagraphs(); | |||||
for(int i = 0; i < srcP.size(); i++){ | |||||
XSLFTextParagraph p1 = srcP.get(i); | |||||
XSLFTextParagraph p2 = tgtP.get(i); | |||||
p2.copy(p1); | |||||
} | |||||
} | |||||
} | } |
import junit.framework.TestCase; | import junit.framework.TestCase; | ||||
import org.apache.poi.xslf.XSLFTestDataSamples; | import org.apache.poi.xslf.XSLFTestDataSamples; | ||||
import org.apache.poi.openxml4j.opc.PackagePart; | |||||
import java.awt.Color; | |||||
import java.util.List; | |||||
import java.util.Arrays; | |||||
import java.util.regex.Pattern; | |||||
/** | /** | ||||
* @author Yegor Kozlov | * @author Yegor Kozlov | ||||
assertTrue(slide.getFollowMasterGraphics()); | assertTrue(slide.getFollowMasterGraphics()); | ||||
} | } | ||||
public void testImportContent(){ | |||||
XMLSlideShow ppt = new XMLSlideShow(); | |||||
XMLSlideShow src = XSLFTestDataSamples.openSampleDocument("themes.pptx"); | |||||
// create a blank slide and import content from the 4th slide of themes.pptx | |||||
XSLFSlide slide1 = ppt.createSlide().importContent(src.getSlides()[3]); | |||||
XSLFShape[] shapes1 = slide1.getShapes(); | |||||
assertEquals(2, shapes1.length); | |||||
XSLFTextShape sh1 = (XSLFTextShape)shapes1[0]; | |||||
assertEquals("Austin Theme", sh1.getText()); | |||||
XSLFTextRun r1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0); | |||||
assertEquals("Century Gothic", r1.getFontFamily()); | |||||
assertEquals(40.0, r1.getFontSize()); | |||||
assertTrue(r1.isBold()); | |||||
assertTrue(r1.isItalic()); | |||||
assertEquals(new Color(148, 198, 0), r1.getFontColor()); | |||||
assertNull(sh1.getFillColor()); | |||||
assertNull(sh1.getLineColor()); | |||||
XSLFTextShape sh2 = (XSLFTextShape)shapes1[1]; | |||||
assertEquals( | |||||
"Text in a autoshape is white\n" + | |||||
"Fill: RGB(148, 198,0)", sh2.getText()); | |||||
XSLFTextRun r2 = sh2.getTextParagraphs().get(0).getTextRuns().get(0); | |||||
assertEquals("Century Gothic", r2.getFontFamily()); | |||||
assertEquals(18.0, r2.getFontSize()); | |||||
assertFalse(r2.isBold()); | |||||
assertFalse(r2.isItalic()); | |||||
assertEquals(Color.white, r2.getFontColor()); | |||||
assertEquals(new Color(148, 198, 0), sh2.getFillColor()); | |||||
assertEquals(new Color(74, 99, 0), sh2.getLineColor()); // slightly different from PowerPoint! | |||||
// the 5th slide has a picture and a texture fill | |||||
XSLFSlide slide2 = ppt.createSlide().importContent(src.getSlides()[4]); | |||||
XSLFShape[] shapes2 = slide2.getShapes(); | |||||
assertEquals(2, shapes2.length); | |||||
XSLFTextShape sh3 = (XSLFTextShape)shapes2[0]; | |||||
assertEquals("This slide overrides master background with a texture fill", sh3.getText()); | |||||
XSLFTextRun r3 = sh3.getTextParagraphs().get(0).getTextRuns().get(0); | |||||
assertEquals("Century Gothic", r3.getFontFamily()); | |||||
//assertEquals(32.4.0, r3.getFontSize()); | |||||
assertTrue(r3.isBold()); | |||||
assertTrue(r3.isItalic()); | |||||
assertEquals(new Color(148, 198, 0), r3.getFontColor()); | |||||
assertNull(sh3.getFillColor()); | |||||
assertNull(sh3.getLineColor()); | |||||
XSLFPictureShape sh4 = (XSLFPictureShape)shapes2[1]; | |||||
XSLFPictureShape srcPic = (XSLFPictureShape)src.getSlides()[4].getShapes()[1]; | |||||
assertTrue(Arrays.equals(sh4.getPictureData().getData(), srcPic.getPictureData().getData())); | |||||
} | |||||
} | } |
package org.apache.poi.xslf.usermodel; | |||||
import junit.framework.TestCase; | |||||
import java.awt.Rectangle; | |||||
import java.awt.Color; | |||||
import java.awt.geom.Rectangle2D; | |||||
import java.io.FileOutputStream; | |||||
import org.apache.poi.xssf.dev.XSSFDump; | |||||
import org.apache.poi.xslf.util.PPTX2PNG; | |||||
/** | |||||
* Created by IntelliJ IDEA. | |||||
* User: yegor | |||||
* Date: Nov 10, 2011 | |||||
* Time: 1:43:25 PM | |||||
* To change this template use File | Settings | File Templates. | |||||
*/ | |||||
public class TestXSLFTextParagraph extends TestCase { | |||||
public void testWrappingWidth() throws Exception { | |||||
XMLSlideShow ppt = new XMLSlideShow(); | |||||
XSLFSlide slide = ppt.createSlide(); | |||||
XSLFTextShape sh = slide.createAutoShape(); | |||||
sh.setLineColor(Color.black); | |||||
XSLFTextParagraph p = sh.addNewTextParagraph(); | |||||
p.addNewTextRun().setText( | |||||
"Paragraph formatting allows for more granular control " + | |||||
"of text within a shape. Properties here apply to all text " + | |||||
"residing within the corresponding paragraph."); | |||||
Rectangle2D anchor = new Rectangle(50, 50, 300, 200); | |||||
sh.setAnchor(anchor); | |||||
double leftInset = sh.getLeftInset(); | |||||
double rightInset = sh.getRightInset(); | |||||
assertEquals(7.2, leftInset); | |||||
assertEquals(7.2, rightInset); | |||||
double leftMargin = p.getLeftMargin(); | |||||
assertEquals(0.0, leftMargin); | |||||
double indent = p.getIndent(); | |||||
assertEquals(0.0, indent); // default | |||||
double expectedWidth; | |||||
// Case 1: bullet=false, leftMargin=0, indent=0. | |||||
expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin; | |||||
assertEquals(285.6, expectedWidth); // 300 - 7.2 - 7.2 - 0 | |||||
assertEquals(expectedWidth, p.getWrappingWidth(true)); | |||||
assertEquals(expectedWidth, p.getWrappingWidth(false)); | |||||
p.setLeftMargin(36); // 0.5" | |||||
leftMargin = p.getLeftMargin(); | |||||
assertEquals(36.0, leftMargin); | |||||
expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin; | |||||
assertEquals(249.6, expectedWidth, 1E-5); // 300 - 7.2 - 7.2 - 36 | |||||
assertEquals(expectedWidth, p.getWrappingWidth(true)); | |||||
assertEquals(expectedWidth, p.getWrappingWidth(false)); | |||||
// increase insets, the wrapping width should get smaller | |||||
sh.setLeftInset(10); | |||||
sh.setRightInset(10); | |||||
leftInset = sh.getLeftInset(); | |||||
rightInset = sh.getRightInset(); | |||||
assertEquals(10.0, leftInset); | |||||
assertEquals(10.0, rightInset); | |||||
expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin; | |||||
assertEquals(244.0, expectedWidth); // 300 - 10 - 10 - 36 | |||||
assertEquals(expectedWidth, p.getWrappingWidth(true)); | |||||
assertEquals(expectedWidth, p.getWrappingWidth(false)); | |||||
// set a positive indent of a 0.5 inch. This means "First Line" indentation: | |||||
// |<--- indent -->|Here goes first line of the text | |||||
// Here go other lines (second and subsequent) | |||||
p.setIndent(36.0); // 0.5" | |||||
indent = p.getIndent(); | |||||
assertEquals(36.0, indent); | |||||
expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin - indent; | |||||
assertEquals(208.0, expectedWidth); // 300 - 10 - 10 - 36 - 6.4 | |||||
assertEquals(expectedWidth, p.getWrappingWidth(true)); // first line is indented | |||||
// other lines are not indented | |||||
expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin; | |||||
assertEquals(244.0, expectedWidth); // 300 - 10 - 10 - 36 | |||||
assertEquals(expectedWidth, p.getWrappingWidth(false)); | |||||
// set a negative indent of a 1 inch. This means "Hanging" indentation: | |||||
// Here goes first line of the text | |||||
// |<--- indent -->|Here go other lines (second and subsequent) | |||||
p.setIndent(-72.0); // 1" | |||||
indent = p.getIndent(); | |||||
assertEquals(-72.0, indent); | |||||
expectedWidth = anchor.getWidth() - leftInset - rightInset; | |||||
assertEquals(280.0, expectedWidth); // 300 - 10 - 10 | |||||
assertEquals(expectedWidth, p.getWrappingWidth(true)); // first line is NOT indented | |||||
// other lines are indented by leftMargin (the value of indent is not used) | |||||
expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin; | |||||
assertEquals(244.0, expectedWidth); // 300 - 10 - 10 - 36 | |||||
assertEquals(expectedWidth, p.getWrappingWidth(false)); | |||||
} | |||||
} |