diff options
Diffstat (limited to 'src')
21 files changed, 1222 insertions, 1227 deletions
diff --git a/src/examples/src/org/apache/poi/hslf/examples/BulletsDemo.java b/src/examples/src/org/apache/poi/hslf/examples/BulletsDemo.java index d95f970ce7..0032bc8097 100644 --- a/src/examples/src/org/apache/poi/hslf/examples/BulletsDemo.java +++ b/src/examples/src/org/apache/poi/hslf/examples/BulletsDemo.java @@ -39,8 +39,8 @@ public final class BulletsDemo { HSLFTextParagraph rt = shape.getTextParagraphs().get(0); rt.getTextRuns().get(0).setFontSize(42); rt.setBullet(true); - rt.setIndent(0); //bullet offset - rt.setLeftMargin(50); //text offset (should be greater than bullet offset) + rt.setIndent(0d); //bullet offset + rt.setLeftMargin(50d); //text offset (should be greater than bullet offset) rt.setBulletChar('\u263A'); //bullet character shape.setText( "January\r" + diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial2.java b/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial2.java index 373f01f33f..91366b9d06 100644 --- a/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial2.java +++ b/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial2.java @@ -48,8 +48,8 @@ public class Tutorial2 { XSLFTextParagraph p2 = shape1.addNewTextParagraph();
// If spaceBefore >= 0, then space is a percentage of normal line height.
// If spaceBefore < 0, the absolute value of linespacing is the spacing in points
- p2.setSpaceBefore(-20); // 20 pt from the previous paragraph
- p2.setSpaceAfter(300); // 3 lines after the paragraph
+ p2.setSpaceBefore(-20d); // 20 pt from the previous paragraph
+ p2.setSpaceAfter(300d); // 3 lines after the paragraph
XSLFTextRun r2 = p2.addNewTextRun();
r2.setText("Paragraph properties apply to all text residing within the corresponding paragraph.");
r2.setFontSize(16);
@@ -62,8 +62,8 @@ public class Tutorial2 { r3.setFontColor(new Color(85, 142, 213));
XSLFTextParagraph p4 = shape1.addNewTextParagraph();
- p4.setSpaceBefore(-20); // 20 pt from the previous paragraph
- p4.setSpaceAfter(300); // 3 lines after the paragraph
+ p4.setSpaceBefore(-20d); // 20 pt from the previous paragraph
+ p4.setSpaceAfter(300d); // 3 lines after the paragraph
XSLFTextRun r4 = p4.addNewTextRun();
r4.setFontSize(16);
r4.setText(
diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial7.java b/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial7.java index a80f23cad7..95252d72f5 100644 --- a/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial7.java +++ b/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial7.java @@ -45,9 +45,9 @@ public class Tutorial7 { XSLFTextParagraph p2 = shape.addNewTextParagraph();
// indentation before text
- p2.setLeftMargin(60);
+ p2.setLeftMargin(60d);
// the bullet is set 40 pt before the text
- p2.setIndent(-40);
+ p2.setIndent(-40d);
p2.setBullet(true);
// customize bullets
p2.setBulletFontColor(Color.red);
diff --git a/src/java/org/apache/poi/util/Units.java b/src/java/org/apache/poi/util/Units.java index bc643fd97b..107a9b583e 100644 --- a/src/java/org/apache/poi/util/Units.java +++ b/src/java/org/apache/poi/util/Units.java @@ -16,6 +16,8 @@ ==================================================================== */
package org.apache.poi.util;
+import org.apache.poi.hslf.usermodel.HSLFShape;
+
/**
* @author Yegor Kozlov
*/
@@ -24,6 +26,22 @@ public class Units { public static final int EMU_PER_POINT = 12700;
/**
+ * Master DPI (576 pixels per inch).
+ * Used by the reference coordinate system in PowerPoint (HSLF)
+ */
+ public static final int MASTER_DPI = 576;
+
+ /**
+ * Pixels DPI (96 pixels per inch)
+ */
+ public static final int PIXEL_DPI = 96;
+
+ /**
+ * Points DPI (72 pixels per inch)
+ */
+ public static final int POINT_DPI = 72;
+
+ /**
* Converts points to EMUs
* @param points points
* @return emus
@@ -70,4 +88,17 @@ public class Units { int fixedPoint = (i << 16) | (f & 0xFFFF);
return fixedPoint;
}
+
+ public static double masterToPoints(int masterDPI) {
+ double points = masterDPI;
+ points *= HSLFShape.POINT_DPI;
+ points /= HSLFShape.MASTER_DPI;
+ return points;
+ }
+
+ public static int pointsToMaster(double points) {
+ points *= HSLFShape.MASTER_DPI;
+ points /= HSLFShape.POINT_DPI;
+ return (int)points;
+ }
}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java index aef03197dd..f0cf3a78a9 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java @@ -137,8 +137,10 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { /**
* Returns the alignment that is applied to the paragraph.
*
- * If this attribute is omitted, then a value of left is implied.
- * @return ??? alignment that is applied to the paragraph
+ * If this attribute is omitted, then null is returned.
+ * User code can imply the value {@link TextAlign#LEFT} then.
+ *
+ * @return alignment that is applied to the paragraph
*/
public TextAlign getTextAlign(){
ParagraphPropertyFetcher<TextAlign> fetcher = new ParagraphPropertyFetcher<TextAlign>(getLevel()){
@@ -152,7 +154,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { }
};
fetchParagraphProperty(fetcher);
- return fetcher.getValue() == null ? TextAlign.LEFT : fetcher.getValue();
+ return fetcher.getValue();
}
/**
@@ -184,7 +186,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { }
};
fetchParagraphProperty(fetcher);
- return fetcher.getValue() == null ? FontAlign.AUTO : fetcher.getValue();
+ return fetcher.getValue();
}
/**
@@ -294,7 +296,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { *
* @return the bullet size
*/
- public double getBulletFontSize(){
+ public Double getBulletFontSize(){
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
public boolean fetch(CTTextParagraphProperties props){
if(props.isSetBuSzPct()){
@@ -309,7 +311,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { }
};
fetchParagraphProperty(fetcher);
- return fetcher.getValue() == null ? 100 : fetcher.getValue();
+ return fetcher.getValue();
}
/**
@@ -334,27 +336,19 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { }
}
- /**
- * Specifies the indent size that will be applied to the first line of text in the paragraph.
- *
- * @param value the indent in points.
- */
@Override
- public void setIndent(double value){
+ public void setIndent(Double indent){
+ if (indent == null && !_p.isSetPPr()) return;
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
- if(value == -1) {
+ if(indent == -1) {
if(pr.isSetIndent()) pr.unsetIndent();
} else {
- pr.setIndent(Units.toEMU(value));
+ pr.setIndent(Units.toEMU(indent));
}
}
- /**
- *
- * @return the indent applied to the first line of text in the paragraph.
- */
@Override
- public double getIndent(){
+ public Double getIndent() {
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
public boolean fetch(CTTextParagraphProperties props){
@@ -367,32 +361,26 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { };
fetchParagraphProperty(fetcher);
- return fetcher.getValue() == null ? 0 : fetcher.getValue();
+ return fetcher.getValue();
}
- /**
- * Specifies the left margin of the paragraph. This is specified in addition to the text body
- * inset and applies only to this text paragraph. That is the text body Inset and the LeftMargin
- * attributes are additive with respect to the text position.
- *
- * @param value the left margin (in points) of the paragraph
- */
@Override
- public void setLeftMargin(double value){
+ public void setLeftMargin(Double leftMargin){
+ if (leftMargin == null && !_p.isSetPPr()) return;
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
- if(value == -1) {
+ if (leftMargin == null) {
if(pr.isSetMarL()) pr.unsetMarL();
} else {
- pr.setMarL(Units.toEMU(value));
+ pr.setMarL(Units.toEMU(leftMargin));
}
}
/**
- * @return the left margin (in points) of the paragraph
+ * @return the left margin (in points) of the paragraph, null if unset
*/
@Override
- public double getLeftMargin(){
+ public Double getLeftMargin(){
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
public boolean fetch(CTTextParagraphProperties props){
if(props.isSetMarL()){
@@ -405,32 +393,26 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { };
fetchParagraphProperty(fetcher);
// if the marL attribute is omitted, then a value of 347663 is implied
- return fetcher.getValue() == null ? 0 : fetcher.getValue();
+ return fetcher.getValue();
}
- /**
- * Specifies the right margin of the paragraph. This is specified in addition to the text body
- * inset and applies only to this text paragraph. That is the text body Inset and the RightMargin
- * attributes are additive with respect to the text position.
- *
- * @param value the right margin (in points) of the paragraph
- */
@Override
- public void setRightMargin(double value){
+ public void setRightMargin(Double rightMargin){
+ if (rightMargin == null && !_p.isSetPPr()) return;
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
- if(value == -1) {
+ if(rightMargin == -1) {
if(pr.isSetMarR()) pr.unsetMarR();
} else {
- pr.setMarR(Units.toEMU(value));
+ pr.setMarR(Units.toEMU(rightMargin));
}
}
/**
*
- * @return the right margin of the paragraph
+ * @return the right margin of the paragraph, null if unset
*/
@Override
- public double getRightMargin(){
+ public Double getRightMargin(){
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
public boolean fetch(CTTextParagraphProperties props){
if(props.isSetMarR()){
@@ -443,14 +425,11 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { };
fetchParagraphProperty(fetcher);
// if the marL attribute is omitted, then a value of 347663 is implied
- return fetcher.getValue() == null ? 0 : fetcher.getValue();
+ return fetcher.getValue();
}
- /**
- *
- * @return the default size for a tab character within this paragraph in points
- */
- public double getDefaultTabSize(){
+ @Override
+ public Double getDefaultTabSize(){
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
public boolean fetch(CTTextParagraphProperties props){
if(props.isSetDefTabSz()){
@@ -462,7 +441,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { }
};
fetchParagraphProperty(fetcher);
- return fetcher.getValue() == null ? 0 : fetcher.getValue();
+ return fetcher.getValue();
}
public double getTabStop(final int idx){
@@ -491,16 +470,25 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { }
@Override
- public void setLineSpacing(double linespacing){
+ public void setLineSpacing(Double lineSpacing){
+ if (lineSpacing == null && !_p.isSetPPr()) return;
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
- CTTextSpacing spc = CTTextSpacing.Factory.newInstance();
- if(linespacing >= 0) spc.addNewSpcPct().setVal((int)(linespacing*1000));
- else spc.addNewSpcPts().setVal((int)(-linespacing*100));
- pr.setLnSpc(spc);
+ if(lineSpacing == null) {
+ if (pr.isSetLnSpc()) pr.unsetLnSpc();
+ } else {
+ CTTextSpacing spc = (pr.isSetLnSpc()) ? pr.getLnSpc() : pr.addNewLnSpc();
+ if (lineSpacing >= 0) {
+ (spc.isSetSpcPct() ? spc.getSpcPct() : spc.addNewSpcPct()).setVal((int)(lineSpacing*1000));
+ if (spc.isSetSpcPts()) spc.unsetSpcPts();
+ } else {
+ (spc.isSetSpcPts() ? spc.getSpcPts() : spc.addNewSpcPts()).setVal((int)(-lineSpacing*100));
+ if (spc.isSetSpcPct()) spc.unsetSpcPct();
+ }
+ }
}
@Override
- public double getLineSpacing(){
+ public Double getLineSpacing(){
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
public boolean fetch(CTTextParagraphProperties props){
if(props.isSetLnSpc()){
@@ -515,8 +503,8 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { };
fetchParagraphProperty(fetcher);
- double lnSpc = fetcher.getValue() == null ? 100 : fetcher.getValue();
- if(lnSpc > 0) {
+ Double lnSpc = fetcher.getValue();
+ if (lnSpc != null && lnSpc > 0) {
// check if the percentage value is scaled
CTTextNormalAutofit normAutofit = getParentShape().getTextBodyPr().getNormAutofit();
if(normAutofit != null) {
@@ -528,26 +516,9 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { return lnSpc;
}
- /**
- * Set the amount of vertical white space that will be present before the paragraph.
- * This space is specified in either percentage or points:
- * <p>
- * If spaceBefore >= 0, then space is a percentage of normal line height.
- * If spaceBefore < 0, the absolute value of linespacing is the spacing in points
- * </p>
- * Examples:
- * <pre><code>
- * // The paragraph will be formatted to have a spacing before the paragraph text.
- * // The spacing will be 200% of the size of the largest text on each line
- * paragraph.setSpaceBefore(200);
- *
- * // The spacing will be a size of 48 points
- * paragraph.setSpaceBefore(-48.0);
- * </code></pre>
- *
- * @param spaceBefore the vertical white space before the paragraph.
- */
- public void setSpaceBefore(double spaceBefore){
+ @Override
+ public void setSpaceBefore(Double spaceBefore){
+ if (spaceBefore == null && !_p.isSetPPr()) return;
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
CTTextSpacing spc = CTTextSpacing.Factory.newInstance();
if(spaceBefore >= 0) spc.addNewSpcPct().setVal((int)(spaceBefore*1000));
@@ -555,17 +526,8 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { pr.setSpcBef(spc);
}
- /**
- * The amount of vertical white space before the paragraph
- * This may be specified in two different ways, percentage spacing and font point spacing:
- * <p>
- * If spaceBefore >= 0, then space is a percentage of normal line height.
- * If spaceBefore < 0, the absolute value of linespacing is the spacing in points
- * </p>
- *
- * @return the vertical white space before the paragraph
- */
- public double getSpaceBefore(){
+ @Override
+ public Double getSpaceBefore(){
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
public boolean fetch(CTTextParagraphProperties props){
if(props.isSetSpcBef()){
@@ -580,30 +542,11 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { };
fetchParagraphProperty(fetcher);
- double spcBef = fetcher.getValue() == null ? 0 : fetcher.getValue();
- return spcBef;
+ return fetcher.getValue();
}
- /**
- * Set the amount of vertical white space that will be present after the paragraph.
- * This space is specified in either percentage or points:
- * <p>
- * If spaceAfter >= 0, then space is a percentage of normal line height.
- * If spaceAfter < 0, the absolute value of linespacing is the spacing in points
- * </p>
- * Examples:
- * <pre><code>
- * // The paragraph will be formatted to have a spacing after the paragraph text.
- * // The spacing will be 200% of the size of the largest text on each line
- * paragraph.setSpaceAfter(200);
- *
- * // The spacing will be a size of 48 points
- * paragraph.setSpaceAfter(-48.0);
- * </code></pre>
- *
- * @param spaceAfter the vertical white space after the paragraph.
- */
- public void setSpaceAfter(double spaceAfter){
+ @Override
+ public void setSpaceAfter(Double spaceAfter){
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
CTTextSpacing spc = CTTextSpacing.Factory.newInstance();
if(spaceAfter >= 0) spc.addNewSpcPct().setVal((int)(spaceAfter*1000));
@@ -611,17 +554,8 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { pr.setSpcAft(spc);
}
- /**
- * The amount of vertical white space after the paragraph
- * This may be specified in two different ways, percentage spacing and font point spacing:
- * <p>
- * If spaceBefore >= 0, then space is a percentage of normal line height.
- * If spaceBefore < 0, the absolute value of linespacing is the spacing in points
- * </p>
- *
- * @return the vertical white space after the paragraph
- */
- public double getSpaceAfter(){
+ @Override
+ public Double getSpaceAfter(){
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
public boolean fetch(CTTextParagraphProperties props){
if(props.isSetSpcAft()){
@@ -635,7 +569,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { }
};
fetchParagraphProperty(fetcher);
- return fetcher.getValue() == null ? 0 : fetcher.getValue();
+ return fetcher.getValue();
}
/**
@@ -647,7 +581,6 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { */
public void setLevel(int level){
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
-
pr.setLvl(level);
}
@@ -657,10 +590,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { */
public int getLevel(){
CTTextParagraphProperties pr = _p.getPPr();
- if(pr == null) return 0;
-
- return pr.getLvl();
-
+ return (pr == null || !pr.isSetLvl()) ? 0 : pr.getLvl();
}
/**
@@ -721,53 +651,70 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { }
- CTTextParagraphProperties getDefaultMasterStyle(){
+ /* package */ CTTextParagraphProperties getDefaultMasterStyle(){
CTPlaceholder ph = _shape.getCTPlaceholder();
- String defaultStyleSelector;
- if(ph == null) defaultStyleSelector = "otherStyle"; // no placeholder means plain text box
- else {
- switch(ph.getType().intValue()){
- case STPlaceholderType.INT_TITLE:
- case STPlaceholderType.INT_CTR_TITLE:
- defaultStyleSelector = "titleStyle";
- break;
- case STPlaceholderType.INT_FTR:
- case STPlaceholderType.INT_SLD_NUM:
- case STPlaceholderType.INT_DT:
- defaultStyleSelector = "otherStyle";
- break;
- default:
- defaultStyleSelector = "bodyStyle";
- break;
- }
+ String defaultStyleSelector;
+ switch(ph == null ? -1 : ph.getType().intValue()) {
+ case STPlaceholderType.INT_TITLE:
+ case STPlaceholderType.INT_CTR_TITLE:
+ defaultStyleSelector = "titleStyle";
+ break;
+ case -1: // no placeholder means plain text box
+ case STPlaceholderType.INT_FTR:
+ case STPlaceholderType.INT_SLD_NUM:
+ case STPlaceholderType.INT_DT:
+ defaultStyleSelector = "otherStyle";
+ break;
+ default:
+ defaultStyleSelector = "bodyStyle";
+ break;
}
int level = getLevel();
// wind up and find the root master sheet which must be slide master
XSLFSheet masterSheet = _shape.getSheet();
- while (masterSheet.getMasterSheet() != null){
- masterSheet = (XSLFSheet)masterSheet.getMasterSheet();
+ for (XSLFSheet m = masterSheet; m != null; m = (XSLFSheet)m.getMasterSheet()) {
+ masterSheet = m;
}
- XmlObject[] o = masterSheet.getXmlObject().selectPath(
- "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " +
- "declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' " +
- ".//p:txStyles/p:" + defaultStyleSelector +"/a:lvl" +(level+1)+ "pPr");
- if (o.length == 1){
- return (CTTextParagraphProperties)o[0];
- } else {
- o = masterSheet.getXmlObject().selectPath(
- "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " +
- "declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' " +
- ".//p:notesStyle/a:lvl" +(level+1)+ "pPr");
-
- if (o.length == 1){
+ String nsDecl =
+ "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " +
+ "declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' ";
+ String xpaths[] = {
+ nsDecl+".//p:txStyles/p:" + defaultStyleSelector +"/a:lvl" +(level+1)+ "pPr",
+ nsDecl+".//p:notesStyle/a:lvl" +(level+1)+ "pPr"
+ };
+ XmlObject xo = masterSheet.getXmlObject();
+ for (String xpath : xpaths) {
+ XmlObject[] o = xo.selectPath(xpath);
+ if (o.length == 1) {
return (CTTextParagraphProperties)o[0];
}
-
- throw new IllegalArgumentException("Failed to fetch default style for " +
- defaultStyleSelector + " and level=" + level);
}
+
+// for (CTTextBody txBody : (CTTextBody[])xo.selectPath(nsDecl+".//p:txBody")) {
+// CTTextParagraphProperties defaultPr = null, lastPr = null;
+// boolean hasLvl = false;
+// for (CTTextParagraph p : txBody.getPArray()) {
+// CTTextParagraphProperties pr = p.getPPr();
+// if (pr.isSetLvl()) {
+// hasLvl |= true;
+// lastPr = pr;
+// if (pr.getLvl() == level) return pr;
+// } else {
+// defaultPr = pr;
+// }
+// }
+// if (!hasLvl) continue;
+// if (level == 0 && defaultPr != null) return defaultPr;
+// if (lastPr != null) return lastPr;
+// break;
+// }
+//
+// String err = "Failed to fetch default style for " + defaultStyleSelector + " and level=" + level;
+// throw new IllegalArgumentException(err);
+
+ return null;
}
private <T> boolean fetchParagraphProperty(ParagraphPropertyFetcher<T> visitor){
@@ -860,9 +807,9 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { }
@Override
- public double getDefaultFontSize() {
+ public Double getDefaultFontSize() {
CTTextCharacterProperties endPr = _p.getEndParaRPr();
- return (endPr == null || !endPr.isSetSz()) ? 12 : (endPr.getSz() / 100);
+ return (endPr == null || !endPr.isSetSz()) ? 12 : (endPr.getSz() / 100.);
}
@Override
@@ -871,6 +818,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { }
public BulletStyle getBulletStyle() {
+ if (!isBullet()) return null;
return new BulletStyle(){
public String getBulletCharacter() {
return XSLFTextParagraph.this.getBulletCharacter();
@@ -880,7 +828,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> { return XSLFTextParagraph.this.getBulletFont();
}
- public double getBulletFontSize() {
+ public Double getBulletFontSize() {
return XSLFTextParagraph.this.getBulletFontSize();
}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java index 2b63a58099..d99df7e79a 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java @@ -17,26 +17,11 @@ package org.apache.poi.xslf.usermodel;
import java.awt.Color;
-import java.awt.font.FontRenderContext;
-import java.awt.font.TextAttribute;
-import java.awt.font.TextLayout;
-import java.text.AttributedString;
import org.apache.poi.sl.usermodel.TextRun;
import org.apache.poi.util.Beta;
import org.apache.poi.xslf.model.CharacterPropertyFetcher;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextNormalAutofit;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
-import org.openxmlformats.schemas.drawingml.x2006.main.STSchemeColorVal;
-import org.openxmlformats.schemas.drawingml.x2006.main.STTextStrikeType;
-import org.openxmlformats.schemas.drawingml.x2006.main.STTextUnderlineType;
+import org.openxmlformats.schemas.drawingml.x2006.main.*;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
/**
@@ -89,28 +74,6 @@ public class XSLFTextRun implements TextRun { return buf.toString();
}
- /**
- * Replace a tab with the effective number of white spaces.
- */
- private String tab2space(){
- AttributedString string = new AttributedString(" ");
- // user can pass an object to convert fonts via a rendering hint
- string.addAttribute(TextAttribute.FAMILY, getFontFamily());
-
- string.addAttribute(TextAttribute.SIZE, (float)getFontSize());
- TextLayout l = new TextLayout(string.getIterator(), new FontRenderContext(null, true, true));
- double wspace = l.getAdvance();
-
- double tabSz = _p.getDefaultTabSize();
-
- int numSpaces = (int)Math.ceil(tabSz / wspace);
- StringBuffer buf = new StringBuffer();
- for(int i = 0; i < numSpaces; i++) {
- buf.append(' ');
- }
- return buf.toString();
- }
-
public void setText(String text){
_r.setT(text);
}
@@ -175,9 +138,10 @@ public class XSLFTextRun implements TextRun { }
/**
- * @return font size in points or -1 if font size is not set.
+ * @return font size in points or null if font size is not set.
*/
- public double getFontSize(){
+ @Override
+ public Double getFontSize(){
double scale = 1;
CTTextNormalAutofit afit = getParentParagraph().getParentShape().getTextBodyPr().getNormAutofit();
if(afit != null) scale = (double)afit.getFontScale() / 100000;
@@ -192,7 +156,7 @@ public class XSLFTextRun implements TextRun { }
};
fetchCharacterProperty(fetcher);
- return fetcher.getValue() == null ? -1 : fetcher.getValue()*scale;
+ return fetcher.getValue() == null ? null : fetcher.getValue()*scale;
}
/**
@@ -514,7 +478,7 @@ public class XSLFTextRun implements TextRun { return new XSLFHyperlink(_r.getRPr().getHlinkClick(), this);
}
- private boolean fetchCharacterProperty(CharacterPropertyFetcher fetcher){
+ private boolean fetchCharacterProperty(CharacterPropertyFetcher<?> fetcher){
boolean ok = false;
if(_r.isSetRPr()) ok = fetcher.fetch(getRPr());
diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFAutoShape.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFAutoShape.java index 6fc5690cca..b3c44f84a7 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFAutoShape.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFAutoShape.java @@ -125,7 +125,7 @@ public class TestXSLFAutoShape { p.setIndent(2.0);
assertEquals(2.0, p.getIndent(), 0);
assertTrue(p.getXmlObject().getPPr().isSetIndent());
- p.setIndent(-1);
+ p.setIndent(-1d);
assertEquals(0.0, p.getIndent(), 0);
assertFalse(p.getXmlObject().getPPr().isSetIndent());
p.setIndent(10.0);
@@ -149,44 +149,44 @@ public class TestXSLFAutoShape { assertFalse(p.getXmlObject().getPPr().isSetSpcAft());
- p.setSpaceAfter(200);
+ p.setSpaceAfter(200d);
assertEquals(200000, p.getXmlObject().getPPr().getSpcAft().getSpcPct().getVal());
assertFalse(p.getXmlObject().getPPr().getSpcAft().isSetSpcPts());
- p.setSpaceAfter(100);
+ p.setSpaceAfter(100d);
assertEquals(100000, p.getXmlObject().getPPr().getSpcAft().getSpcPct().getVal());
assertFalse(p.getXmlObject().getPPr().getSpcAft().isSetSpcPts());
- p.setSpaceAfter(-20);
+ p.setSpaceAfter(-20d);
assertEquals(2000, p.getXmlObject().getPPr().getSpcAft().getSpcPts().getVal());
assertFalse(p.getXmlObject().getPPr().getSpcAft().isSetSpcPct());
- p.setSpaceAfter(-10);
+ p.setSpaceAfter(-10d);
assertEquals(1000, p.getXmlObject().getPPr().getSpcAft().getSpcPts().getVal());
assertFalse(p.getXmlObject().getPPr().getSpcAft().isSetSpcPct());
assertFalse(p.getXmlObject().getPPr().isSetSpcBef());
- p.setSpaceBefore(200);
+ p.setSpaceBefore(200d);
assertEquals(200000, p.getXmlObject().getPPr().getSpcBef().getSpcPct().getVal());
assertFalse(p.getXmlObject().getPPr().getSpcBef().isSetSpcPts());
- p.setSpaceBefore(100);
+ p.setSpaceBefore(100d);
assertEquals(100000, p.getXmlObject().getPPr().getSpcBef().getSpcPct().getVal());
assertFalse(p.getXmlObject().getPPr().getSpcBef().isSetSpcPts());
- p.setSpaceBefore(-20);
+ p.setSpaceBefore(-20d);
assertEquals(2000, p.getXmlObject().getPPr().getSpcBef().getSpcPts().getVal());
assertFalse(p.getXmlObject().getPPr().getSpcBef().isSetSpcPct());
- p.setSpaceBefore(-10);
+ p.setSpaceBefore(-10d);
assertEquals(1000, p.getXmlObject().getPPr().getSpcBef().getSpcPts().getVal());
assertFalse(p.getXmlObject().getPPr().getSpcBef().isSetSpcPct());
assertFalse(p.getXmlObject().getPPr().isSetLnSpc());
- p.setLineSpacing(200);
+ p.setLineSpacing(200d);
assertEquals(200000, p.getXmlObject().getPPr().getLnSpc().getSpcPct().getVal());
assertFalse(p.getXmlObject().getPPr().getLnSpc().isSetSpcPts());
- p.setLineSpacing(100);
+ p.setLineSpacing(100d);
assertEquals(100000, p.getXmlObject().getPPr().getLnSpc().getSpcPct().getVal());
assertFalse(p.getXmlObject().getPPr().getLnSpc().isSetSpcPts());
- p.setLineSpacing(-20);
+ p.setLineSpacing(-20d);
assertEquals(2000, p.getXmlObject().getPPr().getLnSpc().getSpcPts().getVal());
assertFalse(p.getXmlObject().getPPr().getLnSpc().isSetSpcPct());
- p.setLineSpacing(-10);
+ p.setLineSpacing(-10d);
assertEquals(1000, p.getXmlObject().getPPr().getLnSpc().getSpcPts().getVal());
assertFalse(p.getXmlObject().getPPr().getLnSpc().isSetSpcPct());
diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextParagraph.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextParagraph.java index 0998ee8e72..37a01a73ae 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextParagraph.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextParagraph.java @@ -92,7 +92,7 @@ public class TestXSLFTextParagraph { assertEquals(expectedWidth, dtp.getWrappingWidth(true, null), 0);
assertEquals(expectedWidth, dtp.getWrappingWidth(false, null), 0);
- p.setLeftMargin(36); // 0.5"
+ p.setLeftMargin(36d); // 0.5"
leftMargin = p.getLeftMargin();
assertEquals(36.0, leftMargin, 0);
expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin;
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/FontAlignmentProp.java b/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/FontAlignmentProp.java index c9c911ccf9..904feeedf8 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/FontAlignmentProp.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/FontAlignmentProp.java @@ -21,12 +21,13 @@ package org.apache.poi.hslf.model.textproperties; * Definition for the font alignment property. */ public class FontAlignmentProp extends TextProp { + public static final String NAME = "fontAlign"; public static final int BASELINE = 0; public static final int TOP = 1; public static final int CENTER = 2; public static final int BOTTOM = 3; public FontAlignmentProp() { - super(2, 0x10000, "fontAlign"); + super(2, 0x10000, NAME); } }
\ No newline at end of file diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/TextPropCollection.java b/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/TextPropCollection.java index 17d0c1d2c5..84cfe9940f 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/TextPropCollection.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/TextPropCollection.java @@ -31,47 +31,10 @@ import org.apache.poi.util.LittleEndian; * properties, and the indent level if required. */ public class TextPropCollection { - /* - private static TextProp paragraphSpecialPropTypes[] = { - new ParagraphFlagsTextProp(), - new TextProp(2, 0x80, "bullet.char"), - new TextProp(2, 0x10, "bullet.font"), - new TextProp(2, 0x40, "bullet.size"), - new TextProp(4, 0x20, "bullet.color"), - new TextProp(2, 0xD00, "alignment"), - new TextProp(2, 0x1000, "linespacing"), - new TextProp(2, 0x2000, "spacebefore"), - new TextProp(2, 0x4000, "spaceafter"), - new TextProp(2, 0x8000, "text.offset"), - new TextProp(2, 0x10000, "bullet.offset"), - new TextProp(2, 0x20000, "defaulttab"), - new TextProp(2, 0x40000, "para_unknown_2"), - new TextProp(2, 0x80000, "para_unknown_3"), - new TextProp(2, 0x100000, "para_unknown_4"), - new TextProp(2, 0x200000, "para_unknown_5") - }; - - private static TextProp characterSpecialPropTypes[] = { - new CharFlagsTextProp(), - new TextProp(2, 0x10000, "font.index"), - new TextProp(2, 0x20000, "char_unknown_1"), - new TextProp(4, 0x40000, "char_unknown_2"), - new TextProp(2, 0x80000, "font.size"), - new TextProp(2, 0x100000, "char_unknown_3"), - new TextProp(4, 0x200000, "font.color"), - new TextProp(2, 0x800000, "char_unknown_4") - }; -*/ - - /** All the different kinds of paragraph properties we might handle */ public static final TextProp[] paragraphTextPropTypes = { // TextProp order is according to 2.9.20 TextPFException, // bitmask order can be different -// new TextProp(0, 0x1, "hasBullet"), -// new TextProp(0, 0x2, "hasBulletFont"), -// new TextProp(0, 0x4, "hasBulletColor"), -// new TextProp(0, 0x8, "hasBulletSize"), new ParagraphFlagsTextProp(), new TextProp(2, 0x80, "bullet.char"), new TextProp(2, 0x10, "bullet.font"), @@ -95,24 +58,9 @@ public class TextPropCollection { new TextProp(0, 0x2000000, "hasBulletScheme"), // TODO: check size // 0xFC000000 MUST be zero and MUST be ignored }; + /** All the different kinds of character properties we might handle */ public static final TextProp[] characterTextPropTypes = new TextProp[] { -// new TextProp(0, 0x1, "bold"), -// new TextProp(0, 0x2, "italic"), -// new TextProp(0, 0x4, "underline"), -// new TextProp(0, 0x8, "unused1"), -// new TextProp(0, 0x10, "shadow"), -// new TextProp(0, 0x20, "fehint"), -// new TextProp(0, 0x40, "unused2"), -// new TextProp(0, 0x80, "kumi"), -// new TextProp(0, 0x100, "strikethrough"), -// new TextProp(0, 0x200, "emboss"), -// new TextProp(0, 0x400, "nibble1"), -// new TextProp(0, 0x800, "nibble2"), -// new TextProp(0, 0x1000, "nibble3"), -// new TextProp(0, 0x2000, "nibble4"), -// new TextProp(0, 0x4000, "unused4"), -// new TextProp(0, 0x8000, "unused5"), new TextProp(0, 0x100000, "pp10ext"), new TextProp(0, 0x1000000, "newAsian.font.index"), // A bit that specifies whether the newEAFontRef field of the TextCFException10 structure that contains this CFMasks exists. new TextProp(0, 0x2000000, "cs.font.index"), // A bit that specifies whether the csFontRef field of the TextCFException10 structure that contains this CFMasks exists. @@ -166,6 +114,19 @@ public class TextPropCollection { } return null; } + + public TextProp removeByName(String name) { + Iterator<TextProp> iter = textPropList.iterator(); + TextProp tp = null; + while (iter.hasNext()) { + tp = iter.next(); + if (tp.getName().equals(name)){ + iter.remove(); + break; + } + } + return tp; + } /** Add the TextProp with this name to the list */ public TextProp addWithName(String name) { @@ -192,6 +153,10 @@ public class TextPropCollection { return textProp; } + public TextPropType getTextPropType() { + return textPropType; + } + private TextProp[] getPotentialProperties() { return (textPropType == TextPropType.paragraph) ? paragraphTextPropTypes : characterTextPropTypes; } diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/FontCollection.java b/src/scratchpad/src/org/apache/poi/hslf/record/FontCollection.java index 0f7f05148b..b90c698dd6 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/record/FontCollection.java +++ b/src/scratchpad/src/org/apache/poi/hslf/record/FontCollection.java @@ -17,6 +17,7 @@ package org.apache.poi.hslf.record; +import org.apache.poi.hslf.model.PPFont; import org.apache.poi.util.POILogger; import java.io.*; @@ -75,9 +76,9 @@ public final class FontCollection extends RecordContainer { */ public int addFont(String name) { int idx = getFontIndex(name); - if(idx != -1) return idx; + if (idx != -1) return idx; - return addFont(name, 0, 0, 4, 34); + return addFont(name, 0, 0, 4, PPFont.FF_SWISS | PPFont.VARIABLE_PITCH); } public int addFont(String name, int charset, int flags, int type, int pitch) { diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideMaster.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideMaster.java index a6dfedf073..346dab7450 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideMaster.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideMaster.java @@ -76,45 +76,31 @@ public final class HSLFSlideMaster extends HSLFMasterSheet { * This is the "workhorse" which returns the default style attrubutes. */ public TextProp getStyleAttribute(int txtype, int level, String name, boolean isCharacter) { - + if (_txmaster.length <= txtype) return null; + TxMasterStyleAtom t = _txmaster[txtype]; + List<TextPropCollection> styles = isCharacter ? t.getCharacterStyles() : t.getParagraphStyles(); + TextProp prop = null; - for (int i = level; i >= 0; i--) { - List<TextPropCollection> styles = - isCharacter ? _txmaster[txtype].getCharacterStyles() : _txmaster[txtype].getParagraphStyles(); - if (i < styles.size()) prop = styles.get(i).findByName(name); - if (prop != null) break; + for (int i = Math.min(level, styles.size()-1); prop == null && i >= 0; i--) { + prop = styles.get(i).findByName(name); } - if (prop == null) { - if(isCharacter) { - switch (txtype) { - case TextHeaderAtom.CENTRE_BODY_TYPE: - case TextHeaderAtom.HALF_BODY_TYPE: - case TextHeaderAtom.QUARTER_BODY_TYPE: - txtype = TextHeaderAtom.BODY_TYPE; - break; - case TextHeaderAtom.CENTER_TITLE_TYPE: - txtype = TextHeaderAtom.TITLE_TYPE; - break; - default: - return null; - } - } else { - switch (txtype) { - case TextHeaderAtom.CENTRE_BODY_TYPE: - case TextHeaderAtom.HALF_BODY_TYPE: - case TextHeaderAtom.QUARTER_BODY_TYPE: - txtype = TextHeaderAtom.BODY_TYPE; - break; - case TextHeaderAtom.CENTER_TITLE_TYPE: - txtype = TextHeaderAtom.TITLE_TYPE; - break; - default: - return null; - } - } - prop = getStyleAttribute(txtype, level, name, isCharacter); + + if (prop != null) return prop; + + switch (txtype) { + case TextHeaderAtom.CENTRE_BODY_TYPE: + case TextHeaderAtom.HALF_BODY_TYPE: + case TextHeaderAtom.QUARTER_BODY_TYPE: + txtype = TextHeaderAtom.BODY_TYPE; + break; + case TextHeaderAtom.CENTER_TITLE_TYPE: + txtype = TextHeaderAtom.TITLE_TYPE; + break; + default: + return null; } - return prop; + + return getStyleAttribute(txtype, level, name, isCharacter); } /** diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java index c0d381e912..ee99745b5a 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java @@ -34,7 +34,7 @@ import org.apache.poi.util.*; * This class represents a run of text in a powerpoint document. That
* run could be text on a sheet, or text in a note.
* It is only a very basic class for now
- *
+ *
* @author Nick Burch
*/
@@ -44,50 +44,49 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> { /**
* How to align the text
*/
- /* package */ static final int AlignLeft = 0;
- /* package */ static final int AlignCenter = 1;
- /* package */ static final int AlignRight = 2;
- /* package */ static final int AlignJustify = 3;
-
+ /* package */static final int AlignLeft = 0;
+ /* package */static final int AlignCenter = 1;
+ /* package */static final int AlignRight = 2;
+ /* package */static final int AlignJustify = 3;
// Note: These fields are protected to help with unit testing
- // Other classes shouldn't really go playing with them!
- private final TextHeaderAtom _headerAtom;
- private TextBytesAtom _byteAtom;
- private TextCharsAtom _charAtom;
- private final TextPropCollection _paragraphStyle = new TextPropCollection(1, TextPropType.paragraph);
+ // Other classes shouldn't really go playing with them!
+ private final TextHeaderAtom _headerAtom;
+ private TextBytesAtom _byteAtom;
+ private TextCharsAtom _charAtom;
+ private final TextPropCollection _paragraphStyle = new TextPropCollection(1, TextPropType.paragraph);
protected TextRulerAtom _ruler;
- protected List<HSLFTextRun> _runs = new ArrayList<HSLFTextRun>();
- protected HSLFTextShape _parentShape;
+ protected final List<HSLFTextRun> _runs = new ArrayList<HSLFTextRun>();
+ protected HSLFTextShape _parentShape;
private HSLFSheet _sheet;
private int shapeId;
- // private StyleTextPropAtom styleTextPropAtom;
- private StyleTextProp9Atom styleTextProp9Atom;
+ // private StyleTextPropAtom styleTextPropAtom;
+ private StyleTextProp9Atom styleTextProp9Atom;
- /**
+ /**
* Constructs a Text Run from a Unicode text block.
* Either a {@link TextCharsAtom} or a {@link TextBytesAtom} needs to be provided.
- *
+ *
* @param tha the TextHeaderAtom that defines what's what
* @param tba the TextBytesAtom containing the text or null if {@link TextCharsAtom} is provided
* @param tca the TextCharsAtom containing the text or null if {@link TextBytesAtom} is provided
- */
+ */
/* package */ HSLFTextParagraph(
TextHeaderAtom tha,
TextBytesAtom tba,
TextCharsAtom tca
) {
- if (tha == null) {
- throw new IllegalArgumentException("TextHeaderAtom must be set.");
- }
- _headerAtom = tha;
+ if (tha == null) {
+ throw new IllegalArgumentException("TextHeaderAtom must be set.");
+ }
+ _headerAtom = tha;
_byteAtom = tba;
_charAtom = tca;
- }
+ }
- /* package */ HSLFTextParagraph(HSLFTextParagraph other) {
+ /* package */HSLFTextParagraph(HSLFTextParagraph other) {
_headerAtom = other._headerAtom;
_byteAtom = other._byteAtom;
_charAtom = other._charAtom;
@@ -98,67 +97,67 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> { _paragraphStyle.copy(other._paragraphStyle);
}
- public void addTextRun(HSLFTextRun run) {
- _runs.add(run);
- }
+ public void addTextRun(HSLFTextRun run) {
+ _runs.add(run);
+ }
- /**
+ /**
* Fetch the rich text runs (runs of text with the same styling) that
* are contained within this block of text
- */
- public List<HSLFTextRun> getTextRuns() {
- return _runs;
- }
+ */
+ public List<HSLFTextRun> getTextRuns() {
+ return _runs;
+ }
- public TextPropCollection getParagraphStyle() {
- return _paragraphStyle;
- }
+ public TextPropCollection getParagraphStyle() {
+ return _paragraphStyle;
+ }
- public void setParagraphStyle(TextPropCollection paragraphStyle) {
- _paragraphStyle.copy(paragraphStyle);
- }
+ public void setParagraphStyle(TextPropCollection paragraphStyle) {
+ _paragraphStyle.copy(paragraphStyle);
+ }
- /**
+ /**
* Supply the Sheet we belong to, which might have an assigned SlideShow
* Also passes it on to our child RichTextRuns
*/
- public void supplySheet(HSLFSheet sheet){
+ public void supplySheet(HSLFSheet sheet) {
this._sheet = sheet;
if (_runs == null) return;
- for(HSLFTextRun rt : _runs) {
+ for (HSLFTextRun rt : _runs) {
rt.updateSheet();
}
- }
+ }
- public HSLFSheet getSheet(){
+ public HSLFSheet getSheet() {
return this._sheet;
}
/**
- * @return Shape ID
+ * @return Shape ID
*/
- protected int getShapeId(){
+ protected int getShapeId() {
return shapeId;
}
/**
- * @param id Shape ID
+ * @param id Shape ID
*/
- protected void setShapeId(int id){
+ protected void setShapeId(int id) {
shapeId = id;
}
/**
- * @return 0-based index of the text run in the SLWT container
+ * @return 0-based index of the text run in the SLWT container
*/
- protected int getIndex(){
+ protected int getIndex() {
return (_headerAtom != null) ? _headerAtom.getIndex() : -1;
}
/**
* Sets the index of the paragraph in the SLWT container
- *
+ *
* @param index
*/
protected void setIndex(int index) {
@@ -166,10 +165,10 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> { }
/**
- * Returns the type of the text, from the TextHeaderAtom.
- * Possible values can be seen from TextHeaderAtom
- * @see org.apache.poi.hslf.record.TextHeaderAtom
- */
+ * Returns the type of the text, from the TextHeaderAtom.
+ * Possible values can be seen from TextHeaderAtom
+ * @see org.apache.poi.hslf.record.TextHeaderAtom
+ */
public int getRunType() {
return (_headerAtom != null) ? _headerAtom.getTextType() : -1;
}
@@ -177,8 +176,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> { public void setRunType(int runType) {
if (_headerAtom != null) _headerAtom.setTextType(runType);
}
-
-
+
/**
* Is this Text Run one from a {@link PPDrawing}, or is it
* one from the {@link SlideListWithText}?
@@ -187,12 +185,12 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> { return (getIndex() == -1);
}
- public TextRulerAtom getTextRuler(){
+ public TextRulerAtom getTextRuler() {
return _ruler;
}
- public TextRulerAtom createTextRuler(){
+ public TextRulerAtom createTextRuler() {
_ruler = getTextRuler();
if (_ruler == null) {
_ruler = TextRulerAtom.getParagraphInstance();
@@ -207,19 +205,19 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> { /**
* Returns records that make up the list of text paragraphs
* (there can be misc InteractiveInfo, TxInteractiveInfo and other records)
- *
+ *
* @return text run records
*/
- public Record[] getRecords(){
+ public Record[] getRecords() {
Record r[] = _headerAtom.getParentRecord().getChildRecords();
- return getRecords(r, new int[]{0}, _headerAtom);
+ return getRecords(r, new int[] { 0 }, _headerAtom);
}
private static Record[] getRecords(Record[] records, int[] startIdx, TextHeaderAtom headerAtom) {
if (records == null) {
throw new NullPointerException("records need to be set.");
}
-
+
for (; startIdx[0] < records.length; startIdx[0]++) {
Record r = records[startIdx[0]];
if (r instanceof TextHeaderAtom && (headerAtom == null || r == headerAtom)) break;
@@ -229,135 +227,113 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> { logger.log(POILogger.INFO, "header atom wasn't found - container might contain only an OutlineTextRefAtom");
return new Record[0];
}
-
+
int length;
- for (length = 1; startIdx[0]+length < records.length; length++) {
+ for (length = 1; startIdx[0] + length < records.length; length++) {
if (records[startIdx[0]+length] instanceof TextHeaderAtom) break;
}
-
+
Record result[] = new Record[length];
System.arraycopy(records, startIdx[0], result, 0, length);
startIdx[0] += length;
-
+
return result;
}
-
- /** Numbered List info */
- public void setStyleTextProp9Atom(final StyleTextProp9Atom styleTextProp9Atom) {
- this.styleTextProp9Atom = styleTextProp9Atom;
- }
/** Numbered List info */
- public StyleTextProp9Atom getStyleTextProp9Atom() {
- return this.styleTextProp9Atom;
- }
-
- /**
- * Fetch the value of the given Paragraph related TextProp.
- * Returns -1 if that TextProp isn't present.
- * If the TextProp isn't present, the value from the appropriate
- * Master Sheet will apply.
- */
- private int getParaTextPropVal(String propName) {
- TextProp prop = _paragraphStyle.findByName(propName);
- BitMaskTextProp maskProp = (BitMaskTextProp)_paragraphStyle.findByName(ParagraphFlagsTextProp.NAME);
- boolean hardAttribute = (maskProp != null && maskProp.getValue() == 0);
- if (prop == null && !hardAttribute){
- HSLFSheet sheet = getSheet();
- int txtype = getRunType();
- HSLFMasterSheet master = sheet.getMasterSheet();
- if (master != null)
- prop = master.getStyleAttribute(txtype, getIndentLevel(), propName, false);
- }
-
- return prop == null ? -1 : prop.getValue();
+ public void setStyleTextProp9Atom(final StyleTextProp9Atom styleTextProp9Atom) {
+ this.styleTextProp9Atom = styleTextProp9Atom;
}
- /**
- * Sets the value of the given Character TextProp, add if required
- * @param propName The name of the Character TextProp
- * @param val The value to set for the TextProp
- */
- public void setParaTextPropVal(String propName, int val) {
- // Ensure we have the StyleTextProp atom we're going to need
- assert(_paragraphStyle!=null);
- TextProp tp = fetchOrAddTextProp(_paragraphStyle, propName);
- tp.setValue(val);
+ /** Numbered List info */
+ public StyleTextProp9Atom getStyleTextProp9Atom() {
+ return this.styleTextProp9Atom;
}
-
+
@Override
public Iterator<HSLFTextRun> iterator() {
return _runs.iterator();
}
@Override
- public double getLeftMargin() {
- int val = getParaTextPropVal("text.offset");
- return val*HSLFShape.POINT_DPI/((double)HSLFShape.MASTER_DPI);
+ public Double getLeftMargin() {
+ TextProp val = getPropVal(_paragraphStyle, "text.offset", this);
+ return (val == null) ? null : Units.masterToPoints(val.getValue());
}
@Override
- public void setLeftMargin(double leftMargin) {
- int val = (int)(leftMargin*HSLFShape.MASTER_DPI/HSLFShape.POINT_DPI);
- setParaTextPropVal("text.offset", val);
+ public void setLeftMargin(Double leftMargin) {
+ Integer val = (leftMargin == null) ? null : Units.pointsToMaster(leftMargin);
+ setPropVal(_paragraphStyle, "text.offset", val);
}
@Override
- public double getRightMargin() {
+ public Double getRightMargin() {
// TODO: find out, how to determine this value
- return 0;
+ return null;
}
@Override
- public void setRightMargin(double rightMargin) {
+ public void setRightMargin(Double rightMargin) {
// TODO: find out, how to set this value
}
@Override
- public double getIndent() {
- int val = getParaTextPropVal("bullet.offset");
- return val*HSLFShape.POINT_DPI/((double)HSLFShape.MASTER_DPI);
+ public Double getIndent() {
+ TextProp val = getPropVal(_paragraphStyle, "bullet.offset", this);
+ return (val == null) ? null : Units.masterToPoints(val.getValue());
}
@Override
- public void setIndent(double intent) {
- int val = (int)(intent*HSLFShape.MASTER_DPI/HSLFShape.POINT_DPI);
- setParaTextPropVal("bullet.offset", val);
+ public void setIndent(Double indent) {
+ Integer val = (indent == null) ? null : Units.pointsToMaster(indent);
+ setPropVal(_paragraphStyle, "bullet.offset", val);
}
@Override
public String getDefaultFontFamily() {
- return (_runs.isEmpty() ? "Arial" : _runs.get(0).getFontFamily());
+ String typeface = null;
+ if (!_runs.isEmpty()) {
+ typeface = _runs.get(0).getFontFamily();
+ }
+ return (typeface != null) ? typeface : "Arial";
}
@Override
- public double getDefaultFontSize() {
- return (_runs.isEmpty() ? 12 : _runs.get(0).getFontSize());
+ public Double getDefaultFontSize() {
+ Double d = null;
+ if (!_runs.isEmpty()) {
+ d = _runs.get(0).getFontSize();
+ }
+
+ return (d != null) ? d : 12d;
}
/**
* Sets the type of horizontal alignment for the paragraph.
- *
+ *
* @param align - the type of alignment
*/
public void setAlignment(org.apache.poi.sl.usermodel.TextParagraph.TextAlign align) {
- int alignInt;
- switch (align) {
- default:
- case LEFT: alignInt = TextAlignmentProp.LEFT; break;
- case CENTER: alignInt = TextAlignmentProp.CENTER; break;
- case RIGHT: alignInt = TextAlignmentProp.RIGHT; break;
- case DIST: alignInt = TextAlignmentProp.DISTRIBUTED; break;
- case JUSTIFY: alignInt = TextAlignmentProp.JUSTIFY; break;
- case JUSTIFY_LOW: alignInt = TextAlignmentProp.JUSTIFYLOW; break;
- case THAI_DIST: alignInt = TextAlignmentProp.THAIDISTRIBUTED; break;
+ Integer alignInt = null;
+ if (align != null) switch (align) {
+ default:
+ case LEFT: alignInt = TextAlignmentProp.LEFT;break;
+ case CENTER: alignInt = TextAlignmentProp.CENTER; break;
+ case RIGHT: alignInt = TextAlignmentProp.RIGHT; break;
+ case DIST: alignInt = TextAlignmentProp.DISTRIBUTED; break;
+ case JUSTIFY: alignInt = TextAlignmentProp.JUSTIFY; break;
+ case JUSTIFY_LOW: alignInt = TextAlignmentProp.JUSTIFYLOW; break;
+ case THAI_DIST: alignInt = TextAlignmentProp.THAIDISTRIBUTED; break;
}
- setParaTextPropVal("alignment", alignInt);
+ setPropVal(_paragraphStyle, "alignment", alignInt);
}
@Override
public org.apache.poi.sl.usermodel.TextParagraph.TextAlign getTextAlign() {
- switch (getParaTextPropVal("alignment")) {
+ TextProp tp = getPropVal(_paragraphStyle, "alignment", this);
+ if (tp == null) return null;
+ switch (tp.getValue()) {
default:
case TextAlignmentProp.LEFT: return TextAlign.LEFT;
case TextAlignmentProp.CENTER: return TextAlign.CENTER;
@@ -371,34 +347,33 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> { @Override
public FontAlign getFontAlign() {
- switch(getParaTextPropVal("fontAlign")) {
- default:
- case -1: return FontAlign.AUTO;
+ TextProp tp = getPropVal(_paragraphStyle, FontAlignmentProp.NAME, this);
+ if (tp == null) return null;
+
+ switch (tp.getValue()) {
case FontAlignmentProp.BASELINE: return FontAlign.BASELINE;
case FontAlignmentProp.TOP: return FontAlign.TOP;
case FontAlignmentProp.CENTER: return FontAlign.CENTER;
case FontAlignmentProp.BOTTOM: return FontAlign.BOTTOM;
+ default: return FontAlign.AUTO;
}
}
@Override
public BulletStyle getBulletStyle() {
- if (getBulletChar() == 0) return null;
+ if (!isBullet()) return null;
return new BulletStyle() {
public String getBulletCharacter() {
- char chr = HSLFTextParagraph.this.getBulletChar();
- return (chr == 0 ? "" : ""+chr);
+ Character chr = HSLFTextParagraph.this.getBulletChar();
+ return (chr == null || chr == 0) ? "" : "" + chr;
}
public String getBulletFont() {
- int fontIdx = HSLFTextParagraph.this.getBulletFont();
- if (fontIdx == -1) return getDefaultFontFamily();
- PPFont ppFont = getSheet().getSlideShow().getFont(fontIdx);
- return ppFont.getFontName();
+ return HSLFTextParagraph.this.getBulletFont();
}
- public double getBulletFontSize() {
+ public Double getBulletFontSize() {
return HSLFTextParagraph.this.getBulletSize();
}
@@ -417,666 +392,669 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> { _parentShape = parentShape;
}
+ /**
+ *
+ * @return indentation level
+ */
+ public int getIndentLevel() {
+ return _paragraphStyle == null ? 0 : _paragraphStyle.getIndentLevel();
+ }
/**
- *
- * @return indentation level
- */
- public int getIndentLevel() {
- return _paragraphStyle == null ? 0 : _paragraphStyle.getIndentLevel();
- }
-
- /**
- * Sets indentation level
- *
+ * Sets indentation level
+ *
* @param level indentation level. Must be in the range [0, 4]
- */
- public void setIndentLevel(int level) {
+ */
+ public void setIndentLevel(int level) {
if( _paragraphStyle != null ) _paragraphStyle.setIndentLevel((short)level);
- }
-
- /**
- * Sets whether this rich text run has bullets
- */
- public void setBullet(boolean flag) {
- setFlag(ParagraphFlagsTextProp.BULLET_IDX, flag);
- }
-
- /**
- * Returns whether this rich text run has bullets
- */
- public boolean isBullet() {
- return getFlag(ParagraphFlagsTextProp.BULLET_IDX);
- }
-
- /**
- * Returns whether this rich text run has bullets
- */
- public boolean isBulletHard() {
- return getFlag(ParagraphFlagsTextProp.BULLET_IDX);
- }
-
- /**
- * Sets the bullet character
- */
- public void setBulletChar(char c) {
- setParaTextPropVal("bullet.char", c);
- }
-
- /**
- * Returns the bullet character
- */
- public char getBulletChar() {
- int val = getParaTextPropVal("bullet.char");
- return (char)(val == -1 ? 0 : val);
- }
-
- /**
- * Sets the bullet size
- */
- public void setBulletSize(int size) {
- setParaTextPropVal("bullet.size", size);
- }
-
- /**
- * Returns the bullet size
- */
- public int getBulletSize() {
- return getParaTextPropVal("bullet.size");
- }
-
- /**
- * Sets the bullet color
- */
- public void setBulletColor(Color color) {
- int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 254).getRGB();
- setParaTextPropVal("bullet.color", rgb);
- }
-
- /**
- * Returns the bullet color
- */
- public Color getBulletColor() {
- int rgb = getParaTextPropVal("bullet.color");
- if (rgb == -1) {
- // if bullet color is undefined, return color of first run
- if (_runs.isEmpty()) return null;
- return _runs.get(0).getFontColor();
- }
-
- int cidx = rgb >> 24;
- if (rgb % 0x1000000 == 0){
- if (_sheet == null) return null;
- ColorSchemeAtom ca = _sheet.getColorScheme();
- if(cidx >= 0 && cidx <= 7) rgb = ca.getColor(cidx);
- }
- Color tmp = new Color(rgb, true);
- return new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed());
- }
-
- /**
- * Sets the bullet font
- */
- public void setBulletFont(int idx) {
- setParaTextPropVal("bullet.font", idx);
- setFlag(ParagraphFlagsTextProp.BULLET_HARDFONT_IDX, true);
- }
-
- /**
- * Returns the bullet font
- */
- public int getBulletFont() {
- return getParaTextPropVal("bullet.font");
- }
-
- @Override
- public void setLineSpacing(double lineSpacing) {
- // if lineSpacing < 0, we need to convert points (common interface) to master units (hslf)
- if (lineSpacing < 0) {
- lineSpacing = (lineSpacing*HSLFShape.MASTER_DPI/HSLFShape.POINT_DPI);
- }
- setParaTextPropVal("linespacing", (int)lineSpacing);
- }
-
- @Override
- public double getLineSpacing() {
- double val = getParaTextPropVal("linespacing");
- // if lineSpacing < 0, we need to convert master units (hslf) to points (common interface)
- if (val == -1) return 0;
- if (val < -1) val *= HSLFShape.POINT_DPI/((double)HSLFShape.MASTER_DPI);
- return val;
- }
-
- /**
- * Sets spacing before a paragraph.
- * <p>
- * If spacebefore >= 0, then spacebefore is a percentage of normal line height.
- * If spacebefore < 0, the absolute value of spacebefore is the spacing in master coordinates.
- * </p>
- */
- public void setSpaceBefore(int val) {
- setParaTextPropVal("spacebefore", val);
- }
-
- /**
- * Returns spacing before a paragraph
- * <p>
- * If spacebefore >= 0, then spacebefore is a percentage of normal line height.
- * If spacebefore < 0, the absolute value of spacebefore is the spacing in master coordinates.
- * </p>
- *
- * @return the spacing before a paragraph
- */
- @Override
- public double getSpaceBefore() {
- int val = getParaTextPropVal("spacebefore");
- return val == -1 ? 0 : val;
- }
-
- /**
- * Sets spacing after a paragraph.
- * <p>
- * If spaceafter >= 0, then spaceafter is a percentage of normal line height.
- * If spaceafter < 0, the absolute value of spaceafter is the spacing in master coordinates.
- * </p>
- */
- public void setSpaceAfter(int val) {
- setParaTextPropVal("spaceafter", val);
- }
-
- /**
- * Returns spacing after a paragraph
- * <p>
- * If spaceafter >= 0, then spaceafter is a percentage of normal line height.
- * If spaceafter < 0, the absolute value of spaceafter is the spacing in master coordinates.
- * </p>
- *
- * @return the spacing before a paragraph
- */
- @Override
- public double getSpaceAfter() {
- int val = getParaTextPropVal("spaceafter");
- return val == -1 ? 0 : val;
- }
-
- /**
- * Returns the named TextProp, either by fetching it (if it exists) or adding it
- * (if it didn't)
- * @param textPropCol The TextPropCollection to fetch from / add into
- * @param textPropName The name of the TextProp to fetch/add
- */
- protected static TextProp fetchOrAddTextProp(TextPropCollection textPropCol, String textPropName) {
+ }
+
+ /**
+ * Sets whether this rich text run has bullets
+ */
+ public void setBullet(boolean flag) {
+ setFlag(ParagraphFlagsTextProp.BULLET_IDX, flag);
+ }
+
+ /**
+ * Returns whether this rich text run has bullets
+ */
+ public boolean isBullet() {
+ return getFlag(ParagraphFlagsTextProp.BULLET_IDX);
+ }
+
+ /**
+ * Sets the bullet character
+ */
+ public void setBulletChar(Character c) {
+ Integer val = (c == null) ? null : (int)c.charValue();
+ setPropVal(_paragraphStyle, "bullet.char", val);
+ }
+
+ /**
+ * Returns the bullet character
+ */
+ public Character getBulletChar() {
+ TextProp tp = getPropVal(_paragraphStyle, "bullet.char", this);
+ return (tp == null) ? null : (char)tp.getValue();
+ }
+
+ /**
+ * Sets the bullet size
+ */
+ public void setBulletSize(Double size) {
+ setPctOrPoints("bullet.size", size);
+ }
+
+ /**
+ * Returns the bullet size, null if unset
+ */
+ public Double getBulletSize() {
+ return getPctOrPoints("bullet.size");
+ }
+
+ /**
+ * Sets the bullet color
+ */
+ public void setBulletColor(Color color) {
+ Integer val = (color == null) ? null : new Color(color.getBlue(), color.getGreen(), color.getRed(), 254).getRGB();
+ setPropVal(_paragraphStyle, "bullet.color", val);
+ }
+
+ /**
+ * Returns the bullet color
+ */
+ public Color getBulletColor() {
+ TextProp tp = getPropVal(_paragraphStyle, "bullet.color", this);
+ if (tp == null) {
+ // if bullet color is undefined, return color of first run
+ return (_runs.isEmpty()) ? null : _runs.get(0).getFontColor();
+ }
+
+ int rgb = tp.getValue();
+ int cidx = rgb >> 24;
+ if (rgb % 0x1000000 == 0) {
+ if (_sheet == null)
+ return null;
+ ColorSchemeAtom ca = _sheet.getColorScheme();
+ if (cidx >= 0 && cidx <= 7)
+ rgb = ca.getColor(cidx);
+ }
+ Color tmp = new Color(rgb, true);
+ return new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed());
+ }
+
+ /**
+ * Sets the bullet font
+ */
+ public void setBulletFont(String typeface) {
+ if (typeface == null) {
+ setPropVal(_paragraphStyle, "bullet.font", null);
+ setFlag(ParagraphFlagsTextProp.BULLET_HARDFONT_IDX, false);
+ }
+
+ FontCollection fc = getSheet().getSlideShow().getFontCollection();
+ int idx = fc.addFont(typeface);
+
+ setPropVal(_paragraphStyle, "bullet.font", idx);
+ setFlag(ParagraphFlagsTextProp.BULLET_HARDFONT_IDX, true);
+ }
+
+ /**
+ * Returns the bullet font
+ */
+ public String getBulletFont() {
+ TextProp tp = getPropVal(_paragraphStyle, "bullet.font", this);
+ if (tp == null) return getDefaultFontFamily();
+ PPFont ppFont = getSheet().getSlideShow().getFont(tp.getValue());
+ assert(ppFont != null);
+ return ppFont.getFontName();
+ }
+
+ @Override
+ public void setLineSpacing(Double lineSpacing) {
+ setPctOrPoints("linespacing", lineSpacing);
+ }
+
+ @Override
+ public Double getLineSpacing() {
+ return getPctOrPoints("linespacing");
+ }
+
+ @Override
+ public void setSpaceBefore(Double spaceBefore) {
+ setPctOrPoints("spacebefore", spaceBefore);
+ }
+
+ @Override
+ public Double getSpaceBefore() {
+ return getPctOrPoints("spacebefore");
+ }
+
+ @Override
+ public void setSpaceAfter(Double spaceAfter) {
+ setPctOrPoints("spaceafter", spaceAfter);
+ }
+
+ @Override
+ public Double getSpaceAfter() {
+ return getPctOrPoints("spaceafter");
+ }
+
+ @Override
+ public Double getDefaultTabSize() {
+ // TODO: implement
+ return null;
+ }
+
+ private Double getPctOrPoints(String propName) {
+ TextProp tp = getPropVal(_paragraphStyle, propName, this);
+ if (tp == null) return null;
+ int val = tp.getValue();
+ return (val < 0) ? Units.masterToPoints(val) : val;
+ }
+
+ private void setPctOrPoints(String propName, Double dval) {
+ Integer ival = null;
+ if (dval != null) {
+ ival = (dval < 0) ? Units.pointsToMaster(dval) : dval.intValue();
+ }
+ setPropVal(_paragraphStyle, propName, ival);
+ }
+
+ private boolean getFlag(int index) {
+ BitMaskTextProp tp = (BitMaskTextProp)getPropVal(_paragraphStyle, ParagraphFlagsTextProp.NAME, this);
+ return (tp == null) ? false : tp.getSubValue(index);
+ }
+
+ private void setFlag(int index, boolean value) {
+ BitMaskTextProp tp = (BitMaskTextProp)_paragraphStyle.addWithName(ParagraphFlagsTextProp.NAME);
+ tp.setSubValue(value, index);
+ }
+
+ /**
+ * Fetch the value of the given Paragraph related TextProp. Returns null if
+ * that TextProp isn't present. If the TextProp isn't present, the value
+ * from the appropriate Master Sheet will apply.
+ */
+ protected static TextProp getPropVal(TextPropCollection props, String propName, HSLFTextParagraph paragraph) {
+ TextProp prop = props.findByName(propName);
+ if (prop != null) return prop;
+
+ BitMaskTextProp maskProp = (BitMaskTextProp) props.findByName(ParagraphFlagsTextProp.NAME);
+ boolean hardAttribute = (maskProp != null && maskProp.getValue() == 0);
+ if (hardAttribute) return null;
+
+ HSLFSheet sheet = paragraph.getSheet();
+ int txtype = paragraph.getRunType();
+ HSLFMasterSheet master = sheet.getMasterSheet();
+ if (master == null) {
+ logger.log(POILogger.WARN, "MasterSheet is not available");
+ return null;
+ }
+
+ boolean isChar = props.getTextPropType() == TextPropType.character;
+ return master.getStyleAttribute(txtype, paragraph.getIndentLevel(), propName, isChar);
+ }
+
+ /**
+ * Returns the named TextProp, either by fetching it (if it exists) or
+ * adding it (if it didn't)
+ *
+ * @param props the TextPropCollection to fetch from / add into
+ * @param name the name of the TextProp to fetch/add
+ * @param val the value, null if unset
+ */
+ protected static void setPropVal(TextPropCollection props, String name, Integer val) {
+ if (val == null) {
+ props.removeByName(name);
+ return;
+ }
+
// Fetch / Add the TextProp
- return textPropCol.addWithName(textPropName);
+ TextProp tp = props.addWithName(name);
+ tp.setValue(val);
+ }
+
+ /**
+ * Check and add linebreaks to text runs leading other paragraphs
+ *
+ * @param paragraphs
+ */
+ protected static void fixLineEndings(List<HSLFTextParagraph> paragraphs) {
+ HSLFTextRun lastRun = null;
+ for (HSLFTextParagraph p : paragraphs) {
+ if (lastRun != null && !lastRun.getRawText().endsWith("\r")) {
+ lastRun.setText(lastRun.getRawText() + "\r");
+ }
+ List<HSLFTextRun> ltr = p.getTextRuns();
+ if (ltr.isEmpty()) {
+ throw new RuntimeException("paragraph without textruns found");
+ }
+ lastRun = ltr.get(ltr.size() - 1);
+ assert (lastRun.getRawText() != null);
+ }
}
- protected boolean getFlag(int index) {
- if (_paragraphStyle == null) return false;
+ /**
+ * Search for a StyleTextPropAtom is for this text header (list of paragraphs)
+ *
+ * @param header the header
+ * @param textLen the length of the rawtext, or -1 if the length is not known
+ */
+ private static StyleTextPropAtom findStyleAtomPresent(TextHeaderAtom header, int textLen) {
+ boolean afterHeader = false;
+ StyleTextPropAtom style = null;
+ for (Record record : header.getParentRecord().getChildRecords()) {
+ long rt = record.getRecordType();
+ if (afterHeader && rt == RecordTypes.TextHeaderAtom.typeID) {
+ // already on the next header, quit searching
+ break;
+ }
+ afterHeader |= (header == record);
+ if (afterHeader && rt == RecordTypes.StyleTextPropAtom.typeID) {
+ // found it
+ style = (StyleTextPropAtom) record;
+ }
+ }
+
+ if (style == null) {
+ logger.log(POILogger.INFO, "styles atom doesn't exist. Creating dummy record for later saving.");
+ style = new StyleTextPropAtom((textLen < 0) ? 1 : textLen);
+ } else {
+ if (textLen >= 0) {
+ style.setParentTextSize(textLen);
+ }
+ }
- BitMaskTextProp prop = (BitMaskTextProp) _paragraphStyle.findByName(ParagraphFlagsTextProp.NAME);
+ return style;
+ }
- if (prop == null) {
- if (_sheet != null) {
- int txtype = getRunType();
- HSLFMasterSheet master = _sheet.getMasterSheet();
- if (master != null) {
- prop = (BitMaskTextProp) master.getStyleAttribute(txtype, getIndentLevel(), ParagraphFlagsTextProp.NAME, false);
- }
+ /**
+ * Saves the modified paragraphs/textrun to the records.
+ * Also updates the styles to the correct text length.
+ */
+ protected static void storeText(List<HSLFTextParagraph> paragraphs) {
+ fixLineEndings(paragraphs);
+
+ String rawText = toInternalString(getRawText(paragraphs));
+
+ // Will it fit in a 8 bit atom?
+ boolean isUnicode = StringUtil.hasMultibyte(rawText);
+ // isUnicode = true;
+
+ TextHeaderAtom headerAtom = paragraphs.get(0)._headerAtom;
+ TextBytesAtom byteAtom = paragraphs.get(0)._byteAtom;
+ TextCharsAtom charAtom = paragraphs.get(0)._charAtom;
+ StyleTextPropAtom styleAtom = findStyleAtomPresent(headerAtom, rawText.length());
+
+ // Store in the appropriate record
+ Record oldRecord = null, newRecord = null;
+ if (isUnicode) {
+ if (byteAtom != null || charAtom == null) {
+ oldRecord = byteAtom;
+ charAtom = new TextCharsAtom();
+ }
+ newRecord = charAtom;
+ charAtom.setText(rawText);
+ } else {
+ if (charAtom != null || byteAtom == null) {
+ oldRecord = charAtom;
+ byteAtom = new TextBytesAtom();
+ }
+ newRecord = byteAtom;
+ byte[] byteText = new byte[rawText.length()];
+ StringUtil.putCompressedUnicode(rawText, byteText, 0);
+ byteAtom.setText(byteText);
+ }
+ assert (newRecord != null);
+
+ RecordContainer _txtbox = headerAtom.getParentRecord();
+ Record[] cr = _txtbox.getChildRecords();
+ int headerIdx = -1, textIdx = -1, styleIdx = -1;
+ for (int i = 0; i < cr.length; i++) {
+ Record r = cr[i];
+ if (r == headerAtom) headerIdx = i;
+ else if (r == oldRecord || r == newRecord) textIdx = i;
+ else if (r == styleAtom) styleIdx = i;
+ }
+
+ if (textIdx == -1) {
+ // the old record was never registered, ignore it
+ _txtbox.addChildAfter(newRecord, headerAtom);
+ textIdx = headerIdx + 1;
+ } else {
+ // swap not appropriated records - noop if unchanged
+ cr[textIdx] = newRecord;
+ }
+
+ if (styleIdx == -1) {
+ // Add the new StyleTextPropAtom after the TextCharsAtom / TextBytesAtom
+ _txtbox.addChildAfter(styleAtom, newRecord);
+ }
+
+ for (HSLFTextParagraph p : paragraphs) {
+ if (newRecord == byteAtom) {
+ p._byteAtom = byteAtom;
+ p._charAtom = null;
} else {
- logger.log(POILogger.WARN, "MasterSheet is not available");
+ p._byteAtom = null;
+ p._charAtom = charAtom;
+ }
+ }
+
+ // Update the text length for its Paragraph and Character stylings
+ // * reset the length, to the new string's length
+ // * add on +1 if the last block
+
+ styleAtom.clearStyles();
+
+ TextPropCollection lastPTPC = null, lastRTPC = null, ptpc = null, rtpc = null;
+ for (HSLFTextParagraph para : paragraphs) {
+ ptpc = para.getParagraphStyle();
+ ptpc.updateTextSize(0);
+ if (!ptpc.equals(lastPTPC)) {
+ lastPTPC = styleAtom.addParagraphTextPropCollection(0);
+ lastPTPC.copy(ptpc);
+ }
+ for (HSLFTextRun tr : para.getTextRuns()) {
+ rtpc = tr.getCharacterStyle();
+ rtpc.updateTextSize(0);
+ if (!rtpc.equals(lastRTPC)) {
+ lastRTPC = styleAtom.addCharacterTextPropCollection(0);
+ lastRTPC.copy(rtpc);
+ }
+ int len = tr.getLength();
+ ptpc.updateTextSize(ptpc.getCharactersCovered() + len);
+ rtpc.updateTextSize(len);
+ lastPTPC.updateTextSize(lastPTPC.getCharactersCovered() + len);
+ lastRTPC.updateTextSize(lastRTPC.getCharactersCovered() + len);
+ }
+ }
+
+ assert (lastPTPC != null && lastRTPC != null && ptpc != null && rtpc != null);
+ ptpc.updateTextSize(ptpc.getCharactersCovered() + 1);
+ rtpc.updateTextSize(rtpc.getCharactersCovered() + 1);
+ lastPTPC.updateTextSize(lastPTPC.getCharactersCovered() + 1);
+ lastRTPC.updateTextSize(lastRTPC.getCharactersCovered() + 1);
+
+ /**
+ * If TextSpecInfoAtom is present, we must update the text size in it,
+ * otherwise the ppt will be corrupted
+ */
+ for (Record r : paragraphs.get(0).getRecords()) {
+ if (r instanceof TextSpecInfoAtom) {
+ ((TextSpecInfoAtom) r).setParentSize(rawText.length() + 1);
+ break;
+ }
+ }
+
+ if (_txtbox instanceof EscherTextboxWrapper) {
+ try {
+ ((EscherTextboxWrapper) _txtbox).writeOut(null);
+ } catch (IOException e) {
+ throw new RuntimeException("failed dummy write", e);
+ }
+ }
+ }
+
+ /**
+ * Adds the supplied text onto the end of the TextParagraphs,
+ * creating a new RichTextRun for it to sit in.
+ *
+ * @param text the text string used by this object.
+ */
+ protected static HSLFTextRun appendText(List<HSLFTextParagraph> paragraphs, String text, boolean newParagraph) {
+ text = toInternalString(text);
+
+ // check paragraphs
+ assert(!paragraphs.isEmpty() && !paragraphs.get(0).getTextRuns().isEmpty());
+
+ HSLFTextParagraph htp = paragraphs.get(paragraphs.size() - 1);
+ HSLFTextRun htr = htp.getTextRuns().get(htp.getTextRuns().size() - 1);
+
+ boolean isFirst = !newParagraph;
+ for (String rawText : text.split("(?<=\r)")) {
+ if (!isFirst) {
+ TextPropCollection tpc = htp.getParagraphStyle();
+ HSLFTextParagraph prevHtp = htp;
+ htp = new HSLFTextParagraph(htp._headerAtom, htp._byteAtom, htp._charAtom);
+ htp.getParagraphStyle().copy(tpc);
+ htp.setParentShape(prevHtp.getParentShape());
+ htp.setShapeId(prevHtp.getShapeId());
+ htp.supplySheet(prevHtp.getSheet());
+ paragraphs.add(htp);
+ }
+ isFirst = false;
+
+ TextPropCollection tpc = htr.getCharacterStyle();
+ // special case, last text run is empty, we will reuse it
+ if (htr.getLength() > 0) {
+ htr = new HSLFTextRun(htp);
+ htr.getCharacterStyle().copy(tpc);
+ htp.addTextRun(htr);
}
+ htr.setText(rawText);
}
- return prop == null ? false : prop.getSubValue(index);
- }
-
- protected void setFlag(int index, boolean value) {
- // Ensure we have the StyleTextProp atom we're going to need
- assert(_paragraphStyle!=null);
- BitMaskTextProp prop = (BitMaskTextProp) fetchOrAddTextProp(_paragraphStyle, ParagraphFlagsTextProp.NAME);
- prop.setSubValue(value,index);
- }
-
- /**
- * Check and add linebreaks to text runs leading other paragraphs
- *
- * @param paragraphs
- */
- protected static void fixLineEndings(List<HSLFTextParagraph> paragraphs) {
- HSLFTextRun lastRun = null;
- for (HSLFTextParagraph p : paragraphs) {
- if (lastRun != null && !lastRun.getRawText().endsWith("\r")) {
- lastRun.setText(lastRun.getRawText()+"\r");
- }
- List<HSLFTextRun> ltr = p.getTextRuns();
- if (ltr.isEmpty()) {
- throw new RuntimeException("paragraph without textruns found");
- }
- lastRun = ltr.get(ltr.size()-1);
- assert(lastRun.getRawText() != null);
- }
- }
-
- /**
- * Search for a StyleTextPropAtom is for this text header (list of paragraphs)
- *
- * @param header the header
- * @param textLen the length of the rawtext, or -1 if the length is not known
- */
- private static StyleTextPropAtom findStyleAtomPresent(TextHeaderAtom header, int textLen) {
- boolean afterHeader = false;
- StyleTextPropAtom style = null;
- for (Record record : header.getParentRecord().getChildRecords()) {
- long rt = record.getRecordType();
- if (afterHeader && rt == RecordTypes.TextHeaderAtom.typeID) {
- // already on the next header, quit searching
- break;
- }
- afterHeader |= (header == record);
- if (afterHeader && rt == RecordTypes.StyleTextPropAtom.typeID) {
- // found it
- style = (StyleTextPropAtom)record;
- }
- }
-
- if (style == null) {
- logger.log(POILogger.INFO, "styles atom doesn't exist. Creating dummy record for later saving.");
- style = new StyleTextPropAtom((textLen < 0) ? 1 : textLen);
- } else {
- if (textLen >= 0) {
- style.setParentTextSize(textLen);
- }
- }
-
- return style;
- }
-
-
- /**
- * Saves the modified paragraphs/textrun to the records.
- * Also updates the styles to the correct text length.
- */
- protected static void storeText(List<HSLFTextParagraph> paragraphs) {
- fixLineEndings(paragraphs);
-
- String rawText = toInternalString(getRawText(paragraphs));
-
- // Will it fit in a 8 bit atom?
- boolean isUnicode = StringUtil.hasMultibyte(rawText);
- // isUnicode = true;
-
- TextHeaderAtom headerAtom = paragraphs.get(0)._headerAtom;
- TextBytesAtom byteAtom = paragraphs.get(0)._byteAtom;
- TextCharsAtom charAtom = paragraphs.get(0)._charAtom;
- StyleTextPropAtom styleAtom = findStyleAtomPresent(headerAtom, rawText.length());
-
- // Store in the appropriate record
- Record oldRecord = null, newRecord = null;
- if (isUnicode) {
- if (byteAtom != null || charAtom == null) {
- oldRecord = byteAtom;
- charAtom = new TextCharsAtom();
- }
- newRecord = charAtom;
- charAtom.setText(rawText);
- } else {
- if (charAtom != null || byteAtom == null) {
- oldRecord = charAtom;
- byteAtom = new TextBytesAtom();
- }
- newRecord = byteAtom;
- byte[] byteText = new byte[rawText.length()];
- StringUtil.putCompressedUnicode(rawText,byteText,0);
- byteAtom.setText(byteText);
- }
- assert(newRecord != null);
-
- RecordContainer _txtbox = headerAtom.getParentRecord();
- Record[] cr = _txtbox.getChildRecords();
- int headerIdx = -1, textIdx = -1, styleIdx = -1;
- for (int i=0; i<cr.length; i++) {
- Record r = cr[i];
- if (r == headerAtom) headerIdx = i;
- else if (r == oldRecord || r == newRecord) textIdx = i;
- else if (r == styleAtom) styleIdx = i;
- }
-
- if (textIdx == -1) {
- // the old record was never registered, ignore it
- _txtbox.addChildAfter(newRecord, headerAtom);
- textIdx = headerIdx+1;
- } else {
- // swap not appropriated records - noop if unchanged
- cr[textIdx] = newRecord;
- }
-
- if (styleIdx == -1) {
- // Add the new StyleTextPropAtom after the TextCharsAtom / TextBytesAtom
- _txtbox.addChildAfter(styleAtom, newRecord);
- }
-
- for (HSLFTextParagraph p : paragraphs) {
- if (newRecord == byteAtom) {
- p._byteAtom = byteAtom;
- p._charAtom = null;
- } else {
- p._byteAtom = null;
- p._charAtom = charAtom;
- }
- }
-
- // Update the text length for its Paragraph and Character stylings
- // * reset the length, to the new string's length
- // * add on +1 if the last block
-
- styleAtom.clearStyles();
-
- TextPropCollection lastPTPC = null, lastRTPC = null, ptpc = null, rtpc = null;
- for (HSLFTextParagraph para : paragraphs) {
- ptpc = para.getParagraphStyle();
- ptpc.updateTextSize(0);
- if (!ptpc.equals(lastPTPC)) {
- lastPTPC = styleAtom.addParagraphTextPropCollection(0);
- lastPTPC.copy(ptpc);
- }
- for (HSLFTextRun tr : para.getTextRuns()) {
- rtpc = tr.getCharacterStyle();
- rtpc.updateTextSize(0);
- if (!rtpc.equals(lastRTPC)) {
- lastRTPC = styleAtom.addCharacterTextPropCollection(0);
- lastRTPC.copy(rtpc);
- }
- int len = tr.getLength();
- ptpc.updateTextSize(ptpc.getCharactersCovered()+len);
- rtpc.updateTextSize(len);
- lastPTPC.updateTextSize(lastPTPC.getCharactersCovered()+len);
- lastRTPC.updateTextSize(lastRTPC.getCharactersCovered()+len);
- }
- }
-
- assert(lastPTPC != null && lastRTPC != null && ptpc != null && rtpc != null);
- ptpc.updateTextSize(ptpc.getCharactersCovered()+1);
- rtpc.updateTextSize(rtpc.getCharactersCovered()+1);
- lastPTPC.updateTextSize(lastPTPC.getCharactersCovered()+1);
- lastRTPC.updateTextSize(lastRTPC.getCharactersCovered()+1);
-
- /**
- * If TextSpecInfoAtom is present, we must update the text size in it,
- * otherwise the ppt will be corrupted
- */
- for (Record r : paragraphs.get(0).getRecords()) {
- if (r instanceof TextSpecInfoAtom) {
- ((TextSpecInfoAtom)r).setParentSize(rawText.length()+1);
- break;
- }
- }
-
- if (_txtbox instanceof EscherTextboxWrapper) {
- try {
- ((EscherTextboxWrapper)_txtbox).writeOut(null);
- } catch (IOException e) {
- throw new RuntimeException("failed dummy write", e);
- }
- }
- }
-
- /**
- * Adds the supplied text onto the end of the TextParagraphs,
- * creating a new RichTextRun for it to sit in.
- *
- * @param text the text string used by this object.
- */
- protected static HSLFTextRun appendText(List<HSLFTextParagraph> paragraphs, String text, boolean newParagraph) {
- text = toInternalString(text);
-
- // check paragraphs
- assert(!paragraphs.isEmpty() && !paragraphs.get(0).getTextRuns().isEmpty());
-
- HSLFTextParagraph htp = paragraphs.get(paragraphs.size()-1);
- HSLFTextRun htr = htp.getTextRuns().get(htp.getTextRuns().size()-1);
-
- boolean isFirst = !newParagraph;
- for (String rawText : text.split("(?<=\r)")) {
- if (!isFirst) {
- TextPropCollection tpc = htp.getParagraphStyle();
- HSLFTextParagraph prevHtp = htp;
- htp = new HSLFTextParagraph(htp._headerAtom, htp._byteAtom, htp._charAtom);
- htp.getParagraphStyle().copy(tpc);
- htp.setParentShape(prevHtp.getParentShape());
- htp.setShapeId(prevHtp.getShapeId());
- htp.supplySheet(prevHtp.getSheet());
- paragraphs.add(htp);
- }
- isFirst = false;
-
- TextPropCollection tpc = htr.getCharacterStyle();
- // special case, last text run is empty, we will reuse it
- if (htr.getLength() > 0) {
- htr = new HSLFTextRun(htp);
- htr.getCharacterStyle().copy(tpc);
- htp.addTextRun(htr);
- }
- htr.setText(rawText);
- }
-
- storeText(paragraphs);
-
- return htr;
- }
-
- /**
- * Sets (overwrites) the current text.
- * Uses the properties of the first paragraph / textrun
- *
- * @param text the text string used by this object.
- */
- public static HSLFTextRun setText(List<HSLFTextParagraph> paragraphs, String text) {
- // check paragraphs
- assert(!paragraphs.isEmpty() && !paragraphs.get(0).getTextRuns().isEmpty());
-
- Iterator<HSLFTextParagraph> paraIter = paragraphs.iterator();
- HSLFTextParagraph htp = paraIter.next(); // keep first
- assert(htp != null);
- while (paraIter.hasNext()) {
- paraIter.next();
- paraIter.remove();
- }
-
- Iterator<HSLFTextRun> runIter = htp.getTextRuns().iterator();
- HSLFTextRun htr = runIter.next();
- htr.setText("");
- assert(htr != null);
- while (runIter.hasNext()) {
- runIter.next();
- runIter.remove();
- }
-
- return appendText(paragraphs, text, false);
- }
-
- public static String getText(List<HSLFTextParagraph> paragraphs) {
- assert(!paragraphs.isEmpty());
- String rawText = getRawText(paragraphs);
- return toExternalString(rawText, paragraphs.get(0).getRunType());
- }
-
- public static String getRawText(List<HSLFTextParagraph> paragraphs) {
- StringBuilder sb = new StringBuilder();
- for (HSLFTextParagraph p : paragraphs) {
- for (HSLFTextRun r : p.getTextRuns()) {
- sb.append(r.getRawText());
- }
- }
- return sb.toString();
- }
-
- /**
- * Returns a new string with line breaks converted into internal ppt
- * representation
- */
- protected static String toInternalString(String s) {
- String ns = s.replaceAll("\\r?\\n", "\r");
- return ns;
- }
-
- /**
- * Converts raw text from the text paragraphs to a formatted string,
- * i.e. it converts certain control characters used in the raw txt
- *
- * @param rawText the raw text
- * @param runType the run type of the shape, paragraph or headerAtom.
- * use -1 if unknown
- * @return the formatted string
- */
- public static String toExternalString(String rawText, int runType) {
- // PowerPoint seems to store files with \r as the line break
- // The messes things up on everything but a Mac, so translate
- // them to \n
- String text = rawText.replace('\r', '\n');
-
- switch (runType) {
- // 0xB acts like cariage return in page titles and like blank in the
- // others
- case -1:
- case org.apache.poi.hslf.record.TextHeaderAtom.TITLE_TYPE:
- case org.apache.poi.hslf.record.TextHeaderAtom.CENTER_TITLE_TYPE:
- text = text.replace((char) 0x0B, '\n');
- break;
- default:
- text = text.replace((char) 0x0B, ' ');
- break;
- }
-
- return text;
- }
-
- /**
- * For a given PPDrawing, grab all the TextRuns
- */
+ storeText(paragraphs);
+
+ return htr;
+ }
+
+ /**
+ * Sets (overwrites) the current text.
+ * Uses the properties of the first paragraph / textrun
+ *
+ * @param text the text string used by this object.
+ */
+ public static HSLFTextRun setText(List<HSLFTextParagraph> paragraphs, String text) {
+ // check paragraphs
+ assert(!paragraphs.isEmpty() && !paragraphs.get(0).getTextRuns().isEmpty());
+
+ Iterator<HSLFTextParagraph> paraIter = paragraphs.iterator();
+ HSLFTextParagraph htp = paraIter.next(); // keep first
+ assert (htp != null);
+ while (paraIter.hasNext()) {
+ paraIter.next();
+ paraIter.remove();
+ }
+
+ Iterator<HSLFTextRun> runIter = htp.getTextRuns().iterator();
+ HSLFTextRun htr = runIter.next();
+ htr.setText("");
+ assert (htr != null);
+ while (runIter.hasNext()) {
+ runIter.next();
+ runIter.remove();
+ }
+
+ return appendText(paragraphs, text, false);
+ }
+
+ public static String getText(List<HSLFTextParagraph> paragraphs) {
+ assert (!paragraphs.isEmpty());
+ String rawText = getRawText(paragraphs);
+ return toExternalString(rawText, paragraphs.get(0).getRunType());
+ }
+
+ public static String getRawText(List<HSLFTextParagraph> paragraphs) {
+ StringBuilder sb = new StringBuilder();
+ for (HSLFTextParagraph p : paragraphs) {
+ for (HSLFTextRun r : p.getTextRuns()) {
+ sb.append(r.getRawText());
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Returns a new string with line breaks converted into internal ppt
+ * representation
+ */
+ protected static String toInternalString(String s) {
+ String ns = s.replaceAll("\\r?\\n", "\r");
+ return ns;
+ }
+
+ /**
+ * Converts raw text from the text paragraphs to a formatted string,
+ * i.e. it converts certain control characters used in the raw txt
+ *
+ * @param rawText the raw text
+ * @param runType the run type of the shape, paragraph or headerAtom.
+ * use -1 if unknown
+ * @return the formatted string
+ */
+ public static String toExternalString(String rawText, int runType) {
+ // PowerPoint seems to store files with \r as the line break
+ // The messes things up on everything but a Mac, so translate
+ // them to \n
+ String text = rawText.replace('\r', '\n');
+
+ switch (runType) {
+ // 0xB acts like cariage return in page titles and like blank in the
+ // others
+ case -1:
+ case org.apache.poi.hslf.record.TextHeaderAtom.TITLE_TYPE:
+ case org.apache.poi.hslf.record.TextHeaderAtom.CENTER_TITLE_TYPE:
+ text = text.replace((char) 0x0B, '\n');
+ break;
+ default:
+ text = text.replace((char) 0x0B, ' ');
+ break;
+ }
+
+ return text;
+ }
+
+ /**
+ * For a given PPDrawing, grab all the TextRuns
+ */
public static List<List<HSLFTextParagraph>> findTextParagraphs(PPDrawing ppdrawing, HSLFSheet sheet) {
- List<List<HSLFTextParagraph>> runsV = new ArrayList<List<HSLFTextParagraph>>();
- for (EscherTextboxWrapper wrapper : ppdrawing.getTextboxWrappers()) {
- runsV.add(findTextParagraphs(wrapper, sheet));
- }
- return runsV;
- }
-
- /**
- * Scans through the supplied record array, looking for
- * a TextHeaderAtom followed by one of a TextBytesAtom or
- * a TextCharsAtom. Builds up TextRuns from these
- *
- * @param wrapper an EscherTextboxWrapper
- */
- protected static List<HSLFTextParagraph> findTextParagraphs(EscherTextboxWrapper wrapper, HSLFSheet sheet) {
- // propagate parents to parent-aware records
- RecordContainer.handleParentAwareRecords(wrapper);
- int shapeId = wrapper.getShapeId();
- List<HSLFTextParagraph> rv = null;
-
- OutlineTextRefAtom ota = (OutlineTextRefAtom)wrapper.findFirstOfType(OutlineTextRefAtom.typeID);
- if (ota != null) {
- // if we are based on an outline, there are no further records to be parsed from the wrapper
- if (sheet == null) {
- throw new RuntimeException("Outline atom reference can't be solved without a sheet record");
- }
-
- List<List<HSLFTextParagraph>> sheetRuns = sheet.getTextParagraphs();
- assert(sheetRuns != null);
-
- int idx = ota.getTextIndex();
- for (List<HSLFTextParagraph> r : sheetRuns) {
- if (r.isEmpty()) continue;
- int ridx = r.get(0).getIndex();
- if (ridx > idx) break;
- if (ridx == idx) {
- if (rv == null) {
- rv = r;
- } else {
- // create a new container
- // TODO: ... is this case really happening?
- rv = new ArrayList<HSLFTextParagraph>(rv);
- rv.addAll(r);
- }
- }
- }
- if(rv == null || rv.isEmpty()) {
- logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx);
- }
- } else {
- if (sheet != null) {
- // check sheet runs first, so we get exactly the same paragraph list
- List<List<HSLFTextParagraph>> sheetRuns = sheet.getTextParagraphs();
- assert(sheetRuns != null);
-
- for (List<HSLFTextParagraph> paras : sheetRuns) {
+ List<List<HSLFTextParagraph>> runsV = new ArrayList<List<HSLFTextParagraph>>();
+ for (EscherTextboxWrapper wrapper : ppdrawing.getTextboxWrappers()) {
+ runsV.add(findTextParagraphs(wrapper, sheet));
+ }
+ return runsV;
+ }
+
+ /**
+ * Scans through the supplied record array, looking for
+ * a TextHeaderAtom followed by one of a TextBytesAtom or
+ * a TextCharsAtom. Builds up TextRuns from these
+ *
+ * @param wrapper an EscherTextboxWrapper
+ */
+ protected static List<HSLFTextParagraph> findTextParagraphs(EscherTextboxWrapper wrapper, HSLFSheet sheet) {
+ // propagate parents to parent-aware records
+ RecordContainer.handleParentAwareRecords(wrapper);
+ int shapeId = wrapper.getShapeId();
+ List<HSLFTextParagraph> rv = null;
+
+ OutlineTextRefAtom ota = (OutlineTextRefAtom)wrapper.findFirstOfType(OutlineTextRefAtom.typeID);
+ if (ota != null) {
+ // if we are based on an outline, there are no further records to be parsed from the wrapper
+ if (sheet == null) {
+ throw new RuntimeException("Outline atom reference can't be solved without a sheet record");
+ }
+
+ List<List<HSLFTextParagraph>> sheetRuns = sheet.getTextParagraphs();
+ assert (sheetRuns != null);
+
+ int idx = ota.getTextIndex();
+ for (List<HSLFTextParagraph> r : sheetRuns) {
+ if (r.isEmpty()) continue;
+ int ridx = r.get(0).getIndex();
+ if (ridx > idx) break;
+ if (ridx == idx) {
+ if (rv == null) {
+ rv = r;
+ } else {
+ // create a new container
+ // TODO: ... is this case really happening?
+ rv = new ArrayList<HSLFTextParagraph>(rv);
+ rv.addAll(r);
+ }
+ }
+ }
+ if (rv == null || rv.isEmpty()) {
+ logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx);
+ }
+ } else {
+ if (sheet != null) {
+ // check sheet runs first, so we get exactly the same paragraph list
+ List<List<HSLFTextParagraph>> sheetRuns = sheet.getTextParagraphs();
+ assert (sheetRuns != null);
+
+ for (List<HSLFTextParagraph> paras : sheetRuns) {
if (!paras.isEmpty() && paras.get(0)._headerAtom.getParentRecord() == wrapper) {
- rv = paras;
- break;
- }
- }
- }
-
- if (rv == null) {
- // if we haven't found the wrapper in the sheet runs, create a new paragraph list from its record
- List<List<HSLFTextParagraph>> rvl = findTextParagraphs(wrapper.getChildRecords());
- switch (rvl.size()) {
- case 0: break; // nothing found
- case 1: rv = rvl.get(0); break; // normal case
- default:
- throw new RuntimeException("TextBox contains more than one list of paragraphs.");
- }
- }
- }
-
- if (rv != null) {
- StyleTextProp9Atom styleTextProp9Atom = wrapper.getStyleTextProp9Atom();
-
- for (HSLFTextParagraph htp : rv) {
- htp.setShapeId(shapeId);
- htp.setStyleTextProp9Atom(styleTextProp9Atom);
- }
- }
- return rv;
- }
-
- /**
- * Scans through the supplied record array, looking for
- * a TextHeaderAtom followed by one of a TextBytesAtom or
- * a TextCharsAtom. Builds up TextRuns from these
- *
- * @param records the records to build from
- */
+ rv = paras;
+ break;
+ }
+ }
+ }
+
+ if (rv == null) {
+ // if we haven't found the wrapper in the sheet runs, create a new paragraph list from its record
+ List<List<HSLFTextParagraph>> rvl = findTextParagraphs(wrapper.getChildRecords());
+ switch (rvl.size()) {
+ case 0: break; // nothing found
+ case 1: rv = rvl.get(0); break; // normal case
+ default:
+ throw new RuntimeException("TextBox contains more than one list of paragraphs.");
+ }
+ }
+ }
+
+ if (rv != null) {
+ StyleTextProp9Atom styleTextProp9Atom = wrapper.getStyleTextProp9Atom();
+
+ for (HSLFTextParagraph htp : rv) {
+ htp.setShapeId(shapeId);
+ htp.setStyleTextProp9Atom(styleTextProp9Atom);
+ }
+ }
+ return rv;
+ }
+
+ /**
+ * Scans through the supplied record array, looking for
+ * a TextHeaderAtom followed by one of a TextBytesAtom or
+ * a TextCharsAtom. Builds up TextRuns from these
+ *
+ * @param records the records to build from
+ */
protected static List<List<HSLFTextParagraph>> findTextParagraphs(Record[] records) {
List<List<HSLFTextParagraph>> paragraphCollection = new ArrayList<List<HSLFTextParagraph>>();
- int[] recordIdx = {0};
-
+ int[] recordIdx = { 0 };
+
for (int slwtIndex = 0; recordIdx[0] < records.length; slwtIndex++) {
- TextHeaderAtom header = null;
- TextBytesAtom tbytes = null;
- TextCharsAtom tchars = null;
- TextRulerAtom ruler = null;
+ TextHeaderAtom header = null;
+ TextBytesAtom tbytes = null;
+ TextCharsAtom tchars = null;
+ TextRulerAtom ruler = null;
MasterTextPropAtom indents = null;
for (Record r : getRecords(records, recordIdx, null)) {
long rt = r.getRecordType();
if (RecordTypes.TextHeaderAtom.typeID == rt) {
- header = (TextHeaderAtom)r;
+ header = (TextHeaderAtom) r;
} else if (RecordTypes.TextBytesAtom.typeID == rt) {
- tbytes = (TextBytesAtom)r;
+ tbytes = (TextBytesAtom) r;
} else if (RecordTypes.TextCharsAtom.typeID == rt) {
- tchars = (TextCharsAtom)r;
+ tchars = (TextCharsAtom) r;
} else if (RecordTypes.TextRulerAtom.typeID == rt) {
- ruler = (TextRulerAtom)r;
+ ruler = (TextRulerAtom) r;
} else if (RecordTypes.MasterTextPropAtom.typeID == rt) {
- indents = (MasterTextPropAtom)r;
+ indents = (MasterTextPropAtom) r;
}
// don't search for RecordTypes.StyleTextPropAtom.typeID here ... see findStyleAtomPresent below
}
if (header == null) break;
-
+
if (header.getParentRecord() instanceof SlideListWithText) {
// runs found in PPDrawing are not linked with SlideListWithTexts
header.setIndex(slwtIndex);
@@ -1093,7 +1071,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> { List<HSLFTextParagraph> paragraphs = new ArrayList<HSLFTextParagraph>();
paragraphCollection.add(paragraphs);
-
+
// split, but keep delimiter
for (String para : rawText.split("(?<=\r)")) {
HSLFTextParagraph tpara = new HSLFTextParagraph(header, tbytes, tchars);
@@ -1116,7 +1094,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> { if (paragraphCollection.isEmpty()) {
logger.log(POILogger.DEBUG, "No text records found.");
}
-
+
return paragraphCollection;
}
@@ -1124,25 +1102,25 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> { int paraIdx = 0, runIdx = 0;
HSLFTextRun trun;
- for (int csIdx=0; csIdx<charStyles.size(); csIdx++) {
+ for (int csIdx = 0; csIdx < charStyles.size(); csIdx++) {
TextPropCollection p = charStyles.get(csIdx);
- for (int ccRun = 0, ccStyle = p.getCharactersCovered(); ccRun < ccStyle; ) {
+ for (int ccRun = 0, ccStyle = p.getCharactersCovered(); ccRun < ccStyle;) {
HSLFTextParagraph para = paragraphs.get(paraIdx);
List<HSLFTextRun> runs = para.getTextRuns();
trun = runs.get(runIdx);
int len = trun.getLength();
- if (ccRun+len <= ccStyle) {
+ if (ccRun + len <= ccStyle) {
ccRun += len;
} else {
String text = trun.getRawText();
- trun.setText(text.substring(0,ccStyle-ccRun));
+ trun.setText(text.substring(0, ccStyle - ccRun));
HSLFTextRun nextRun = new HSLFTextRun(para);
- nextRun.setText(text.substring(ccStyle-ccRun));
- runs.add(runIdx+1, nextRun);
+ nextRun.setText(text.substring(ccStyle - ccRun));
+ runs.add(runIdx + 1, nextRun);
- ccRun += ccStyle-ccRun;
+ ccRun += ccStyle - ccRun;
}
TextPropCollection pCopy = new TextPropCollection(0, TextPropType.character);
@@ -1151,7 +1129,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> { len = trun.getLength();
if (paraIdx == paragraphs.size()-1 && runIdx == runs.size()-1) {
- if (csIdx < charStyles.size()-1) {
+ if (csIdx < charStyles.size() - 1) {
// special case, empty trailing text run
HSLFTextRun nextRun = new HSLFTextRun(para);
nextRun.setText("");
@@ -1204,7 +1182,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> { len += trun.getLength();
}
para.setIndentLevel(p.getIndentLevel());
- ccPara += len+1;
+ ccPara += len + 1;
}
}
}
@@ -1237,6 +1215,6 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> { }
public EscherTextboxWrapper getTextboxWrapper() {
- return (EscherTextboxWrapper)_headerAtom.getParentRecord();
+ return (EscherTextboxWrapper) _headerAtom.getParentRecord();
}
}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java index 1e1dca888f..bb4f140415 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java @@ -17,7 +17,8 @@ package org.apache.poi.hslf.usermodel; -import static org.apache.poi.hslf.usermodel.HSLFTextParagraph.fetchOrAddTextProp; +import static org.apache.poi.hslf.usermodel.HSLFTextParagraph.setPropVal; +import static org.apache.poi.hslf.usermodel.HSLFTextParagraph.getPropVal; import java.awt.Color; @@ -132,39 +133,17 @@ public final class HSLFTextRun implements TextRun { * it if required. */ private void setCharFlagsTextPropVal(int index, boolean value) { - if(getFlag(index) != value) setFlag(index, value); + // TODO: check if paragraph/chars can be handled the same ... + if (getFlag(index) != value) setFlag(index, value); } /** - * Fetch the value of the given Character related TextProp. - * Returns -1 if that TextProp isn't present. - * If the TextProp isn't present, the value from the appropriate - * Master Sheet will apply. - */ - private int getCharTextPropVal(String propName) { - TextProp prop = null; - if (characterStyle != null){ - prop = characterStyle.findByName(propName); - } - - if (prop == null){ - HSLFSheet sheet = parentParagraph.getSheet(); - int txtype = parentParagraph.getRunType(); - HSLFMasterSheet master = sheet.getMasterSheet(); - if (master != null) - prop = master.getStyleAttribute(txtype, parentParagraph.getIndentLevel(), propName, true); - } - return prop == null ? -1 : prop.getValue(); - } - - /** * Sets the value of the given Paragraph TextProp, add if required * @param propName The name of the Paragraph TextProp * @param val The value to set for the TextProp */ public void setCharTextPropVal(String propName, int val) { - TextProp tp = fetchOrAddTextProp(characterStyle, propName); - tp.setValue(val); + setPropVal(characterStyle, propName, val); } @@ -260,8 +239,8 @@ public final class HSLFTextRun implements TextRun { * @return the percentage of the font size. If the value is positive, it is superscript, otherwise it is subscript */ public int getSuperscript() { - int val = getCharTextPropVal("superscript"); - return val == -1 ? 0 : val; + TextProp tp = getPropVal(characterStyle, "superscript", parentParagraph); + return tp == null ? 0 : tp.getValue(); } /** @@ -270,14 +249,15 @@ public final class HSLFTextRun implements TextRun { * @param val the percentage of the font size. If the value is positive, it is superscript, otherwise it is subscript */ public void setSuperscript(int val) { - setCharTextPropVal("superscript", val); + setPropVal(characterStyle, "superscript", val); } /** * Gets the font size */ - public double getFontSize() { - return getCharTextPropVal("font.size"); + public Double getFontSize() { + TextProp tp = getPropVal(characterStyle, "font.size", parentParagraph); + return tp == null ? null : (double)tp.getValue(); } @@ -292,7 +272,8 @@ public final class HSLFTextRun implements TextRun { * Gets the font index */ public int getFontIndex() { - return getCharTextPropVal("font.index"); + TextProp tp = getPropVal(characterStyle, "font.index", parentParagraph); + return tp == null ? -1 : tp.getValue(); } /** @@ -329,9 +310,9 @@ public final class HSLFTextRun implements TextRun { if (sheet == null || slideShow == null) { return _fontFamily; } - int fontIdx = getCharTextPropVal("font.index"); - if(fontIdx == -1) { return null; } - return slideShow.getFontCollection().getFontWithId(fontIdx); + TextProp tp = getPropVal(characterStyle, "font.index", parentParagraph); + if (tp == null) { return null; } + return slideShow.getFontCollection().getFontWithId(tp.getValue()); } /** @@ -339,7 +320,9 @@ public final class HSLFTextRun implements TextRun { * @see java.awt.Color */ public Color getFontColor() { - int rgb = getCharTextPropVal("font.color"); + TextProp tp = getPropVal(characterStyle, "font.color", parentParagraph); + if (tp == null) return null; + int rgb = tp.getValue(); int cidx = rgb >> 24; if (rgb % 0x1000000 == 0){ @@ -370,7 +353,7 @@ public final class HSLFTextRun implements TextRun { } protected void setFlag(int index, boolean value) { - BitMaskTextProp prop = (BitMaskTextProp) fetchOrAddTextProp(characterStyle, CharFlagsTextProp.NAME); + BitMaskTextProp prop = (BitMaskTextProp)characterStyle.addWithName(CharFlagsTextProp.NAME); prop.setSubValue(value, index); } diff --git a/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextParagraph.java b/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextParagraph.java index 3db3c6f6d0..d3c606a62d 100644 --- a/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextParagraph.java +++ b/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextParagraph.java @@ -55,12 +55,21 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable { double rightInset = insets.right;
double penY = y;
- double leftMargin = paragraph.getLeftMargin();
boolean firstLine = true;
- double indent = paragraph.getIndent();
+ Double leftMargin = paragraph.getLeftMargin();
+ Double indent = paragraph.getIndent();
+ if (leftMargin == null) {
+ leftMargin = (indent != null) ? -indent : 0;
+ }
+ if (indent == null) {
+ indent = (leftMargin != null) ? -leftMargin : 0;
+ }
+
//The vertical line spacing
- double spacing = paragraph.getLineSpacing();
+ Double spacing = paragraph.getLineSpacing();
+ if (spacing == null) spacing = 100d;
+
for(DrawTextFragment line : lines){
double penX = x + leftMargin;
@@ -77,7 +86,7 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable { bullet.setPosition(penX + indent, penY);
} else if(indent > 0){
// a positive value means the "First Line" indentation:
- // the first line is indented and other lines start at the bullet ofset
+ // the first line is indented and other lines start at the bullet offset
bullet.setPosition(penX, penY);
penX += indent;
} else {
@@ -96,7 +105,9 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable { Rectangle2D anchor = DrawShape.getAnchor(graphics, paragraph.getParentShape());
- switch (paragraph.getTextAlign()) {
+ TextAlign ta = paragraph.getTextAlign();
+ if (ta == null) ta = TextAlign.LEFT;
+ switch (ta) {
case CENTER:
penX += (anchor.getWidth() - leftMargin - line.getWidth() - leftInset - rightInset) / 2;
break;
@@ -219,9 +230,10 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable { if (buColor == null) buColor = (Color)firstLineAttr.getAttribute(TextAttribute.FOREGROUND);
float fontSize = (Float)firstLineAttr.getAttribute(TextAttribute.SIZE);
- float buSz = (float)bulletStyle.getBulletFontSize();
- if(buSz > 0) fontSize *= buSz* 0.01;
- else fontSize = -buSz;
+ Double buSz = bulletStyle.getBulletFontSize();
+ if (buSz == null) buSz = 100d;
+ if (buSz > 0) fontSize *= buSz* 0.01;
+ else fontSize = (float)-buSz;
AttributedString str = new AttributedString(buCharacter);
@@ -237,10 +249,13 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable { protected String getRenderableText(TextRun tr) {
StringBuilder buf = new StringBuilder();
TextCap cap = tr.getTextCap();
+ String tabs = null;
for (char c : tr.getRawText().toCharArray()) {
if(c == '\t') {
- // TODO: finish support for tabs
- buf.append(" ");
+ if (tabs == null) {
+ tabs = tab2space(tr);
+ }
+ buf.append(tabs);
continue;
}
@@ -255,6 +270,34 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable { return buf.toString();
}
+
+ /**
+ * Replace a tab with the effective number of white spaces.
+ */
+ private String tab2space(TextRun tr) {
+ AttributedString string = new AttributedString(" ");
+ String typeFace = tr.getFontFamily();
+ if (typeFace == null) typeFace = "Lucida Sans";
+ string.addAttribute(TextAttribute.FAMILY, typeFace);
+
+ Double fs = tr.getFontSize();
+ if (fs == null) fs = 12d;
+ string.addAttribute(TextAttribute.SIZE, fs.floatValue());
+
+ TextLayout l = new TextLayout(string.getIterator(), new FontRenderContext(null, true, true));
+ double wspace = l.getAdvance();
+
+ Double tabSz = paragraph.getDefaultTabSize();
+ if (tabSz == null) tabSz = wspace*4;
+
+ int numSpaces = (int)Math.ceil(tabSz / wspace);
+ StringBuilder buf = new StringBuilder();
+ for(int i = 0; i < numSpaces; i++) {
+ buf.append(' ');
+ }
+ return buf.toString();
+ }
+
/**
* Returns wrapping width to break lines in this paragraph
@@ -271,8 +314,14 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable { Rectangle2D anchor = DrawShape.getAnchor(graphics, paragraph.getParentShape());
- double leftMargin = paragraph.getLeftMargin();
- double indent = paragraph.getIndent();
+ Double leftMargin = paragraph.getLeftMargin();
+ Double indent = paragraph.getIndent();
+ if (leftMargin == null) {
+ leftMargin = (indent != null) ? -indent : 0;
+ }
+ if (indent == null) {
+ indent = (leftMargin != null) ? -leftMargin : 0;
+ }
double width;
TextShape<? extends TextParagraph<T>> ts = paragraph.getParentShape();
@@ -323,7 +372,9 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable { text.append(runText);
int endIndex = text.length();
- attList.add(new AttributedStringData(TextAttribute.FOREGROUND, run.getFontColor(), beginIndex, endIndex));
+ Color fgColor = run.getFontColor();
+ if (fgColor == null) fgColor = Color.BLACK;
+ attList.add(new AttributedStringData(TextAttribute.FOREGROUND, fgColor, beginIndex, endIndex));
// user can pass an custom object to convert fonts
String fontFamily = run.getFontFamily();
@@ -335,10 +386,14 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable { if(fontHandler != null) {
fontFamily = fontHandler.getRendererableFont(fontFamily, run.getPitchAndFamily());
}
+ if (fontFamily == null) {
+ fontFamily = paragraph.getDefaultFontFamily();
+ }
attList.add(new AttributedStringData(TextAttribute.FAMILY, fontFamily, beginIndex, endIndex));
- float fontSz = (float)run.getFontSize();
- attList.add(new AttributedStringData(TextAttribute.SIZE, fontSz, beginIndex, endIndex));
+ Double fontSz = run.getFontSize();
+ if (fontSz == null) fontSz = paragraph.getDefaultFontSize();
+ attList.add(new AttributedStringData(TextAttribute.SIZE, fontSz.floatValue(), beginIndex, endIndex));
if(run.isBold()) {
attList.add(new AttributedStringData(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, beginIndex, endIndex));
@@ -364,9 +419,9 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable { // ensure that the paragraph contains at least one character
// We need this trick to correctly measure text
if (text.length() == 0) {
- float fontSz = (float)paragraph.getDefaultFontSize();
+ Double fontSz = paragraph.getDefaultFontSize();
text.append(" ");
- attList.add(new AttributedStringData(TextAttribute.SIZE, fontSz, 0, 1));
+ attList.add(new AttributedStringData(TextAttribute.SIZE, fontSz.floatValue(), 0, 1));
}
AttributedString string = new AttributedString(text.toString());
diff --git a/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextShape.java b/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextShape.java index 247c7c1845..bb6c6dd29f 100644 --- a/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextShape.java +++ b/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextShape.java @@ -95,7 +95,8 @@ public class DrawTextShape<T extends TextShape<? extends TextParagraph<? extends if (!isFirstLine) {
// the amount of vertical white space before the paragraph
- double spaceBefore = p.getSpaceBefore();
+ Double spaceBefore = p.getSpaceBefore();
+ if (spaceBefore == null) spaceBefore = 0d;
if(spaceBefore > 0) {
// positive value means percentage spacing of the height of the first line, e.g.
// the higher the first line, the bigger the space before the paragraph
@@ -112,7 +113,8 @@ public class DrawTextShape<T extends TextShape<? extends TextParagraph<? extends y += dp.getY();
if (paragraphs.hasNext()) {
- double spaceAfter = p.getSpaceAfter();
+ Double spaceAfter = p.getSpaceAfter();
+ if (spaceAfter == null) spaceAfter = 0d;
if(spaceAfter > 0) {
// positive value means percentage spacing of the height of the last line, e.g.
// the higher the last line, the bigger the space after the paragraph
diff --git a/src/scratchpad/src/org/apache/poi/sl/usermodel/TextParagraph.java b/src/scratchpad/src/org/apache/poi/sl/usermodel/TextParagraph.java index 14eb03c842..e85eee140b 100644 --- a/src/scratchpad/src/org/apache/poi/sl/usermodel/TextParagraph.java +++ b/src/scratchpad/src/org/apache/poi/sl/usermodel/TextParagraph.java @@ -104,10 +104,18 @@ public interface TextParagraph<T extends TextRun> extends Iterable<T> { public interface BulletStyle {
String getBulletCharacter();
String getBulletFont();
- double getBulletFontSize();
+
+ /**
+ * The bullet point font size
+ * If bulletFontSize >= 0, then space is a percentage of normal line height.
+ * If bulletFontSize < 0, the absolute value in points
+ *
+ * @return the bullet point font size
+ */
+ Double getBulletFontSize();
Color getBulletFontColor();
}
-
+
/**
* The amount of vertical white space before the paragraph
* This may be specified in two different ways, percentage spacing and font point spacing:
@@ -116,9 +124,30 @@ public interface TextParagraph<T extends TextRun> extends Iterable<T> { * If spaceBefore < 0, the absolute value in points
* </p>
*
- * @return the vertical white space before the paragraph
+ * @return the vertical white space before the paragraph, or null if unset
*/
- double getSpaceBefore();
+ Double getSpaceBefore();
+
+ /**
+ * Set the amount of vertical white space that will be present before the paragraph.
+ * This space is specified in either percentage or points:
+ * <p>
+ * If spaceBefore >= 0, then space is a percentage of normal line height.
+ * If spaceBefore < 0, the absolute value of linespacing is the spacing in points
+ * </p>
+ * Examples:
+ * <pre><code>
+ * // The paragraph will be formatted to have a spacing before the paragraph text.
+ * // The spacing will be 200% of the size of the largest text on each line
+ * paragraph.setSpaceBefore(200);
+ *
+ * // The spacing will be a size of 48 points
+ * paragraph.setSpaceBefore(-48.0);
+ * </code></pre>
+ *
+ * @param spaceBefore the vertical white space before the paragraph, null to unset
+ */
+ void setSpaceBefore(Double spaceBefore);
/**
* The amount of vertical white space after the paragraph
@@ -128,40 +157,74 @@ public interface TextParagraph<T extends TextRun> extends Iterable<T> { * If spaceBefore < 0, the absolute value of linespacing is the spacing in points
* </p>
*
- * @return the vertical white space after the paragraph
+ * @return the vertical white space after the paragraph or null, if unset
*/
- double getSpaceAfter();
+ Double getSpaceAfter();
/**
- * @return the left margin (in points) of the paragraph
+ * Set the amount of vertical white space that will be present after the paragraph.
+ * This space is specified in either percentage or points:
+ * <p>
+ * If spaceAfter >= 0, then space is a percentage of normal line height.
+ * If spaceAfter < 0, the absolute value of linespacing is the spacing in points
+ * </p>
+ * Examples:
+ * <pre><code>
+ * // The paragraph will be formatted to have a spacing after the paragraph text.
+ * // The spacing will be 200% of the size of the largest text on each line
+ * paragraph.setSpaceAfter(200);
+ *
+ * // The spacing will be a size of 48 points
+ * paragraph.setSpaceAfter(-48.0);
+ * </code></pre>
+ *
+ * @param spaceAfter the vertical white space after the paragraph, null to unset
*/
- double getLeftMargin();
+ public void setSpaceAfter(Double spaceAfter);
+
+ /**
+ * @return the left margin (in points) of the paragraph or null, if unset
+ */
+ Double getLeftMargin();
/**
- * @param leftMargin the left margin (in points)
+ * Specifies the left margin of the paragraph. This is specified in addition to the text body
+ * inset and applies only to this text paragraph. That is the text body Inset and the LeftMargin
+ * attributes are additive with respect to the text position.
+ *
+ * @param leftMargin the left margin (in points) or null to unset
*/
- void setLeftMargin(double leftMargin);
+ void setLeftMargin(Double leftMargin);
/**
- * @return the right margin (in points) of the paragraph
+ * Specifies the right margin of the paragraph. This is specified in addition to the text body
+ * inset and applies only to this text paragraph. That is the text body Inset and the RightMargin
+ * attributes are additive with respect to the text position.
+ *
+ * The right margin is not support and therefore ignored by the HSLF implementation.
+ *
+ * @return the right margin (in points) of the paragraph or null, if unset
*/
- double getRightMargin();
+ Double getRightMargin();
/**
* @param rightMargin the right margin (in points) of the paragraph
*/
- void setRightMargin(double rightMargin);
+ void setRightMargin(Double rightMargin);
/**
* @return the indent (in points) applied to the first line of text in the paragraph.
+ * or null, if unset
*/
- double getIndent();
+ Double getIndent();
/**
+ * Specifies the indent size that will be applied to the first line of text in the paragraph.
+ *
* @param indent the indent (in points) applied to the first line of text in the paragraph
*/
- void setIndent(double indent);
+ void setIndent(Double indent);
/**
* Returns the vertical line spacing that is to be used within a paragraph.
@@ -171,9 +234,9 @@ public interface TextParagraph<T extends TextRun> extends Iterable<T> { * If linespacing < 0, the absolute value of linespacing is the spacing in points
* </p>
*
- * @return the vertical line spacing.
+ * @return the vertical line spacing or null, if unset
*/
- double getLineSpacing();
+ Double getLineSpacing();
/**
* This element specifies the vertical line spacing that is to be used within a paragraph.
@@ -196,14 +259,14 @@ public interface TextParagraph<T extends TextRun> extends Iterable<T> { *
* @param linespacing the vertical line spacing
*/
- void setLineSpacing(double lineSpacing);
+ void setLineSpacing(Double lineSpacing);
String getDefaultFontFamily();
/**
- * @return the default font size, in case its not set in the textrun
+ * @return the default font size, in case its not set in the textrun or null, if unset
*/
- double getDefaultFontSize();
+ Double getDefaultFontSize();
/**
* Returns the alignment that is applied to the paragraph.
@@ -217,8 +280,10 @@ public interface TextParagraph<T extends TextRun> extends Iterable<T> { /**
* Returns the font alignment that is applied to the paragraph.
*
- * If this attribute is omitted, then a value of auto (~ left) is implied.
- * @return ??? alignment that is applied to the paragraph
+ * If this attribute is omitted, then null is return,
+ * user code can imply the a value of {@link FontAlign#AUTO}
+ *
+ * @return alignment that is applied to the paragraph
*/
FontAlign getFontAlign();
@@ -227,5 +292,11 @@ public interface TextParagraph<T extends TextRun> extends Iterable<T> { */
BulletStyle getBulletStyle();
+ /**
+ * @return the default size for a tab character within this paragraph in points, null if unset
+ */
+ Double getDefaultTabSize();
+
+
TextShape<? extends TextParagraph<T>> getParentShape();
}
diff --git a/src/scratchpad/src/org/apache/poi/sl/usermodel/TextRun.java b/src/scratchpad/src/org/apache/poi/sl/usermodel/TextRun.java index 8ac40c1892..bc1652afe5 100644 --- a/src/scratchpad/src/org/apache/poi/sl/usermodel/TextRun.java +++ b/src/scratchpad/src/org/apache/poi/sl/usermodel/TextRun.java @@ -21,8 +21,6 @@ import java.awt.Color; /** * Some text. - * - * TODO - decide on how we do rich text stuff */ public interface TextRun { enum TextCap { @@ -31,13 +29,13 @@ public interface TextRun { ALL } - public String getRawText(); - public void setText(String text); + String getRawText(); + void setText(String text); TextCap getTextCap(); Color getFontColor(); - double getFontSize(); + Double getFontSize(); String getFontFamily(); boolean isBold(); diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestPicture.java b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestPicture.java index 8e5652fb81..4733999d49 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestPicture.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestPicture.java @@ -22,8 +22,7 @@ import static org.junit.Assert.*; import java.awt.*; import java.awt.image.BufferedImage; import java.io.*; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import javax.imageio.ImageIO; @@ -35,7 +34,6 @@ import org.apache.poi.sl.usermodel.Slide; import org.apache.poi.sl.usermodel.SlideShow; import org.apache.poi.util.JvmBugs; import org.apache.poi.xslf.usermodel.XMLSlideShow; -import org.junit.Ignore; import org.junit.Test; /** @@ -142,29 +140,43 @@ public final class TestPicture { @Test // @Ignore("Just for visual validation - antialiasing is different on various systems") public void bug54541() throws Exception { - String file = new String[]{ - "54542_cropped_bitmap.pptx", - "54541_cropped_bitmap.ppt", - "54541_cropped_bitmap2.ppt", - "sample_pptx_grouping_issues.pptx" - }[3]; - InputStream is = _slTests.openResourceAsStream(file); - SlideShow ss = file.endsWith("pptx") ? new XMLSlideShow(is) : new HSLFSlideShow(is); - is.close(); + String files[] = { +// "sample_pptx_grouping_issues.pptx", +// "54542_cropped_bitmap.pptx", +// "54541_cropped_bitmap.ppt", +// "54541_cropped_bitmap2.ppt", +// "alterman_security.ppt", + "alterman_security2.pptx", + }; + + BitSet pages = new BitSet(); + pages.set(2); - boolean debugOut = false; - Dimension pg = ss.getPageSize(); - int i=1; - for(Slide<?,?,?> slide : ss.getSlides()) { - if (debugOut) { - DummyGraphics2d graphics = new DummyGraphics2d(); - slide.draw(graphics); - } else { - BufferedImage img = new BufferedImage(pg.width, pg.height, BufferedImage.TYPE_INT_RGB); - Graphics2D graphics = img.createGraphics(); - fixFonts(graphics); - slide.draw(graphics); - ImageIO.write(img, "PNG", new File("test"+(i++)+"hslf.png")); + for (String file : files) { + InputStream is = _slTests.openResourceAsStream(file); + SlideShow ss = file.endsWith("pptx") ? new XMLSlideShow(is) : new HSLFSlideShow(is); + is.close(); + + boolean debugOut = false; + Dimension pg = ss.getPageSize(); + for (Slide<?,?,?> slide : ss.getSlides()) { + int slideNo = slide.getSlideNumber(); + if (!pages.get(slideNo-1)) { + if (pages.nextSetBit(slideNo-1) == -1) break; else continue; + } + if (debugOut) { + DummyGraphics2d graphics = new DummyGraphics2d(); + slide.draw(graphics); + } else { + BufferedImage img = new BufferedImage(pg.width, pg.height, BufferedImage.TYPE_INT_ARGB); + Graphics2D graphics = img.createGraphics(); + fixFonts(graphics); + slide.draw(graphics); + graphics.setColor(Color.BLACK); + graphics.setStroke(new BasicStroke(1)); + graphics.drawRect(0, 0, (int)pg.getWidth()-1, (int)pg.getHeight()-1); + ImageIO.write(img, "PNG", new File(file.replaceFirst(".pptx?", "-")+slideNo+".png")); + } } } } diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestRichTextRun.java b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestRichTextRun.java index 0468955eeb..b57e9f503c 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestRichTextRun.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestRichTextRun.java @@ -470,7 +470,7 @@ public final class TestRichTextRun { assertEquals(expected, HSLFTextParagraph.getRawText(txt.get(1))); assertEquals(4, txt.get(1).size()); rt = txt.get(1).get(0); - assertEquals('\u2022', rt.getBulletChar()); + assertEquals('\u2022', (char)rt.getBulletChar()); assertTrue(rt.isBullet()); @@ -486,7 +486,7 @@ public final class TestRichTextRun { assertEquals(4, txt.get(0).size()); rt = txt.get(0).get(0); assertTrue(rt.isBullet()); - assertEquals('\u2022', rt.getBulletChar()); + assertEquals('\u2022', (char)rt.getBulletChar()); expected = "I\u2019m a text box with user-defined\r" + @@ -495,7 +495,7 @@ public final class TestRichTextRun { assertEquals(2, txt.get(1).size()); rt = txt.get(1).get(0); assertTrue(rt.isBullet()); - assertEquals('\u263A', rt.getBulletChar()); + assertEquals('\u263A', (char)rt.getBulletChar()); } @Test @@ -513,8 +513,8 @@ public final class TestRichTextRun { HSLFTextRun tr = rt.getTextRuns().get(0); tr.setFontSize(42); rt.setBullet(true); - rt.setLeftMargin(50); - rt.setIndent(0); + rt.setLeftMargin(50d); + rt.setIndent(0d); rt.setBulletChar('\u263A'); slide.addShape(shape); @@ -522,7 +522,7 @@ public final class TestRichTextRun { assertEquals(true, rt.isBullet()); assertEquals(50.0, rt.getLeftMargin(), 0); assertEquals(0, rt.getIndent(), 0); - assertEquals('\u263A', rt.getBulletChar()); + assertEquals('\u263A', (char)rt.getBulletChar()); shape.setAnchor(new java.awt.Rectangle(50, 50, 500, 300)); slide.addShape(shape); @@ -541,7 +541,7 @@ public final class TestRichTextRun { assertEquals(true, rt.isBullet()); assertEquals(50.0, rt.getLeftMargin(), 0); assertEquals(0, rt.getIndent(), 0); - assertEquals('\u263A', rt.getBulletChar()); + assertEquals('\u263A', (char)rt.getBulletChar()); } @Test diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestTextRun.java b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestTextRun.java index 9dda9af244..c2f7ac9d08 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestTextRun.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestTextRun.java @@ -556,7 +556,7 @@ public final class TestTextRun { int i=0; for (List<HSLFTextParagraph> textParas : slide.getTextParagraphs()) { assertEquals("Arial", textParas.get(0).getTextRuns().get(0).getFontFamily()); - assertEquals(sizes[i++], (int)textParas.get(0).getTextRuns().get(0).getFontSize()); + assertEquals(sizes[i++], textParas.get(0).getTextRuns().get(0).getFontSize().intValue()); } } |