/**\r
* Returns the alignment that is applied to the paragraph.\r
*\r
- * If this attribute is omitted, then a value of left is implied.\r
- * @return ??? alignment that is applied to the paragraph\r
+ * If this attribute is omitted, then null is returned.\r
+ * User code can imply the value {@link TextAlign#LEFT} then.\r
+ *\r
+ * @return alignment that is applied to the paragraph\r
*/\r
public TextAlign getTextAlign(){\r
ParagraphPropertyFetcher<TextAlign> fetcher = new ParagraphPropertyFetcher<TextAlign>(getLevel()){\r
}\r
};\r
fetchParagraphProperty(fetcher);\r
- return fetcher.getValue() == null ? TextAlign.LEFT : fetcher.getValue();\r
+ return fetcher.getValue();\r
}\r
\r
/**\r
}\r
};\r
fetchParagraphProperty(fetcher);\r
- return fetcher.getValue() == null ? FontAlign.AUTO : fetcher.getValue();\r
+ return fetcher.getValue();\r
}\r
\r
/**\r
*\r
* @return the bullet size\r
*/\r
- public double getBulletFontSize(){\r
+ public Double getBulletFontSize(){\r
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){\r
public boolean fetch(CTTextParagraphProperties props){\r
if(props.isSetBuSzPct()){\r
}\r
};\r
fetchParagraphProperty(fetcher);\r
- return fetcher.getValue() == null ? 100 : fetcher.getValue();\r
+ return fetcher.getValue();\r
}\r
\r
/**\r
}\r
}\r
\r
- /**\r
- * Specifies the indent size that will be applied to the first line of text in the paragraph.\r
- *\r
- * @param value the indent in points. \r
- */\r
@Override\r
- public void setIndent(double value){\r
+ public void setIndent(Double indent){\r
+ if (indent == null && !_p.isSetPPr()) return;\r
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
- if(value == -1) {\r
+ if(indent == -1) {\r
if(pr.isSetIndent()) pr.unsetIndent();\r
} else {\r
- pr.setIndent(Units.toEMU(value));\r
+ pr.setIndent(Units.toEMU(indent));\r
}\r
}\r
\r
- /**\r
- *\r
- * @return the indent applied to the first line of text in the paragraph.\r
- */\r
@Override\r
- public double getIndent(){\r
+ public Double getIndent() {\r
\r
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){\r
public boolean fetch(CTTextParagraphProperties props){\r
};\r
fetchParagraphProperty(fetcher);\r
\r
- return fetcher.getValue() == null ? 0 : fetcher.getValue();\r
+ return fetcher.getValue();\r
}\r
\r
- /**\r
- * Specifies the left margin of the paragraph. This is specified in addition to the text body\r
- * inset and applies only to this text paragraph. That is the text body Inset and the LeftMargin\r
- * attributes are additive with respect to the text position.\r
- *\r
- * @param value the left margin (in points) of the paragraph\r
- */\r
@Override\r
- public void setLeftMargin(double value){\r
+ public void setLeftMargin(Double leftMargin){\r
+ if (leftMargin == null && !_p.isSetPPr()) return;\r
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
- if(value == -1) {\r
+ if (leftMargin == null) {\r
if(pr.isSetMarL()) pr.unsetMarL();\r
} else {\r
- pr.setMarL(Units.toEMU(value));\r
+ pr.setMarL(Units.toEMU(leftMargin));\r
}\r
\r
}\r
\r
/**\r
- * @return the left margin (in points) of the paragraph\r
+ * @return the left margin (in points) of the paragraph, null if unset\r
*/\r
@Override\r
- public double getLeftMargin(){\r
+ public Double getLeftMargin(){\r
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){\r
public boolean fetch(CTTextParagraphProperties props){\r
if(props.isSetMarL()){\r
};\r
fetchParagraphProperty(fetcher);\r
// if the marL attribute is omitted, then a value of 347663 is implied\r
- return fetcher.getValue() == null ? 0 : fetcher.getValue();\r
+ return fetcher.getValue();\r
}\r
\r
- /**\r
- * Specifies the right margin of the paragraph. This is specified in addition to the text body\r
- * inset and applies only to this text paragraph. That is the text body Inset and the RightMargin\r
- * attributes are additive with respect to the text position.\r
- *\r
- * @param value the right margin (in points) of the paragraph\r
- */\r
@Override\r
- public void setRightMargin(double value){\r
+ public void setRightMargin(Double rightMargin){\r
+ if (rightMargin == null && !_p.isSetPPr()) return;\r
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
- if(value == -1) {\r
+ if(rightMargin == -1) {\r
if(pr.isSetMarR()) pr.unsetMarR();\r
} else {\r
- pr.setMarR(Units.toEMU(value));\r
+ pr.setMarR(Units.toEMU(rightMargin));\r
}\r
}\r
\r
/**\r
*\r
- * @return the right margin of the paragraph\r
+ * @return the right margin of the paragraph, null if unset\r
*/\r
@Override\r
- public double getRightMargin(){\r
+ public Double getRightMargin(){\r
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){\r
public boolean fetch(CTTextParagraphProperties props){\r
if(props.isSetMarR()){\r
};\r
fetchParagraphProperty(fetcher);\r
// if the marL attribute is omitted, then a value of 347663 is implied\r
- return fetcher.getValue() == null ? 0 : fetcher.getValue();\r
+ return fetcher.getValue();\r
}\r
\r
- /**\r
- *\r
- * @return the default size for a tab character within this paragraph in points\r
- */\r
- public double getDefaultTabSize(){\r
+ @Override\r
+ public Double getDefaultTabSize(){\r
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){\r
public boolean fetch(CTTextParagraphProperties props){\r
if(props.isSetDefTabSz()){\r
}\r
};\r
fetchParagraphProperty(fetcher);\r
- return fetcher.getValue() == null ? 0 : fetcher.getValue();\r
+ return fetcher.getValue();\r
}\r
\r
public double getTabStop(final int idx){\r
}\r
\r
@Override\r
- public void setLineSpacing(double linespacing){\r
+ public void setLineSpacing(Double lineSpacing){\r
+ if (lineSpacing == null && !_p.isSetPPr()) return;\r
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
- CTTextSpacing spc = CTTextSpacing.Factory.newInstance();\r
- if(linespacing >= 0) spc.addNewSpcPct().setVal((int)(linespacing*1000));\r
- else spc.addNewSpcPts().setVal((int)(-linespacing*100));\r
- pr.setLnSpc(spc);\r
+ if(lineSpacing == null) {\r
+ if (pr.isSetLnSpc()) pr.unsetLnSpc();\r
+ } else {\r
+ CTTextSpacing spc = (pr.isSetLnSpc()) ? pr.getLnSpc() : pr.addNewLnSpc();\r
+ if (lineSpacing >= 0) {\r
+ (spc.isSetSpcPct() ? spc.getSpcPct() : spc.addNewSpcPct()).setVal((int)(lineSpacing*1000));\r
+ if (spc.isSetSpcPts()) spc.unsetSpcPts();\r
+ } else {\r
+ (spc.isSetSpcPts() ? spc.getSpcPts() : spc.addNewSpcPts()).setVal((int)(-lineSpacing*100));\r
+ if (spc.isSetSpcPct()) spc.unsetSpcPct();\r
+ }\r
+ }\r
}\r
\r
@Override\r
- public double getLineSpacing(){\r
+ public Double getLineSpacing(){\r
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){\r
public boolean fetch(CTTextParagraphProperties props){\r
if(props.isSetLnSpc()){\r
};\r
fetchParagraphProperty(fetcher);\r
\r
- double lnSpc = fetcher.getValue() == null ? 100 : fetcher.getValue();\r
- if(lnSpc > 0) {\r
+ Double lnSpc = fetcher.getValue();\r
+ if (lnSpc != null && lnSpc > 0) {\r
// check if the percentage value is scaled\r
CTTextNormalAutofit normAutofit = getParentShape().getTextBodyPr().getNormAutofit();\r
if(normAutofit != null) {\r
return lnSpc;\r
}\r
\r
- /**\r
- * Set the amount of vertical white space that will be present before the paragraph.\r
- * This space is specified in either percentage or points:\r
- * <p>\r
- * If spaceBefore >= 0, then space is a percentage of normal line height.\r
- * If spaceBefore < 0, the absolute value of linespacing is the spacing in points\r
- * </p>\r
- * Examples:\r
- * <pre><code>\r
- * // The paragraph will be formatted to have a spacing before the paragraph text.\r
- * // The spacing will be 200% of the size of the largest text on each line\r
- * paragraph.setSpaceBefore(200);\r
- *\r
- * // The spacing will be a size of 48 points\r
- * paragraph.setSpaceBefore(-48.0);\r
- * </code></pre>\r
- *\r
- * @param spaceBefore the vertical white space before the paragraph.\r
- */\r
- public void setSpaceBefore(double spaceBefore){\r
+ @Override\r
+ public void setSpaceBefore(Double spaceBefore){\r
+ if (spaceBefore == null && !_p.isSetPPr()) return;\r
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
CTTextSpacing spc = CTTextSpacing.Factory.newInstance();\r
if(spaceBefore >= 0) spc.addNewSpcPct().setVal((int)(spaceBefore*1000));\r
pr.setSpcBef(spc);\r
}\r
\r
- /**\r
- * The amount of vertical white space before the paragraph\r
- * This may be specified in two different ways, percentage spacing and font point spacing:\r
- * <p>\r
- * If spaceBefore >= 0, then space is a percentage of normal line height.\r
- * If spaceBefore < 0, the absolute value of linespacing is the spacing in points\r
- * </p>\r
- *\r
- * @return the vertical white space before the paragraph\r
- */\r
- public double getSpaceBefore(){\r
+ @Override\r
+ public Double getSpaceBefore(){\r
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){\r
public boolean fetch(CTTextParagraphProperties props){\r
if(props.isSetSpcBef()){\r
};\r
fetchParagraphProperty(fetcher);\r
\r
- double spcBef = fetcher.getValue() == null ? 0 : fetcher.getValue();\r
- return spcBef;\r
+ return fetcher.getValue();\r
}\r
\r
- /**\r
- * Set the amount of vertical white space that will be present after the paragraph.\r
- * This space is specified in either percentage or points:\r
- * <p>\r
- * If spaceAfter >= 0, then space is a percentage of normal line height.\r
- * If spaceAfter < 0, the absolute value of linespacing is the spacing in points\r
- * </p>\r
- * Examples:\r
- * <pre><code>\r
- * // The paragraph will be formatted to have a spacing after the paragraph text.\r
- * // The spacing will be 200% of the size of the largest text on each line\r
- * paragraph.setSpaceAfter(200);\r
- *\r
- * // The spacing will be a size of 48 points\r
- * paragraph.setSpaceAfter(-48.0);\r
- * </code></pre>\r
- *\r
- * @param spaceAfter the vertical white space after the paragraph.\r
- */\r
- public void setSpaceAfter(double spaceAfter){\r
+ @Override\r
+ public void setSpaceAfter(Double spaceAfter){\r
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
CTTextSpacing spc = CTTextSpacing.Factory.newInstance();\r
if(spaceAfter >= 0) spc.addNewSpcPct().setVal((int)(spaceAfter*1000));\r
pr.setSpcAft(spc);\r
}\r
\r
- /**\r
- * The amount of vertical white space after the paragraph\r
- * This may be specified in two different ways, percentage spacing and font point spacing:\r
- * <p>\r
- * If spaceBefore >= 0, then space is a percentage of normal line height.\r
- * If spaceBefore < 0, the absolute value of linespacing is the spacing in points\r
- * </p>\r
- *\r
- * @return the vertical white space after the paragraph\r
- */\r
- public double getSpaceAfter(){\r
+ @Override\r
+ public Double getSpaceAfter(){\r
ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){\r
public boolean fetch(CTTextParagraphProperties props){\r
if(props.isSetSpcAft()){\r
}\r
};\r
fetchParagraphProperty(fetcher);\r
- return fetcher.getValue() == null ? 0 : fetcher.getValue();\r
+ return fetcher.getValue();\r
}\r
\r
/**\r
*/\r
public void setLevel(int level){\r
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
-\r
pr.setLvl(level);\r
}\r
\r
*/\r
public int getLevel(){\r
CTTextParagraphProperties pr = _p.getPPr();\r
- if(pr == null) return 0;\r
-\r
- return pr.getLvl();\r
-\r
+ return (pr == null || !pr.isSetLvl()) ? 0 : pr.getLvl();\r
}\r
\r
/**\r
}\r
\r
\r
- CTTextParagraphProperties getDefaultMasterStyle(){\r
+ /* package */ CTTextParagraphProperties getDefaultMasterStyle(){\r
CTPlaceholder ph = _shape.getCTPlaceholder();\r
- String defaultStyleSelector;\r
- if(ph == null) defaultStyleSelector = "otherStyle"; // no placeholder means plain text box\r
- else {\r
- switch(ph.getType().intValue()){\r
- case STPlaceholderType.INT_TITLE:\r
- case STPlaceholderType.INT_CTR_TITLE:\r
- defaultStyleSelector = "titleStyle";\r
- break;\r
- case STPlaceholderType.INT_FTR:\r
- case STPlaceholderType.INT_SLD_NUM:\r
- case STPlaceholderType.INT_DT:\r
- defaultStyleSelector = "otherStyle";\r
- break;\r
- default:\r
- defaultStyleSelector = "bodyStyle";\r
- break;\r
- }\r
+ String defaultStyleSelector; \r
+ switch(ph == null ? -1 : ph.getType().intValue()) {\r
+ case STPlaceholderType.INT_TITLE:\r
+ case STPlaceholderType.INT_CTR_TITLE:\r
+ defaultStyleSelector = "titleStyle";\r
+ break;\r
+ case -1: // no placeholder means plain text box\r
+ case STPlaceholderType.INT_FTR:\r
+ case STPlaceholderType.INT_SLD_NUM:\r
+ case STPlaceholderType.INT_DT:\r
+ defaultStyleSelector = "otherStyle";\r
+ break;\r
+ default:\r
+ defaultStyleSelector = "bodyStyle";\r
+ break;\r
}\r
int level = getLevel();\r
\r
// wind up and find the root master sheet which must be slide master\r
XSLFSheet masterSheet = _shape.getSheet();\r
- while (masterSheet.getMasterSheet() != null){\r
- masterSheet = (XSLFSheet)masterSheet.getMasterSheet();\r
+ for (XSLFSheet m = masterSheet; m != null; m = (XSLFSheet)m.getMasterSheet()) {\r
+ masterSheet = m;\r
}\r
\r
- XmlObject[] o = masterSheet.getXmlObject().selectPath(\r
- "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " +\r
- "declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' " +\r
- ".//p:txStyles/p:" + defaultStyleSelector +"/a:lvl" +(level+1)+ "pPr");\r
- if (o.length == 1){\r
- return (CTTextParagraphProperties)o[0];\r
- } else {\r
- o = masterSheet.getXmlObject().selectPath(\r
- "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " +\r
- "declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' " +\r
- ".//p:notesStyle/a:lvl" +(level+1)+ "pPr");\r
- \r
- if (o.length == 1){\r
+ String nsDecl =\r
+ "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " +\r
+ "declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' ";\r
+ String xpaths[] = {\r
+ nsDecl+".//p:txStyles/p:" + defaultStyleSelector +"/a:lvl" +(level+1)+ "pPr",\r
+ nsDecl+".//p:notesStyle/a:lvl" +(level+1)+ "pPr"\r
+ };\r
+ XmlObject xo = masterSheet.getXmlObject();\r
+ for (String xpath : xpaths) {\r
+ XmlObject[] o = xo.selectPath(xpath);\r
+ if (o.length == 1) {\r
return (CTTextParagraphProperties)o[0];\r
}\r
- \r
- throw new IllegalArgumentException("Failed to fetch default style for " +\r
- defaultStyleSelector + " and level=" + level);\r
}\r
+ \r
+// for (CTTextBody txBody : (CTTextBody[])xo.selectPath(nsDecl+".//p:txBody")) {\r
+// CTTextParagraphProperties defaultPr = null, lastPr = null;\r
+// boolean hasLvl = false;\r
+// for (CTTextParagraph p : txBody.getPArray()) {\r
+// CTTextParagraphProperties pr = p.getPPr();\r
+// if (pr.isSetLvl()) {\r
+// hasLvl |= true;\r
+// lastPr = pr;\r
+// if (pr.getLvl() == level) return pr;\r
+// } else {\r
+// defaultPr = pr;\r
+// }\r
+// }\r
+// if (!hasLvl) continue;\r
+// if (level == 0 && defaultPr != null) return defaultPr;\r
+// if (lastPr != null) return lastPr;\r
+// break;\r
+// }\r
+// \r
+// String err = "Failed to fetch default style for " + defaultStyleSelector + " and level=" + level;\r
+// throw new IllegalArgumentException(err);\r
+ \r
+ return null;\r
}\r
\r
private <T> boolean fetchParagraphProperty(ParagraphPropertyFetcher<T> visitor){\r
}\r
\r
@Override\r
- public double getDefaultFontSize() {\r
+ public Double getDefaultFontSize() {\r
CTTextCharacterProperties endPr = _p.getEndParaRPr();\r
- return (endPr == null || !endPr.isSetSz()) ? 12 : (endPr.getSz() / 100);\r
+ return (endPr == null || !endPr.isSetSz()) ? 12 : (endPr.getSz() / 100.);\r
}\r
\r
@Override\r
}\r
\r
public BulletStyle getBulletStyle() {\r
+ if (!isBullet()) return null;\r
return new BulletStyle(){\r
public String getBulletCharacter() {\r
return XSLFTextParagraph.this.getBulletCharacter();\r
return XSLFTextParagraph.this.getBulletFont();\r
}\r
\r
- public double getBulletFontSize() {\r
+ public Double getBulletFontSize() {\r
return XSLFTextParagraph.this.getBulletFontSize();\r
}\r
\r
* This class represents a run of text in a powerpoint document. That\r
* run could be text on a sheet, or text in a note.\r
* It is only a very basic class for now\r
- *\r
+ * \r
* @author Nick Burch\r
*/\r
\r
/**\r
* How to align the text\r
*/\r
- /* package */ static final int AlignLeft = 0;\r
- /* package */ static final int AlignCenter = 1;\r
- /* package */ static final int AlignRight = 2;\r
- /* package */ static final int AlignJustify = 3;\r
-\r
+ /* package */static final int AlignLeft = 0;\r
+ /* package */static final int AlignCenter = 1;\r
+ /* package */static final int AlignRight = 2;\r
+ /* package */static final int AlignJustify = 3;\r
\r
// Note: These fields are protected to help with unit testing\r
- // Other classes shouldn't really go playing with them!\r
- private final TextHeaderAtom _headerAtom;\r
- private TextBytesAtom _byteAtom;\r
- private TextCharsAtom _charAtom;\r
- private final TextPropCollection _paragraphStyle = new TextPropCollection(1, TextPropType.paragraph);\r
+ // Other classes shouldn't really go playing with them!\r
+ private final TextHeaderAtom _headerAtom;\r
+ private TextBytesAtom _byteAtom;\r
+ private TextCharsAtom _charAtom;\r
+ private final TextPropCollection _paragraphStyle = new TextPropCollection(1, TextPropType.paragraph);\r
\r
protected TextRulerAtom _ruler;\r
- protected List<HSLFTextRun> _runs = new ArrayList<HSLFTextRun>();\r
- protected HSLFTextShape _parentShape;\r
+ protected final List<HSLFTextRun> _runs = new ArrayList<HSLFTextRun>();\r
+ protected HSLFTextShape _parentShape;\r
private HSLFSheet _sheet;\r
private int shapeId;\r
\r
- // private StyleTextPropAtom styleTextPropAtom;\r
- private StyleTextProp9Atom styleTextProp9Atom;\r
+ // private StyleTextPropAtom styleTextPropAtom;\r
+ private StyleTextProp9Atom styleTextProp9Atom;\r
\r
- /**\r
+ /**\r
* Constructs a Text Run from a Unicode text block.\r
* Either a {@link TextCharsAtom} or a {@link TextBytesAtom} needs to be provided.\r
- *\r
+ * \r
* @param tha the TextHeaderAtom that defines what's what\r
* @param tba the TextBytesAtom containing the text or null if {@link TextCharsAtom} is provided\r
* @param tca the TextCharsAtom containing the text or null if {@link TextBytesAtom} is provided\r
- */\r
+ */\r
/* package */ HSLFTextParagraph(\r
TextHeaderAtom tha,\r
TextBytesAtom tba,\r
TextCharsAtom tca\r
) {\r
- if (tha == null) {\r
- throw new IllegalArgumentException("TextHeaderAtom must be set.");\r
- }\r
- _headerAtom = tha;\r
+ if (tha == null) {\r
+ throw new IllegalArgumentException("TextHeaderAtom must be set.");\r
+ }\r
+ _headerAtom = tha;\r
_byteAtom = tba;\r
_charAtom = tca;\r
- }\r
+ }\r
\r
- /* package */ HSLFTextParagraph(HSLFTextParagraph other) {\r
+ /* package */HSLFTextParagraph(HSLFTextParagraph other) {\r
_headerAtom = other._headerAtom;\r
_byteAtom = other._byteAtom;\r
_charAtom = other._charAtom;\r
_paragraphStyle.copy(other._paragraphStyle);\r
}\r
\r
- public void addTextRun(HSLFTextRun run) {\r
- _runs.add(run);\r
- }\r
+ public void addTextRun(HSLFTextRun run) {\r
+ _runs.add(run);\r
+ }\r
\r
- /**\r
+ /**\r
* Fetch the rich text runs (runs of text with the same styling) that\r
* are contained within this block of text\r
- */\r
- public List<HSLFTextRun> getTextRuns() {\r
- return _runs;\r
- }\r
+ */\r
+ public List<HSLFTextRun> getTextRuns() {\r
+ return _runs;\r
+ }\r
\r
- public TextPropCollection getParagraphStyle() {\r
- return _paragraphStyle;\r
- }\r
+ public TextPropCollection getParagraphStyle() {\r
+ return _paragraphStyle;\r
+ }\r
\r
- public void setParagraphStyle(TextPropCollection paragraphStyle) {\r
- _paragraphStyle.copy(paragraphStyle);\r
- }\r
+ public void setParagraphStyle(TextPropCollection paragraphStyle) {\r
+ _paragraphStyle.copy(paragraphStyle);\r
+ }\r
\r
- /**\r
+ /**\r
* Supply the Sheet we belong to, which might have an assigned SlideShow\r
* Also passes it on to our child RichTextRuns\r
*/\r
- public void supplySheet(HSLFSheet sheet){\r
+ public void supplySheet(HSLFSheet sheet) {\r
this._sheet = sheet;\r
\r
if (_runs == null) return;\r
- for(HSLFTextRun rt : _runs) {\r
+ for (HSLFTextRun rt : _runs) {\r
rt.updateSheet();\r
}\r
- }\r
+ }\r
\r
- public HSLFSheet getSheet(){\r
+ public HSLFSheet getSheet() {\r
return this._sheet;\r
}\r
\r
/**\r
- * @return Shape ID\r
+ * @return Shape ID\r
*/\r
- protected int getShapeId(){\r
+ protected int getShapeId() {\r
return shapeId;\r
}\r
\r
/**\r
- * @param id Shape ID\r
+ * @param id Shape ID\r
*/\r
- protected void setShapeId(int id){\r
+ protected void setShapeId(int id) {\r
shapeId = id;\r
}\r
\r
/**\r
- * @return 0-based index of the text run in the SLWT container\r
+ * @return 0-based index of the text run in the SLWT container\r
*/\r
- protected int getIndex(){\r
+ protected int getIndex() {\r
return (_headerAtom != null) ? _headerAtom.getIndex() : -1;\r
}\r
\r
/**\r
* Sets the index of the paragraph in the SLWT container\r
- *\r
+ * \r
* @param index\r
*/\r
protected void setIndex(int index) {\r
}\r
\r
/**\r
- * Returns the type of the text, from the TextHeaderAtom.\r
- * Possible values can be seen from TextHeaderAtom\r
- * @see org.apache.poi.hslf.record.TextHeaderAtom\r
- */\r
+ * Returns the type of the text, from the TextHeaderAtom.\r
+ * Possible values can be seen from TextHeaderAtom\r
+ * @see org.apache.poi.hslf.record.TextHeaderAtom\r
+ */\r
public int getRunType() {\r
return (_headerAtom != null) ? _headerAtom.getTextType() : -1;\r
}\r
public void setRunType(int runType) {\r
if (_headerAtom != null) _headerAtom.setTextType(runType);\r
}\r
- \r
- \r
+\r
/**\r
* Is this Text Run one from a {@link PPDrawing}, or is it\r
* one from the {@link SlideListWithText}?\r
return (getIndex() == -1);\r
}\r
\r
- public TextRulerAtom getTextRuler(){\r
+ public TextRulerAtom getTextRuler() {\r
return _ruler;\r
\r
}\r
\r
- public TextRulerAtom createTextRuler(){\r
+ public TextRulerAtom createTextRuler() {\r
_ruler = getTextRuler();\r
if (_ruler == null) {\r
_ruler = TextRulerAtom.getParagraphInstance();\r
/**\r
* Returns records that make up the list of text paragraphs\r
* (there can be misc InteractiveInfo, TxInteractiveInfo and other records)\r
- *\r
+ * \r
* @return text run records\r
*/\r
- public Record[] getRecords(){\r
+ public Record[] getRecords() {\r
Record r[] = _headerAtom.getParentRecord().getChildRecords();\r
- return getRecords(r, new int[]{0}, _headerAtom);\r
+ return getRecords(r, new int[] { 0 }, _headerAtom);\r
}\r
\r
private static Record[] getRecords(Record[] records, int[] startIdx, TextHeaderAtom headerAtom) {\r
if (records == null) {\r
throw new NullPointerException("records need to be set.");\r
}\r
- \r
+\r
for (; startIdx[0] < records.length; startIdx[0]++) {\r
Record r = records[startIdx[0]];\r
if (r instanceof TextHeaderAtom && (headerAtom == null || r == headerAtom)) break;\r
logger.log(POILogger.INFO, "header atom wasn't found - container might contain only an OutlineTextRefAtom");\r
return new Record[0];\r
}\r
- \r
+\r
int length;\r
- for (length = 1; startIdx[0]+length < records.length; length++) {\r
+ for (length = 1; startIdx[0] + length < records.length; length++) {\r
if (records[startIdx[0]+length] instanceof TextHeaderAtom) break;\r
}\r
- \r
+\r
Record result[] = new Record[length];\r
System.arraycopy(records, startIdx[0], result, 0, length);\r
startIdx[0] += length;\r
- \r
+\r
return result;\r
}\r
- \r
- /** Numbered List info */\r
- public void setStyleTextProp9Atom(final StyleTextProp9Atom styleTextProp9Atom) {\r
- this.styleTextProp9Atom = styleTextProp9Atom;\r
- }\r
\r
/** Numbered List info */\r
- public StyleTextProp9Atom getStyleTextProp9Atom() {\r
- return this.styleTextProp9Atom;\r
- }\r
-\r
- /**\r
- * Fetch the value of the given Paragraph related TextProp.\r
- * Returns -1 if that TextProp isn't present.\r
- * If the TextProp isn't present, the value from the appropriate\r
- * Master Sheet will apply.\r
- */\r
- private int getParaTextPropVal(String propName) {\r
- TextProp prop = _paragraphStyle.findByName(propName);\r
- BitMaskTextProp maskProp = (BitMaskTextProp)_paragraphStyle.findByName(ParagraphFlagsTextProp.NAME);\r
- boolean hardAttribute = (maskProp != null && maskProp.getValue() == 0);\r
- if (prop == null && !hardAttribute){\r
- HSLFSheet sheet = getSheet();\r
- int txtype = getRunType();\r
- HSLFMasterSheet master = sheet.getMasterSheet();\r
- if (master != null)\r
- prop = master.getStyleAttribute(txtype, getIndentLevel(), propName, false);\r
- }\r
-\r
- return prop == null ? -1 : prop.getValue();\r
+ public void setStyleTextProp9Atom(final StyleTextProp9Atom styleTextProp9Atom) {\r
+ this.styleTextProp9Atom = styleTextProp9Atom;\r
}\r
\r
- /**\r
- * Sets the value of the given Character TextProp, add if required\r
- * @param propName The name of the Character TextProp\r
- * @param val The value to set for the TextProp\r
- */\r
- public void setParaTextPropVal(String propName, int val) {\r
- // Ensure we have the StyleTextProp atom we're going to need\r
- assert(_paragraphStyle!=null);\r
- TextProp tp = fetchOrAddTextProp(_paragraphStyle, propName);\r
- tp.setValue(val);\r
+ /** Numbered List info */\r
+ public StyleTextProp9Atom getStyleTextProp9Atom() {\r
+ return this.styleTextProp9Atom;\r
}\r
-\r
+ \r
@Override\r
public Iterator<HSLFTextRun> iterator() {\r
return _runs.iterator();\r
}\r
\r
@Override\r
- public double getLeftMargin() {\r
- int val = getParaTextPropVal("text.offset");\r
- return val*HSLFShape.POINT_DPI/((double)HSLFShape.MASTER_DPI);\r
+ public Double getLeftMargin() {\r
+ TextProp val = getPropVal(_paragraphStyle, "text.offset", this);\r
+ return (val == null) ? null : Units.masterToPoints(val.getValue());\r
}\r
\r
@Override\r
- public void setLeftMargin(double leftMargin) {\r
- int val = (int)(leftMargin*HSLFShape.MASTER_DPI/HSLFShape.POINT_DPI);\r
- setParaTextPropVal("text.offset", val);\r
+ public void setLeftMargin(Double leftMargin) {\r
+ Integer val = (leftMargin == null) ? null : Units.pointsToMaster(leftMargin);\r
+ setPropVal(_paragraphStyle, "text.offset", val);\r
}\r
\r
@Override\r
- public double getRightMargin() {\r
+ public Double getRightMargin() {\r
// TODO: find out, how to determine this value\r
- return 0;\r
+ return null;\r
}\r
\r
@Override\r
- public void setRightMargin(double rightMargin) {\r
+ public void setRightMargin(Double rightMargin) {\r
// TODO: find out, how to set this value\r
}\r
\r
@Override\r
- public double getIndent() {\r
- int val = getParaTextPropVal("bullet.offset");\r
- return val*HSLFShape.POINT_DPI/((double)HSLFShape.MASTER_DPI);\r
+ public Double getIndent() {\r
+ TextProp val = getPropVal(_paragraphStyle, "bullet.offset", this);\r
+ return (val == null) ? null : Units.masterToPoints(val.getValue());\r
}\r
\r
@Override\r
- public void setIndent(double intent) {\r
- int val = (int)(intent*HSLFShape.MASTER_DPI/HSLFShape.POINT_DPI);\r
- setParaTextPropVal("bullet.offset", val);\r
+ public void setIndent(Double indent) {\r
+ Integer val = (indent == null) ? null : Units.pointsToMaster(indent);\r
+ setPropVal(_paragraphStyle, "bullet.offset", val);\r
}\r
\r
@Override\r
public String getDefaultFontFamily() {\r
- return (_runs.isEmpty() ? "Arial" : _runs.get(0).getFontFamily());\r
+ String typeface = null;\r
+ if (!_runs.isEmpty()) {\r
+ typeface = _runs.get(0).getFontFamily();\r
+ }\r
+ return (typeface != null) ? typeface : "Arial";\r
}\r
\r
@Override\r
- public double getDefaultFontSize() {\r
- return (_runs.isEmpty() ? 12 : _runs.get(0).getFontSize());\r
+ public Double getDefaultFontSize() {\r
+ Double d = null;\r
+ if (!_runs.isEmpty()) {\r
+ d = _runs.get(0).getFontSize();\r
+ }\r
+ \r
+ return (d != null) ? d : 12d;\r
}\r
\r
/**\r
* Sets the type of horizontal alignment for the paragraph.\r
- *\r
+ * \r
* @param align - the type of alignment\r
*/\r
public void setAlignment(org.apache.poi.sl.usermodel.TextParagraph.TextAlign align) {\r
- int alignInt;\r
- switch (align) {\r
- default:\r
- case LEFT: alignInt = TextAlignmentProp.LEFT; break;\r
- case CENTER: alignInt = TextAlignmentProp.CENTER; break;\r
- case RIGHT: alignInt = TextAlignmentProp.RIGHT; break;\r
- case DIST: alignInt = TextAlignmentProp.DISTRIBUTED; break;\r
- case JUSTIFY: alignInt = TextAlignmentProp.JUSTIFY; break;\r
- case JUSTIFY_LOW: alignInt = TextAlignmentProp.JUSTIFYLOW; break;\r
- case THAI_DIST: alignInt = TextAlignmentProp.THAIDISTRIBUTED; break;\r
+ Integer alignInt = null;\r
+ if (align != null) switch (align) {\r
+ default:\r
+ case LEFT: alignInt = TextAlignmentProp.LEFT;break;\r
+ case CENTER: alignInt = TextAlignmentProp.CENTER; break;\r
+ case RIGHT: alignInt = TextAlignmentProp.RIGHT; break;\r
+ case DIST: alignInt = TextAlignmentProp.DISTRIBUTED; break;\r
+ case JUSTIFY: alignInt = TextAlignmentProp.JUSTIFY; break;\r
+ case JUSTIFY_LOW: alignInt = TextAlignmentProp.JUSTIFYLOW; break;\r
+ case THAI_DIST: alignInt = TextAlignmentProp.THAIDISTRIBUTED; break;\r
}\r
- setParaTextPropVal("alignment", alignInt);\r
+ setPropVal(_paragraphStyle, "alignment", alignInt);\r
}\r
\r
@Override\r
public org.apache.poi.sl.usermodel.TextParagraph.TextAlign getTextAlign() {\r
- switch (getParaTextPropVal("alignment")) {\r
+ TextProp tp = getPropVal(_paragraphStyle, "alignment", this);\r
+ if (tp == null) return null;\r
+ switch (tp.getValue()) {\r
default:\r
case TextAlignmentProp.LEFT: return TextAlign.LEFT;\r
case TextAlignmentProp.CENTER: return TextAlign.CENTER;\r
\r
@Override\r
public FontAlign getFontAlign() {\r
- switch(getParaTextPropVal("fontAlign")) {\r
- default:\r
- case -1: return FontAlign.AUTO;\r
+ TextProp tp = getPropVal(_paragraphStyle, FontAlignmentProp.NAME, this);\r
+ if (tp == null) return null;\r
+ \r
+ switch (tp.getValue()) {\r
case FontAlignmentProp.BASELINE: return FontAlign.BASELINE;\r
case FontAlignmentProp.TOP: return FontAlign.TOP;\r
case FontAlignmentProp.CENTER: return FontAlign.CENTER;\r
case FontAlignmentProp.BOTTOM: return FontAlign.BOTTOM;\r
+ default: return FontAlign.AUTO;\r
}\r
}\r
\r
@Override\r
public BulletStyle getBulletStyle() {\r
- if (getBulletChar() == 0) return null;\r
+ if (!isBullet()) return null;\r
\r
return new BulletStyle() {\r
public String getBulletCharacter() {\r
- char chr = HSLFTextParagraph.this.getBulletChar();\r
- return (chr == 0 ? "" : ""+chr);\r
+ Character chr = HSLFTextParagraph.this.getBulletChar();\r
+ return (chr == null || chr == 0) ? "" : "" + chr;\r
}\r
\r
public String getBulletFont() {\r
- int fontIdx = HSLFTextParagraph.this.getBulletFont();\r
- if (fontIdx == -1) return getDefaultFontFamily();\r
- PPFont ppFont = getSheet().getSlideShow().getFont(fontIdx);\r
- return ppFont.getFontName();\r
+ return HSLFTextParagraph.this.getBulletFont();\r
}\r
\r
- public double getBulletFontSize() {\r
+ public Double getBulletFontSize() {\r
return HSLFTextParagraph.this.getBulletSize();\r
}\r
\r
_parentShape = parentShape;\r
}\r
\r
+ /**\r
+ * \r
+ * @return indentation level\r
+ */\r
+ public int getIndentLevel() {\r
+ return _paragraphStyle == null ? 0 : _paragraphStyle.getIndentLevel();\r
+ }\r
\r
/**\r
- *\r
- * @return indentation level\r
- */\r
- public int getIndentLevel() {\r
- return _paragraphStyle == null ? 0 : _paragraphStyle.getIndentLevel();\r
- }\r
-\r
- /**\r
- * Sets indentation level\r
- *\r
+ * Sets indentation level\r
+ * \r
* @param level indentation level. Must be in the range [0, 4]\r
- */\r
- public void setIndentLevel(int level) {\r
+ */\r
+ public void setIndentLevel(int level) {\r
if( _paragraphStyle != null ) _paragraphStyle.setIndentLevel((short)level);\r
- }\r
-\r
- /**\r
- * Sets whether this rich text run has bullets\r
- */\r
- public void setBullet(boolean flag) {\r
- setFlag(ParagraphFlagsTextProp.BULLET_IDX, flag);\r
- }\r
-\r
- /**\r
- * Returns whether this rich text run has bullets\r
- */\r
- public boolean isBullet() {\r
- return getFlag(ParagraphFlagsTextProp.BULLET_IDX);\r
- }\r
-\r
- /**\r
- * Returns whether this rich text run has bullets\r
- */\r
- public boolean isBulletHard() {\r
- return getFlag(ParagraphFlagsTextProp.BULLET_IDX);\r
- }\r
-\r
- /**\r
- * Sets the bullet character\r
- */\r
- public void setBulletChar(char c) {\r
- setParaTextPropVal("bullet.char", c);\r
- }\r
-\r
- /**\r
- * Returns the bullet character\r
- */\r
- public char getBulletChar() {\r
- int val = getParaTextPropVal("bullet.char");\r
- return (char)(val == -1 ? 0 : val);\r
- }\r
-\r
- /**\r
- * Sets the bullet size\r
- */\r
- public void setBulletSize(int size) {\r
- setParaTextPropVal("bullet.size", size);\r
- }\r
-\r
- /**\r
- * Returns the bullet size\r
- */\r
- public int getBulletSize() {\r
- return getParaTextPropVal("bullet.size");\r
- }\r
-\r
- /**\r
- * Sets the bullet color\r
- */\r
- public void setBulletColor(Color color) {\r
- int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 254).getRGB();\r
- setParaTextPropVal("bullet.color", rgb);\r
- }\r
-\r
- /**\r
- * Returns the bullet color\r
- */\r
- public Color getBulletColor() {\r
- int rgb = getParaTextPropVal("bullet.color");\r
- if (rgb == -1) {\r
- // if bullet color is undefined, return color of first run\r
- if (_runs.isEmpty()) return null;\r
- return _runs.get(0).getFontColor();\r
- }\r
-\r
- int cidx = rgb >> 24;\r
- if (rgb % 0x1000000 == 0){\r
- if (_sheet == null) return null;\r
- ColorSchemeAtom ca = _sheet.getColorScheme();\r
- if(cidx >= 0 && cidx <= 7) rgb = ca.getColor(cidx);\r
- }\r
- Color tmp = new Color(rgb, true);\r
- return new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed());\r
- }\r
-\r
- /**\r
- * Sets the bullet font\r
- */\r
- public void setBulletFont(int idx) {\r
- setParaTextPropVal("bullet.font", idx);\r
- setFlag(ParagraphFlagsTextProp.BULLET_HARDFONT_IDX, true);\r
- }\r
-\r
- /**\r
- * Returns the bullet font\r
- */\r
- public int getBulletFont() {\r
- return getParaTextPropVal("bullet.font");\r
- }\r
-\r
- @Override\r
- public void setLineSpacing(double lineSpacing) {\r
- // if lineSpacing < 0, we need to convert points (common interface) to master units (hslf)\r
- if (lineSpacing < 0) {\r
- lineSpacing = (lineSpacing*HSLFShape.MASTER_DPI/HSLFShape.POINT_DPI);\r
- }\r
- setParaTextPropVal("linespacing", (int)lineSpacing);\r
- }\r
-\r
- @Override\r
- public double getLineSpacing() {\r
- double val = getParaTextPropVal("linespacing");\r
- // if lineSpacing < 0, we need to convert master units (hslf) to points (common interface)\r
- if (val == -1) return 0;\r
- if (val < -1) val *= HSLFShape.POINT_DPI/((double)HSLFShape.MASTER_DPI);\r
- return val;\r
- }\r
-\r
- /**\r
- * Sets spacing before a paragraph.\r
- * <p>\r
- * If spacebefore >= 0, then spacebefore is a percentage of normal line height.\r
- * If spacebefore < 0, the absolute value of spacebefore is the spacing in master coordinates.\r
- * </p>\r
- */\r
- public void setSpaceBefore(int val) {\r
- setParaTextPropVal("spacebefore", val);\r
- }\r
-\r
- /**\r
- * Returns spacing before a paragraph\r
- * <p>\r
- * If spacebefore >= 0, then spacebefore is a percentage of normal line height.\r
- * If spacebefore < 0, the absolute value of spacebefore is the spacing in master coordinates.\r
- * </p>\r
- *\r
- * @return the spacing before a paragraph\r
- */\r
- @Override\r
- public double getSpaceBefore() {\r
- int val = getParaTextPropVal("spacebefore");\r
- return val == -1 ? 0 : val;\r
- }\r
-\r
- /**\r
- * Sets spacing after a paragraph.\r
- * <p>\r
- * If spaceafter >= 0, then spaceafter is a percentage of normal line height.\r
- * If spaceafter < 0, the absolute value of spaceafter is the spacing in master coordinates.\r
- * </p>\r
- */\r
- public void setSpaceAfter(int val) {\r
- setParaTextPropVal("spaceafter", val);\r
- }\r
-\r
- /**\r
- * Returns spacing after a paragraph\r
- * <p>\r
- * If spaceafter >= 0, then spaceafter is a percentage of normal line height.\r
- * If spaceafter < 0, the absolute value of spaceafter is the spacing in master coordinates.\r
- * </p>\r
- *\r
- * @return the spacing before a paragraph\r
- */\r
- @Override\r
- public double getSpaceAfter() {\r
- int val = getParaTextPropVal("spaceafter");\r
- return val == -1 ? 0 : val;\r
- }\r
-\r
- /**\r
- * Returns the named TextProp, either by fetching it (if it exists) or adding it\r
- * (if it didn't)\r
- * @param textPropCol The TextPropCollection to fetch from / add into\r
- * @param textPropName The name of the TextProp to fetch/add\r
- */\r
- protected static TextProp fetchOrAddTextProp(TextPropCollection textPropCol, String textPropName) {\r
+ }\r
+\r
+ /**\r
+ * Sets whether this rich text run has bullets\r
+ */\r
+ public void setBullet(boolean flag) {\r
+ setFlag(ParagraphFlagsTextProp.BULLET_IDX, flag);\r
+ }\r
+\r
+ /**\r
+ * Returns whether this rich text run has bullets\r
+ */\r
+ public boolean isBullet() {\r
+ return getFlag(ParagraphFlagsTextProp.BULLET_IDX);\r
+ }\r
+\r
+ /**\r
+ * Sets the bullet character\r
+ */\r
+ public void setBulletChar(Character c) {\r
+ Integer val = (c == null) ? null : (int)c.charValue();\r
+ setPropVal(_paragraphStyle, "bullet.char", val);\r
+ }\r
+\r
+ /**\r
+ * Returns the bullet character\r
+ */\r
+ public Character getBulletChar() {\r
+ TextProp tp = getPropVal(_paragraphStyle, "bullet.char", this);\r
+ return (tp == null) ? null : (char)tp.getValue();\r
+ }\r
+\r
+ /**\r
+ * Sets the bullet size\r
+ */\r
+ public void setBulletSize(Double size) {\r
+ setPctOrPoints("bullet.size", size);\r
+ }\r
+\r
+ /**\r
+ * Returns the bullet size, null if unset\r
+ */\r
+ public Double getBulletSize() {\r
+ return getPctOrPoints("bullet.size");\r
+ }\r
+\r
+ /**\r
+ * Sets the bullet color\r
+ */\r
+ public void setBulletColor(Color color) {\r
+ Integer val = (color == null) ? null : new Color(color.getBlue(), color.getGreen(), color.getRed(), 254).getRGB();\r
+ setPropVal(_paragraphStyle, "bullet.color", val);\r
+ }\r
+\r
+ /**\r
+ * Returns the bullet color\r
+ */\r
+ public Color getBulletColor() {\r
+ TextProp tp = getPropVal(_paragraphStyle, "bullet.color", this);\r
+ if (tp == null) {\r
+ // if bullet color is undefined, return color of first run\r
+ return (_runs.isEmpty()) ? null : _runs.get(0).getFontColor();\r
+ }\r
+\r
+ int rgb = tp.getValue();\r
+ int cidx = rgb >> 24;\r
+ if (rgb % 0x1000000 == 0) {\r
+ if (_sheet == null)\r
+ return null;\r
+ ColorSchemeAtom ca = _sheet.getColorScheme();\r
+ if (cidx >= 0 && cidx <= 7)\r
+ rgb = ca.getColor(cidx);\r
+ }\r
+ Color tmp = new Color(rgb, true);\r
+ return new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed());\r
+ }\r
+\r
+ /**\r
+ * Sets the bullet font\r
+ */\r
+ public void setBulletFont(String typeface) {\r
+ if (typeface == null) {\r
+ setPropVal(_paragraphStyle, "bullet.font", null);\r
+ setFlag(ParagraphFlagsTextProp.BULLET_HARDFONT_IDX, false);\r
+ }\r
+\r
+ FontCollection fc = getSheet().getSlideShow().getFontCollection();\r
+ int idx = fc.addFont(typeface);\r
+\r
+ setPropVal(_paragraphStyle, "bullet.font", idx);\r
+ setFlag(ParagraphFlagsTextProp.BULLET_HARDFONT_IDX, true);\r
+ }\r
+\r
+ /**\r
+ * Returns the bullet font\r
+ */\r
+ public String getBulletFont() {\r
+ TextProp tp = getPropVal(_paragraphStyle, "bullet.font", this);\r
+ if (tp == null) return getDefaultFontFamily();\r
+ PPFont ppFont = getSheet().getSlideShow().getFont(tp.getValue());\r
+ assert(ppFont != null);\r
+ return ppFont.getFontName();\r
+ }\r
+\r
+ @Override\r
+ public void setLineSpacing(Double lineSpacing) {\r
+ setPctOrPoints("linespacing", lineSpacing);\r
+ }\r
+\r
+ @Override\r
+ public Double getLineSpacing() {\r
+ return getPctOrPoints("linespacing");\r
+ }\r
+\r
+ @Override\r
+ public void setSpaceBefore(Double spaceBefore) {\r
+ setPctOrPoints("spacebefore", spaceBefore);\r
+ }\r
+\r
+ @Override\r
+ public Double getSpaceBefore() {\r
+ return getPctOrPoints("spacebefore");\r
+ }\r
+\r
+ @Override\r
+ public void setSpaceAfter(Double spaceAfter) {\r
+ setPctOrPoints("spaceafter", spaceAfter);\r
+ }\r
+\r
+ @Override\r
+ public Double getSpaceAfter() {\r
+ return getPctOrPoints("spaceafter");\r
+ }\r
+\r
+ @Override\r
+ public Double getDefaultTabSize() {\r
+ // TODO: implement\r
+ return null;\r
+ }\r
+ \r
+ private Double getPctOrPoints(String propName) {\r
+ TextProp tp = getPropVal(_paragraphStyle, propName, this);\r
+ if (tp == null) return null;\r
+ int val = tp.getValue();\r
+ return (val < 0) ? Units.masterToPoints(val) : val;\r
+ }\r
+\r
+ private void setPctOrPoints(String propName, Double dval) {\r
+ Integer ival = null;\r
+ if (dval != null) {\r
+ ival = (dval < 0) ? Units.pointsToMaster(dval) : dval.intValue();\r
+ }\r
+ setPropVal(_paragraphStyle, propName, ival);\r
+ }\r
+ \r
+ private boolean getFlag(int index) {\r
+ BitMaskTextProp tp = (BitMaskTextProp)getPropVal(_paragraphStyle, ParagraphFlagsTextProp.NAME, this);\r
+ return (tp == null) ? false : tp.getSubValue(index);\r
+ }\r
+\r
+ private void setFlag(int index, boolean value) {\r
+ BitMaskTextProp tp = (BitMaskTextProp)_paragraphStyle.addWithName(ParagraphFlagsTextProp.NAME);\r
+ tp.setSubValue(value, index);\r
+ }\r
+\r
+ /**\r
+ * Fetch the value of the given Paragraph related TextProp. Returns null if\r
+ * that TextProp isn't present. If the TextProp isn't present, the value\r
+ * from the appropriate Master Sheet will apply.\r
+ */\r
+ protected static TextProp getPropVal(TextPropCollection props, String propName, HSLFTextParagraph paragraph) {\r
+ TextProp prop = props.findByName(propName);\r
+ if (prop != null) return prop;\r
+\r
+ BitMaskTextProp maskProp = (BitMaskTextProp) props.findByName(ParagraphFlagsTextProp.NAME);\r
+ boolean hardAttribute = (maskProp != null && maskProp.getValue() == 0);\r
+ if (hardAttribute) return null;\r
+\r
+ HSLFSheet sheet = paragraph.getSheet();\r
+ int txtype = paragraph.getRunType();\r
+ HSLFMasterSheet master = sheet.getMasterSheet();\r
+ if (master == null) {\r
+ logger.log(POILogger.WARN, "MasterSheet is not available");\r
+ return null;\r
+ }\r
+\r
+ boolean isChar = props.getTextPropType() == TextPropType.character;\r
+ return master.getStyleAttribute(txtype, paragraph.getIndentLevel(), propName, isChar);\r
+ }\r
+\r
+ /**\r
+ * Returns the named TextProp, either by fetching it (if it exists) or\r
+ * adding it (if it didn't)\r
+ * \r
+ * @param props the TextPropCollection to fetch from / add into\r
+ * @param name the name of the TextProp to fetch/add\r
+ * @param val the value, null if unset\r
+ */\r
+ protected static void setPropVal(TextPropCollection props, String name, Integer val) {\r
+ if (val == null) {\r
+ props.removeByName(name);\r
+ return;\r
+ }\r
+ \r
// Fetch / Add the TextProp\r
- return textPropCol.addWithName(textPropName);\r
+ TextProp tp = props.addWithName(name);\r
+ tp.setValue(val);\r
+ }\r
+ \r
+ /**\r
+ * Check and add linebreaks to text runs leading other paragraphs\r
+ * \r
+ * @param paragraphs\r
+ */\r
+ protected static void fixLineEndings(List<HSLFTextParagraph> paragraphs) {\r
+ HSLFTextRun lastRun = null;\r
+ for (HSLFTextParagraph p : paragraphs) {\r
+ if (lastRun != null && !lastRun.getRawText().endsWith("\r")) {\r
+ lastRun.setText(lastRun.getRawText() + "\r");\r
+ }\r
+ List<HSLFTextRun> ltr = p.getTextRuns();\r
+ if (ltr.isEmpty()) {\r
+ throw new RuntimeException("paragraph without textruns found");\r
+ }\r
+ lastRun = ltr.get(ltr.size() - 1);\r
+ assert (lastRun.getRawText() != null);\r
+ }\r
}\r
\r
- protected boolean getFlag(int index) {\r
- if (_paragraphStyle == null) return false;\r
+ /**\r
+ * Search for a StyleTextPropAtom is for this text header (list of paragraphs)\r
+ * \r
+ * @param header the header\r
+ * @param textLen the length of the rawtext, or -1 if the length is not known\r
+ */\r
+ private static StyleTextPropAtom findStyleAtomPresent(TextHeaderAtom header, int textLen) {\r
+ boolean afterHeader = false;\r
+ StyleTextPropAtom style = null;\r
+ for (Record record : header.getParentRecord().getChildRecords()) {\r
+ long rt = record.getRecordType();\r
+ if (afterHeader && rt == RecordTypes.TextHeaderAtom.typeID) {\r
+ // already on the next header, quit searching\r
+ break;\r
+ }\r
+ afterHeader |= (header == record);\r
+ if (afterHeader && rt == RecordTypes.StyleTextPropAtom.typeID) {\r
+ // found it\r
+ style = (StyleTextPropAtom) record;\r
+ }\r
+ }\r
+\r
+ if (style == null) {\r
+ logger.log(POILogger.INFO, "styles atom doesn't exist. Creating dummy record for later saving.");\r
+ style = new StyleTextPropAtom((textLen < 0) ? 1 : textLen);\r
+ } else {\r
+ if (textLen >= 0) {\r
+ style.setParentTextSize(textLen);\r
+ }\r
+ }\r
\r
- BitMaskTextProp prop = (BitMaskTextProp) _paragraphStyle.findByName(ParagraphFlagsTextProp.NAME);\r
+ return style;\r
+ }\r
\r
- if (prop == null) {\r
- if (_sheet != null) {\r
- int txtype = getRunType();\r
- HSLFMasterSheet master = _sheet.getMasterSheet();\r
- if (master != null) {\r
- prop = (BitMaskTextProp) master.getStyleAttribute(txtype, getIndentLevel(), ParagraphFlagsTextProp.NAME, false);\r
- }\r
+ /**\r
+ * Saves the modified paragraphs/textrun to the records.\r
+ * Also updates the styles to the correct text length.\r
+ */\r
+ protected static void storeText(List<HSLFTextParagraph> paragraphs) {\r
+ fixLineEndings(paragraphs);\r
+\r
+ String rawText = toInternalString(getRawText(paragraphs));\r
+\r
+ // Will it fit in a 8 bit atom?\r
+ boolean isUnicode = StringUtil.hasMultibyte(rawText);\r
+ // isUnicode = true;\r
+\r
+ TextHeaderAtom headerAtom = paragraphs.get(0)._headerAtom;\r
+ TextBytesAtom byteAtom = paragraphs.get(0)._byteAtom;\r
+ TextCharsAtom charAtom = paragraphs.get(0)._charAtom;\r
+ StyleTextPropAtom styleAtom = findStyleAtomPresent(headerAtom, rawText.length());\r
+\r
+ // Store in the appropriate record\r
+ Record oldRecord = null, newRecord = null;\r
+ if (isUnicode) {\r
+ if (byteAtom != null || charAtom == null) {\r
+ oldRecord = byteAtom;\r
+ charAtom = new TextCharsAtom();\r
+ }\r
+ newRecord = charAtom;\r
+ charAtom.setText(rawText);\r
+ } else {\r
+ if (charAtom != null || byteAtom == null) {\r
+ oldRecord = charAtom;\r
+ byteAtom = new TextBytesAtom();\r
+ }\r
+ newRecord = byteAtom;\r
+ byte[] byteText = new byte[rawText.length()];\r
+ StringUtil.putCompressedUnicode(rawText, byteText, 0);\r
+ byteAtom.setText(byteText);\r
+ }\r
+ assert (newRecord != null);\r
+\r
+ RecordContainer _txtbox = headerAtom.getParentRecord();\r
+ Record[] cr = _txtbox.getChildRecords();\r
+ int headerIdx = -1, textIdx = -1, styleIdx = -1;\r
+ for (int i = 0; i < cr.length; i++) {\r
+ Record r = cr[i];\r
+ if (r == headerAtom) headerIdx = i;\r
+ else if (r == oldRecord || r == newRecord) textIdx = i;\r
+ else if (r == styleAtom) styleIdx = i;\r
+ }\r
+\r
+ if (textIdx == -1) {\r
+ // the old record was never registered, ignore it\r
+ _txtbox.addChildAfter(newRecord, headerAtom);\r
+ textIdx = headerIdx + 1;\r
+ } else {\r
+ // swap not appropriated records - noop if unchanged\r
+ cr[textIdx] = newRecord;\r
+ }\r
+\r
+ if (styleIdx == -1) {\r
+ // Add the new StyleTextPropAtom after the TextCharsAtom / TextBytesAtom\r
+ _txtbox.addChildAfter(styleAtom, newRecord);\r
+ }\r
+\r
+ for (HSLFTextParagraph p : paragraphs) {\r
+ if (newRecord == byteAtom) {\r
+ p._byteAtom = byteAtom;\r
+ p._charAtom = null;\r
} else {\r
- logger.log(POILogger.WARN, "MasterSheet is not available");\r
+ p._byteAtom = null;\r
+ p._charAtom = charAtom;\r
+ }\r
+ }\r
+\r
+ // Update the text length for its Paragraph and Character stylings\r
+ // * reset the length, to the new string's length\r
+ // * add on +1 if the last block\r
+\r
+ styleAtom.clearStyles();\r
+\r
+ TextPropCollection lastPTPC = null, lastRTPC = null, ptpc = null, rtpc = null;\r
+ for (HSLFTextParagraph para : paragraphs) {\r
+ ptpc = para.getParagraphStyle();\r
+ ptpc.updateTextSize(0);\r
+ if (!ptpc.equals(lastPTPC)) {\r
+ lastPTPC = styleAtom.addParagraphTextPropCollection(0);\r
+ lastPTPC.copy(ptpc);\r
+ }\r
+ for (HSLFTextRun tr : para.getTextRuns()) {\r
+ rtpc = tr.getCharacterStyle();\r
+ rtpc.updateTextSize(0);\r
+ if (!rtpc.equals(lastRTPC)) {\r
+ lastRTPC = styleAtom.addCharacterTextPropCollection(0);\r
+ lastRTPC.copy(rtpc);\r
+ }\r
+ int len = tr.getLength();\r
+ ptpc.updateTextSize(ptpc.getCharactersCovered() + len);\r
+ rtpc.updateTextSize(len);\r
+ lastPTPC.updateTextSize(lastPTPC.getCharactersCovered() + len);\r
+ lastRTPC.updateTextSize(lastRTPC.getCharactersCovered() + len);\r
+ }\r
+ }\r
+\r
+ assert (lastPTPC != null && lastRTPC != null && ptpc != null && rtpc != null);\r
+ ptpc.updateTextSize(ptpc.getCharactersCovered() + 1);\r
+ rtpc.updateTextSize(rtpc.getCharactersCovered() + 1);\r
+ lastPTPC.updateTextSize(lastPTPC.getCharactersCovered() + 1);\r
+ lastRTPC.updateTextSize(lastRTPC.getCharactersCovered() + 1);\r
+\r
+ /**\r
+ * If TextSpecInfoAtom is present, we must update the text size in it,\r
+ * otherwise the ppt will be corrupted\r
+ */\r
+ for (Record r : paragraphs.get(0).getRecords()) {\r
+ if (r instanceof TextSpecInfoAtom) {\r
+ ((TextSpecInfoAtom) r).setParentSize(rawText.length() + 1);\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (_txtbox instanceof EscherTextboxWrapper) {\r
+ try {\r
+ ((EscherTextboxWrapper) _txtbox).writeOut(null);\r
+ } catch (IOException e) {\r
+ throw new RuntimeException("failed dummy write", e);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Adds the supplied text onto the end of the TextParagraphs,\r
+ * creating a new RichTextRun for it to sit in.\r
+ * \r
+ * @param text the text string used by this object.\r
+ */\r
+ protected static HSLFTextRun appendText(List<HSLFTextParagraph> paragraphs, String text, boolean newParagraph) {\r
+ text = toInternalString(text);\r
+\r
+ // check paragraphs\r
+ assert(!paragraphs.isEmpty() && !paragraphs.get(0).getTextRuns().isEmpty());\r
+\r
+ HSLFTextParagraph htp = paragraphs.get(paragraphs.size() - 1);\r
+ HSLFTextRun htr = htp.getTextRuns().get(htp.getTextRuns().size() - 1);\r
+\r
+ boolean isFirst = !newParagraph;\r
+ for (String rawText : text.split("(?<=\r)")) {\r
+ if (!isFirst) {\r
+ TextPropCollection tpc = htp.getParagraphStyle();\r
+ HSLFTextParagraph prevHtp = htp;\r
+ htp = new HSLFTextParagraph(htp._headerAtom, htp._byteAtom, htp._charAtom);\r
+ htp.getParagraphStyle().copy(tpc);\r
+ htp.setParentShape(prevHtp.getParentShape());\r
+ htp.setShapeId(prevHtp.getShapeId());\r
+ htp.supplySheet(prevHtp.getSheet());\r
+ paragraphs.add(htp);\r
+ }\r
+ isFirst = false;\r
+\r
+ TextPropCollection tpc = htr.getCharacterStyle();\r
+ // special case, last text run is empty, we will reuse it\r
+ if (htr.getLength() > 0) {\r
+ htr = new HSLFTextRun(htp);\r
+ htr.getCharacterStyle().copy(tpc);\r
+ htp.addTextRun(htr);\r
}\r
+ htr.setText(rawText);\r
}\r
\r
- return prop == null ? false : prop.getSubValue(index);\r
- }\r
-\r
- protected void setFlag(int index, boolean value) {\r
- // Ensure we have the StyleTextProp atom we're going to need\r
- assert(_paragraphStyle!=null);\r
- BitMaskTextProp prop = (BitMaskTextProp) fetchOrAddTextProp(_paragraphStyle, ParagraphFlagsTextProp.NAME);\r
- prop.setSubValue(value,index);\r
- }\r
-\r
- /**\r
- * Check and add linebreaks to text runs leading other paragraphs\r
- *\r
- * @param paragraphs\r
- */\r
- protected static void fixLineEndings(List<HSLFTextParagraph> paragraphs) {\r
- HSLFTextRun lastRun = null;\r
- for (HSLFTextParagraph p : paragraphs) {\r
- if (lastRun != null && !lastRun.getRawText().endsWith("\r")) {\r
- lastRun.setText(lastRun.getRawText()+"\r");\r
- }\r
- List<HSLFTextRun> ltr = p.getTextRuns();\r
- if (ltr.isEmpty()) {\r
- throw new RuntimeException("paragraph without textruns found");\r
- }\r
- lastRun = ltr.get(ltr.size()-1);\r
- assert(lastRun.getRawText() != null);\r
- }\r
- }\r
-\r
- /**\r
- * Search for a StyleTextPropAtom is for this text header (list of paragraphs)\r
- * \r
- * @param header the header\r
- * @param textLen the length of the rawtext, or -1 if the length is not known\r
- */\r
- private static StyleTextPropAtom findStyleAtomPresent(TextHeaderAtom header, int textLen) {\r
- boolean afterHeader = false;\r
- StyleTextPropAtom style = null;\r
- for (Record record : header.getParentRecord().getChildRecords()) {\r
- long rt = record.getRecordType();\r
- if (afterHeader && rt == RecordTypes.TextHeaderAtom.typeID) {\r
- // already on the next header, quit searching\r
- break;\r
- }\r
- afterHeader |= (header == record);\r
- if (afterHeader && rt == RecordTypes.StyleTextPropAtom.typeID) {\r
- // found it\r
- style = (StyleTextPropAtom)record;\r
- }\r
- }\r
-\r
- if (style == null) {\r
- logger.log(POILogger.INFO, "styles atom doesn't exist. Creating dummy record for later saving.");\r
- style = new StyleTextPropAtom((textLen < 0) ? 1 : textLen);\r
- } else {\r
- if (textLen >= 0) {\r
- style.setParentTextSize(textLen);\r
- }\r
- }\r
- \r
- return style;\r
- }\r
-\r
-\r
- /**\r
- * Saves the modified paragraphs/textrun to the records.\r
- * Also updates the styles to the correct text length.\r
- */\r
- protected static void storeText(List<HSLFTextParagraph> paragraphs) {\r
- fixLineEndings(paragraphs);\r
-\r
- String rawText = toInternalString(getRawText(paragraphs));\r
-\r
- // Will it fit in a 8 bit atom?\r
- boolean isUnicode = StringUtil.hasMultibyte(rawText);\r
- // isUnicode = true;\r
-\r
- TextHeaderAtom headerAtom = paragraphs.get(0)._headerAtom;\r
- TextBytesAtom byteAtom = paragraphs.get(0)._byteAtom;\r
- TextCharsAtom charAtom = paragraphs.get(0)._charAtom;\r
- StyleTextPropAtom styleAtom = findStyleAtomPresent(headerAtom, rawText.length());\r
-\r
- // Store in the appropriate record\r
- Record oldRecord = null, newRecord = null;\r
- if (isUnicode) {\r
- if (byteAtom != null || charAtom == null) {\r
- oldRecord = byteAtom;\r
- charAtom = new TextCharsAtom();\r
- }\r
- newRecord = charAtom;\r
- charAtom.setText(rawText);\r
- } else {\r
- if (charAtom != null || byteAtom == null) {\r
- oldRecord = charAtom;\r
- byteAtom = new TextBytesAtom();\r
- }\r
- newRecord = byteAtom;\r
- byte[] byteText = new byte[rawText.length()];\r
- StringUtil.putCompressedUnicode(rawText,byteText,0);\r
- byteAtom.setText(byteText);\r
- }\r
- assert(newRecord != null);\r
- \r
- RecordContainer _txtbox = headerAtom.getParentRecord();\r
- Record[] cr = _txtbox.getChildRecords();\r
- int headerIdx = -1, textIdx = -1, styleIdx = -1;\r
- for (int i=0; i<cr.length; i++) {\r
- Record r = cr[i];\r
- if (r == headerAtom) headerIdx = i;\r
- else if (r == oldRecord || r == newRecord) textIdx = i;\r
- else if (r == styleAtom) styleIdx = i;\r
- }\r
-\r
- if (textIdx == -1) {\r
- // the old record was never registered, ignore it\r
- _txtbox.addChildAfter(newRecord, headerAtom);\r
- textIdx = headerIdx+1;\r
- } else {\r
- // swap not appropriated records - noop if unchanged\r
- cr[textIdx] = newRecord;\r
- }\r
-\r
- if (styleIdx == -1) {\r
- // Add the new StyleTextPropAtom after the TextCharsAtom / TextBytesAtom\r
- _txtbox.addChildAfter(styleAtom, newRecord);\r
- }\r
- \r
- for (HSLFTextParagraph p : paragraphs) {\r
- if (newRecord == byteAtom) {\r
- p._byteAtom = byteAtom;\r
- p._charAtom = null;\r
- } else {\r
- p._byteAtom = null;\r
- p._charAtom = charAtom;\r
- }\r
- }\r
- \r
- // Update the text length for its Paragraph and Character stylings\r
- // * reset the length, to the new string's length\r
- // * add on +1 if the last block\r
-\r
- styleAtom.clearStyles();\r
-\r
- TextPropCollection lastPTPC = null, lastRTPC = null, ptpc = null, rtpc = null;\r
- for (HSLFTextParagraph para : paragraphs) {\r
- ptpc = para.getParagraphStyle();\r
- ptpc.updateTextSize(0);\r
- if (!ptpc.equals(lastPTPC)) {\r
- lastPTPC = styleAtom.addParagraphTextPropCollection(0);\r
- lastPTPC.copy(ptpc);\r
- }\r
- for (HSLFTextRun tr : para.getTextRuns()) {\r
- rtpc = tr.getCharacterStyle();\r
- rtpc.updateTextSize(0);\r
- if (!rtpc.equals(lastRTPC)) {\r
- lastRTPC = styleAtom.addCharacterTextPropCollection(0);\r
- lastRTPC.copy(rtpc);\r
- }\r
- int len = tr.getLength();\r
- ptpc.updateTextSize(ptpc.getCharactersCovered()+len);\r
- rtpc.updateTextSize(len);\r
- lastPTPC.updateTextSize(lastPTPC.getCharactersCovered()+len);\r
- lastRTPC.updateTextSize(lastRTPC.getCharactersCovered()+len);\r
- }\r
- }\r
-\r
- assert(lastPTPC != null && lastRTPC != null && ptpc != null && rtpc != null);\r
- ptpc.updateTextSize(ptpc.getCharactersCovered()+1);\r
- rtpc.updateTextSize(rtpc.getCharactersCovered()+1);\r
- lastPTPC.updateTextSize(lastPTPC.getCharactersCovered()+1);\r
- lastRTPC.updateTextSize(lastRTPC.getCharactersCovered()+1);\r
-\r
- /**\r
- * If TextSpecInfoAtom is present, we must update the text size in it,\r
- * otherwise the ppt will be corrupted\r
- */\r
- for (Record r : paragraphs.get(0).getRecords()) {\r
- if (r instanceof TextSpecInfoAtom) {\r
- ((TextSpecInfoAtom)r).setParentSize(rawText.length()+1);\r
- break;\r
- }\r
- }\r
- \r
- if (_txtbox instanceof EscherTextboxWrapper) {\r
- try {\r
- ((EscherTextboxWrapper)_txtbox).writeOut(null);\r
- } catch (IOException e) {\r
- throw new RuntimeException("failed dummy write", e);\r
- }\r
- }\r
- }\r
-\r
- /**\r
- * Adds the supplied text onto the end of the TextParagraphs,\r
- * creating a new RichTextRun for it to sit in.\r
- *\r
- * @param text the text string used by this object.\r
- */\r
- protected static HSLFTextRun appendText(List<HSLFTextParagraph> paragraphs, String text, boolean newParagraph) {\r
- text = toInternalString(text);\r
-\r
- // check paragraphs\r
- assert(!paragraphs.isEmpty() && !paragraphs.get(0).getTextRuns().isEmpty());\r
-\r
- HSLFTextParagraph htp = paragraphs.get(paragraphs.size()-1);\r
- HSLFTextRun htr = htp.getTextRuns().get(htp.getTextRuns().size()-1);\r
-\r
- boolean isFirst = !newParagraph;\r
- for (String rawText : text.split("(?<=\r)")) {\r
- if (!isFirst) {\r
- TextPropCollection tpc = htp.getParagraphStyle();\r
- HSLFTextParagraph prevHtp = htp;\r
- htp = new HSLFTextParagraph(htp._headerAtom, htp._byteAtom, htp._charAtom);\r
- htp.getParagraphStyle().copy(tpc);\r
- htp.setParentShape(prevHtp.getParentShape());\r
- htp.setShapeId(prevHtp.getShapeId());\r
- htp.supplySheet(prevHtp.getSheet());\r
- paragraphs.add(htp);\r
- }\r
- isFirst = false;\r
- \r
- TextPropCollection tpc = htr.getCharacterStyle();\r
- // special case, last text run is empty, we will reuse it\r
- if (htr.getLength() > 0) {\r
- htr = new HSLFTextRun(htp);\r
- htr.getCharacterStyle().copy(tpc);\r
- htp.addTextRun(htr);\r
- }\r
- htr.setText(rawText);\r
- }\r
- \r
- storeText(paragraphs);\r
-\r
- return htr;\r
- }\r
-\r
- /**\r
- * Sets (overwrites) the current text.\r
- * Uses the properties of the first paragraph / textrun\r
- *\r
- * @param text the text string used by this object.\r
- */\r
- public static HSLFTextRun setText(List<HSLFTextParagraph> paragraphs, String text) {\r
- // check paragraphs\r
- assert(!paragraphs.isEmpty() && !paragraphs.get(0).getTextRuns().isEmpty());\r
-\r
- Iterator<HSLFTextParagraph> paraIter = paragraphs.iterator();\r
- HSLFTextParagraph htp = paraIter.next(); // keep first\r
- assert(htp != null);\r
- while (paraIter.hasNext()) {\r
- paraIter.next();\r
- paraIter.remove();\r
- }\r
-\r
- Iterator<HSLFTextRun> runIter = htp.getTextRuns().iterator();\r
- HSLFTextRun htr = runIter.next();\r
- htr.setText("");\r
- assert(htr != null);\r
- while (runIter.hasNext()) {\r
- runIter.next();\r
- runIter.remove();\r
- }\r
-\r
- return appendText(paragraphs, text, false);\r
- }\r
-\r
- public static String getText(List<HSLFTextParagraph> paragraphs) {\r
- assert(!paragraphs.isEmpty());\r
- String rawText = getRawText(paragraphs);\r
- return toExternalString(rawText, paragraphs.get(0).getRunType());\r
- }\r
- \r
- public static String getRawText(List<HSLFTextParagraph> paragraphs) {\r
- StringBuilder sb = new StringBuilder();\r
- for (HSLFTextParagraph p : paragraphs) {\r
- for (HSLFTextRun r : p.getTextRuns()) {\r
- sb.append(r.getRawText());\r
- }\r
- }\r
- return sb.toString();\r
- }\r
-\r
- /**\r
- * Returns a new string with line breaks converted into internal ppt\r
- * representation\r
- */\r
- protected static String toInternalString(String s) {\r
- String ns = s.replaceAll("\\r?\\n", "\r");\r
- return ns;\r
- }\r
-\r
- /**\r
- * Converts raw text from the text paragraphs to a formatted string,\r
- * i.e. it converts certain control characters used in the raw txt\r
- *\r
- * @param rawText the raw text\r
- * @param runType the run type of the shape, paragraph or headerAtom.\r
- * use -1 if unknown\r
- * @return the formatted string\r
- */\r
- public static String toExternalString(String rawText, int runType) {\r
- // PowerPoint seems to store files with \r as the line break\r
- // The messes things up on everything but a Mac, so translate\r
- // them to \n\r
- String text = rawText.replace('\r', '\n');\r
-\r
- switch (runType) {\r
- // 0xB acts like cariage return in page titles and like blank in the\r
- // others\r
- case -1:\r
- case org.apache.poi.hslf.record.TextHeaderAtom.TITLE_TYPE:\r
- case org.apache.poi.hslf.record.TextHeaderAtom.CENTER_TITLE_TYPE:\r
- text = text.replace((char) 0x0B, '\n');\r
- break;\r
- default:\r
- text = text.replace((char) 0x0B, ' ');\r
- break;\r
- }\r
-\r
- return text;\r
- }\r
-\r
- /**\r
- * For a given PPDrawing, grab all the TextRuns\r
- */\r
+ storeText(paragraphs);\r
+\r
+ return htr;\r
+ }\r
+\r
+ /**\r
+ * Sets (overwrites) the current text.\r
+ * Uses the properties of the first paragraph / textrun\r
+ * \r
+ * @param text the text string used by this object.\r
+ */\r
+ public static HSLFTextRun setText(List<HSLFTextParagraph> paragraphs, String text) {\r
+ // check paragraphs\r
+ assert(!paragraphs.isEmpty() && !paragraphs.get(0).getTextRuns().isEmpty());\r
+\r
+ Iterator<HSLFTextParagraph> paraIter = paragraphs.iterator();\r
+ HSLFTextParagraph htp = paraIter.next(); // keep first\r
+ assert (htp != null);\r
+ while (paraIter.hasNext()) {\r
+ paraIter.next();\r
+ paraIter.remove();\r
+ }\r
+\r
+ Iterator<HSLFTextRun> runIter = htp.getTextRuns().iterator();\r
+ HSLFTextRun htr = runIter.next();\r
+ htr.setText("");\r
+ assert (htr != null);\r
+ while (runIter.hasNext()) {\r
+ runIter.next();\r
+ runIter.remove();\r
+ }\r
+\r
+ return appendText(paragraphs, text, false);\r
+ }\r
+\r
+ public static String getText(List<HSLFTextParagraph> paragraphs) {\r
+ assert (!paragraphs.isEmpty());\r
+ String rawText = getRawText(paragraphs);\r
+ return toExternalString(rawText, paragraphs.get(0).getRunType());\r
+ }\r
+\r
+ public static String getRawText(List<HSLFTextParagraph> paragraphs) {\r
+ StringBuilder sb = new StringBuilder();\r
+ for (HSLFTextParagraph p : paragraphs) {\r
+ for (HSLFTextRun r : p.getTextRuns()) {\r
+ sb.append(r.getRawText());\r
+ }\r
+ }\r
+ return sb.toString();\r
+ }\r
+\r
+ /**\r
+ * Returns a new string with line breaks converted into internal ppt\r
+ * representation\r
+ */\r
+ protected static String toInternalString(String s) {\r
+ String ns = s.replaceAll("\\r?\\n", "\r");\r
+ return ns;\r
+ }\r
+\r
+ /**\r
+ * Converts raw text from the text paragraphs to a formatted string,\r
+ * i.e. it converts certain control characters used in the raw txt\r
+ * \r
+ * @param rawText the raw text\r
+ * @param runType the run type of the shape, paragraph or headerAtom.\r
+ * use -1 if unknown\r
+ * @return the formatted string\r
+ */\r
+ public static String toExternalString(String rawText, int runType) {\r
+ // PowerPoint seems to store files with \r as the line break\r
+ // The messes things up on everything but a Mac, so translate\r
+ // them to \n\r
+ String text = rawText.replace('\r', '\n');\r
+\r
+ switch (runType) {\r
+ // 0xB acts like cariage return in page titles and like blank in the\r
+ // others\r
+ case -1:\r
+ case org.apache.poi.hslf.record.TextHeaderAtom.TITLE_TYPE:\r
+ case org.apache.poi.hslf.record.TextHeaderAtom.CENTER_TITLE_TYPE:\r
+ text = text.replace((char) 0x0B, '\n');\r
+ break;\r
+ default:\r
+ text = text.replace((char) 0x0B, ' ');\r
+ break;\r
+ }\r
+\r
+ return text;\r
+ }\r
+\r
+ /**\r
+ * For a given PPDrawing, grab all the TextRuns\r
+ */\r
public static List<List<HSLFTextParagraph>> findTextParagraphs(PPDrawing ppdrawing, HSLFSheet sheet) {\r
- List<List<HSLFTextParagraph>> runsV = new ArrayList<List<HSLFTextParagraph>>();\r
- for (EscherTextboxWrapper wrapper : ppdrawing.getTextboxWrappers()) {\r
- runsV.add(findTextParagraphs(wrapper, sheet));\r
- }\r
- return runsV;\r
- }\r
-\r
- /**\r
- * Scans through the supplied record array, looking for\r
- * a TextHeaderAtom followed by one of a TextBytesAtom or\r
- * a TextCharsAtom. Builds up TextRuns from these\r
- *\r
- * @param wrapper an EscherTextboxWrapper\r
- */\r
- protected static List<HSLFTextParagraph> findTextParagraphs(EscherTextboxWrapper wrapper, HSLFSheet sheet) {\r
- // propagate parents to parent-aware records\r
- RecordContainer.handleParentAwareRecords(wrapper);\r
- int shapeId = wrapper.getShapeId();\r
- List<HSLFTextParagraph> rv = null;\r
- \r
- OutlineTextRefAtom ota = (OutlineTextRefAtom)wrapper.findFirstOfType(OutlineTextRefAtom.typeID);\r
- if (ota != null) {\r
- // if we are based on an outline, there are no further records to be parsed from the wrapper\r
- if (sheet == null) {\r
- throw new RuntimeException("Outline atom reference can't be solved without a sheet record");\r
- }\r
- \r
- List<List<HSLFTextParagraph>> sheetRuns = sheet.getTextParagraphs();\r
- assert(sheetRuns != null);\r
- \r
- int idx = ota.getTextIndex();\r
- for (List<HSLFTextParagraph> r : sheetRuns) {\r
- if (r.isEmpty()) continue;\r
- int ridx = r.get(0).getIndex();\r
- if (ridx > idx) break;\r
- if (ridx == idx) {\r
- if (rv == null) {\r
- rv = r;\r
- } else {\r
- // create a new container\r
- // TODO: ... is this case really happening?\r
- rv = new ArrayList<HSLFTextParagraph>(rv);\r
- rv.addAll(r);\r
- }\r
- }\r
- }\r
- if(rv == null || rv.isEmpty()) {\r
- logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx);\r
- }\r
- } else {\r
- if (sheet != null) {\r
- // check sheet runs first, so we get exactly the same paragraph list\r
- List<List<HSLFTextParagraph>> sheetRuns = sheet.getTextParagraphs();\r
- assert(sheetRuns != null);\r
-\r
- for (List<HSLFTextParagraph> paras : sheetRuns) {\r
+ List<List<HSLFTextParagraph>> runsV = new ArrayList<List<HSLFTextParagraph>>();\r
+ for (EscherTextboxWrapper wrapper : ppdrawing.getTextboxWrappers()) {\r
+ runsV.add(findTextParagraphs(wrapper, sheet));\r
+ }\r
+ return runsV;\r
+ }\r
+\r
+ /**\r
+ * Scans through the supplied record array, looking for\r
+ * a TextHeaderAtom followed by one of a TextBytesAtom or\r
+ * a TextCharsAtom. Builds up TextRuns from these\r
+ * \r
+ * @param wrapper an EscherTextboxWrapper\r
+ */\r
+ protected static List<HSLFTextParagraph> findTextParagraphs(EscherTextboxWrapper wrapper, HSLFSheet sheet) {\r
+ // propagate parents to parent-aware records\r
+ RecordContainer.handleParentAwareRecords(wrapper);\r
+ int shapeId = wrapper.getShapeId();\r
+ List<HSLFTextParagraph> rv = null;\r
+\r
+ OutlineTextRefAtom ota = (OutlineTextRefAtom)wrapper.findFirstOfType(OutlineTextRefAtom.typeID);\r
+ if (ota != null) {\r
+ // if we are based on an outline, there are no further records to be parsed from the wrapper\r
+ if (sheet == null) {\r
+ throw new RuntimeException("Outline atom reference can't be solved without a sheet record");\r
+ }\r
+\r
+ List<List<HSLFTextParagraph>> sheetRuns = sheet.getTextParagraphs();\r
+ assert (sheetRuns != null);\r
+\r
+ int idx = ota.getTextIndex();\r
+ for (List<HSLFTextParagraph> r : sheetRuns) {\r
+ if (r.isEmpty()) continue;\r
+ int ridx = r.get(0).getIndex();\r
+ if (ridx > idx) break;\r
+ if (ridx == idx) {\r
+ if (rv == null) {\r
+ rv = r;\r
+ } else {\r
+ // create a new container\r
+ // TODO: ... is this case really happening?\r
+ rv = new ArrayList<HSLFTextParagraph>(rv);\r
+ rv.addAll(r);\r
+ }\r
+ }\r
+ }\r
+ if (rv == null || rv.isEmpty()) {\r
+ logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx);\r
+ }\r
+ } else {\r
+ if (sheet != null) {\r
+ // check sheet runs first, so we get exactly the same paragraph list\r
+ List<List<HSLFTextParagraph>> sheetRuns = sheet.getTextParagraphs();\r
+ assert (sheetRuns != null);\r
+\r
+ for (List<HSLFTextParagraph> paras : sheetRuns) {\r
if (!paras.isEmpty() && paras.get(0)._headerAtom.getParentRecord() == wrapper) {\r
- rv = paras;\r
- break;\r
- }\r
- }\r
- }\r
- \r
- if (rv == null) {\r
- // if we haven't found the wrapper in the sheet runs, create a new paragraph list from its record\r
- List<List<HSLFTextParagraph>> rvl = findTextParagraphs(wrapper.getChildRecords());\r
- switch (rvl.size()) {\r
- case 0: break; // nothing found\r
- case 1: rv = rvl.get(0); break; // normal case\r
- default:\r
- throw new RuntimeException("TextBox contains more than one list of paragraphs.");\r
- }\r
- }\r
- }\r
- \r
- if (rv != null) {\r
- StyleTextProp9Atom styleTextProp9Atom = wrapper.getStyleTextProp9Atom();\r
- \r
- for (HSLFTextParagraph htp : rv) {\r
- htp.setShapeId(shapeId);\r
- htp.setStyleTextProp9Atom(styleTextProp9Atom);\r
- }\r
- }\r
- return rv;\r
- }\r
-\r
- /**\r
- * Scans through the supplied record array, looking for\r
- * a TextHeaderAtom followed by one of a TextBytesAtom or\r
- * a TextCharsAtom. Builds up TextRuns from these\r
- *\r
- * @param records the records to build from\r
- */\r
+ rv = paras;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (rv == null) {\r
+ // if we haven't found the wrapper in the sheet runs, create a new paragraph list from its record\r
+ List<List<HSLFTextParagraph>> rvl = findTextParagraphs(wrapper.getChildRecords());\r
+ switch (rvl.size()) {\r
+ case 0: break; // nothing found\r
+ case 1: rv = rvl.get(0); break; // normal case\r
+ default:\r
+ throw new RuntimeException("TextBox contains more than one list of paragraphs.");\r
+ }\r
+ }\r
+ }\r
+\r
+ if (rv != null) {\r
+ StyleTextProp9Atom styleTextProp9Atom = wrapper.getStyleTextProp9Atom();\r
+\r
+ for (HSLFTextParagraph htp : rv) {\r
+ htp.setShapeId(shapeId);\r
+ htp.setStyleTextProp9Atom(styleTextProp9Atom);\r
+ }\r
+ }\r
+ return rv;\r
+ }\r
+\r
+ /**\r
+ * Scans through the supplied record array, looking for\r
+ * a TextHeaderAtom followed by one of a TextBytesAtom or\r
+ * a TextCharsAtom. Builds up TextRuns from these\r
+ * \r
+ * @param records the records to build from\r
+ */\r
protected static List<List<HSLFTextParagraph>> findTextParagraphs(Record[] records) {\r
List<List<HSLFTextParagraph>> paragraphCollection = new ArrayList<List<HSLFTextParagraph>>();\r
\r
- int[] recordIdx = {0};\r
- \r
+ int[] recordIdx = { 0 };\r
+\r
for (int slwtIndex = 0; recordIdx[0] < records.length; slwtIndex++) {\r
- TextHeaderAtom header = null;\r
- TextBytesAtom tbytes = null;\r
- TextCharsAtom tchars = null;\r
- TextRulerAtom ruler = null;\r
+ TextHeaderAtom header = null;\r
+ TextBytesAtom tbytes = null;\r
+ TextCharsAtom tchars = null;\r
+ TextRulerAtom ruler = null;\r
MasterTextPropAtom indents = null;\r
\r
for (Record r : getRecords(records, recordIdx, null)) {\r
long rt = r.getRecordType();\r
if (RecordTypes.TextHeaderAtom.typeID == rt) {\r
- header = (TextHeaderAtom)r;\r
+ header = (TextHeaderAtom) r;\r
} else if (RecordTypes.TextBytesAtom.typeID == rt) {\r
- tbytes = (TextBytesAtom)r;\r
+ tbytes = (TextBytesAtom) r;\r
} else if (RecordTypes.TextCharsAtom.typeID == rt) {\r
- tchars = (TextCharsAtom)r;\r
+ tchars = (TextCharsAtom) r;\r
} else if (RecordTypes.TextRulerAtom.typeID == rt) {\r
- ruler = (TextRulerAtom)r;\r
+ ruler = (TextRulerAtom) r;\r
} else if (RecordTypes.MasterTextPropAtom.typeID == rt) {\r
- indents = (MasterTextPropAtom)r;\r
+ indents = (MasterTextPropAtom) r;\r
}\r
// don't search for RecordTypes.StyleTextPropAtom.typeID here ... see findStyleAtomPresent below\r
}\r
\r
if (header == null) break;\r
- \r
+\r
if (header.getParentRecord() instanceof SlideListWithText) {\r
// runs found in PPDrawing are not linked with SlideListWithTexts\r
header.setIndex(slwtIndex);\r
\r
List<HSLFTextParagraph> paragraphs = new ArrayList<HSLFTextParagraph>();\r
paragraphCollection.add(paragraphs);\r
- \r
+\r
// split, but keep delimiter\r
for (String para : rawText.split("(?<=\r)")) {\r
HSLFTextParagraph tpara = new HSLFTextParagraph(header, tbytes, tchars);\r
if (paragraphCollection.isEmpty()) {\r
logger.log(POILogger.DEBUG, "No text records found.");\r
}\r
- \r
+\r
return paragraphCollection;\r
}\r
\r
int paraIdx = 0, runIdx = 0;\r
HSLFTextRun trun;\r
\r
- for (int csIdx=0; csIdx<charStyles.size(); csIdx++) {\r
+ for (int csIdx = 0; csIdx < charStyles.size(); csIdx++) {\r
TextPropCollection p = charStyles.get(csIdx);\r
- for (int ccRun = 0, ccStyle = p.getCharactersCovered(); ccRun < ccStyle; ) {\r
+ for (int ccRun = 0, ccStyle = p.getCharactersCovered(); ccRun < ccStyle;) {\r
HSLFTextParagraph para = paragraphs.get(paraIdx);\r
List<HSLFTextRun> runs = para.getTextRuns();\r
trun = runs.get(runIdx);\r
int len = trun.getLength();\r
\r
- if (ccRun+len <= ccStyle) {\r
+ if (ccRun + len <= ccStyle) {\r
ccRun += len;\r
} else {\r
String text = trun.getRawText();\r
- trun.setText(text.substring(0,ccStyle-ccRun));\r
+ trun.setText(text.substring(0, ccStyle - ccRun));\r
\r
HSLFTextRun nextRun = new HSLFTextRun(para);\r
- nextRun.setText(text.substring(ccStyle-ccRun));\r
- runs.add(runIdx+1, nextRun);\r
+ nextRun.setText(text.substring(ccStyle - ccRun));\r
+ runs.add(runIdx + 1, nextRun);\r
\r
- ccRun += ccStyle-ccRun;\r
+ ccRun += ccStyle - ccRun;\r
}\r
\r
TextPropCollection pCopy = new TextPropCollection(0, TextPropType.character);\r
\r
len = trun.getLength();\r
if (paraIdx == paragraphs.size()-1 && runIdx == runs.size()-1) {\r
- if (csIdx < charStyles.size()-1) {\r
+ if (csIdx < charStyles.size() - 1) {\r
// special case, empty trailing text run\r
HSLFTextRun nextRun = new HSLFTextRun(para);\r
nextRun.setText("");\r
len += trun.getLength();\r
}\r
para.setIndentLevel(p.getIndentLevel());\r
- ccPara += len+1;\r
+ ccPara += len + 1;\r
}\r
}\r
}\r
}\r
\r
public EscherTextboxWrapper getTextboxWrapper() {\r
- return (EscherTextboxWrapper)_headerAtom.getParentRecord();\r
+ return (EscherTextboxWrapper) _headerAtom.getParentRecord();\r
}\r
}\r