import java.awt.*;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.util.List;
import org.apache.poi.hslf.model.*;
import org.apache.poi.hslf.record.TextHeaderAtom;
slide.addShape(box1);
HSLFTextBox box2 = new HSLFTextBox();
- box2.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(28);
box2.setRunType(TextHeaderAtom.BODY_TYPE);
box2.setText(
- "HSLF provides a way to read, create and modify MS PowerPoint presentations\r" +
- "Pure Java API - you don't need PowerPoint to read and write *.ppt files\r" +
- "Comprehensive support of PowerPoint objects");
- box2.setAnchor(new Rectangle(36, 80, 648, 200));
- slide.addShape(box2);
-
- HSLFTextBox box3 = new HSLFTextBox();
- box2.getTextParagraphs().get(0).setIndentLevel(1);
- box2.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(24);
- box3.setRunType(TextHeaderAtom.BODY_TYPE);
- box3.setText(
+ "HSLF provides a way to read, create and modify MS PowerPoint presentations\r" +
+ "Pure Java API - you don't need PowerPoint to read and write *.ppt files\r" +
+ "Comprehensive support of PowerPoint objects\r" +
"Rich text\r" +
"Tables\r" +
"Shapes\r" +
"Pictures\r" +
- "Master slides");
- box3.setAnchor(new Rectangle(36, 265, 648, 150));
- slide.addShape(box3);
+ "Master slides\r" +
+ "Access to low level data structures"
+ );
- HSLFTextBox box4 = new HSLFTextBox();
- box4.setRunType(TextHeaderAtom.BODY_TYPE);
- box4.setText("Access to low level data structures");
- box4.setAnchor(new Rectangle(36, 430, 648, 50));
- slide.addShape(box4);
+ List<HSLFTextParagraph> tp = box2.getTextParagraphs();
+ for (int i : new byte[]{0,1,2,8}) {
+ tp.get(i).getTextRuns().get(0).setFontSize(28);
+ }
+ for (int i : new byte[]{3,4,5,6,7}) {
+ tp.get(i).getTextRuns().get(0).setFontSize(24);
+ tp.get(i).setIndentLevel(1);
+ }
+ box2.setAnchor(new Rectangle(36, 80, 648, 400));
+ slide.addShape(box2);
}
public static void slide4(HSLFSlideShow ppt) throws IOException {
rt3.setFontName("Courier New");
rt3.setFontSize(8);
box3.setText(
- " SlideShow ppt = new SlideShow();\r" +
- " Slide slide = ppt.createSlide();\r" +
- "\r" +
- " TextBox box2 = new TextBox();\r" +
- " box2.setHorizontalAlignment(TextBox.AlignCenter);\r" +
- " box2.setVerticalAlignment(TextBox.AnchorMiddle);\r" +
- " box2.getTextRun().setText(\"Java Code\");\r" +
- " box2.getFill().setForegroundColor(new Color(187, 224, 227));\r" +
- " box2.setLineColor(Color.black);\r" +
- " box2.setLineWidth(0.75);\r" +
- " box2.setAnchor(new Rectangle(66, 243, 170, 170));\r" +
- " slide.addShape(box2);\r" +
- "\r" +
- " TextBox box3 = new TextBox();\r" +
- " box3.setHorizontalAlignment(TextBox.AlignCenter);\r" +
- " box3.setVerticalAlignment(TextBox.AnchorMiddle);\r" +
- " box3.getTextRun().setText(\"*.ppt file\");\r" +
- " box3.setLineWidth(0.75);\r" +
- " box3.setLineColor(Color.black);\r" +
- " box3.getFill().setForegroundColor(new Color(187, 224, 227));\r" +
- " box3.setAnchor(new Rectangle(473, 243, 170, 170));\r" +
- " slide.addShape(box3);\r" +
- "\r" +
- " AutoShape box4 = new AutoShape(ShapeTypes.Arrow);\r" +
- " box4.getFill().setForegroundColor(new Color(187, 224, 227));\r" +
- " box4.setLineWidth(0.75);\r" +
- " box4.setLineColor(Color.black);\r" +
- " box4.setAnchor(new Rectangle(253, 288, 198, 85));\r" +
- " slide.addShape(box4);\r" +
- "\r" +
- " FileOutputStream out = new FileOutputStream(\"hslf-demo.ppt\");\r" +
- " ppt.write(out);\r" +
- " out.close();");
+ "SlideShow ppt = new SlideShow();\u000b" +
+ "Slide slide = ppt.createSlide();\u000b" +
+ "\u000b" +
+ "TextBox box2 = new TextBox();\u000b" +
+ "box2.setHorizontalAlignment(TextBox.AlignCenter);\u000b" +
+ "box2.setVerticalAlignment(TextBox.AnchorMiddle);\u000b" +
+ "box2.getTextRun().setText(\"Java Code\");\u000b" +
+ "box2.getFill().setForegroundColor(new Color(187, 224, 227));\u000b" +
+ "box2.setLineColor(Color.black);\u000b" +
+ "box2.setLineWidth(0.75);\u000b" +
+ "box2.setAnchor(new Rectangle(66, 243, 170, 170));\u000b" +
+ "slide.addShape(box2);\u000b" +
+ "\u000b" +
+ "TextBox box3 = new TextBox();\u000b" +
+ "box3.setHorizontalAlignment(TextBox.AlignCenter);\u000b" +
+ "box3.setVerticalAlignment(TextBox.AnchorMiddle);\u000b" +
+ "box3.getTextRun().setText(\"*.ppt file\");\u000b" +
+ "box3.setLineWidth(0.75);\u000b" +
+ "box3.setLineColor(Color.black);\u000b" +
+ "box3.getFill().setForegroundColor(new Color(187, 224, 227));\u000b" +
+ "box3.setAnchor(new Rectangle(473, 243, 170, 170));\u000b" +
+ "slide.addShape(box3);\u000b" +
+ "\u000b" +
+ "AutoShape box4 = new AutoShape(ShapeTypes.Arrow);\u000b" +
+ "box4.getFill().setForegroundColor(new Color(187, 224, 227));\u000b" +
+ "box4.setLineWidth(0.75);\u000b" +
+ "box4.setLineColor(Color.black);\u000b" +
+ "box4.setAnchor(new Rectangle(253, 288, 198, 85));\u000b" +
+ "slide.addShape(box4);\u000b" +
+ "\u000b" +
+ "FileOutputStream out = new FileOutputStream(\"hslf-demo.ppt\");\u000b" +
+ "ppt.write(out);\u000b" +
+ "out.close();");
box3.setAnchor(new Rectangle(30, 150, 618, 411));
+ box3.setHorizontalCentered(true);
slide.addShape(box3);
}
rt3.setFontName("Courier New");
rt3.setFontSize(8);
box3.setText(
- " //bar chart data. The first value is the bar color, the second is the width\r" +
- " Object[] def = new Object[]{\r" +
- " Color.yellow, new Integer(100),\r" +
- " Color.green, new Integer(150),\r" +
- " Color.gray, new Integer(75),\r" +
- " Color.red, new Integer(200),\r" +
- " };\r" +
- "\r" +
- " SlideShow ppt = new SlideShow();\r" +
- " Slide slide = ppt.createSlide();\r" +
- "\r" +
- " ShapeGroup group = new ShapeGroup();\r" +
- " //define position of the drawing in the slide\r" +
- " Rectangle bounds = new java.awt.Rectangle(200, 100, 350, 300);\r" +
- " group.setAnchor(bounds);\r" +
- " slide.addShape(group);\r" +
- " Graphics2D graphics = new PPGraphics2D(group);\r" +
- "\r" +
- " //draw a simple bar graph\r" +
- " int x = bounds.x + 50, y = bounds.y + 50;\r" +
- " graphics.setFont(new Font(\"Arial\", Font.BOLD, 10));\r" +
- " for (int i = 0, idx = 1; i < def.length; i+=2, idx++) {\r" +
- " graphics.setColor(Color.black);\r" +
- " int width = ((Integer)def[i+1]).intValue();\r" +
- " graphics.drawString(\"Q\" + idx, x-20, y+20);\r" +
- " graphics.drawString(width + \"%\", x + width + 10, y + 20);\r" +
- " graphics.setColor((Color)def[i]);\r" +
- " graphics.fill(new Rectangle(x, y, width, 30));\r" +
- " y += 40;\r" +
- " }\r" +
- " graphics.setColor(Color.black);\r" +
- " graphics.setFont(new Font(\"Arial\", Font.BOLD, 14));\r" +
- " graphics.draw(bounds);\r" +
- " graphics.drawString(\"Performance\", x + 70, y + 40);\r" +
- "\r" +
- " FileOutputStream out = new FileOutputStream(\"hslf-demo.ppt\");\r" +
- " ppt.write(out);\r" +
- " out.close();");
+ "//bar chart data. The first value is the bar color, the second is the width\u000b" +
+ "Object[] def = new Object[]{\u000b" +
+ " Color.yellow, new Integer(100),\u000b" +
+ " Color.green, new Integer(150),\u000b" +
+ " Color.gray, new Integer(75),\u000b" +
+ " Color.red, new Integer(200),\u000b" +
+ "};\u000b" +
+ "\u000b" +
+ "SlideShow ppt = new SlideShow();\u000b" +
+ "Slide slide = ppt.createSlide();\u000b" +
+ "\u000b" +
+ "ShapeGroup group = new ShapeGroup();\u000b" +
+ "//define position of the drawing in the slide\u000b" +
+ "Rectangle bounds = new java.awt.Rectangle(200, 100, 350, 300);\u000b" +
+ "group.setAnchor(bounds);\u000b" +
+ "slide.addShape(group);\u000b" +
+ "Graphics2D graphics = new PPGraphics2D(group);\u000b" +
+ "\u000b" +
+ "//draw a simple bar graph\u000b" +
+ "int x = bounds.x + 50, y = bounds.y + 50;\u000b" +
+ "graphics.setFont(new Font(\"Arial\", Font.BOLD, 10));\u000b" +
+ "for (int i = 0, idx = 1; i < def.length; i+=2, idx++) {\u000b" +
+ " graphics.setColor(Color.black);\u000b" +
+ " int width = ((Integer)def[i+1]).intValue();\u000b" +
+ " graphics.drawString(\"Q\" + idx, x-20, y+20);\u000b" +
+ " graphics.drawString(width + \"%\", x + width + 10, y + 20);\u000b" +
+ " graphics.setColor((Color)def[i]);\u000b" +
+ " graphics.fill(new Rectangle(x, y, width, 30));\u000b" +
+ " y += 40;\u000b" +
+ "}\u000b" +
+ "graphics.setColor(Color.black);\u000b" +
+ "graphics.setFont(new Font(\"Arial\", Font.BOLD, 14));\u000b" +
+ "graphics.draw(bounds);\u000b" +
+ "graphics.drawString(\"Performance\", x + 70, y + 40);\u000b" +
+ "\u000b" +
+ "FileOutputStream out = new FileOutputStream(\"hslf-demo.ppt\");\u000b" +
+ "ppt.write(out);\u000b" +
+ "out.close();");
box3.setAnchor(new Rectangle(96, 110, 499, 378));
+ box3.setHorizontalCentered(true);
slide.addShape(box3);
}
slide.addShape(box1);
HSLFTextBox box2 = new HSLFTextBox();
- box2.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(32);
box2.setRunType(TextHeaderAtom.BODY_TYPE);
box2.setText(
- "Support for more PowerPoint functionality\r" +
- "Rendering slides into java.awt.Graphics2D");
- box2.setAnchor(new Rectangle(36, 126, 648, 100));
- slide.addShape(box2);
-
- HSLFTextBox box3 = new HSLFTextBox();
- box3.getTextParagraphs().get(0).setIndentLevel(1);
- box3.setRunType(TextHeaderAtom.BODY_TYPE);
- box3.setText(
- "A way to export slides into images or other formats");
- box3.setAnchor(new Rectangle(36, 220, 648, 70));
- slide.addShape(box3);
-
- HSLFTextBox box4 = new HSLFTextBox();
- box4.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(32);
- box4.setRunType(TextHeaderAtom.BODY_TYPE);
- box4.setText(
- "Integration with Apache FOP - Formatting Objects Processor");
- box4.setAnchor(new Rectangle(36, 290, 648, 90));
- slide.addShape(box4);
-
- HSLFTextBox box5 = new HSLFTextBox();
- box5.getTextParagraphs().get(0).setIndentLevel(1);
- box5.setRunType(TextHeaderAtom.BODY_TYPE);
- box5.setText(
+ "Support for more PowerPoint functionality\r" +
+ "Rendering slides into java.awt.Graphics2D\r" +
+ "A way to export slides into images or other formats\r" +
+ "Integration with Apache FOP - Formatting Objects Processor\r" +
"Transformation of XSL-FO into PPT\r" +
- "PPT2PDF transcoder");
- box5.setAnchor(new Rectangle(36, 380, 648, 100));
- slide.addShape(box5);
+ "PPT2PDF transcoder"
+ );
+
+ List<HSLFTextParagraph> tp = box2.getTextParagraphs();
+ for (int i : new byte[]{0,1,3}) {
+ tp.get(i).getTextRuns().get(0).setFontSize(28);
+ }
+ for (int i : new byte[]{2,4,5}) {
+ tp.get(i).getTextRuns().get(0).setFontSize(24);
+ tp.get(i).setIndentLevel(1);
+ }
+
+ box2.setAnchor(new Rectangle(36, 126, 648, 400));
+ slide.addShape(box2);
}
public static void slide12(HSLFSlideShow ppt) throws IOException {
}
/**
- * As we're purely mask based, just set flags for stuff
- * that is set
+ * Calculate mask from the subPropMatches.
*/
public int getWriteMask() {
- return dataValue;
+ /*
+ * The dataValue can't be taken as a mask, as sometimes certain properties
+ * are explicitly set to false, i.e. the mask says the property is defined
+ * but in the actually nibble the property is set to false
+ */
+ int mask = 0, i = 0;
+ for (int subMask : subPropMasks) {
+ if (subPropMatches[i++]) mask |= subMask;
+ }
+ return mask;
+ }
+
+ public void setWriteMask(int containsField) {
+ int i = 0;
+ for (int subMask : subPropMasks) {
+ if ((containsField & subMask) != 0) subPropMatches[i] = true;
+ i++;
+ }
}
/**
* Set the value of the text property, and recompute the sub
- * properties based on it
+ * properties based on it, i.e. all unset subvalues won't be saved.
+ * Use {@link #setSubValue(boolean, int)} to explicitly set subvalues to {@code false}.
*/
+ @Override
public void setValue(int val) {
dataValue = val;
// Figure out the values of the sub properties
- for(int i=0; i< subPropMatches.length; i++) {
- subPropMatches[i] = false;
- if((dataValue & subPropMasks[i]) != 0) {
- subPropMatches[i] = true;
- }
+ int i = 0;
+ for(int mask : subPropMasks) {
+ subPropMatches[i++] = ((val & mask) != 0);
}
}
* Fetch the true/false status of the subproperty with the given index
*/
public boolean getSubValue(int idx) {
- return subPropMatches[idx];
+ return (dataValue & subPropMasks[idx]) != 0;
}
/**
* Set the true/false status of the subproperty with the given index
*/
public void setSubValue(boolean value, int idx) {
- if (subPropMatches[idx] == value) return;
- subPropMatches[idx] = value;
- dataValue ^= subPropMasks[idx];
+ subPropMatches[idx] = true;
+ if (value) {
+ dataValue |= subPropMasks[idx];
+ } else {
+ dataValue &= ~subPropMasks[idx];
+ }
}
@Override
public static final String NAME = "char_flags";
public CharFlagsTextProp() {
- super(2,0xffff, NAME, new String[] {
+ super(2, 0xffff, NAME, new String[] {
"bold", // 0x0001 A bit that specifies whether the characters are bold.
"italic", // 0x0002 A bit that specifies whether the characters are italicized.
"underline", // 0x0004 A bit that specifies whether the characters are underlined.
- "char_unknown_1", // 0x0008 Undefined and MUST be ignored.
+ "unused1", // 0x0008 Undefined and MUST be ignored.
"shadow", // 0x0010 A bit that specifies whether the characters have a shadow effect.
"fehint", // 0x0020 A bit that specifies whether characters originated from double-byte input.
- "char_unknown_2", // 0x0040 Undefined and MUST be ignored.
+ "unused2", // 0x0040 Undefined and MUST be ignored.
"kumi", // 0x0080 A bit that specifies whether Kumimoji are used for vertical text.
"strikethrough", // 0x0100 Undefined and MUST be ignored.
"emboss", // 0x0200 A bit that specifies whether the characters are embossed.
- "char_unknown_3", // 0x0400 Undefined and MUST be ignored.
- "char_unknown_4", // 0x0800 Undefined and MUST be ignored.
- "char_unknown_5", // 0x1000 Undefined and MUST be ignored.
+ "pp9rt_1", // 0x0400 An unsigned integer that specifies the run grouping of additional text properties in StyleTextProp9Atom record.
+ "pp9rt_2", // 0x0800
+ "pp9rt_3", // 0x1000
+ "pp9rt_4", // 0x2000
+ "unused4_1", // 0x4000 Undefined and MUST be ignored.
+ "unused4_2", // 0x8000 Undefined and MUST be ignored.
}
);
}
* For a given run of characters, holds the properties (which could
* be paragraph properties or character properties).
* Used to hold the number of characters affected, the list of active
- * properties, and the random reserved field if required.
+ * properties, and the indent level if required.
*/
public class TextPropCollection {
- private int charactersCovered;
- private short reservedField;
+ /*
+ 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"),
+ new TextProp(2, 0x40, "bullet.size"),
+ new TextProp(4, 0x20, "bullet.color"),
+ new TextAlignmentProp(),
+ new TextProp(2, 0x1000, "linespacing"),
+ new TextProp(2, 0x2000, "spacebefore"),
+ new TextProp(2, 0x4000, "spaceafter"),
+ new TextProp(2, 0x100, "text.offset"), // left margin
+ // 0x200 - Undefined and MUST be ignored
+ new TextProp(2, 0x400, "bullet.offset"), // indent
+ new TextProp(2, 0x8000, "defaultTabSize"),
+ new TabStopPropCollection(), // tabstops size is variable!
+ new FontAlignmentProp(),
+ new TextProp(2, 0xE0000, "wrapFlags"), // charWrap | wordWrap | overflow
+ new TextProp(2, 0x200000, "textDirection"),
+ // 0x400000 MUST be zero and MUST be ignored
+ new TextProp(0, 0x800000, "bullet.blip"), // TODO: check size
+ new TextProp(0, 0x1000000, "bullet.scheme"), // TODO: check size
+ 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.
+ new TextProp(0, 0x4000000, "pp11ext"), // A bit that specifies whether the pp11ext field of the TextCFException10 structure that contains this CFMasks exists.
+ new CharFlagsTextProp(),
+ new TextProp(2, 0x10000, "font.index"),
+ new TextProp(2, 0x200000, "asian.font.index"),
+ new TextProp(2, 0x400000, "ansi.font.index"),
+ new TextProp(2, 0x800000, "symbol.font.index"),
+ new TextProp(2, 0x20000, "font.size"),
+ new TextProp(4, 0x40000, "font.color"),
+ new TextProp(2, 0x80000, "superscript")
+ };
+
+ public enum TextPropType {
+ paragraph, character;
+ }
+
+ private int charactersCovered;
+
+ // indentLevel is only valid for paragraph collection
+ // if it's set to -1, it must be omitted - see 2.9.36 TextMasterStyleLevel
+ private short indentLevel = 0;
private final List<TextProp> textPropList = new ArrayList<TextProp>();
private int maskSpecial = 0;
- private final TextProp[] potentialPropList;
+ private final TextPropType textPropType;
+ /**
+ * Create a new collection of text properties (be they paragraph
+ * or character) which will be groked via a subsequent call to
+ * buildTextPropList().
+ */
+ public TextPropCollection(int charactersCovered, TextPropType textPropType) {
+ this.charactersCovered = charactersCovered;
+ this.textPropType = textPropType;
+ }
+
public int getSpecialMask() { return maskSpecial; }
/** Fetch the number of characters this styling applies to */
if (existing != null) return existing;
TextProp base = null;
- for (TextProp tp : potentialPropList) {
+ for (TextProp tp : getPotentialProperties()) {
if (tp.getName().equals(name)) {
base = tp;
break;
addProp(textProp);
return textProp;
}
+
+ private TextProp[] getPotentialProperties() {
+ return (textPropType == TextPropType.paragraph) ? paragraphTextPropTypes : characterTextPropTypes;
+ }
/**
* Add the property at the correct position. Replaces an existing property with the same name.
int pos = 0;
boolean found = false;
- for (TextProp curProp : potentialPropList) {
+ for (TextProp curProp : getPotentialProperties()) {
String potName = curProp.getName();
if (pos == textPropList.size() || potName.equals(textProp.getName())) {
if (textPropList.size() > pos && potName.equals(textPropList.get(pos).getName())) {
// For each possible entry, see if we match the mask
// If we do, decode that, save it, and shuffle on
- for(TextProp tp : potentialPropList) {
+ for(TextProp tp : getPotentialProperties()) {
// Check there's still data left to read
// Check if this property is found in the mask
continue;
}
prop.setValue(val);
+ if (prop instanceof BitMaskTextProp) {
+ ((BitMaskTextProp)prop).setWriteMask(containsField);
+ }
bytesPassed += prop.getSize();
addProp(prop);
}
return bytesPassed;
}
- /**
- * Create a new collection of text properties (be they paragraph
- * or character) which will be groked via a subsequent call to
- * buildTextPropList().
- */
- public TextPropCollection(int charactersCovered, short reservedField, TextProp[] potentialPropList) {
- this.charactersCovered = charactersCovered;
- this.reservedField = reservedField;
- this.potentialPropList = potentialPropList;
- }
-
- /**
- * Create a new collection of text properties (be they paragraph
- * or character) for a run of text without any
- */
- public TextPropCollection(int textSize, TextProp[] potentialPropList) {
- this(textSize, (short)-1, potentialPropList);
- }
-
/**
* Clones the given text properties
*/
public void copy(TextPropCollection other) {
this.charactersCovered = other.charactersCovered;
- this.reservedField = other.reservedField;
+ this.indentLevel = other.indentLevel;
this.maskSpecial = other.maskSpecial;
this.textPropList.clear();
for (TextProp tp : other.textPropList) {
// First goes the number of characters we affect
StyleTextPropAtom.writeLittleEndian(charactersCovered,o);
- // Then we have the reserved field if required
- if(reservedField > -1) {
- StyleTextPropAtom.writeLittleEndian(reservedField,o);
+ // Then we have the indentLevel field if it's a paragraph collection
+ if (textPropType == TextPropType.paragraph && indentLevel > -1) {
+ StyleTextPropAtom.writeLittleEndian(indentLevel, o);
}
// Then the mask field
int mask = maskSpecial;
- for(TextProp textProp : textPropList) {
- //sometimes header indicates that the bitmask is present but its value is 0
+ for (TextProp textProp : textPropList) {
+ // sometimes header indicates that the bitmask is present but its value is 0
if (textProp instanceof BitMaskTextProp) {
- if(mask == 0) mask |= textProp.getWriteMask();
+ if (mask == 0) mask |= textProp.getWriteMask();
}
else {
mask |= textProp.getWriteMask();
StyleTextPropAtom.writeLittleEndian(mask,o);
// Then the contents of all the properties
- for (TextProp potProp : potentialPropList) {
+ for (TextProp potProp : getPotentialProperties()) {
for(TextProp textProp : textPropList) {
if (!textProp.getName().equals(potProp.getName())) continue;
int val = textProp.getValue();
- if (textProp instanceof BitMaskTextProp && val == 0
- && !(textProp instanceof ParagraphFlagsTextProp)
-// && !(textProp instanceof CharFlagsTextProp)
- ) {
+ if (textProp instanceof BitMaskTextProp && textProp.getWriteMask() == 0) {
// don't add empty properties, as they can't be recognized while reading
- // strangely this doesn't apply for ParagraphFlagsTextProp in contrast
- // to the documentation in 2.9.20 TextPFException
continue;
} else if (textProp.getSize() == 2) {
StyleTextPropAtom.writeLittleEndian((short)val,o);
}
}
- public short getReservedField(){
- return reservedField;
+ public short getIndentLevel(){
+ return indentLevel;
}
- public void setReservedField(short val){
- reservedField = val;
+ public void setIndentLevel(short indentLevel) {
+ if (textPropType == TextPropType.character) {
+ throw new RuntimeException("trying to set an indent on a character collection.");
+ }
+ this.indentLevel = indentLevel;
}
public int hashCode() {
int result = 1;
result = prime * result + charactersCovered;
result = prime * result + maskSpecial;
- result = prime * result + reservedField;
+ result = prime * result + indentLevel;
result = prime * result + ((textPropList == null) ? 0 : textPropList.hashCode());
return result;
}
if (getClass() != other.getClass()) return false;
TextPropCollection o = (TextPropCollection)other;
- if (o.maskSpecial != this.maskSpecial || o.reservedField != this.reservedField) {
+ if (o.maskSpecial != this.maskSpecial || o.indentLevel != this.indentLevel) {
return false;
}
for(TextProp p : getTextPropList()) {
out.append(" " + p.getName() + " = " + p.getValue() );
out.append(" (0x" + HexDump.toHex(p.getValue()) + ")\n");
+ if (p instanceof BitMaskTextProp) {
+ BitMaskTextProp bm = (BitMaskTextProp)p;
+ int i = 0;
+ for (String s : bm.getSubPropNames()) {
+ if (bm.getSubPropMatches()[i]) {
+ out.append(" " + s + " = " + bm.getSubValue(i) + "\n");
+ }
+ i++;
+ }
+ }
}
out.append(" bytes that would be written: \n");
import java.util.List;
import org.apache.poi.hslf.model.textproperties.*;
+import org.apache.poi.hslf.model.textproperties.TextPropCollection.TextPropType;
import org.apache.poi.util.*;
/**
return length;
}
- /** 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"),
- new TextProp(2, 0x40, "bullet.size"),
- new TextProp(4, 0x20, "bullet.color"),
- new TextAlignmentProp(),
- new TextProp(2, 0x1000, "linespacing"),
- new TextProp(2, 0x2000, "spacebefore"),
- new TextProp(2, 0x4000, "spaceafter"),
- new TextProp(2, 0x100, "text.offset"), // left margin
- // 0x200 - Undefined and MUST be ignored
- new TextProp(2, 0x400, "bullet.offset"), // indent
- new TextProp(2, 0x8000, "defaultTabSize"),
- new TabStopPropCollection(), // tabstops size is variable!
- new FontAlignmentProp(),
- new TextProp(2, 0xE0000, "wrapFlags"), // charWrap | wordWrap | overflow
- new TextProp(2, 0x200000, "textDirection"),
- // 0x400000 MUST be zero and MUST be ignored
- new TextProp(0, 0x800000, "bullet.blip"), // TODO: check size
- new TextProp(0, 0x1000000, "bullet.scheme"), // TODO: check size
- 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, "unused3"),
- 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 CharFlagsTextProp(),
- new TextProp(2, 0x10000, "font.index"),
- new TextProp(0, 0x100000, "pp10ext"),
- new TextProp(2, 0x200000, "asian.font.index"),
- new TextProp(2, 0x400000, "ansi.font.index"),
- new TextProp(2, 0x800000, "symbol.font.index"),
- new TextProp(2, 0x20000, "font.size"),
- new TextProp(4, 0x40000, "font.color"),
- new TextProp(2, 0x80000, "superscript")
- };
-
/* *************** record code follows ********************** */
/**
paragraphStyles = new ArrayList<TextPropCollection>();
charStyles = new ArrayList<TextPropCollection>();
- TextPropCollection defaultParagraphTextProps =
- new TextPropCollection(parentTextSize, (short)0, paragraphTextPropTypes);
- defaultParagraphTextProps.addWithName("paragraph_flags");
- paragraphStyles.add(defaultParagraphTextProps);
-
- TextPropCollection defaultCharacterTextProps =
- new TextPropCollection(parentTextSize, characterTextPropTypes);
- defaultCharacterTextProps.addWithName("char_flags");
- charStyles.add(defaultCharacterTextProps);
+ addParagraphTextPropCollection(parentTextSize);
+ addCharacterTextPropCollection(parentTextSize);
// Set us as now initialised
initialised = true;
* contains, so we can go ahead and initialise ourselves.
*/
public void setParentTextSize(int size) {
- // if (initialised) return;
+ if (initialised) return;
int pos = 0;
int textHandled = 0;
pos += 4;
// Now make sense of those properties
- TextPropCollection thisCollection = new TextPropCollection(textLen, indent, paragraphTextPropTypes);
+ TextPropCollection thisCollection = new TextPropCollection(textLen, TextPropType.paragraph);
+ thisCollection.setIndentLevel(indent);
int plSize = thisCollection.buildTextPropList(paraFlags, rawContents, pos);
pos += plSize;
textHandled += textLen;
pos += 4;
- // There is no 2 byte value
- short no_val = -1;
-
// Grab the 4 byte value that tells us what properties follow
int charFlags = LittleEndian.getInt(rawContents,pos);
pos += 4;
// Now make sense of those properties
// (Assuming we actually have some)
- TextPropCollection thisCollection = new TextPropCollection(textLen, no_val, characterTextPropTypes);
+ TextPropCollection thisCollection = new TextPropCollection(textLen, TextPropType.character);
int chSize = thisCollection.buildTextPropList(charFlags, rawContents, pos);
pos += chSize;
// Now, we do the character ones
for(TextPropCollection tpc : charStyles) {
// ditto for the char flags
- tpc.addWithName(CharFlagsTextProp.NAME);
+ // tpc.addWithName(CharFlagsTextProp.NAME);
tpc.writeOut(baos);
}
* @return the new TextPropCollection, which will then be in the list
*/
public TextPropCollection addParagraphTextPropCollection(int charactersCovered) {
- TextPropCollection tpc = new TextPropCollection(charactersCovered, (short)0, paragraphTextPropTypes);
+ TextPropCollection tpc = new TextPropCollection(charactersCovered, TextPropType.paragraph);
paragraphStyles.add(tpc);
return tpc;
}
* @return the new TextPropCollection, which will then be in the list
*/
public TextPropCollection addCharacterTextPropCollection(int charactersCovered) {
- TextPropCollection tpc = new TextPropCollection(charactersCovered, characterTextPropTypes);
+ TextPropCollection tpc = new TextPropCollection(charactersCovered, TextPropType.character);
charStyles.add(tpc);
return tpc;
}
import java.io.IOException;
import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
-import org.apache.poi.hslf.model.textproperties.CharFlagsTextProp;
-import org.apache.poi.hslf.model.textproperties.ParagraphFlagsTextProp;
-import org.apache.poi.hslf.model.textproperties.TextProp;
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
+import org.apache.poi.hslf.model.textproperties.TextPropCollection.TextPropType;
import org.apache.poi.util.LittleEndian;
/**
*/
public static final int MAX_INDENT = 5;
-/*
- 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")
- };
-*/
private byte[] _header;
private static long _type = 4003;
private byte[] _data;
- private TextPropCollection[] prstyles;
- private TextPropCollection[] chstyles;
+ private List<TextPropCollection> paragraphStyles;
+ private List<TextPropCollection> charStylesyles;
protected TxMasterStyleAtom(byte[] source, int start, int len) {
_header = new byte[8];
*
* @return character styles defined in this record
*/
- public TextPropCollection[] getCharacterStyles(){
- return chstyles;
+ public List<TextPropCollection> getCharacterStyles(){
+ return charStylesyles;
}
/**
*
* @return paragraph styles defined in this record
*/
- public TextPropCollection[] getParagraphStyles(){
- return prstyles;
+ public List<TextPropCollection> getParagraphStyles(){
+ return paragraphStyles;
}
/**
/**
* parse the record data and initialize styles
*/
- @SuppressWarnings("unused")
protected void init(){
//type of the text
int type = getTextType();
short levels = LittleEndian.getShort(_data, 0);
pos += LittleEndian.SHORT_SIZE;
- prstyles = new TextPropCollection[levels];
- chstyles = new TextPropCollection[levels];
+ paragraphStyles = new ArrayList<TextPropCollection>(levels);
+ charStylesyles = new ArrayList<TextPropCollection>(levels);
for(short j = 0; j < levels; j++) {
-
+ TextPropCollection prprops = new TextPropCollection(0, TextPropType.paragraph); // getParagraphProps(type, j)
if (type >= TextHeaderAtom.CENTRE_BODY_TYPE) {
// Fetch the 2 byte value, that is safe to ignore for some types of text
- short val = LittleEndian.getShort(_data, pos);
+ short indentLevel = LittleEndian.getShort(_data, pos);
+ prprops.setIndentLevel(indentLevel);
pos += LittleEndian.SHORT_SIZE;
+ } else {
+ prprops.setIndentLevel((short)-1);
}
head = LittleEndian.getInt(_data, pos);
pos += LittleEndian.INT_SIZE;
- TextPropCollection prprops = new TextPropCollection(0, getParagraphProps(type, j));
+
pos += prprops.buildTextPropList( head, _data, pos);
- prstyles[j] = prprops;
+ paragraphStyles.add(prprops);
head = LittleEndian.getInt(_data, pos);
pos += LittleEndian.INT_SIZE;
- TextPropCollection chprops = new TextPropCollection(0, getCharacterProps(type, j));
+ TextPropCollection chprops = new TextPropCollection(0, TextPropType.character); // getCharacterProps(type, j)
pos += chprops.buildTextPropList( head, _data, pos);
- chstyles[j] = chprops;
+ charStylesyles.add(chprops);
}
}
* Depending on the level and type, it may be our special
* ones, or the standard StyleTextPropAtom ones
*/
- protected TextProp[] getParagraphProps(int type, int level){
- return StyleTextPropAtom.paragraphTextPropTypes;
+// protected TextProp[] getParagraphProps(int type, int level){
+// return StyleTextPropAtom.paragraphTextPropTypes;
// return (level != 0 || type >= MAX_INDENT)
// ? StyleTextPropAtom.paragraphTextPropTypes
// : paragraphSpecialPropTypes;
- }
+// }
/**
* Character properties for the specified text type and
* Depending on the level and type, it may be our special
* ones, or the standard StyleTextPropAtom ones
*/
- protected TextProp[] getCharacterProps(int type, int level){
- return StyleTextPropAtom.characterTextPropTypes;
+// protected TextProp[] getCharacterProps(int type, int level){
+// return StyleTextPropAtom.characterTextPropTypes;
// return (level != 0 || type >= MAX_INDENT)
// ? StyleTextPropAtom.characterTextPropTypes
// : characterSpecialPropTypes;
- }
+// }
}
TextProp prop = null;
for (int i = level; i >= 0; i--) {
- TextPropCollection[] styles =
+ List<TextPropCollection> styles =
isCharacter ? _txmaster[txtype].getCharacterStyles() : _txmaster[txtype].getParagraphStyles();
- if (i < styles.length) prop = styles[i].findByName(name);
+ if (i < styles.size()) prop = styles.get(i).findByName(name);
if (prop != null) break;
}
if (prop == null) {
package org.apache.poi.hslf.usermodel;\r
\r
import java.awt.Color;\r
-import java.io.ByteArrayOutputStream;\r
-import java.io.IOException;\r
import java.util.*;\r
\r
import org.apache.poi.hslf.model.PPFont;\r
import org.apache.poi.hslf.model.textproperties.*;\r
+import org.apache.poi.hslf.model.textproperties.TextPropCollection.TextPropType;\r
import org.apache.poi.hslf.record.*;\r
import org.apache.poi.sl.usermodel.TextParagraph;\r
import org.apache.poi.util.*;\r
private TextBytesAtom _byteAtom;\r
private TextCharsAtom _charAtom;\r
private StyleTextPropAtom _styleAtom;\r
- private TextPropCollection _paragraphStyle = new TextPropCollection(1, StyleTextPropAtom.paragraphTextPropTypes);\r
+ private TextPropCollection _paragraphStyle = new TextPropCollection(1, TextPropType.paragraph);\r
\r
protected TextRulerAtom _ruler;\r
protected List<HSLFTextRun> _runs = new ArrayList<HSLFTextRun>();\r
* @return indentation level\r
*/\r
public int getIndentLevel() {\r
- return _paragraphStyle == null ? 0 : _paragraphStyle.getReservedField();\r
+ return _paragraphStyle == null ? 0 : _paragraphStyle.getIndentLevel();\r
}\r
\r
/**\r
* @param level indentation level. Must be in the range [0, 4]\r
*/\r
public void setIndentLevel(int level) {\r
- if( _paragraphStyle != null ) _paragraphStyle.setReservedField((short)level);\r
+ if( _paragraphStyle != null ) _paragraphStyle.setIndentLevel((short)level);\r
}\r
\r
/**\r
*/\r
protected static TextProp fetchOrAddTextProp(TextPropCollection textPropCol, String textPropName) {\r
// Fetch / Add the TextProp\r
- TextProp tp = textPropCol.findByName(textPropName);\r
- if (tp == null) {\r
- tp = textPropCol.addWithName(textPropName);\r
- }\r
- return tp;\r
+ return textPropCol.addWithName(textPropName);\r
}\r
\r
protected boolean getFlag(int index) {\r
protected void setFlag(int index, boolean value) {\r
// Ensure we have the StyleTextProp atom we're going to need\r
if(_paragraphStyle == null) {\r
- _paragraphStyle = new TextPropCollection(1, StyleTextPropAtom.paragraphTextPropTypes);\r
+ _paragraphStyle = new TextPropCollection(1, TextPropType.paragraph);\r
}\r
\r
BitMaskTextProp prop = (BitMaskTextProp) fetchOrAddTextProp(_paragraphStyle, ParagraphFlagsTextProp.NAME);\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
htp.setShapeId(prevHtp.getShapeId());\r
htp.supplySheet(prevHtp.getSheet());\r
paragraphs.add(htp);\r
- isFirst = false;\r
}\r
+ isFirst = false;\r
\r
TextPropCollection tpc = htr.getCharacterStyle();\r
// special case, last text run is empty, we will reuse it\r
ccRun += ccStyle-ccRun;\r
}\r
\r
- TextPropCollection pCopy = new TextPropCollection(0, StyleTextPropAtom.characterTextPropTypes);\r
+ TextPropCollection pCopy = new TextPropCollection(0, TextPropType.character);\r
pCopy.copy(p);\r
trun.setCharacterStyle(pCopy);\r
\r
for (int ccPara = 0, ccStyle = p.getCharactersCovered(); ccPara < ccStyle; paraIdx++) {\r
if (paraIdx >= paragraphs.size() || ccPara >= ccStyle-1) return;\r
HSLFTextParagraph htp = paragraphs.get(paraIdx);\r
- TextPropCollection pCopy = new TextPropCollection(0, StyleTextPropAtom.paragraphTextPropTypes);\r
+ TextPropCollection pCopy = new TextPropCollection(0, TextPropType.paragraph);\r
pCopy.copy(p);\r
htp.setParagraphStyle(pCopy);\r
int len = 0;\r
HSLFTextParagraph htp = new HSLFTextParagraph(tha, tba, null, sta);\r
htp.setParagraphStyle(paraStyle);\r
htp._records = new Record[0];\r
- htp.setBullet(false);\r
- htp.setLineSpacing(100);\r
- htp.setLeftMargin(0);\r
- htp.setIndent(0);\r
+// htp.setBullet(false);\r
+// htp.setLineSpacing(100);\r
+// htp.setLeftMargin(0);\r
+// htp.setIndent(0);\r
// set wrap flags\r
\r
HSLFTextRun htr = new HSLFTextRun(htp);\r
htr.setCharacterStyle(charStyle);\r
htr.setText("\r");\r
- htr.setFontColor(Color.black);\r
+// htr.setFontColor(Color.black);\r
htp.addTextRun(htr);\r
\r
return Arrays.asList(htp);\r
import java.awt.Color;
import org.apache.poi.hslf.model.textproperties.*;
+import org.apache.poi.hslf.model.textproperties.TextPropCollection.TextPropType;
import org.apache.poi.hslf.record.ColorSchemeAtom;
-import org.apache.poi.hslf.record.StyleTextPropAtom;
import org.apache.poi.sl.usermodel.TextRun;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
* Our paragraph and character style.
* Note - we may share these styles with other RichTextRuns
*/
- private TextPropCollection characterStyle = new TextPropCollection(0, StyleTextPropAtom.characterTextPropTypes);
+ private TextPropCollection characterStyle = new TextPropCollection(1, TextPropType.character);
/**
* Create a new wrapper around a rich text string
}
public void setCharacterStyle(TextPropCollection characterStyle) {
+ assert(characterStyle != null);
this.characterStyle = characterStyle;
}
* @param val The value to set for the TextProp
*/
public void setCharTextPropVal(String propName, int val) {
- // Ensure we have the StyleTextProp atom we're going to need
- if(characterStyle == null) {
- characterStyle = new TextPropCollection(1, StyleTextPropAtom.characterTextPropTypes);
- // characterStyle will now be defined
- }
-
TextProp tp = fetchOrAddTextProp(characterStyle, propName);
tp.setValue(val);
}
}
protected void setFlag(int index, boolean value) {
- // Ensure we have the StyleTextProp atom we're going to need
- if (characterStyle == null) {
- characterStyle = new TextPropCollection(1, StyleTextPropAtom.characterTextPropTypes);
- }
-
BitMaskTextProp prop = (BitMaskTextProp) fetchOrAddTextProp(characterStyle, CharFlagsTextProp.NAME);
prop.setSubValue(value, index);
}