diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/TextPropCollection.java b/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/TextPropCollection.java index 84cfe9940f..08696b2187 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/TextPropCollection.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/TextPropCollection.java @@ -20,6 +20,7 @@ package org.apache.poi.hslf.model.textproperties; import java.io.*; import java.util.*; +import org.apache.poi.hslf.exceptions.HSLFException; import org.apache.poi.hslf.record.StyleTextPropAtom; import org.apache.poi.util.HexDump; import org.apache.poi.util.LittleEndian; @@ -32,7 +33,7 @@ import org.apache.poi.util.LittleEndian; */ public class TextPropCollection { /** All the different kinds of paragraph properties we might handle */ - public static final TextProp[] paragraphTextPropTypes = { + private static final TextProp[] paragraphTextPropTypes = { // TextProp order is according to 2.9.20 TextPFException, // bitmask order can be different new ParagraphFlagsTextProp(), @@ -60,7 +61,7 @@ public class TextPropCollection { }; /** All the different kinds of character properties we might handle */ - public static final TextProp[] characterTextPropTypes = new TextProp[] { + private static final TextProp[] characterTextPropTypes = new TextProp[] { 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. @@ -84,7 +85,7 @@ public class TextPropCollection { // 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 textPropList = new ArrayList(); + private final Map textProps = new HashMap(); private int maskSpecial = 0; private final TextPropType textPropType; @@ -98,101 +99,89 @@ public class TextPropCollection { this.textPropType = textPropType; } - public int getSpecialMask() { return maskSpecial; } + public int getSpecialMask() { + return maskSpecial; + } /** Fetch the number of characters this styling applies to */ - public int getCharactersCovered() { return charactersCovered; } - /** Fetch the TextProps that define this styling */ - public List getTextPropList() { return textPropList; } + public int getCharactersCovered() { + return charactersCovered; + } + + /** Fetch the TextProps that define this styling in the record order */ + public List getTextPropList() { + List orderedList = new ArrayList(); + for (TextProp potProp : getPotentialProperties()) { + TextProp textProp = textProps.get(potProp.getName()); + if (textProp != null) { + orderedList.add(textProp); + } + } + return orderedList; + } /** Fetch the TextProp with this name, or null if it isn't present */ - public TextProp findByName(String textPropName) { - for(TextProp prop : textPropList) { - if(prop.getName().equals(textPropName)) { - return prop; - } - } - return null; + public final TextProp findByName(String textPropName) { + return textProps.get(textPropName); } - public TextProp removeByName(String name) { - Iterator iter = textPropList.iterator(); - TextProp tp = null; - while (iter.hasNext()) { - tp = iter.next(); - if (tp.getName().equals(name)){ - iter.remove(); - break; - } - } - return tp; + public final TextProp removeByName(String name) { + return textProps.remove(name); } - /** Add the TextProp with this name to the list */ - public TextProp addWithName(String name) { - // Find the base TextProp to base on - TextProp existing = findByName(name); - if (existing != null) return existing; - - TextProp base = null; - for (TextProp tp : getPotentialProperties()) { - if (tp.getName().equals(name)) { - base = tp; - break; - } - } - - if(base == null) { - 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 - TextProp textProp = base.clone(); - addProp(textProp); - return textProp; - } - - public TextPropType getTextPropType() { + public final TextPropType getTextPropType() { return textPropType; } private TextProp[] getPotentialProperties() { return (textPropType == TextPropType.paragraph) ? paragraphTextPropTypes : characterTextPropTypes; } + + /** + * Checks the paragraph or character properties for the given property name. + * Throws a HSLFException, if the name doesn't belong into this set of properties + * + * @param name the property name + * @return if found, the property template to copy from + */ + private TextProp validatePropName(String name) { + for (TextProp tp : getPotentialProperties()) { + if (tp.getName().equals(name)) { + return tp; + } + } + String errStr = + "No TextProp with name " + name + " is defined to add from. " + + "Character and paragraphs have their own properties/names."; + throw new HSLFException(errStr); + } + /** Add the TextProp with this name to the list */ + public final TextProp addWithName(String name) { + // Find the base TextProp to base on + TextProp existing = findByName(name); + if (existing != null) return existing; + + // Add a copy of this property + TextProp textProp = validatePropName(name).clone(); + textProps.put(name,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 : getPotentialProperties()) { - 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++; - } - } + public final void addProp(TextProp textProp) { + if (textProp == null) { + throw new HSLFException("TextProp must not be null"); + } - if(!found) { - String err = "TextProp with name " + textProp.getName() + " doesn't belong to this collection."; - throw new IllegalArgumentException(err); - } + String propName = textProp.getName(); + validatePropName(propName); + + textProps.put(propName, textProp); } /** @@ -254,8 +243,8 @@ public class TextPropCollection { this.charactersCovered = other.charactersCovered; this.indentLevel = other.indentLevel; this.maskSpecial = other.maskSpecial; - this.textPropList.clear(); - for (TextProp tp : other.textPropList) { + this.textProps.clear(); + for (TextProp tp : other.textProps.values()) { TextProp tpCopy = (tp instanceof BitMaskTextProp) ? ((BitMaskTextProp)tp).cloneAll() : tp.clone(); @@ -285,25 +274,22 @@ public class TextPropCollection { // Then the mask field int mask = maskSpecial; - for (TextProp textProp : textPropList) { + for (TextProp textProp : textProps.values()) { mask |= textProp.getWriteMask(); } StyleTextPropAtom.writeLittleEndian(mask,o); // Then the contents of all the properties - for (TextProp potProp : getPotentialProperties()) { - for(TextProp textProp : textPropList) { - if (!textProp.getName().equals(potProp.getName())) continue; - int val = textProp.getValue(); - if (textProp instanceof BitMaskTextProp && textProp.getWriteMask() == 0) { - // don't add empty properties, as they can't be recognized while reading - continue; - } else if (textProp.getSize() == 2) { - StyleTextPropAtom.writeLittleEndian((short)val,o); - } else if (textProp.getSize() == 4) { - StyleTextPropAtom.writeLittleEndian(val,o); - } - } + for (TextProp textProp : getTextPropList()) { + int val = textProp.getValue(); + if (textProp instanceof BitMaskTextProp && textProp.getWriteMask() == 0) { + // don't add empty properties, as they can't be recognized while reading + continue; + } else if (textProp.getSize() == 2) { + StyleTextPropAtom.writeLittleEndian((short)val,o); + } else if (textProp.getSize() == 4) { + StyleTextPropAtom.writeLittleEndian(val,o); + } } } @@ -324,7 +310,7 @@ public class TextPropCollection { result = prime * result + charactersCovered; result = prime * result + maskSpecial; result = prime * result + indentLevel; - result = prime * result + ((textPropList == null) ? 0 : textPropList.hashCode()); + result = prime * result + ((textProps == null) ? 0 : textProps.hashCode()); return result; } /** @@ -340,21 +326,7 @@ public class TextPropCollection { return false; } - if (textPropList == null) { - return (o.textPropList == null); - } - - Map m = new HashMap(); - for (TextProp tp : o.textPropList) { - m.put(tp.getName(), tp); - } - - for (TextProp tp : this.textPropList) { - TextProp otp = m.get(tp.getName()); - if (!tp.equals(otp)) return false; - } - - return true; + return textProps.equals(o.textProps); } public String toString() { diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java index 79ca35caf7..bc8ac93c6e 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java @@ -26,6 +26,7 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; +import org.apache.poi.hslf.exceptions.HSLFException; import org.apache.poi.hslf.model.PPFont; import org.apache.poi.hslf.model.textproperties.BitMaskTextProp; import org.apache.poi.hslf.model.textproperties.FontAlignmentProp; @@ -466,6 +467,28 @@ public final class HSLFTextParagraph implements TextParagraph ppt = SlideShowFactory.create(_slTests.getFile("bug45124.ppt")); + Slide slide1 = ppt.getSlides().get(1); + + TextBox res = slide1.createTextBox(); + res.setAnchor(new java.awt.Rectangle(60, 150, 700, 100)); + res.setText("I am italic-false, bold-true inserted text"); + + + TextParagraph tp = res.getTextParagraphs().get(0); + TextRun rt = tp.getTextRuns().get(0); + rt.setItalic(false); + assertTrue(rt.isBold()); + + tp.setBulletStyle(Color.red, 'A'); + + SlideShow ppt2 = HSLFTestDataSamples.writeOutAndReadBack((HSLFSlideShow)ppt); + ppt.close(); + + res = (TextBox)ppt2.getSlides().get(1).getShapes().get(1); + tp = res.getTextParagraphs().get(0); + rt = tp.getTextRuns().get(0); + + assertFalse(rt.isItalic()); + assertTrue(rt.isBold()); + PaintStyle ps = tp.getBulletStyle().getBulletFontColor(); + assertTrue(ps instanceof SolidPaint); + Color actColor = DrawPaint.applyColorTransform(((SolidPaint)ps).getSolidColor()); + assertEquals(Color.red, actColor); + assertEquals("A", tp.getBulletStyle().getBulletCharacter()); + + ppt2.close(); } } diff --git a/test-data/slideshow/bug45124.ppt b/test-data/slideshow/bug45124.ppt new file mode 100644 index 0000000000..2fd87b15e3 Binary files /dev/null and b/test-data/slideshow/bug45124.ppt differ