mirror of https://github.com/apache/poi.git
A few text handling related fixes
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/common_sl@1680695 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
d2e7cd51c3
commit
fd637ce0ed
|
@ -17,11 +17,11 @@
|
||||||
|
|
||||||
package org.apache.poi.hslf.model.textproperties;
|
package org.apache.poi.hslf.model.textproperties;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.*;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import org.apache.poi.hslf.record.StyleTextPropAtom;
|
import org.apache.poi.hslf.record.StyleTextPropAtom;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,8 +33,9 @@ import org.apache.poi.util.LittleEndian;
|
||||||
public class TextPropCollection {
|
public class TextPropCollection {
|
||||||
private int charactersCovered;
|
private int charactersCovered;
|
||||||
private short reservedField;
|
private short reservedField;
|
||||||
private List<TextProp> textPropList;
|
private final List<TextProp> textPropList = new ArrayList<TextProp>();
|
||||||
private int maskSpecial = 0;
|
private int maskSpecial = 0;
|
||||||
|
private final TextProp[] potentialPropList;
|
||||||
|
|
||||||
public int getSpecialMask() { return maskSpecial; }
|
public int getSpecialMask() { return maskSpecial; }
|
||||||
|
|
||||||
|
@ -45,8 +46,7 @@ public class TextPropCollection {
|
||||||
|
|
||||||
/** Fetch the TextProp with this name, or null if it isn't present */
|
/** Fetch the TextProp with this name, or null if it isn't present */
|
||||||
public TextProp findByName(String textPropName) {
|
public TextProp findByName(String textPropName) {
|
||||||
for(int i=0; i<textPropList.size(); i++) {
|
for(TextProp prop : textPropList) {
|
||||||
TextProp prop = textPropList.get(i);
|
|
||||||
if(prop.getName().equals(textPropName)) {
|
if(prop.getName().equals(textPropName)) {
|
||||||
return prop;
|
return prop;
|
||||||
}
|
}
|
||||||
|
@ -57,45 +57,73 @@ public class TextPropCollection {
|
||||||
/** Add the TextProp with this name to the list */
|
/** Add the TextProp with this name to the list */
|
||||||
public TextProp addWithName(String name) {
|
public TextProp addWithName(String name) {
|
||||||
// Find the base TextProp to base on
|
// Find the base TextProp to base on
|
||||||
|
TextProp existing = findByName(name);
|
||||||
|
if (existing != null) return existing;
|
||||||
|
|
||||||
TextProp base = null;
|
TextProp base = null;
|
||||||
for(int i=0; i < StyleTextPropAtom.characterTextPropTypes.length; i++) {
|
for (TextProp tp : potentialPropList) {
|
||||||
if(StyleTextPropAtom.characterTextPropTypes[i].getName().equals(name)) {
|
if (tp.getName().equals(name)) {
|
||||||
base = StyleTextPropAtom.characterTextPropTypes[i];
|
base = tp;
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
for(int i=0; i < StyleTextPropAtom.paragraphTextPropTypes.length; i++) {
|
|
||||||
if(StyleTextPropAtom.paragraphTextPropTypes[i].getName().equals(name)) {
|
|
||||||
base = StyleTextPropAtom.paragraphTextPropTypes[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(base == null) {
|
if(base == null) {
|
||||||
throw new IllegalArgumentException("No TextProp with name " + name + " is defined to add from");
|
throw new IllegalArgumentException("No TextProp with name " + name + " is defined to add from. "
|
||||||
|
+ "Character and paragraphs have their own properties/names.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a copy of this property, in the right place to the list
|
// Add a copy of this property, in the right place to the list
|
||||||
TextProp textProp = base.clone();
|
TextProp textProp = base.clone();
|
||||||
int pos = 0;
|
addProp(textProp);
|
||||||
for(int i=0; i<textPropList.size(); i++) {
|
|
||||||
TextProp curProp = textPropList.get(i);
|
|
||||||
if(textProp.getMask() > curProp.getMask()) {
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
textPropList.add(pos, textProp);
|
|
||||||
return textProp;
|
return textProp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the property at the correct position. Replaces an existing property with the same name.
|
||||||
|
*
|
||||||
|
* @param textProp the property to be added
|
||||||
|
*/
|
||||||
|
public void addProp(TextProp textProp) {
|
||||||
|
assert(textProp != null);
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
boolean found = false;
|
||||||
|
for (TextProp curProp : potentialPropList) {
|
||||||
|
String potName = curProp.getName();
|
||||||
|
if (pos == textPropList.size() || potName.equals(textProp.getName())) {
|
||||||
|
if (textPropList.size() > pos && potName.equals(textPropList.get(pos).getName())) {
|
||||||
|
// replace existing prop (with same name)
|
||||||
|
textPropList.set(pos, textProp);
|
||||||
|
} else {
|
||||||
|
textPropList.add(pos, textProp);
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (potName.equals(textPropList.get(pos).getName())) {
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!found) {
|
||||||
|
String err = "TextProp with name " + textProp.getName() + " doesn't belong to this collection.";
|
||||||
|
throw new IllegalArgumentException(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For an existing set of text properties, build the list of
|
* For an existing set of text properties, build the list of
|
||||||
* properties coded for in a given run of properties.
|
* properties coded for in a given run of properties.
|
||||||
* @return the number of bytes that were used encoding the properties list
|
* @return the number of bytes that were used encoding the properties list
|
||||||
*/
|
*/
|
||||||
public int buildTextPropList(int containsField, TextProp[] potentialProperties, byte[] data, int dataOffset) {
|
public int buildTextPropList(int containsField, byte[] data, int dataOffset) {
|
||||||
int bytesPassed = 0;
|
int bytesPassed = 0;
|
||||||
|
|
||||||
// For each possible entry, see if we match the mask
|
// For each possible entry, see if we match the mask
|
||||||
// If we do, decode that, save it, and shuffle on
|
// If we do, decode that, save it, and shuffle on
|
||||||
for(TextProp tp : potentialProperties) {
|
for(TextProp tp : potentialPropList) {
|
||||||
// Check there's still data left to read
|
// Check there's still data left to read
|
||||||
|
|
||||||
// Check if this property is found in the mask
|
// Check if this property is found in the mask
|
||||||
|
@ -123,7 +151,7 @@ public class TextPropCollection {
|
||||||
}
|
}
|
||||||
prop.setValue(val);
|
prop.setValue(val);
|
||||||
bytesPassed += prop.getSize();
|
bytesPassed += prop.getSize();
|
||||||
textPropList.add(prop);
|
addProp(prop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,20 +164,18 @@ public class TextPropCollection {
|
||||||
* or character) which will be groked via a subsequent call to
|
* or character) which will be groked via a subsequent call to
|
||||||
* buildTextPropList().
|
* buildTextPropList().
|
||||||
*/
|
*/
|
||||||
public TextPropCollection(int charactersCovered, short reservedField) {
|
public TextPropCollection(int charactersCovered, short reservedField, TextProp[] potentialPropList) {
|
||||||
this.charactersCovered = charactersCovered;
|
this.charactersCovered = charactersCovered;
|
||||||
this.reservedField = reservedField;
|
this.reservedField = reservedField;
|
||||||
textPropList = new ArrayList<TextProp>();
|
this.potentialPropList = potentialPropList;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new collection of text properties (be they paragraph
|
* Create a new collection of text properties (be they paragraph
|
||||||
* or character) for a run of text without any
|
* or character) for a run of text without any
|
||||||
*/
|
*/
|
||||||
public TextPropCollection(int textSize) {
|
public TextPropCollection(int textSize, TextProp[] potentialPropList) {
|
||||||
charactersCovered = textSize;
|
this(textSize, (short)-1, potentialPropList);
|
||||||
reservedField = -1;
|
|
||||||
textPropList = new ArrayList<TextProp>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -158,12 +184,13 @@ public class TextPropCollection {
|
||||||
public void copy(TextPropCollection other) {
|
public void copy(TextPropCollection other) {
|
||||||
this.charactersCovered = other.charactersCovered;
|
this.charactersCovered = other.charactersCovered;
|
||||||
this.reservedField = other.reservedField;
|
this.reservedField = other.reservedField;
|
||||||
|
this.maskSpecial = other.maskSpecial;
|
||||||
this.textPropList.clear();
|
this.textPropList.clear();
|
||||||
for (TextProp tp : other.textPropList) {
|
for (TextProp tp : other.textPropList) {
|
||||||
TextProp tpCopy = (tp instanceof BitMaskTextProp)
|
TextProp tpCopy = (tp instanceof BitMaskTextProp)
|
||||||
? ((BitMaskTextProp)tp).cloneAll()
|
? ((BitMaskTextProp)tp).cloneAll()
|
||||||
: tp.clone();
|
: tp.clone();
|
||||||
this.textPropList.add(tpCopy);
|
addProp(tpCopy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +205,7 @@ public class TextPropCollection {
|
||||||
/**
|
/**
|
||||||
* Writes out to disk the header, and then all the properties
|
* Writes out to disk the header, and then all the properties
|
||||||
*/
|
*/
|
||||||
public void writeOut(OutputStream o, TextProp[] potentialProperties) throws IOException {
|
public void writeOut(OutputStream o) throws IOException {
|
||||||
// First goes the number of characters we affect
|
// First goes the number of characters we affect
|
||||||
StyleTextPropAtom.writeLittleEndian(charactersCovered,o);
|
StyleTextPropAtom.writeLittleEndian(charactersCovered,o);
|
||||||
|
|
||||||
|
@ -201,12 +228,17 @@ public class TextPropCollection {
|
||||||
StyleTextPropAtom.writeLittleEndian(mask,o);
|
StyleTextPropAtom.writeLittleEndian(mask,o);
|
||||||
|
|
||||||
// Then the contents of all the properties
|
// Then the contents of all the properties
|
||||||
for (TextProp potProp : potentialProperties) {
|
for (TextProp potProp : potentialPropList) {
|
||||||
for(TextProp textProp : textPropList) {
|
for(TextProp textProp : textPropList) {
|
||||||
if (!textProp.getName().equals(potProp.getName())) continue;
|
if (!textProp.getName().equals(potProp.getName())) continue;
|
||||||
int val = textProp.getValue();
|
int val = textProp.getValue();
|
||||||
if (textProp instanceof BitMaskTextProp && val == 0) {
|
if (textProp instanceof BitMaskTextProp && val == 0
|
||||||
|
&& !(textProp instanceof ParagraphFlagsTextProp)
|
||||||
|
// && !(textProp instanceof CharFlagsTextProp)
|
||||||
|
) {
|
||||||
// don't add empty properties, as they can't be recognized while reading
|
// 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;
|
continue;
|
||||||
} else if (textProp.getSize() == 2) {
|
} else if (textProp.getSize() == 2) {
|
||||||
StyleTextPropAtom.writeLittleEndian((short)val,o);
|
StyleTextPropAtom.writeLittleEndian((short)val,o);
|
||||||
|
@ -264,4 +296,26 @@ public class TextPropCollection {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder out = new StringBuilder();
|
||||||
|
out.append(" chars covered: " + getCharactersCovered());
|
||||||
|
out.append(" special mask flags: 0x" + HexDump.toHex(getSpecialMask()) + "\n");
|
||||||
|
for(TextProp p : getTextPropList()) {
|
||||||
|
out.append(" " + p.getName() + " = " + p.getValue() );
|
||||||
|
out.append(" (0x" + HexDump.toHex(p.getValue()) + ")\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
out.append(" bytes that would be written: \n");
|
||||||
|
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
writeOut(baos);
|
||||||
|
byte[] b = baos.toByteArray();
|
||||||
|
out.append(HexDump.dump(b, 0, 0));
|
||||||
|
} catch (Exception e ) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return out.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,15 +218,23 @@ public final class StyleTextPropAtom extends RecordAtom
|
||||||
charStyles = new ArrayList<TextPropCollection>();
|
charStyles = new ArrayList<TextPropCollection>();
|
||||||
|
|
||||||
TextPropCollection defaultParagraphTextProps =
|
TextPropCollection defaultParagraphTextProps =
|
||||||
new TextPropCollection(parentTextSize, (short)0);
|
new TextPropCollection(parentTextSize, (short)0, paragraphTextPropTypes);
|
||||||
|
defaultParagraphTextProps.addWithName("paragraph_flags");
|
||||||
paragraphStyles.add(defaultParagraphTextProps);
|
paragraphStyles.add(defaultParagraphTextProps);
|
||||||
|
|
||||||
TextPropCollection defaultCharacterTextProps =
|
TextPropCollection defaultCharacterTextProps =
|
||||||
new TextPropCollection(parentTextSize);
|
new TextPropCollection(parentTextSize, characterTextPropTypes);
|
||||||
|
defaultCharacterTextProps.addWithName("char_flags");
|
||||||
charStyles.add(defaultCharacterTextProps);
|
charStyles.add(defaultCharacterTextProps);
|
||||||
|
|
||||||
// Set us as now initialised
|
// Set us as now initialised
|
||||||
initialised = true;
|
initialised = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
updateRawContents();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -245,10 +253,6 @@ public final class StyleTextPropAtom extends RecordAtom
|
||||||
// on the properties
|
// on the properties
|
||||||
updateRawContents();
|
updateRawContents();
|
||||||
|
|
||||||
// Now ensure that the header size is correct
|
|
||||||
int newSize = rawContents.length + reserved.length;
|
|
||||||
LittleEndian.putInt(_header,4,newSize);
|
|
||||||
|
|
||||||
// Write out the (new) header
|
// Write out the (new) header
|
||||||
out.write(_header);
|
out.write(_header);
|
||||||
|
|
||||||
|
@ -265,9 +269,14 @@ public final class StyleTextPropAtom extends RecordAtom
|
||||||
* contains, so we can go ahead and initialise ourselves.
|
* contains, so we can go ahead and initialise ourselves.
|
||||||
*/
|
*/
|
||||||
public void setParentTextSize(int size) {
|
public void setParentTextSize(int size) {
|
||||||
|
// if (initialised) return;
|
||||||
|
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
int textHandled = 0;
|
int textHandled = 0;
|
||||||
|
|
||||||
|
paragraphStyles.clear();
|
||||||
|
charStyles.clear();
|
||||||
|
|
||||||
// While we have text in need of paragraph stylings, go ahead and
|
// While we have text in need of paragraph stylings, go ahead and
|
||||||
// grok the contents as paragraph formatting data
|
// grok the contents as paragraph formatting data
|
||||||
int prsize = size;
|
int prsize = size;
|
||||||
|
@ -286,9 +295,8 @@ public final class StyleTextPropAtom extends RecordAtom
|
||||||
pos += 4;
|
pos += 4;
|
||||||
|
|
||||||
// Now make sense of those properties
|
// Now make sense of those properties
|
||||||
TextPropCollection thisCollection = new TextPropCollection(textLen, indent);
|
TextPropCollection thisCollection = new TextPropCollection(textLen, indent, paragraphTextPropTypes);
|
||||||
int plSize = thisCollection.buildTextPropList(
|
int plSize = thisCollection.buildTextPropList(paraFlags, rawContents, pos);
|
||||||
paraFlags, paragraphTextPropTypes, rawContents, pos);
|
|
||||||
pos += plSize;
|
pos += plSize;
|
||||||
|
|
||||||
// Save this properties set
|
// Save this properties set
|
||||||
|
@ -323,9 +331,8 @@ public final class StyleTextPropAtom extends RecordAtom
|
||||||
|
|
||||||
// Now make sense of those properties
|
// Now make sense of those properties
|
||||||
// (Assuming we actually have some)
|
// (Assuming we actually have some)
|
||||||
TextPropCollection thisCollection = new TextPropCollection(textLen, no_val);
|
TextPropCollection thisCollection = new TextPropCollection(textLen, no_val, characterTextPropTypes);
|
||||||
int chSize = thisCollection.buildTextPropList(
|
int chSize = thisCollection.buildTextPropList(charFlags, rawContents, pos);
|
||||||
charFlags, characterTextPropTypes, rawContents, pos);
|
|
||||||
pos += chSize;
|
pos += chSize;
|
||||||
|
|
||||||
// Save this properties set
|
// Save this properties set
|
||||||
|
@ -363,33 +370,32 @@ public final class StyleTextPropAtom extends RecordAtom
|
||||||
* Updates the cache of the raw contents. Serialised the styles out.
|
* Updates the cache of the raw contents. Serialised the styles out.
|
||||||
*/
|
*/
|
||||||
private void updateRawContents() throws IOException {
|
private void updateRawContents() throws IOException {
|
||||||
if(!initialised) {
|
if (initialised) {
|
||||||
// We haven't groked the styles since creation, so just stick
|
// Only update the style bytes, if the styles have been potentially
|
||||||
// with what we found
|
// changed
|
||||||
return;
|
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
// First up, we need to serialise the paragraph properties
|
||||||
|
for(TextPropCollection tpc : paragraphStyles) {
|
||||||
|
// ensure, that the paragraphs flags exist, no matter if anthing is set
|
||||||
|
tpc.addWithName(ParagraphFlagsTextProp.NAME);
|
||||||
|
tpc.writeOut(baos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, we do the character ones
|
||||||
|
for(TextPropCollection tpc : charStyles) {
|
||||||
|
// ditto for the char flags
|
||||||
|
tpc.addWithName(CharFlagsTextProp.NAME);
|
||||||
|
tpc.writeOut(baos);
|
||||||
|
}
|
||||||
|
|
||||||
|
rawContents = baos.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
// Now ensure that the header size is correct
|
||||||
|
int newSize = rawContents.length + reserved.length;
|
||||||
// First up, we need to serialise the paragraph properties
|
LittleEndian.putInt(_header,4,newSize);
|
||||||
for(int i=0; i<paragraphStyles.size(); i++) {
|
|
||||||
TextPropCollection tpc = paragraphStyles.get(i);
|
|
||||||
tpc.writeOut(baos, paragraphTextPropTypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, we do the character ones
|
|
||||||
for(int i=0; i<charStyles.size(); i++) {
|
|
||||||
TextPropCollection tpc = charStyles.get(i);
|
|
||||||
tpc.writeOut(baos, characterTextPropTypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
rawContents = baos.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRawContents(byte[] bytes) {
|
|
||||||
rawContents = bytes;
|
|
||||||
reserved = new byte[0];
|
|
||||||
initialised = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -398,6 +404,8 @@ public final class StyleTextPropAtom extends RecordAtom
|
||||||
public void clearStyles() {
|
public void clearStyles() {
|
||||||
paragraphStyles.clear();
|
paragraphStyles.clear();
|
||||||
charStyles.clear();
|
charStyles.clear();
|
||||||
|
reserved = new byte[0];
|
||||||
|
initialised = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -406,7 +414,7 @@ public final class StyleTextPropAtom extends RecordAtom
|
||||||
* @return the new TextPropCollection, which will then be in the list
|
* @return the new TextPropCollection, which will then be in the list
|
||||||
*/
|
*/
|
||||||
public TextPropCollection addParagraphTextPropCollection(int charactersCovered) {
|
public TextPropCollection addParagraphTextPropCollection(int charactersCovered) {
|
||||||
TextPropCollection tpc = new TextPropCollection(charactersCovered, (short)0);
|
TextPropCollection tpc = new TextPropCollection(charactersCovered, (short)0, paragraphTextPropTypes);
|
||||||
paragraphStyles.add(tpc);
|
paragraphStyles.add(tpc);
|
||||||
return tpc;
|
return tpc;
|
||||||
}
|
}
|
||||||
|
@ -416,7 +424,7 @@ public final class StyleTextPropAtom extends RecordAtom
|
||||||
* @return the new TextPropCollection, which will then be in the list
|
* @return the new TextPropCollection, which will then be in the list
|
||||||
*/
|
*/
|
||||||
public TextPropCollection addCharacterTextPropCollection(int charactersCovered) {
|
public TextPropCollection addCharacterTextPropCollection(int charactersCovered) {
|
||||||
TextPropCollection tpc = new TextPropCollection(charactersCovered);
|
TextPropCollection tpc = new TextPropCollection(charactersCovered, characterTextPropTypes);
|
||||||
charStyles.add(tpc);
|
charStyles.add(tpc);
|
||||||
return tpc;
|
return tpc;
|
||||||
}
|
}
|
||||||
|
@ -438,51 +446,25 @@ public final class StyleTextPropAtom extends RecordAtom
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
out.append("Paragraph properties\n");
|
out.append("Paragraph properties\n");
|
||||||
|
|
||||||
for(TextPropCollection pr : getParagraphStyles()) {
|
for(TextPropCollection pr : getParagraphStyles()) {
|
||||||
out.append(" chars covered: " + pr.getCharactersCovered());
|
out.append(pr);
|
||||||
out.append(" special mask flags: 0x" + HexDump.toHex(pr.getSpecialMask()) + "\n");
|
|
||||||
for(TextProp p : pr.getTextPropList()) {
|
|
||||||
out.append(" " + p.getName() + " = " + p.getValue() );
|
|
||||||
out.append(" (0x" + HexDump.toHex(p.getValue()) + ")\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
out.append(" para bytes that would be written: \n");
|
|
||||||
|
|
||||||
try {
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
pr.writeOut(baos, paragraphTextPropTypes);
|
|
||||||
byte[] b = baos.toByteArray();
|
|
||||||
out.append(HexDump.dump(b, 0, 0));
|
|
||||||
} catch (Exception e ) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out.append("Character properties\n");
|
out.append("Character properties\n");
|
||||||
for(TextPropCollection pr : getCharacterStyles()) {
|
for(TextPropCollection pr : getCharacterStyles()) {
|
||||||
out.append(" chars covered: " + pr.getCharactersCovered() );
|
out.append(pr);
|
||||||
out.append(" special mask flags: 0x" + HexDump.toHex(pr.getSpecialMask()) + "\n");
|
|
||||||
for(TextProp p : pr.getTextPropList()) {
|
|
||||||
out.append(" " + p.getName() + " = " + p.getValue() );
|
|
||||||
out.append(" (0x" + HexDump.toHex(p.getValue()) + ")\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
out.append(" char bytes that would be written: \n");
|
|
||||||
|
|
||||||
try {
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
pr.writeOut(baos, characterTextPropTypes);
|
|
||||||
byte[] b = baos.toByteArray();
|
|
||||||
out.append(HexDump.dump(b, 0, 0));
|
|
||||||
} catch (Exception e ) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out.append("Reserved bytes\n");
|
||||||
|
out.append( HexDump.dump(reserved, 0, 0) );
|
||||||
}
|
}
|
||||||
|
|
||||||
out.append(" original byte stream \n");
|
out.append(" original byte stream \n");
|
||||||
out.append( HexDump.dump(rawContents, 0, 0) );
|
|
||||||
|
byte buf[] = new byte[rawContents.length+reserved.length];
|
||||||
|
System.arraycopy(rawContents, 0, buf, 0, rawContents.length);
|
||||||
|
System.arraycopy(reserved, 0, buf, rawContents.length, reserved.length);
|
||||||
|
out.append( HexDump.dump(buf, 0, 0) );
|
||||||
|
|
||||||
return out.toString();
|
return out.toString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,14 +182,14 @@ public final class TxMasterStyleAtom extends RecordAtom {
|
||||||
|
|
||||||
head = LittleEndian.getInt(_data, pos);
|
head = LittleEndian.getInt(_data, pos);
|
||||||
pos += LittleEndian.INT_SIZE;
|
pos += LittleEndian.INT_SIZE;
|
||||||
TextPropCollection prprops = new TextPropCollection(0);
|
TextPropCollection prprops = new TextPropCollection(0, getParagraphProps(type, j));
|
||||||
pos += prprops.buildTextPropList( head, getParagraphProps(type, j), _data, pos);
|
pos += prprops.buildTextPropList( head, _data, pos);
|
||||||
prstyles[j] = prprops;
|
prstyles[j] = prprops;
|
||||||
|
|
||||||
head = LittleEndian.getInt(_data, pos);
|
head = LittleEndian.getInt(_data, pos);
|
||||||
pos += LittleEndian.INT_SIZE;
|
pos += LittleEndian.INT_SIZE;
|
||||||
TextPropCollection chprops = new TextPropCollection(0);
|
TextPropCollection chprops = new TextPropCollection(0, getCharacterProps(type, j));
|
||||||
pos += chprops.buildTextPropList( head, getCharacterProps(type, j), _data, pos);
|
pos += chprops.buildTextPropList( head, _data, pos);
|
||||||
chstyles[j] = chprops;
|
chstyles[j] = chprops;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
package org.apache.poi.hslf.usermodel;
|
package org.apache.poi.hslf.usermodel;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import org.apache.poi.hslf.model.PPFont;
|
import org.apache.poi.hslf.model.PPFont;
|
||||||
|
@ -36,7 +38,7 @@ import org.apache.poi.util.*;
|
||||||
|
|
||||||
public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
protected static POILogger logger = POILogFactory.getLogger(HSLFTextParagraph.class);
|
protected static POILogger logger = POILogFactory.getLogger(HSLFTextParagraph.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* How to align the text
|
* How to align the text
|
||||||
*/
|
*/
|
||||||
|
@ -44,16 +46,16 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
/* package */ static final int AlignCenter = 1;
|
/* package */ static final int AlignCenter = 1;
|
||||||
/* package */ static final int AlignRight = 2;
|
/* package */ static final int AlignRight = 2;
|
||||||
/* package */ static final int AlignJustify = 3;
|
/* package */ static final int AlignJustify = 3;
|
||||||
|
|
||||||
|
|
||||||
// Note: These fields are protected to help with unit testing
|
// Note: These fields are protected to help with unit testing
|
||||||
// Other classes shouldn't really go playing with them!
|
// Other classes shouldn't really go playing with them!
|
||||||
private final TextHeaderAtom _headerAtom;
|
private final TextHeaderAtom _headerAtom;
|
||||||
private final TextBytesAtom _byteAtom;
|
private TextBytesAtom _byteAtom;
|
||||||
private final TextCharsAtom _charAtom;
|
private TextCharsAtom _charAtom;
|
||||||
private StyleTextPropAtom _styleAtom;
|
private StyleTextPropAtom _styleAtom;
|
||||||
private TextPropCollection _paragraphStyle = new TextPropCollection(1);
|
private TextPropCollection _paragraphStyle = new TextPropCollection(1, StyleTextPropAtom.paragraphTextPropTypes);
|
||||||
|
|
||||||
protected TextRulerAtom _ruler;
|
protected TextRulerAtom _ruler;
|
||||||
protected List<HSLFTextRun> _runs = new ArrayList<HSLFTextRun>();
|
protected List<HSLFTextRun> _runs = new ArrayList<HSLFTextRun>();
|
||||||
protected HSLFTextShape _parentShape;
|
protected HSLFTextShape _parentShape;
|
||||||
|
@ -70,7 +72,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a Text Run from a Unicode text block.
|
* Constructs a Text Run from a Unicode text block.
|
||||||
* Either a {@link TextCharsAtom} or a {@link TextBytesAtom} needs to be provided.
|
* Either a {@link TextCharsAtom} or a {@link TextBytesAtom} needs to be provided.
|
||||||
*
|
*
|
||||||
* @param tha the TextHeaderAtom that defines what's what
|
* @param tha the TextHeaderAtom that defines what's what
|
||||||
* @param tba the TextBytesAtom containing the text or null if {@link TextCharsAtom} is provided
|
* @param tba the TextBytesAtom containing the text or null if {@link TextCharsAtom} is provided
|
||||||
|
@ -105,7 +107,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
public void addTextRun(HSLFTextRun run) {
|
public void addTextRun(HSLFTextRun run) {
|
||||||
_runs.add(run);
|
_runs.add(run);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch the rich text runs (runs of text with the same styling) that
|
* Fetch the rich text runs (runs of text with the same styling) that
|
||||||
* are contained within this block of text
|
* are contained within this block of text
|
||||||
|
@ -117,11 +119,11 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
public TextPropCollection getParagraphStyle() {
|
public TextPropCollection getParagraphStyle() {
|
||||||
return _paragraphStyle;
|
return _paragraphStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setParagraphStyle(TextPropCollection paragraphStyle) {
|
public void setParagraphStyle(TextPropCollection paragraphStyle) {
|
||||||
_paragraphStyle = paragraphStyle;
|
_paragraphStyle = paragraphStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Supply the Sheet we belong to, which might have an assigned SlideShow
|
* Supply the Sheet we belong to, which might have an assigned SlideShow
|
||||||
* Also passes it on to our child RichTextRuns
|
* Also passes it on to our child RichTextRuns
|
||||||
|
@ -161,14 +163,14 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the index of the paragraph in the SLWT container
|
* Sets the index of the paragraph in the SLWT container
|
||||||
*
|
*
|
||||||
* @param index
|
* @param index
|
||||||
*/
|
*/
|
||||||
protected void setIndex(int index) {
|
protected void setIndex(int index) {
|
||||||
if (_headerAtom != null) _headerAtom.setIndex(index);
|
if (_headerAtom != null) _headerAtom.setIndex(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the type of the text, from the TextHeaderAtom.
|
* Returns the type of the text, from the TextHeaderAtom.
|
||||||
* Possible values can be seen from TextHeaderAtom
|
* Possible values can be seen from TextHeaderAtom
|
||||||
|
@ -177,7 +179,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
public int getRunType() {
|
public int getRunType() {
|
||||||
return (_headerAtom != null) ? _headerAtom.getTextType() : -1;
|
return (_headerAtom != null) ? _headerAtom.getTextType() : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this Text Run one from a {@link PPDrawing}, or is it
|
* Is this Text Run one from a {@link PPDrawing}, or is it
|
||||||
* one from the {@link SlideListWithText}?
|
* one from the {@link SlideListWithText}?
|
||||||
|
@ -208,12 +210,12 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
public Record[] getRecords(){
|
public Record[] getRecords(){
|
||||||
return _records;
|
return _records;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Numbered List info */
|
/** Numbered List info */
|
||||||
public void setStyleTextProp9Atom(final StyleTextProp9Atom styleTextProp9Atom) {
|
public void setStyleTextProp9Atom(final StyleTextProp9Atom styleTextProp9Atom) {
|
||||||
this.styleTextProp9Atom = styleTextProp9Atom;
|
this.styleTextProp9Atom = styleTextProp9Atom;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Numbered List info */
|
/** Numbered List info */
|
||||||
public StyleTextProp9Atom getStyleTextProp9Atom() {
|
public StyleTextProp9Atom getStyleTextProp9Atom() {
|
||||||
return this.styleTextProp9Atom;
|
return this.styleTextProp9Atom;
|
||||||
|
@ -221,7 +223,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
|
|
||||||
/** Characters covered */
|
/** Characters covered */
|
||||||
public StyleTextPropAtom getStyleTextPropAtom() {
|
public StyleTextPropAtom getStyleTextPropAtom() {
|
||||||
return this._styleAtom;
|
return this._styleAtom;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -258,56 +260,14 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
public void setParaTextPropVal(String propName, int val) {
|
public void setParaTextPropVal(String propName, int val) {
|
||||||
// Ensure we have the StyleTextProp atom we're going to need
|
// Ensure we have the StyleTextProp atom we're going to need
|
||||||
if(_paragraphStyle == null) {
|
if(_paragraphStyle == null) {
|
||||||
ensureStyleAtomPresent();
|
_styleAtom = findStyleAtomPresent(_headerAtom, -1);
|
||||||
// paragraphStyle will now be defined
|
_paragraphStyle = _styleAtom.getParagraphStyles().get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(_paragraphStyle!=null);
|
assert(_paragraphStyle!=null);
|
||||||
TextProp tp = fetchOrAddTextProp(_paragraphStyle, propName);
|
TextProp tp = fetchOrAddTextProp(_paragraphStyle, propName);
|
||||||
tp.setValue(val);
|
tp.setValue(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensure a StyleTextPropAtom is present for this run,
|
|
||||||
* by adding if required. Normally for internal TextRun use.
|
|
||||||
*/
|
|
||||||
protected StyleTextPropAtom ensureStyleAtomPresent() {
|
|
||||||
if (_styleAtom != null) {
|
|
||||||
return _styleAtom;
|
|
||||||
}
|
|
||||||
|
|
||||||
_styleAtom = ensureStyleAtomPresent(_headerAtom, _byteAtom, _charAtom);
|
|
||||||
_paragraphStyle = _styleAtom.getParagraphStyles().get(0);
|
|
||||||
|
|
||||||
return _styleAtom;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static StyleTextPropAtom ensureStyleAtomPresent(TextHeaderAtom header, TextBytesAtom tbytes, TextCharsAtom tchars) {
|
|
||||||
RecordContainer wrapper = header.getParentRecord();
|
|
||||||
StyleTextPropAtom styleAtom = null;
|
|
||||||
|
|
||||||
boolean afterHeader = false;
|
|
||||||
for (Record record : wrapper.getChildRecords()) {
|
|
||||||
if (afterHeader && record.getRecordType() == RecordTypes.TextHeaderAtom.typeID) break;
|
|
||||||
afterHeader |= (header == record);
|
|
||||||
if (afterHeader && record.getRecordType() == RecordTypes.StyleTextPropAtom.typeID) {
|
|
||||||
styleAtom = (StyleTextPropAtom)record;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (styleAtom != null) return styleAtom;
|
|
||||||
|
|
||||||
String rawText = (tchars != null) ? tchars.getText() : tbytes.getText();
|
|
||||||
|
|
||||||
// Create a new one at the right size
|
|
||||||
styleAtom = new StyleTextPropAtom(rawText.length()+1);
|
|
||||||
|
|
||||||
// Add the new StyleTextPropAtom after the TextCharsAtom / TextBytesAtom
|
|
||||||
wrapper.addChildAfter(styleAtom, (tbytes == null ? tchars : tbytes));
|
|
||||||
|
|
||||||
return styleAtom;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<HSLFTextRun> iterator() {
|
public Iterator<HSLFTextRun> iterator() {
|
||||||
|
@ -325,7 +285,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
int val = (int)(leftMargin*HSLFShape.MASTER_DPI/HSLFShape.POINT_DPI);
|
int val = (int)(leftMargin*HSLFShape.MASTER_DPI/HSLFShape.POINT_DPI);
|
||||||
setParaTextPropVal("text.offset", val);
|
setParaTextPropVal("text.offset", val);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getRightMargin() {
|
public double getRightMargin() {
|
||||||
// TODO: find out, how to determine this value
|
// TODO: find out, how to determine this value
|
||||||
|
@ -336,7 +296,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
public void setRightMargin(double rightMargin) {
|
public void setRightMargin(double rightMargin) {
|
||||||
// TODO: find out, how to set this value
|
// TODO: find out, how to set this value
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getIndent() {
|
public double getIndent() {
|
||||||
int val = getParaTextPropVal("bullet.offset");
|
int val = getParaTextPropVal("bullet.offset");
|
||||||
|
@ -378,7 +338,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
}
|
}
|
||||||
setParaTextPropVal("alignment", alignInt);
|
setParaTextPropVal("alignment", alignInt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public org.apache.poi.sl.usermodel.TextParagraph.TextAlign getTextAlign() {
|
public org.apache.poi.sl.usermodel.TextParagraph.TextAlign getTextAlign() {
|
||||||
switch (getParaTextPropVal("alignment")) {
|
switch (getParaTextPropVal("alignment")) {
|
||||||
|
@ -408,7 +368,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
@Override
|
@Override
|
||||||
public BulletStyle getBulletStyle() {
|
public BulletStyle getBulletStyle() {
|
||||||
if (getBulletChar() == 0) return null;
|
if (getBulletChar() == 0) return null;
|
||||||
|
|
||||||
return new BulletStyle() {
|
return new BulletStyle() {
|
||||||
public String getBulletCharacter() {
|
public String getBulletCharacter() {
|
||||||
char chr = HSLFTextParagraph.this.getBulletChar();
|
char chr = HSLFTextParagraph.this.getBulletChar();
|
||||||
|
@ -441,7 +401,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
_parentShape = parentShape;
|
_parentShape = parentShape;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return indentation level
|
* @return indentation level
|
||||||
|
@ -622,7 +582,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
int val = getParaTextPropVal("spaceafter");
|
int val = getParaTextPropVal("spaceafter");
|
||||||
return val == -1 ? 0 : val;
|
return val == -1 ? 0 : val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the named TextProp, either by fetching it (if it exists) or adding it
|
* Returns the named TextProp, either by fetching it (if it exists) or adding it
|
||||||
* (if it didn't)
|
* (if it didn't)
|
||||||
|
@ -661,7 +621,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
protected void setFlag(int index, boolean value) {
|
protected void setFlag(int index, boolean value) {
|
||||||
// Ensure we have the StyleTextProp atom we're going to need
|
// Ensure we have the StyleTextProp atom we're going to need
|
||||||
if(_paragraphStyle == null) {
|
if(_paragraphStyle == null) {
|
||||||
_paragraphStyle = new TextPropCollection(1);
|
_paragraphStyle = new TextPropCollection(1, StyleTextPropAtom.paragraphTextPropTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
BitMaskTextProp prop = (BitMaskTextProp) fetchOrAddTextProp(_paragraphStyle, ParagraphFlagsTextProp.NAME);
|
BitMaskTextProp prop = (BitMaskTextProp) fetchOrAddTextProp(_paragraphStyle, ParagraphFlagsTextProp.NAME);
|
||||||
|
@ -685,81 +645,120 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
}
|
}
|
||||||
lastRun = ltr.get(ltr.size()-1);
|
lastRun = ltr.get(ltr.size()-1);
|
||||||
assert(lastRun.getRawText() != null);
|
assert(lastRun.getRawText() != null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search for a StyleTextPropAtom is for this text header (list of paragraphs)
|
||||||
|
*
|
||||||
|
* @param header the header
|
||||||
|
* @param textLen the length of the rawtext, or -1 if the length is not known
|
||||||
|
*/
|
||||||
|
private static StyleTextPropAtom findStyleAtomPresent(TextHeaderAtom header, int textLen) {
|
||||||
|
boolean afterHeader = false;
|
||||||
|
StyleTextPropAtom style = null;
|
||||||
|
for (Record record : header.getParentRecord().getChildRecords()) {
|
||||||
|
if (afterHeader && record.getRecordType() == RecordTypes.TextHeaderAtom.typeID) {
|
||||||
|
// already on the next header, quit searching
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
afterHeader |= (header == record);
|
||||||
|
if (afterHeader && record.getRecordType() == RecordTypes.StyleTextPropAtom.typeID) {
|
||||||
|
// found it
|
||||||
|
style = (StyleTextPropAtom)record;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (style == null) {
|
||||||
|
logger.log(POILogger.INFO, "styles atom doesn't exist. Creating dummy record for later saving.");
|
||||||
|
style = new StyleTextPropAtom((textLen < 0) ? 1 : textLen);
|
||||||
|
} else {
|
||||||
|
if (textLen >= 0) {
|
||||||
|
style.setParentTextSize(textLen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the modified paragraphs/textrun to the records.
|
* Saves the modified paragraphs/textrun to the records.
|
||||||
* Also updates the styles to the correct text length.
|
* Also updates the styles to the correct text length.
|
||||||
*/
|
*/
|
||||||
protected static void storeText(List<HSLFTextParagraph> paragraphs) {
|
protected static void storeText(List<HSLFTextParagraph> paragraphs) {
|
||||||
fixLineEndings(paragraphs);
|
fixLineEndings(paragraphs);
|
||||||
|
|
||||||
String rawText = toInternalString(getRawText(paragraphs));
|
String rawText = toInternalString(getRawText(paragraphs));
|
||||||
|
|
||||||
// Will it fit in a 8 bit atom?
|
// Will it fit in a 8 bit atom?
|
||||||
boolean isUnicode = StringUtil.hasMultibyte(rawText);
|
boolean isUnicode = StringUtil.hasMultibyte(rawText);
|
||||||
|
// isUnicode = true;
|
||||||
|
|
||||||
TextHeaderAtom headerAtom = paragraphs.get(0)._headerAtom;
|
TextHeaderAtom headerAtom = paragraphs.get(0)._headerAtom;
|
||||||
TextBytesAtom byteAtom = paragraphs.get(0)._byteAtom;
|
TextBytesAtom byteAtom = paragraphs.get(0)._byteAtom;
|
||||||
TextCharsAtom charAtom = paragraphs.get(0)._charAtom;
|
TextCharsAtom charAtom = paragraphs.get(0)._charAtom;
|
||||||
|
StyleTextPropAtom styleAtom = findStyleAtomPresent(headerAtom, rawText.length());
|
||||||
|
|
||||||
// Store in the appropriate record
|
// Store in the appropriate record
|
||||||
Record oldRecord = null, newRecord = null;
|
Record oldRecord = null, newRecord = null;
|
||||||
if (isUnicode) {
|
if (isUnicode) {
|
||||||
if (byteAtom != null) {
|
if (byteAtom != null || charAtom == null) {
|
||||||
oldRecord = byteAtom;
|
oldRecord = byteAtom;
|
||||||
newRecord = charAtom = new TextCharsAtom();
|
charAtom = new TextCharsAtom();
|
||||||
}
|
}
|
||||||
|
newRecord = charAtom;
|
||||||
charAtom.setText(rawText);
|
charAtom.setText(rawText);
|
||||||
} else {
|
} else {
|
||||||
if (charAtom != null) {
|
if (charAtom != null || byteAtom == null) {
|
||||||
oldRecord = charAtom;
|
oldRecord = charAtom;
|
||||||
newRecord = byteAtom = new TextBytesAtom();
|
byteAtom = new TextBytesAtom();
|
||||||
}
|
}
|
||||||
|
newRecord = byteAtom;
|
||||||
byte[] byteText = new byte[rawText.length()];
|
byte[] byteText = new byte[rawText.length()];
|
||||||
StringUtil.putCompressedUnicode(rawText,byteText,0);
|
StringUtil.putCompressedUnicode(rawText,byteText,0);
|
||||||
byteAtom.setText(byteText);
|
byteAtom.setText(byteText);
|
||||||
}
|
}
|
||||||
|
assert(newRecord != null);
|
||||||
RecordContainer _txtbox = headerAtom.getParentRecord();
|
|
||||||
|
|
||||||
if (oldRecord != null) {
|
RecordContainer _txtbox = headerAtom.getParentRecord();
|
||||||
// swap not appropriated records
|
Record[] cr = _txtbox.getChildRecords();
|
||||||
Record[] cr = _txtbox.getChildRecords();
|
int headerIdx = -1, textIdx = -1, styleIdx = -1;
|
||||||
int idx=0;
|
for (int i=0; i<cr.length; i++) {
|
||||||
for (Record r : cr) {
|
Record r = cr[i];
|
||||||
if(r.equals(oldRecord)) break;
|
if (r == headerAtom) headerIdx = i;
|
||||||
idx++;
|
else if (r == oldRecord || r == newRecord) textIdx = i;
|
||||||
}
|
else if (r == styleAtom) styleIdx = i;
|
||||||
if (idx >= cr.length) {
|
|
||||||
throw new RuntimeException("child record not found - malformed container record");
|
|
||||||
}
|
|
||||||
cr[idx] = newRecord;
|
|
||||||
|
|
||||||
if (newRecord == byteAtom) {
|
|
||||||
charAtom = null;
|
|
||||||
} else {
|
|
||||||
byteAtom = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure a StyleTextPropAtom is present, adding if required
|
if (textIdx == -1) {
|
||||||
StyleTextPropAtom styleAtom = ensureStyleAtomPresent(headerAtom, byteAtom, charAtom);
|
// the old record was never registered, ignore it
|
||||||
|
_txtbox.addChildAfter(newRecord, headerAtom);
|
||||||
|
textIdx = headerIdx+1;
|
||||||
|
} else {
|
||||||
|
// swap not appropriated records - noop if unchanged
|
||||||
|
cr[textIdx] = newRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (styleIdx == -1) {
|
||||||
|
// Add the new StyleTextPropAtom after the TextCharsAtom / TextBytesAtom
|
||||||
|
_txtbox.addChildAfter(styleAtom, newRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (HSLFTextParagraph p : paragraphs) {
|
||||||
|
if (newRecord == byteAtom) {
|
||||||
|
p._charAtom = null;
|
||||||
|
} else {
|
||||||
|
p._byteAtom = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update the text length for its Paragraph and Character stylings
|
// Update the text length for its Paragraph and Character stylings
|
||||||
// If it's shared:
|
|
||||||
// * calculate the new length based on the run's old text
|
|
||||||
// * this should leave in any +1's for the end of block if needed
|
|
||||||
// If it isn't shared:
|
|
||||||
// * reset the length, to the new string's length
|
// * reset the length, to the new string's length
|
||||||
// * add on +1 if the last block
|
// * add on +1 if the last block
|
||||||
// The last run needs its stylings to be 1 longer than the raw
|
|
||||||
// text is. This is to define the stylings that any new text
|
|
||||||
// that is added will inherit
|
|
||||||
|
|
||||||
styleAtom.clearStyles();
|
styleAtom.clearStyles();
|
||||||
|
|
||||||
TextPropCollection lastPTPC = null, lastRTPC = null, ptpc = null, rtpc = null;
|
TextPropCollection lastPTPC = null, lastRTPC = null, ptpc = null, rtpc = null;
|
||||||
for (HSLFTextParagraph para : paragraphs) {
|
for (HSLFTextParagraph para : paragraphs) {
|
||||||
ptpc = para.getParagraphStyle();
|
ptpc = para.getParagraphStyle();
|
||||||
|
@ -782,13 +781,13 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
lastRTPC.updateTextSize(lastRTPC.getCharactersCovered()+len);
|
lastRTPC.updateTextSize(lastRTPC.getCharactersCovered()+len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(lastPTPC != null && lastRTPC != null && ptpc != null && rtpc != null);
|
assert(lastPTPC != null && lastRTPC != null && ptpc != null && rtpc != null);
|
||||||
ptpc.updateTextSize(ptpc.getCharactersCovered()+1);
|
ptpc.updateTextSize(ptpc.getCharactersCovered()+1);
|
||||||
rtpc.updateTextSize(rtpc.getCharactersCovered()+1);
|
rtpc.updateTextSize(rtpc.getCharactersCovered()+1);
|
||||||
lastPTPC.updateTextSize(lastPTPC.getCharactersCovered()+1);
|
lastPTPC.updateTextSize(lastPTPC.getCharactersCovered()+1);
|
||||||
lastRTPC.updateTextSize(lastRTPC.getCharactersCovered()+1);
|
lastRTPC.updateTextSize(lastRTPC.getCharactersCovered()+1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If TextSpecInfoAtom is present, we must update the text size in it,
|
* If TextSpecInfoAtom is present, we must update the text size in it,
|
||||||
* otherwise the ppt will be corrupted
|
* otherwise the ppt will be corrupted
|
||||||
|
@ -803,7 +802,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
/**
|
/**
|
||||||
* Adds the supplied text onto the end of the TextParagraphs,
|
* Adds the supplied text onto the end of the TextParagraphs,
|
||||||
* creating a new RichTextRun for it to sit in.
|
* creating a new RichTextRun for it to sit in.
|
||||||
*
|
*
|
||||||
* @param text the text string used by this object.
|
* @param text the text string used by this object.
|
||||||
*/
|
*/
|
||||||
protected static HSLFTextRun appendText(List<HSLFTextParagraph> paragraphs, String text, boolean newParagraph) {
|
protected static HSLFTextRun appendText(List<HSLFTextParagraph> paragraphs, String text, boolean newParagraph) {
|
||||||
|
@ -811,14 +810,10 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
|
|
||||||
// check paragraphs
|
// check paragraphs
|
||||||
assert(!paragraphs.isEmpty() && !paragraphs.get(0).getTextRuns().isEmpty());
|
assert(!paragraphs.isEmpty() && !paragraphs.get(0).getTextRuns().isEmpty());
|
||||||
|
|
||||||
HSLFTextParagraph htp = paragraphs.get(paragraphs.size()-1);
|
HSLFTextParagraph htp = paragraphs.get(paragraphs.size()-1);
|
||||||
HSLFTextRun htr = htp.getTextRuns().get(htp.getTextRuns().size()-1);
|
HSLFTextRun htr = htp.getTextRuns().get(htp.getTextRuns().size()-1);
|
||||||
|
|
||||||
if (newParagraph) {
|
|
||||||
htr.setText(htr.getRawText()+"\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isFirst = !newParagraph;
|
boolean isFirst = !newParagraph;
|
||||||
for (String rawText : text.split("(?<=\r)")) {
|
for (String rawText : text.split("(?<=\r)")) {
|
||||||
if (!isFirst) {
|
if (!isFirst) {
|
||||||
|
@ -832,6 +827,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
paragraphs.add(htp);
|
paragraphs.add(htp);
|
||||||
isFirst = false;
|
isFirst = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextPropCollection tpc = htr.getCharacterStyle();
|
TextPropCollection tpc = htr.getCharacterStyle();
|
||||||
// special case, last text run is empty, we will reuse it
|
// special case, last text run is empty, we will reuse it
|
||||||
if (htr.getLength() > 0) {
|
if (htr.getLength() > 0) {
|
||||||
|
@ -841,21 +837,19 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
}
|
}
|
||||||
htr.setText(rawText);
|
htr.setText(rawText);
|
||||||
}
|
}
|
||||||
|
|
||||||
storeText(paragraphs);
|
|
||||||
|
|
||||||
|
storeText(paragraphs);
|
||||||
|
|
||||||
return htr;
|
return htr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets (overwrites) the current text.
|
* Sets (overwrites) the current text.
|
||||||
* Uses the properties of the first paragraph / textrun
|
* Uses the properties of the first paragraph / textrun
|
||||||
*
|
*
|
||||||
* @param text the text string used by this object.
|
* @param text the text string used by this object.
|
||||||
*/
|
*/
|
||||||
public static HSLFTextRun setText(List<HSLFTextParagraph> paragraphs, String text) {
|
public static HSLFTextRun setText(List<HSLFTextParagraph> paragraphs, String text) {
|
||||||
text = HSLFTextParagraph.toInternalString(text);
|
|
||||||
|
|
||||||
// check paragraphs
|
// check paragraphs
|
||||||
assert(!paragraphs.isEmpty() && !paragraphs.get(0).getTextRuns().isEmpty());
|
assert(!paragraphs.isEmpty() && !paragraphs.get(0).getTextRuns().isEmpty());
|
||||||
|
|
||||||
|
@ -866,7 +860,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
paraIter.next();
|
paraIter.next();
|
||||||
paraIter.remove();
|
paraIter.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator<HSLFTextRun> runIter = htp.getTextRuns().iterator();
|
Iterator<HSLFTextRun> runIter = htp.getTextRuns().iterator();
|
||||||
HSLFTextRun htr = runIter.next();
|
HSLFTextRun htr = runIter.next();
|
||||||
htr.setText("");
|
htr.setText("");
|
||||||
|
@ -875,10 +869,10 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
runIter.next();
|
runIter.next();
|
||||||
runIter.remove();
|
runIter.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
return appendText(paragraphs, text, false);
|
return appendText(paragraphs, text, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getRawText(List<HSLFTextParagraph> paragraphs) {
|
public static String getRawText(List<HSLFTextParagraph> paragraphs) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
for (HSLFTextParagraph p : paragraphs) {
|
for (HSLFTextParagraph p : paragraphs) {
|
||||||
|
@ -886,9 +880,9 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
sb.append(r.getRawText());
|
sb.append(r.getRawText());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new string with line breaks converted into internal ppt
|
* Returns a new string with line breaks converted into internal ppt
|
||||||
* representation
|
* representation
|
||||||
|
@ -948,7 +942,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
* @param found vector to add any found to
|
* @param found vector to add any found to
|
||||||
*/
|
*/
|
||||||
protected static List<List<HSLFTextParagraph>> findTextParagraphs(final Record[] records) {
|
protected static List<List<HSLFTextParagraph>> findTextParagraphs(final Record[] records) {
|
||||||
return findTextParagraphs(records, null);
|
return findTextParagraphs(records, null);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Scans through the supplied record array, looking for
|
* Scans through the supplied record array, looking for
|
||||||
|
@ -980,41 +974,40 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
*/
|
*/
|
||||||
protected static List<List<HSLFTextParagraph>> findTextParagraphs(Record[] records, StyleTextProp9Atom styleTextProp9Atom) {
|
protected static List<List<HSLFTextParagraph>> findTextParagraphs(Record[] records, StyleTextProp9Atom styleTextProp9Atom) {
|
||||||
List<List<HSLFTextParagraph>> paragraphCollection = new ArrayList<List<HSLFTextParagraph>>();
|
List<List<HSLFTextParagraph>> paragraphCollection = new ArrayList<List<HSLFTextParagraph>>();
|
||||||
|
|
||||||
if (records == null) {
|
if (records == null) {
|
||||||
throw new NullPointerException("records need to be filled.");
|
throw new NullPointerException("records need to be filled.");
|
||||||
}
|
}
|
||||||
|
|
||||||
int recordIdx;
|
int recordIdx;
|
||||||
for (recordIdx = 0; recordIdx < records.length; recordIdx++) {
|
for (recordIdx = 0; recordIdx < records.length; recordIdx++) {
|
||||||
if (records[recordIdx] instanceof TextHeaderAtom) break;
|
if (records[recordIdx] instanceof TextHeaderAtom) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recordIdx == records.length) {
|
if (recordIdx == records.length) {
|
||||||
logger.log(POILogger.INFO, "No text records found.");
|
logger.log(POILogger.INFO, "No text records found.");
|
||||||
return paragraphCollection;
|
return paragraphCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int slwtIndex = 0; recordIdx < records.length; slwtIndex++) {
|
for (int slwtIndex = 0; recordIdx < records.length; slwtIndex++) {
|
||||||
List<HSLFTextParagraph> paragraphs = new ArrayList<HSLFTextParagraph>();
|
List<HSLFTextParagraph> paragraphs = new ArrayList<HSLFTextParagraph>();
|
||||||
paragraphCollection.add(paragraphs);
|
paragraphCollection.add(paragraphs);
|
||||||
|
|
||||||
TextHeaderAtom header = (TextHeaderAtom)records[recordIdx++];
|
TextHeaderAtom header = (TextHeaderAtom)records[recordIdx++];
|
||||||
TextBytesAtom tbytes = null;
|
TextBytesAtom tbytes = null;
|
||||||
TextCharsAtom tchars = null;
|
TextCharsAtom tchars = null;
|
||||||
StyleTextPropAtom styles = null;
|
|
||||||
TextRulerAtom ruler = null;
|
TextRulerAtom ruler = null;
|
||||||
MasterTextPropAtom indents = null;
|
MasterTextPropAtom indents = null;
|
||||||
|
|
||||||
List<Record> otherRecordList = new ArrayList<Record>();
|
List<Record> otherRecordList = new ArrayList<Record>();
|
||||||
|
|
||||||
for (; recordIdx < records.length; recordIdx++) {
|
for (; recordIdx < records.length; recordIdx++) {
|
||||||
Record r = records[recordIdx];
|
Record r = records[recordIdx];
|
||||||
long rt = r.getRecordType();
|
long rt = r.getRecordType();
|
||||||
if (RecordTypes.TextHeaderAtom.typeID == rt) break;
|
if (RecordTypes.TextHeaderAtom.typeID == rt) break;
|
||||||
else if (RecordTypes.TextBytesAtom.typeID == rt) tbytes = (TextBytesAtom)r;
|
else if (RecordTypes.TextBytesAtom.typeID == rt) tbytes = (TextBytesAtom)r;
|
||||||
else if (RecordTypes.TextCharsAtom.typeID == rt) tchars = (TextCharsAtom)r;
|
else if (RecordTypes.TextCharsAtom.typeID == rt) tchars = (TextCharsAtom)r;
|
||||||
else if (RecordTypes.StyleTextPropAtom.typeID == rt) styles = (StyleTextPropAtom)r;
|
// don't search for RecordTypes.StyleTextPropAtom.typeID here ... see findStyleAtomPresent below
|
||||||
else if (RecordTypes.TextRulerAtom.typeID == rt) ruler = (TextRulerAtom)r;
|
else if (RecordTypes.TextRulerAtom.typeID == rt) ruler = (TextRulerAtom)r;
|
||||||
else if (RecordTypes.MasterTextPropAtom.typeID == rt) {
|
else if (RecordTypes.MasterTextPropAtom.typeID == rt) {
|
||||||
indents = (MasterTextPropAtom)r;
|
indents = (MasterTextPropAtom)r;
|
||||||
|
@ -1023,23 +1016,24 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
otherRecordList.add(r);
|
otherRecordList.add(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(header != null);
|
assert(header != null);
|
||||||
if (header.getParentRecord() instanceof SlideListWithText) {
|
if (header.getParentRecord() instanceof SlideListWithText) {
|
||||||
// runs found in PPDrawing are not linked with SlideListWithTexts
|
// runs found in PPDrawing are not linked with SlideListWithTexts
|
||||||
header.setIndex(slwtIndex);
|
header.setIndex(slwtIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
Record otherRecords[] = otherRecordList.toArray(new Record[otherRecordList.size()]);
|
Record otherRecords[] = otherRecordList.toArray(new Record[otherRecordList.size()]);
|
||||||
|
|
||||||
if (tbytes == null && tchars == null) {
|
if (tbytes == null && tchars == null) {
|
||||||
tbytes = new TextBytesAtom();
|
tbytes = new TextBytesAtom();
|
||||||
header.getParentRecord().addChildAfter(tbytes, header);
|
// header.getParentRecord().addChildAfter(tbytes, header);
|
||||||
logger.log(POILogger.INFO, "bytes nor chars atom doesn't exist. Creating dummy record for later saving.");
|
logger.log(POILogger.INFO, "bytes nor chars atom doesn't exist. Creating dummy record for later saving.");
|
||||||
}
|
}
|
||||||
|
|
||||||
String rawText = (tchars != null) ? tchars.getText() : tbytes.getText();
|
String rawText = (tchars != null) ? tchars.getText() : tbytes.getText();
|
||||||
|
StyleTextPropAtom styles = findStyleAtomPresent(header, rawText.length());
|
||||||
|
|
||||||
// split, but keep delimiter
|
// split, but keep delimiter
|
||||||
for (String para : rawText.split("(?<=\r)")) {
|
for (String para : rawText.split("(?<=\r)")) {
|
||||||
HSLFTextParagraph tpara = new HSLFTextParagraph(header, tbytes, tchars, styles);
|
HSLFTextParagraph tpara = new HSLFTextParagraph(header, tbytes, tchars, styles);
|
||||||
|
@ -1048,32 +1042,26 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
tpara._ruler = ruler;
|
tpara._ruler = ruler;
|
||||||
tpara._records = otherRecords;
|
tpara._records = otherRecords;
|
||||||
tpara.getParagraphStyle().updateTextSize(para.length());
|
tpara.getParagraphStyle().updateTextSize(para.length());
|
||||||
|
|
||||||
HSLFTextRun trun = new HSLFTextRun(tpara);
|
HSLFTextRun trun = new HSLFTextRun(tpara);
|
||||||
tpara.addTextRun(trun);
|
tpara.addTextRun(trun);
|
||||||
trun.setText(para);
|
trun.setText(para);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (styles == null) {
|
|
||||||
styles = ensureStyleAtomPresent(header, tbytes, tchars);
|
|
||||||
} else {
|
|
||||||
styles.setParentTextSize(rawText.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
applyCharacterStyles(paragraphs, styles.getCharacterStyles());
|
applyCharacterStyles(paragraphs, styles.getCharacterStyles());
|
||||||
applyParagraphStyles(paragraphs, styles.getParagraphStyles());
|
applyParagraphStyles(paragraphs, styles.getParagraphStyles());
|
||||||
if (indents != null) {
|
if (indents != null) {
|
||||||
applyParagraphIndents(paragraphs, indents.getIndents());
|
applyParagraphIndents(paragraphs, indents.getIndents());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return paragraphCollection;
|
return paragraphCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void applyCharacterStyles(List<HSLFTextParagraph> paragraphs, List<TextPropCollection> charStyles) {
|
protected static void applyCharacterStyles(List<HSLFTextParagraph> paragraphs, List<TextPropCollection> charStyles) {
|
||||||
int paraIdx = 0, runIdx = 0;
|
int paraIdx = 0, runIdx = 0;
|
||||||
HSLFTextRun trun;
|
HSLFTextRun trun;
|
||||||
|
|
||||||
for (int csIdx=0; csIdx<charStyles.size(); csIdx++) {
|
for (int csIdx=0; csIdx<charStyles.size(); csIdx++) {
|
||||||
TextPropCollection p = charStyles.get(csIdx);
|
TextPropCollection p = charStyles.get(csIdx);
|
||||||
for (int ccRun = 0, ccStyle = p.getCharactersCovered(); ccRun < ccStyle; ) {
|
for (int ccRun = 0, ccStyle = p.getCharactersCovered(); ccRun < ccStyle; ) {
|
||||||
|
@ -1081,21 +1069,21 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
List<HSLFTextRun> runs = para.getTextRuns();
|
List<HSLFTextRun> runs = para.getTextRuns();
|
||||||
trun = runs.get(runIdx);
|
trun = runs.get(runIdx);
|
||||||
int len = trun.getLength();
|
int len = trun.getLength();
|
||||||
|
|
||||||
if (ccRun+len <= ccStyle) {
|
if (ccRun+len <= ccStyle) {
|
||||||
ccRun += len;
|
ccRun += len;
|
||||||
} else {
|
} else {
|
||||||
String text = trun.getRawText();
|
String text = trun.getRawText();
|
||||||
trun.setText(text.substring(0,ccStyle-ccRun));
|
trun.setText(text.substring(0,ccStyle-ccRun));
|
||||||
|
|
||||||
HSLFTextRun nextRun = new HSLFTextRun(para);
|
HSLFTextRun nextRun = new HSLFTextRun(para);
|
||||||
nextRun.setText(text.substring(ccStyle-ccRun));
|
nextRun.setText(text.substring(ccStyle-ccRun));
|
||||||
runs.add(runIdx+1, nextRun);
|
runs.add(runIdx+1, nextRun);
|
||||||
|
|
||||||
ccRun += ccStyle-ccRun;
|
ccRun += ccStyle-ccRun;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextPropCollection pCopy = new TextPropCollection(0);
|
TextPropCollection pCopy = new TextPropCollection(0, StyleTextPropAtom.characterTextPropTypes);
|
||||||
pCopy.copy(p);
|
pCopy.copy(p);
|
||||||
trun.setCharacterStyle(pCopy);
|
trun.setCharacterStyle(pCopy);
|
||||||
|
|
||||||
|
@ -1113,7 +1101,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pCopy.updateTextSize(len);
|
pCopy.updateTextSize(len);
|
||||||
|
|
||||||
// need to compare it again, in case a run has been added after
|
// need to compare it again, in case a run has been added after
|
||||||
if (++runIdx == runs.size()) {
|
if (++runIdx == runs.size()) {
|
||||||
paraIdx++;
|
paraIdx++;
|
||||||
|
@ -1122,14 +1110,14 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void applyParagraphStyles(List<HSLFTextParagraph> paragraphs, List<TextPropCollection> paraStyles) {
|
protected static void applyParagraphStyles(List<HSLFTextParagraph> paragraphs, List<TextPropCollection> paraStyles) {
|
||||||
int paraIdx = 0;
|
int paraIdx = 0;
|
||||||
for (TextPropCollection p : paraStyles) {
|
for (TextPropCollection p : paraStyles) {
|
||||||
for (int ccPara = 0, ccStyle = p.getCharactersCovered(); ccPara < ccStyle; paraIdx++) {
|
for (int ccPara = 0, ccStyle = p.getCharactersCovered(); ccPara < ccStyle; paraIdx++) {
|
||||||
if (paraIdx >= paragraphs.size() || ccPara >= ccStyle-1) return;
|
if (paraIdx >= paragraphs.size() || ccPara >= ccStyle-1) return;
|
||||||
HSLFTextParagraph htp = paragraphs.get(paraIdx);
|
HSLFTextParagraph htp = paragraphs.get(paraIdx);
|
||||||
TextPropCollection pCopy = new TextPropCollection(0);
|
TextPropCollection pCopy = new TextPropCollection(0, StyleTextPropAtom.paragraphTextPropTypes);
|
||||||
pCopy.copy(p);
|
pCopy.copy(p);
|
||||||
htp.setParagraphStyle(pCopy);
|
htp.setParagraphStyle(pCopy);
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
@ -1142,7 +1130,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void applyParagraphIndents(List<HSLFTextParagraph> paragraphs, List<IndentProp> paraStyles) {
|
protected static void applyParagraphIndents(List<HSLFTextParagraph> paragraphs, List<IndentProp> paraStyles) {
|
||||||
int paraIdx = 0;
|
int paraIdx = 0;
|
||||||
for (IndentProp p : paraStyles) {
|
for (IndentProp p : paraStyles) {
|
||||||
|
@ -1157,23 +1145,23 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static List<HSLFTextParagraph> createEmptyParagraph() {
|
protected static List<HSLFTextParagraph> createEmptyParagraph() {
|
||||||
EscherTextboxWrapper wrapper = new EscherTextboxWrapper();
|
EscherTextboxWrapper wrapper = new EscherTextboxWrapper();
|
||||||
|
|
||||||
TextHeaderAtom tha = new TextHeaderAtom();
|
TextHeaderAtom tha = new TextHeaderAtom();
|
||||||
tha.setParentRecord(wrapper);
|
tha.setParentRecord(wrapper);
|
||||||
wrapper.appendChildRecord(tha);
|
wrapper.appendChildRecord(tha);
|
||||||
|
|
||||||
TextBytesAtom tba = new TextBytesAtom();
|
TextBytesAtom tba = new TextBytesAtom();
|
||||||
tba.setText("\r".getBytes());
|
tba.setText("\r".getBytes());
|
||||||
wrapper.appendChildRecord(tba);
|
wrapper.appendChildRecord(tba);
|
||||||
|
|
||||||
StyleTextPropAtom sta = new StyleTextPropAtom(1);
|
StyleTextPropAtom sta = new StyleTextPropAtom(1);
|
||||||
TextPropCollection paraStyle = sta.addParagraphTextPropCollection(1);
|
TextPropCollection paraStyle = sta.addParagraphTextPropCollection(1);
|
||||||
TextPropCollection charStyle = sta.addCharacterTextPropCollection(1);
|
TextPropCollection charStyle = sta.addCharacterTextPropCollection(1);
|
||||||
wrapper.appendChildRecord(sta);
|
wrapper.appendChildRecord(sta);
|
||||||
|
|
||||||
HSLFTextParagraph htp = new HSLFTextParagraph(tha, tba, null, sta);
|
HSLFTextParagraph htp = new HSLFTextParagraph(tha, tba, null, sta);
|
||||||
htp.setParagraphStyle(paraStyle);
|
htp.setParagraphStyle(paraStyle);
|
||||||
htp._records = new Record[0];
|
htp._records = new Record[0];
|
||||||
|
@ -1182,16 +1170,16 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
|
||||||
htp.setLeftMargin(0);
|
htp.setLeftMargin(0);
|
||||||
htp.setIndent(0);
|
htp.setIndent(0);
|
||||||
// set wrap flags
|
// set wrap flags
|
||||||
|
|
||||||
HSLFTextRun htr = new HSLFTextRun(htp);
|
HSLFTextRun htr = new HSLFTextRun(htp);
|
||||||
htr.setCharacterStyle(charStyle);
|
htr.setCharacterStyle(charStyle);
|
||||||
htr.setText("\r");
|
htr.setText("\r");
|
||||||
htr.setFontColor(Color.black);
|
htr.setFontColor(Color.black);
|
||||||
htp.addTextRun(htr);
|
htp.addTextRun(htr);
|
||||||
|
|
||||||
return Arrays.asList(htp);
|
return Arrays.asList(htp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public EscherTextboxWrapper getTextboxWrapper() {
|
public EscherTextboxWrapper getTextboxWrapper() {
|
||||||
return (EscherTextboxWrapper)_headerAtom.getParentRecord();
|
return (EscherTextboxWrapper)_headerAtom.getParentRecord();
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.awt.Color;
|
||||||
|
|
||||||
import org.apache.poi.hslf.model.textproperties.*;
|
import org.apache.poi.hslf.model.textproperties.*;
|
||||||
import org.apache.poi.hslf.record.ColorSchemeAtom;
|
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.sl.usermodel.TextRun;
|
||||||
import org.apache.poi.util.POILogFactory;
|
import org.apache.poi.util.POILogFactory;
|
||||||
import org.apache.poi.util.POILogger;
|
import org.apache.poi.util.POILogger;
|
||||||
|
@ -44,7 +45,7 @@ public final class HSLFTextRun implements TextRun {
|
||||||
* Our paragraph and character style.
|
* Our paragraph and character style.
|
||||||
* Note - we may share these styles with other RichTextRuns
|
* Note - we may share these styles with other RichTextRuns
|
||||||
*/
|
*/
|
||||||
private TextPropCollection characterStyle = new TextPropCollection(0);
|
private TextPropCollection characterStyle = new TextPropCollection(0, StyleTextPropAtom.characterTextPropTypes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new wrapper around a rich text string
|
* Create a new wrapper around a rich text string
|
||||||
|
@ -163,7 +164,7 @@ public final class HSLFTextRun implements TextRun {
|
||||||
public void setCharTextPropVal(String propName, int val) {
|
public void setCharTextPropVal(String propName, int val) {
|
||||||
// Ensure we have the StyleTextProp atom we're going to need
|
// Ensure we have the StyleTextProp atom we're going to need
|
||||||
if(characterStyle == null) {
|
if(characterStyle == null) {
|
||||||
characterStyle = new TextPropCollection(1);
|
characterStyle = new TextPropCollection(1, StyleTextPropAtom.characterTextPropTypes);
|
||||||
// characterStyle will now be defined
|
// characterStyle will now be defined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,7 +377,7 @@ public final class HSLFTextRun implements TextRun {
|
||||||
protected void setFlag(int index, boolean value) {
|
protected void setFlag(int index, boolean value) {
|
||||||
// Ensure we have the StyleTextProp atom we're going to need
|
// Ensure we have the StyleTextProp atom we're going to need
|
||||||
if (characterStyle == null) {
|
if (characterStyle == null) {
|
||||||
characterStyle = new TextPropCollection(1);
|
characterStyle = new TextPropCollection(1, StyleTextPropAtom.characterTextPropTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
BitMaskTextProp prop = (BitMaskTextProp) fetchOrAddTextProp(characterStyle, CharFlagsTextProp.NAME);
|
BitMaskTextProp prop = (BitMaskTextProp) fetchOrAddTextProp(characterStyle, CharFlagsTextProp.NAME);
|
||||||
|
|
|
@ -18,10 +18,10 @@
|
||||||
package org.apache.poi.hslf.usermodel;
|
package org.apache.poi.hslf.usermodel;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import org.apache.poi.hslf.*;
|
|
||||||
import org.apache.poi.hslf.model.*;
|
|
||||||
import org.apache.poi.POIDataSamples;
|
import org.apache.poi.POIDataSamples;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,39 +40,39 @@ public final class TestCounts extends TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSheetsCount() {
|
public void testSheetsCount() {
|
||||||
HSLFSlide[] slides = ss.getSlides();
|
List<HSLFSlide> slides = ss.getSlides();
|
||||||
// Two sheets - master sheet is separate
|
// Two sheets - master sheet is separate
|
||||||
assertEquals(2, slides.length);
|
assertEquals(2, slides.size());
|
||||||
|
|
||||||
// They are slides 1+2
|
// They are slides 1+2
|
||||||
assertEquals(1, slides[0].getSlideNumber());
|
assertEquals(1, slides.get(0).getSlideNumber());
|
||||||
assertEquals(2, slides[1].getSlideNumber());
|
assertEquals(2, slides.get(1).getSlideNumber());
|
||||||
|
|
||||||
// The ref IDs are 4 and 6
|
// The ref IDs are 4 and 6
|
||||||
assertEquals(4, slides[0]._getSheetRefId());
|
assertEquals(4, slides.get(0)._getSheetRefId());
|
||||||
assertEquals(6, slides[1]._getSheetRefId());
|
assertEquals(6, slides.get(1)._getSheetRefId());
|
||||||
|
|
||||||
// These are slides 1+2 -> 256+257
|
// These are slides 1+2 -> 256+257
|
||||||
assertEquals(256, slides[0]._getSheetNumber());
|
assertEquals(256, slides.get(0)._getSheetNumber());
|
||||||
assertEquals(257, slides[1]._getSheetNumber());
|
assertEquals(257, slides.get(1)._getSheetNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testNotesCount() {
|
public void testNotesCount() {
|
||||||
HSLFNotes[] notes = ss.getNotes();
|
List<HSLFNotes> notes = ss.getNotes();
|
||||||
// Two sheets -> two notes
|
// Two sheets -> two notes
|
||||||
// Note: there are also notes on the slide master
|
// Note: there are also notes on the slide master
|
||||||
//assertEquals(3, notes.length); // When we do slide masters
|
//assertEquals(3, notes.length); // When we do slide masters
|
||||||
assertEquals(2, notes.length);
|
assertEquals(2, notes.size());
|
||||||
|
|
||||||
// First is for master
|
// First is for master
|
||||||
//assertEquals(-2147483648, notes[0]._getSheetNumber()); // When we do slide masters
|
//assertEquals(-2147483648, notes.get(0)._getSheetNumber()); // When we do slide masters
|
||||||
|
|
||||||
// Next two are for the two slides
|
// Next two are for the two slides
|
||||||
assertEquals(256, notes[0]._getSheetNumber());
|
assertEquals(256, notes.get(0)._getSheetNumber());
|
||||||
assertEquals(257, notes[1]._getSheetNumber());
|
assertEquals(257, notes.get(1)._getSheetNumber());
|
||||||
|
|
||||||
// They happen to go between the two slides in Ref terms
|
// They happen to go between the two slides in Ref terms
|
||||||
assertEquals(5, notes[0]._getSheetRefId());
|
assertEquals(5, notes.get(0)._getSheetRefId());
|
||||||
assertEquals(7, notes[1]._getSheetRefId());
|
assertEquals(7, notes.get(1)._getSheetRefId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,21 +40,21 @@ public final class TestNotesText extends TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testNotesOne() {
|
public void testNotesOne() {
|
||||||
HSLFNotes notes = ss.getNotes()[0];
|
HSLFNotes notes = ss.getNotes().get(0);
|
||||||
|
|
||||||
String[] expectText = new String[] {"These are the notes for page 1"};
|
String[] expectText = new String[] {"These are the notes for page 1"};
|
||||||
assertEquals(expectText.length, notes.getTextParagraphs().length);
|
assertEquals(expectText.length, notes.getTextParagraphs().size());
|
||||||
for(int i=0; i<expectText.length; i++) {
|
for(int i=0; i<expectText.length; i++) {
|
||||||
assertEquals(expectText[i], notes.getTextParagraphs()[i].getRawText());
|
assertEquals(expectText[i], HSLFTextParagraph.getRawText(notes.getTextParagraphs().get(i)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testNotesTwo() {
|
public void testNotesTwo() {
|
||||||
HSLFNotes notes = ss.getNotes()[1];
|
HSLFNotes notes = ss.getNotes().get(1);
|
||||||
String[] expectText = new String[] {"These are the notes on page two, again lacking formatting"};
|
String[] expectText = new String[] {"These are the notes on page two, again lacking formatting"};
|
||||||
assertEquals(expectText.length, notes.getTextParagraphs().length);
|
assertEquals(expectText.length, notes.getTextParagraphs().size());
|
||||||
for(int i=0; i<expectText.length; i++) {
|
for(int i=0; i<expectText.length; i++) {
|
||||||
assertEquals(expectText[i], notes.getTextParagraphs()[i].getRawText());
|
assertEquals(expectText[i], HSLFTextParagraph.getRawText(notes.getTextParagraphs().get(i)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue