poi-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kiwiwi...@apache.org
Subject svn commit: r1686117 [2/3] - in /poi/branches/common_sl: src/examples/src/org/apache/poi/hslf/examples/ src/examples/src/org/apache/poi/xslf/usermodel/ src/java/org/apache/poi/util/ src/ooxml/java/org/apache/poi/xslf/usermodel/ src/ooxml/testcases/org/...
Date Wed, 17 Jun 2015 22:21:14 GMT
Modified: poi/branches/common_sl/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java
URL: http://svn.apache.org/viewvc/poi/branches/common_sl/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java?rev=1686117&r1=1686116&r2=1686117&view=diff
==============================================================================
--- poi/branches/common_sl/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java (original)
+++ poi/branches/common_sl/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java Wed Jun 17 22:21:13 2015
@@ -34,7 +34,7 @@ import org.apache.poi.util.*;
  * This class represents a run of text in a powerpoint document. That
  *  run could be text on a sheet, or text in a note.
  *  It is only a very basic class for now
- *
+ * 
  * @author Nick Burch
  */
 
@@ -44,50 +44,49 @@ public final class HSLFTextParagraph imp
     /**
      * How to align the text
      */
-    /* package */ static final int AlignLeft = 0;
-    /* package */ static final int AlignCenter = 1;
-    /* package */ static final int AlignRight = 2;
-    /* package */ static final int AlignJustify = 3;
-
+    /* package */static final int AlignLeft = 0;
+    /* package */static final int AlignCenter = 1;
+    /* package */static final int AlignRight = 2;
+    /* package */static final int AlignJustify = 3;
 
     // Note: These fields are protected to help with unit testing
-	//   Other classes shouldn't really go playing with them!
-	private final TextHeaderAtom _headerAtom;
-	private TextBytesAtom  _byteAtom;
-	private TextCharsAtom  _charAtom;
-	private final TextPropCollection _paragraphStyle = new TextPropCollection(1, TextPropType.paragraph);
+    // Other classes shouldn't really go playing with them!
+    private final TextHeaderAtom _headerAtom;
+    private TextBytesAtom _byteAtom;
+    private TextCharsAtom _charAtom;
+    private final TextPropCollection _paragraphStyle = new TextPropCollection(1, TextPropType.paragraph);
 
     protected TextRulerAtom _ruler;
-	protected List<HSLFTextRun> _runs = new ArrayList<HSLFTextRun>();
-	protected HSLFTextShape _parentShape;
+    protected final List<HSLFTextRun> _runs = new ArrayList<HSLFTextRun>();
+    protected HSLFTextShape _parentShape;
     private HSLFSheet _sheet;
     private int shapeId;
 
-	// private StyleTextPropAtom styleTextPropAtom;
-	private StyleTextProp9Atom styleTextProp9Atom;
+    // private StyleTextPropAtom styleTextPropAtom;
+    private StyleTextProp9Atom styleTextProp9Atom;
 
-	/**
+    /**
     * Constructs a Text Run from a Unicode text block.
     * Either a {@link TextCharsAtom} or a {@link TextBytesAtom} needs to be provided.
-    *
+     * 
     * @param tha the TextHeaderAtom that defines what's what
     * @param tba the TextBytesAtom containing the text or null if {@link TextCharsAtom} is provided
     * @param tca the TextCharsAtom containing the text or null if {@link TextBytesAtom} is provided
-	 */
+     */
 	/* package */ HSLFTextParagraph(
         TextHeaderAtom tha,
         TextBytesAtom tba,
         TextCharsAtom tca
     ) {
-	    if (tha == null)  {
-	        throw new IllegalArgumentException("TextHeaderAtom must be set.");
-	    }
-		_headerAtom = tha;
+        if (tha == null) {
+            throw new IllegalArgumentException("TextHeaderAtom must be set.");
+        }
+        _headerAtom = tha;
         _byteAtom = tba;
         _charAtom = tca;
-	}
+    }
 
-    /* package */ HSLFTextParagraph(HSLFTextParagraph other) {
+    /* package */HSLFTextParagraph(HSLFTextParagraph other) {
         _headerAtom = other._headerAtom;
         _byteAtom = other._byteAtom;
         _charAtom = other._charAtom;
@@ -98,67 +97,67 @@ public final class HSLFTextParagraph imp
         _paragraphStyle.copy(other._paragraphStyle);
     }
 
-	public void addTextRun(HSLFTextRun run) {
-	    _runs.add(run);
-	}
+    public void addTextRun(HSLFTextRun run) {
+        _runs.add(run);
+    }
 
-	/**
+    /**
 	 * Fetch the rich text runs (runs of text with the same styling) that
 	 *  are contained within this block of text
-	 */
-	public List<HSLFTextRun> getTextRuns() {
-		return 	_runs;
-	}
-
-	public TextPropCollection getParagraphStyle() {
-	    return _paragraphStyle;
-	}
-
-	public void setParagraphStyle(TextPropCollection paragraphStyle) {
-	    _paragraphStyle.copy(paragraphStyle);
-	}
+     */
+    public List<HSLFTextRun> getTextRuns() {
+        return _runs;
+    }
 
-	/**
+    public TextPropCollection getParagraphStyle() {
+        return _paragraphStyle;
+    }
+
+    public void setParagraphStyle(TextPropCollection paragraphStyle) {
+        _paragraphStyle.copy(paragraphStyle);
+    }
+
+    /**
      * Supply the Sheet we belong to, which might have an assigned SlideShow
      * Also passes it on to our child RichTextRuns
      */
-	public void supplySheet(HSLFSheet sheet){
+    public void supplySheet(HSLFSheet sheet) {
         this._sheet = sheet;
 
         if (_runs == null) return;
-        for(HSLFTextRun rt : _runs) {
+        for (HSLFTextRun rt : _runs) {
             rt.updateSheet();
         }
-	}
+    }
 
-    public HSLFSheet getSheet(){
+    public HSLFSheet getSheet() {
         return this._sheet;
     }
 
     /**
-     * @return  Shape ID
+     * @return Shape ID
      */
-    protected int getShapeId(){
+    protected int getShapeId() {
         return shapeId;
     }
 
     /**
-     *  @param id Shape ID
+     * @param id Shape ID
      */
-    protected void setShapeId(int id){
+    protected void setShapeId(int id) {
         shapeId = id;
     }
 
     /**
-     * @return  0-based index of the text run in the SLWT container
+     * @return 0-based index of the text run in the SLWT container
      */
-    protected int getIndex(){
+    protected int getIndex() {
         return (_headerAtom != null) ? _headerAtom.getIndex() : -1;
     }
 
     /**
      * Sets the index of the paragraph in the SLWT container
-     *
+     * 
      * @param index
      */
     protected void setIndex(int index) {
@@ -166,10 +165,10 @@ public final class HSLFTextParagraph imp
     }
 
     /**
-    * Returns the type of the text, from the TextHeaderAtom.
-    * Possible values can be seen from TextHeaderAtom
-    * @see org.apache.poi.hslf.record.TextHeaderAtom
-    */
+     * Returns the type of the text, from the TextHeaderAtom.
+     * Possible values can be seen from TextHeaderAtom
+     * @see org.apache.poi.hslf.record.TextHeaderAtom
+     */
     public int getRunType() {
         return (_headerAtom != null) ? _headerAtom.getTextType() : -1;
     }
@@ -177,8 +176,7 @@ public final class HSLFTextParagraph imp
     public void setRunType(int runType) {
         if (_headerAtom != null) _headerAtom.setTextType(runType);
     }
-    
-    
+
     /**
      * Is this Text Run one from a {@link PPDrawing}, or is it
      *  one from the {@link SlideListWithText}?
@@ -187,12 +185,12 @@ public final class HSLFTextParagraph imp
         return (getIndex() == -1);
     }
 
-    public TextRulerAtom getTextRuler(){
+    public TextRulerAtom getTextRuler() {
         return _ruler;
 
     }
 
-    public TextRulerAtom createTextRuler(){
+    public TextRulerAtom createTextRuler() {
         _ruler = getTextRuler();
         if (_ruler == null) {
             _ruler = TextRulerAtom.getParagraphInstance();
@@ -207,19 +205,19 @@ public final class HSLFTextParagraph imp
     /**
      * Returns records that make up the list of text paragraphs
      * (there can be misc InteractiveInfo, TxInteractiveInfo and other records)
-     *
+     * 
      * @return text run records
      */
-    public Record[] getRecords(){
+    public Record[] getRecords() {
         Record r[] = _headerAtom.getParentRecord().getChildRecords();
-        return getRecords(r, new int[]{0}, _headerAtom);
+        return getRecords(r, new int[] { 0 }, _headerAtom);
     }
 
     private static Record[] getRecords(Record[] records, int[] startIdx, TextHeaderAtom headerAtom) {
         if (records == null) {
             throw new NullPointerException("records need to be set.");
         }
-        
+
         for (; startIdx[0] < records.length; startIdx[0]++) {
             Record r = records[startIdx[0]];
             if (r instanceof TextHeaderAtom && (headerAtom == null || r == headerAtom)) break;
@@ -229,135 +227,113 @@ public final class HSLFTextParagraph imp
             logger.log(POILogger.INFO, "header atom wasn't found - container might contain only an OutlineTextRefAtom");
             return new Record[0];
         }
-        
+
         int length;
-        for (length = 1; startIdx[0]+length < records.length; length++) {
+        for (length = 1; startIdx[0] + length < records.length; length++) {
             if (records[startIdx[0]+length] instanceof TextHeaderAtom) break;
         }
-        
+
         Record result[] = new Record[length];
         System.arraycopy(records, startIdx[0], result, 0, length);
         startIdx[0] += length;
-        
+
         return result;
     }
-    
-    /** Numbered List info */
-	public void setStyleTextProp9Atom(final StyleTextProp9Atom styleTextProp9Atom) {
-		this.styleTextProp9Atom = styleTextProp9Atom;
-	}
 
     /** Numbered List info */
-	public StyleTextProp9Atom getStyleTextProp9Atom() {
-		return this.styleTextProp9Atom;
-	}
-
-	/**
-     * Fetch the value of the given Paragraph related TextProp.
-     * Returns -1 if that TextProp isn't present.
-     * If the TextProp isn't present, the value from the appropriate
-     *  Master Sheet will apply.
-     */
-    private int getParaTextPropVal(String propName) {
-        TextProp prop = _paragraphStyle.findByName(propName);
-        BitMaskTextProp maskProp = (BitMaskTextProp)_paragraphStyle.findByName(ParagraphFlagsTextProp.NAME);
-        boolean hardAttribute = (maskProp != null && maskProp.getValue() == 0);
-        if (prop == null && !hardAttribute){
-            HSLFSheet sheet = getSheet();
-            int txtype = getRunType();
-            HSLFMasterSheet master = sheet.getMasterSheet();
-            if (master != null)
-                prop = master.getStyleAttribute(txtype, getIndentLevel(), propName, false);
-        }
-
-        return prop == null ? -1 : prop.getValue();
+	public void setStyleTextProp9Atom(final StyleTextProp9Atom styleTextProp9Atom) {
+        this.styleTextProp9Atom = styleTextProp9Atom;
     }
 
-    /**
-     * Sets the value of the given Character TextProp, add if required
-     * @param propName The name of the Character TextProp
-     * @param val The value to set for the TextProp
-     */
-    public void setParaTextPropVal(String propName, int val) {
-        // Ensure we have the StyleTextProp atom we're going to need
-        assert(_paragraphStyle!=null);
-        TextProp tp = fetchOrAddTextProp(_paragraphStyle, propName);
-        tp.setValue(val);
+    /** Numbered List info */
+    public StyleTextProp9Atom getStyleTextProp9Atom() {
+        return this.styleTextProp9Atom;
     }
-
+    
     @Override
     public Iterator<HSLFTextRun> iterator() {
         return _runs.iterator();
     }
 
     @Override
-    public double getLeftMargin() {
-        int val = getParaTextPropVal("text.offset");
-        return val*HSLFShape.POINT_DPI/((double)HSLFShape.MASTER_DPI);
+    public Double getLeftMargin() {
+        TextProp val = getPropVal(_paragraphStyle, "text.offset", this);
+        return (val == null) ? null : Units.masterToPoints(val.getValue());
     }
 
     @Override
-    public void setLeftMargin(double leftMargin) {
-        int val = (int)(leftMargin*HSLFShape.MASTER_DPI/HSLFShape.POINT_DPI);
-        setParaTextPropVal("text.offset", val);
+    public void setLeftMargin(Double leftMargin) {
+        Integer val = (leftMargin == null) ? null : Units.pointsToMaster(leftMargin);
+        setPropVal(_paragraphStyle, "text.offset", val);
     }
 
     @Override
-    public double getRightMargin() {
+    public Double getRightMargin() {
         // TODO: find out, how to determine this value
-        return 0;
+        return null;
     }
 
     @Override
-    public void setRightMargin(double rightMargin) {
+    public void setRightMargin(Double rightMargin) {
         // TODO: find out, how to set this value
     }
 
     @Override
-    public double getIndent() {
-        int val = getParaTextPropVal("bullet.offset");
-        return val*HSLFShape.POINT_DPI/((double)HSLFShape.MASTER_DPI);
+    public Double getIndent() {
+        TextProp val = getPropVal(_paragraphStyle, "bullet.offset", this);
+        return (val == null) ? null : Units.masterToPoints(val.getValue());
     }
 
     @Override
-    public void setIndent(double intent) {
-        int val = (int)(intent*HSLFShape.MASTER_DPI/HSLFShape.POINT_DPI);
-        setParaTextPropVal("bullet.offset", val);
+    public void setIndent(Double indent) {
+        Integer val = (indent == null) ? null : Units.pointsToMaster(indent);
+        setPropVal(_paragraphStyle, "bullet.offset", val);
     }
 
     @Override
     public String getDefaultFontFamily() {
-        return (_runs.isEmpty() ? "Arial" : _runs.get(0).getFontFamily());
+        String typeface = null;
+        if (!_runs.isEmpty()) {
+            typeface = _runs.get(0).getFontFamily();
+        }
+        return (typeface != null) ? typeface : "Arial";
     }
 
     @Override
-    public double getDefaultFontSize() {
-        return (_runs.isEmpty() ? 12 : _runs.get(0).getFontSize());
+    public Double getDefaultFontSize() {
+        Double d = null;
+        if (!_runs.isEmpty()) {
+            d = _runs.get(0).getFontSize();
+        }
+        
+        return (d != null) ? d : 12d;
     }
 
     /**
      * Sets the type of horizontal alignment for the paragraph.
-     *
+     * 
      * @param align - the type of alignment
      */
     public void setAlignment(org.apache.poi.sl.usermodel.TextParagraph.TextAlign align) {
-        int alignInt;
-        switch (align) {
-        default:
-        case LEFT: alignInt = TextAlignmentProp.LEFT; break;
-        case CENTER: alignInt = TextAlignmentProp.CENTER; break;
-        case RIGHT: alignInt = TextAlignmentProp.RIGHT; break;
-        case DIST: alignInt = TextAlignmentProp.DISTRIBUTED; break;
-        case JUSTIFY: alignInt = TextAlignmentProp.JUSTIFY; break;
-        case JUSTIFY_LOW: alignInt = TextAlignmentProp.JUSTIFYLOW; break;
-        case THAI_DIST: alignInt = TextAlignmentProp.THAIDISTRIBUTED; break;
+        Integer alignInt = null;
+        if (align != null) switch (align) {
+            default:
+            case LEFT: alignInt = TextAlignmentProp.LEFT;break;
+            case CENTER: alignInt = TextAlignmentProp.CENTER; break;
+            case RIGHT: alignInt = TextAlignmentProp.RIGHT; break;
+            case DIST: alignInt = TextAlignmentProp.DISTRIBUTED; break;
+            case JUSTIFY: alignInt = TextAlignmentProp.JUSTIFY; break;
+            case JUSTIFY_LOW: alignInt = TextAlignmentProp.JUSTIFYLOW; break;
+            case THAI_DIST: alignInt = TextAlignmentProp.THAIDISTRIBUTED; break;
         }
-        setParaTextPropVal("alignment", alignInt);
+        setPropVal(_paragraphStyle, "alignment", alignInt);
     }
 
     @Override
     public org.apache.poi.sl.usermodel.TextParagraph.TextAlign getTextAlign() {
-        switch (getParaTextPropVal("alignment")) {
+        TextProp tp = getPropVal(_paragraphStyle, "alignment", this);
+        if (tp == null) return null;
+        switch (tp.getValue()) {
             default:
             case TextAlignmentProp.LEFT: return TextAlign.LEFT;
             case TextAlignmentProp.CENTER: return TextAlign.CENTER;
@@ -371,34 +347,33 @@ public final class HSLFTextParagraph imp
 
     @Override
     public FontAlign getFontAlign() {
-        switch(getParaTextPropVal("fontAlign")) {
-            default:
-            case -1: return FontAlign.AUTO;
+        TextProp tp = getPropVal(_paragraphStyle, FontAlignmentProp.NAME, this);
+        if (tp == null) return null;
+        
+        switch (tp.getValue()) {
             case FontAlignmentProp.BASELINE: return FontAlign.BASELINE;
             case FontAlignmentProp.TOP: return FontAlign.TOP;
             case FontAlignmentProp.CENTER: return FontAlign.CENTER;
             case FontAlignmentProp.BOTTOM: return FontAlign.BOTTOM;
+            default: return FontAlign.AUTO;
         }
     }
 
     @Override
     public BulletStyle getBulletStyle() {
-        if (getBulletChar() == 0) return null;
+        if (!isBullet()) return null;
 
         return new BulletStyle() {
             public String getBulletCharacter() {
-                char chr =  HSLFTextParagraph.this.getBulletChar();
-                return (chr == 0 ? "" : ""+chr);
+                Character chr = HSLFTextParagraph.this.getBulletChar();
+                return (chr == null || chr == 0) ? "" : "" + chr;
             }
 
             public String getBulletFont() {
-                int fontIdx = HSLFTextParagraph.this.getBulletFont();
-                if (fontIdx == -1) return getDefaultFontFamily();
-                PPFont ppFont = getSheet().getSlideShow().getFont(fontIdx);
-                return ppFont.getFontName();
+                return HSLFTextParagraph.this.getBulletFont();
             }
 
-            public double getBulletFontSize() {
+            public Double getBulletFontSize() {
                 return HSLFTextParagraph.this.getBulletSize();
             }
 
@@ -417,666 +392,669 @@ public final class HSLFTextParagraph imp
         _parentShape = parentShape;
     }
 
+    /**
+     * 
+     * @return indentation level
+     */
+    public int getIndentLevel() {
+        return _paragraphStyle == null ? 0 : _paragraphStyle.getIndentLevel();
+    }
 
     /**
-    *
-    * @return indentation level
-    */
-   public int getIndentLevel() {
-       return _paragraphStyle == null ? 0 : _paragraphStyle.getIndentLevel();
-   }
-
-   /**
-    * Sets indentation level
-    *
+     * Sets indentation level
+     * 
     * @param level indentation level. Must be in the range [0, 4]
-    */
-   public void setIndentLevel(int level) {
+     */
+    public void setIndentLevel(int level) {
        if( _paragraphStyle != null ) _paragraphStyle.setIndentLevel((short)level);
-   }
+    }
+
+    /**
+     * Sets whether this rich text run has bullets
+     */
+    public void setBullet(boolean flag) {
+        setFlag(ParagraphFlagsTextProp.BULLET_IDX, flag);
+    }
+
+    /**
+     * Returns whether this rich text run has bullets
+     */
+    public boolean isBullet() {
+        return getFlag(ParagraphFlagsTextProp.BULLET_IDX);
+    }
+
+    /**
+     * Sets the bullet character
+     */
+    public void setBulletChar(Character c) {
+        Integer val = (c == null) ? null : (int)c.charValue();
+        setPropVal(_paragraphStyle, "bullet.char", val);
+    }
+
+    /**
+     * Returns the bullet character
+     */
+    public Character getBulletChar() {
+        TextProp tp = getPropVal(_paragraphStyle, "bullet.char", this);
+        return (tp == null) ? null : (char)tp.getValue();
+    }
+
+    /**
+     * Sets the bullet size
+     */
+    public void setBulletSize(Double size) {
+        setPctOrPoints("bullet.size", size);
+    }
+
+    /**
+     * Returns the bullet size, null if unset
+     */
+    public Double getBulletSize() {
+        return getPctOrPoints("bullet.size");
+    }
+
+    /**
+     * Sets the bullet color
+     */
+    public void setBulletColor(Color color) {
+        Integer val = (color == null) ? null : new Color(color.getBlue(), color.getGreen(), color.getRed(), 254).getRGB();
+        setPropVal(_paragraphStyle, "bullet.color", val);
+    }
+
+    /**
+     * Returns the bullet color
+     */
+    public Color getBulletColor() {
+        TextProp tp = getPropVal(_paragraphStyle, "bullet.color", this);
+        if (tp == null) {
+            // if bullet color is undefined, return color of first run
+            return (_runs.isEmpty()) ? null : _runs.get(0).getFontColor();
+        }
+
+        int rgb = tp.getValue();
+        int cidx = rgb >> 24;
+        if (rgb % 0x1000000 == 0) {
+            if (_sheet == null)
+                return null;
+            ColorSchemeAtom ca = _sheet.getColorScheme();
+            if (cidx >= 0 && cidx <= 7)
+                rgb = ca.getColor(cidx);
+        }
+        Color tmp = new Color(rgb, true);
+        return new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed());
+    }
+
+    /**
+     * Sets the bullet font
+     */
+    public void setBulletFont(String typeface) {
+        if (typeface == null) {
+            setPropVal(_paragraphStyle, "bullet.font", null);
+            setFlag(ParagraphFlagsTextProp.BULLET_HARDFONT_IDX, false);
+        }
+
+        FontCollection fc = getSheet().getSlideShow().getFontCollection();
+        int idx = fc.addFont(typeface);
+
+        setPropVal(_paragraphStyle, "bullet.font", idx);
+        setFlag(ParagraphFlagsTextProp.BULLET_HARDFONT_IDX, true);
+    }
+
+    /**
+     * Returns the bullet font
+     */
+    public String getBulletFont() {
+        TextProp tp = getPropVal(_paragraphStyle, "bullet.font", this);
+        if (tp == null) return getDefaultFontFamily();
+        PPFont ppFont = getSheet().getSlideShow().getFont(tp.getValue());
+        assert(ppFont != null);
+        return ppFont.getFontName();
+    }
+
+    @Override
+    public void setLineSpacing(Double lineSpacing) {
+        setPctOrPoints("linespacing", lineSpacing);
+    }
+
+    @Override
+    public Double getLineSpacing() {
+        return getPctOrPoints("linespacing");
+    }
+
+    @Override
+    public void setSpaceBefore(Double spaceBefore) {
+        setPctOrPoints("spacebefore", spaceBefore);
+    }
+
+    @Override
+    public Double getSpaceBefore() {
+        return getPctOrPoints("spacebefore");
+    }
+
+    @Override
+    public void setSpaceAfter(Double spaceAfter) {
+        setPctOrPoints("spaceafter", spaceAfter);
+    }
+
+    @Override
+    public Double getSpaceAfter() {
+        return getPctOrPoints("spaceafter");
+    }
+
+    @Override
+    public Double getDefaultTabSize() {
+        // TODO: implement
+        return null;
+    }
+    
+    private Double getPctOrPoints(String propName) {
+        TextProp tp = getPropVal(_paragraphStyle, propName, this);
+        if (tp == null) return null;
+        int val = tp.getValue();
+        return (val < 0) ? Units.masterToPoints(val) : val;
+    }
+
+    private void setPctOrPoints(String propName, Double dval) {
+        Integer ival = null;
+        if (dval != null) {
+            ival = (dval < 0) ? Units.pointsToMaster(dval) : dval.intValue();
+        }
+        setPropVal(_paragraphStyle, propName, ival);
+    }
+    
+    private boolean getFlag(int index) {
+        BitMaskTextProp tp = (BitMaskTextProp)getPropVal(_paragraphStyle, ParagraphFlagsTextProp.NAME, this);
+        return (tp == null) ? false : tp.getSubValue(index);
+    }
+
+    private void setFlag(int index, boolean value) {
+        BitMaskTextProp tp = (BitMaskTextProp)_paragraphStyle.addWithName(ParagraphFlagsTextProp.NAME);
+        tp.setSubValue(value, index);
+    }
+
+    /**
+     * Fetch the value of the given Paragraph related TextProp. Returns null if
+     * that TextProp isn't present. If the TextProp isn't present, the value
+     * from the appropriate Master Sheet will apply.
+     */
+    protected static TextProp getPropVal(TextPropCollection props, String propName, HSLFTextParagraph paragraph) {
+        TextProp prop = props.findByName(propName);
+        if (prop != null) return prop;
 
-   /**
-    * Sets whether this rich text run has bullets
-    */
-   public void setBullet(boolean flag) {
-       setFlag(ParagraphFlagsTextProp.BULLET_IDX, flag);
-   }
-
-   /**
-    * Returns whether this rich text run has bullets
-    */
-   public boolean isBullet() {
-       return getFlag(ParagraphFlagsTextProp.BULLET_IDX);
-   }
-
-   /**
-    * Returns whether this rich text run has bullets
-    */
-   public boolean isBulletHard() {
-       return getFlag(ParagraphFlagsTextProp.BULLET_IDX);
-   }
-
-   /**
-    * Sets the bullet character
-    */
-   public void setBulletChar(char c) {
-       setParaTextPropVal("bullet.char", c);
-   }
-
-   /**
-    * Returns the bullet character
-    */
-   public char getBulletChar() {
-       int val = getParaTextPropVal("bullet.char");
-       return (char)(val == -1 ? 0 : val);
-   }
-
-   /**
-    * Sets the bullet size
-    */
-   public void setBulletSize(int size) {
-       setParaTextPropVal("bullet.size", size);
-   }
-
-   /**
-    * Returns the bullet size
-    */
-   public int getBulletSize() {
-       return getParaTextPropVal("bullet.size");
-   }
-
-   /**
-    * Sets the bullet color
-    */
-   public void setBulletColor(Color color) {
-       int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 254).getRGB();
-       setParaTextPropVal("bullet.color", rgb);
-   }
-
-   /**
-    * Returns the bullet color
-    */
-   public Color getBulletColor() {
-       int rgb = getParaTextPropVal("bullet.color");
-       if (rgb == -1) {
-           // if bullet color is undefined, return color of first run
-           if (_runs.isEmpty()) return null;
-           return _runs.get(0).getFontColor();
-       }
-
-       int cidx = rgb >> 24;
-       if (rgb % 0x1000000 == 0){
-           if (_sheet == null) return null;
-           ColorSchemeAtom ca = _sheet.getColorScheme();
-           if(cidx >= 0 && cidx <= 7) rgb = ca.getColor(cidx);
-       }
-       Color tmp = new Color(rgb, true);
-       return new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed());
-   }
-
-   /**
-    * Sets the bullet font
-    */
-   public void setBulletFont(int idx) {
-       setParaTextPropVal("bullet.font", idx);
-       setFlag(ParagraphFlagsTextProp.BULLET_HARDFONT_IDX, true);
-   }
-
-   /**
-    * Returns the bullet font
-    */
-   public int getBulletFont() {
-       return getParaTextPropVal("bullet.font");
-   }
-
-   @Override
-   public void setLineSpacing(double lineSpacing) {
-       // if lineSpacing < 0, we need to convert points (common interface) to master units (hslf)
-       if (lineSpacing < 0) {
-           lineSpacing = (lineSpacing*HSLFShape.MASTER_DPI/HSLFShape.POINT_DPI);
-       }
-       setParaTextPropVal("linespacing", (int)lineSpacing);
-   }
-
-   @Override
-   public double getLineSpacing() {
-       double val = getParaTextPropVal("linespacing");
-       // if lineSpacing < 0, we need to convert master units (hslf) to points (common interface)
-       if (val == -1) return 0;
-       if (val < -1) val *= HSLFShape.POINT_DPI/((double)HSLFShape.MASTER_DPI);
-       return val;
-   }
-
-   /**
-    * Sets spacing before a paragraph.
-    * <p>
-    * If spacebefore >= 0, then spacebefore is a percentage of normal line height.
-    * If spacebefore < 0, the absolute value of spacebefore is the spacing in master coordinates.
-    * </p>
-    */
-   public void setSpaceBefore(int val) {
-       setParaTextPropVal("spacebefore", val);
-   }
-
-   /**
-    * Returns spacing before a paragraph
-    * <p>
-    * If spacebefore >= 0, then spacebefore is a percentage of normal line height.
-    * If spacebefore < 0, the absolute value of spacebefore is the spacing in master coordinates.
-    * </p>
-    *
-    * @return the spacing before a paragraph
-    */
-   @Override
-   public double getSpaceBefore() {
-       int val = getParaTextPropVal("spacebefore");
-       return val == -1 ? 0 : val;
-   }
-
-   /**
-    * Sets spacing after a paragraph.
-    * <p>
-    * If spaceafter >= 0, then spaceafter is a percentage of normal line height.
-    * If spaceafter < 0, the absolute value of spaceafter is the spacing in master coordinates.
-    * </p>
-    */
-   public void setSpaceAfter(int val) {
-       setParaTextPropVal("spaceafter", val);
-   }
-
-   /**
-    * Returns spacing after a paragraph
-    * <p>
-    * If spaceafter >= 0, then spaceafter is a percentage of normal line height.
-    * If spaceafter < 0, the absolute value of spaceafter is the spacing in master coordinates.
-    * </p>
-    *
-    * @return the spacing before a paragraph
-    */
-   @Override
-   public double getSpaceAfter() {
-       int val = getParaTextPropVal("spaceafter");
-       return val == -1 ? 0 : val;
-   }
-
-   /**
-    * Returns the named TextProp, either by fetching it (if it exists) or adding it
-    *  (if it didn't)
-    * @param textPropCol The TextPropCollection to fetch from / add into
-    * @param textPropName The name of the TextProp to fetch/add
-    */
-    protected static TextProp fetchOrAddTextProp(TextPropCollection textPropCol, String textPropName) {
+        BitMaskTextProp maskProp = (BitMaskTextProp) props.findByName(ParagraphFlagsTextProp.NAME);
+        boolean hardAttribute = (maskProp != null && maskProp.getValue() == 0);
+        if (hardAttribute) return null;
+
+        HSLFSheet sheet = paragraph.getSheet();
+        int txtype = paragraph.getRunType();
+        HSLFMasterSheet master = sheet.getMasterSheet();
+        if (master == null) {
+            logger.log(POILogger.WARN, "MasterSheet is not available");
+            return null;
+        }
+
+        boolean isChar = props.getTextPropType() == TextPropType.character;
+        return master.getStyleAttribute(txtype, paragraph.getIndentLevel(), propName, isChar);
+    }
+
+    /**
+     * Returns the named TextProp, either by fetching it (if it exists) or
+     * adding it (if it didn't)
+     * 
+     * @param props the TextPropCollection to fetch from / add into
+     * @param name the name of the TextProp to fetch/add
+     * @param val the value, null if unset
+     */
+    protected static void setPropVal(TextPropCollection props, String name, Integer val) {
+        if (val == null) {
+            props.removeByName(name);
+            return;
+        }
+        
         // Fetch / Add the TextProp
-        return textPropCol.addWithName(textPropName);
+        TextProp tp = props.addWithName(name);
+        tp.setValue(val);
     }
+    
+    /**
+     * Check and add linebreaks to text runs leading other paragraphs
+     * 
+     * @param paragraphs
+     */
+    protected static void fixLineEndings(List<HSLFTextParagraph> paragraphs) {
+        HSLFTextRun lastRun = null;
+        for (HSLFTextParagraph p : paragraphs) {
+            if (lastRun != null && !lastRun.getRawText().endsWith("\r")) {
+                lastRun.setText(lastRun.getRawText() + "\r");
+            }
+            List<HSLFTextRun> ltr = p.getTextRuns();
+            if (ltr.isEmpty()) {
+                throw new RuntimeException("paragraph without textruns found");
+            }
+            lastRun = ltr.get(ltr.size() - 1);
+            assert (lastRun.getRawText() != null);
+        }
+    }
+
+    /**
+     * Search for a StyleTextPropAtom is for this text header (list of paragraphs)
+     * 
+     * @param header the header
+     * @param textLen the length of the rawtext, or -1 if the length is not known
+     */
+    private static StyleTextPropAtom findStyleAtomPresent(TextHeaderAtom header, int textLen) {
+        boolean afterHeader = false;
+        StyleTextPropAtom style = null;
+        for (Record record : header.getParentRecord().getChildRecords()) {
+            long rt = record.getRecordType();
+            if (afterHeader && rt == RecordTypes.TextHeaderAtom.typeID) {
+                // already on the next header, quit searching
+                break;
+            }
+            afterHeader |= (header == record);
+            if (afterHeader && rt == RecordTypes.StyleTextPropAtom.typeID) {
+                // found it
+                style = (StyleTextPropAtom) record;
+            }
+        }
+
+        if (style == null) {
+            logger.log(POILogger.INFO, "styles atom doesn't exist. Creating dummy record for later saving.");
+            style = new StyleTextPropAtom((textLen < 0) ? 1 : textLen);
+        } else {
+            if (textLen >= 0) {
+                style.setParentTextSize(textLen);
+            }
+        }
 
-    protected boolean getFlag(int index) {
-        if (_paragraphStyle == null) return false;
+        return style;
+    }
 
-        BitMaskTextProp prop = (BitMaskTextProp) _paragraphStyle.findByName(ParagraphFlagsTextProp.NAME);
+    /**
+     * Saves the modified paragraphs/textrun to the records.
+     * Also updates the styles to the correct text length.
+     */
+    protected static void storeText(List<HSLFTextParagraph> paragraphs) {
+        fixLineEndings(paragraphs);
 
-        if (prop == null) {
-            if (_sheet != null) {
-                int txtype = getRunType();
-                HSLFMasterSheet master = _sheet.getMasterSheet();
-                if (master != null) {
-                    prop = (BitMaskTextProp) master.getStyleAttribute(txtype, getIndentLevel(), ParagraphFlagsTextProp.NAME, false);
-                }
+        String rawText = toInternalString(getRawText(paragraphs));
+
+        // Will it fit in a 8 bit atom?
+        boolean isUnicode = StringUtil.hasMultibyte(rawText);
+        // isUnicode = true;
+
+        TextHeaderAtom headerAtom = paragraphs.get(0)._headerAtom;
+        TextBytesAtom byteAtom = paragraphs.get(0)._byteAtom;
+        TextCharsAtom charAtom = paragraphs.get(0)._charAtom;
+        StyleTextPropAtom styleAtom = findStyleAtomPresent(headerAtom, rawText.length());
+
+        // Store in the appropriate record
+        Record oldRecord = null, newRecord = null;
+        if (isUnicode) {
+            if (byteAtom != null || charAtom == null) {
+                oldRecord = byteAtom;
+                charAtom = new TextCharsAtom();
+            }
+            newRecord = charAtom;
+            charAtom.setText(rawText);
+        } else {
+            if (charAtom != null || byteAtom == null) {
+                oldRecord = charAtom;
+                byteAtom = new TextBytesAtom();
+            }
+            newRecord = byteAtom;
+            byte[] byteText = new byte[rawText.length()];
+            StringUtil.putCompressedUnicode(rawText, byteText, 0);
+            byteAtom.setText(byteText);
+        }
+        assert (newRecord != null);
+
+        RecordContainer _txtbox = headerAtom.getParentRecord();
+        Record[] cr = _txtbox.getChildRecords();
+        int headerIdx = -1, textIdx = -1, styleIdx = -1;
+        for (int i = 0; i < cr.length; i++) {
+            Record r = cr[i];
+            if (r == headerAtom) headerIdx = i;
+            else if (r == oldRecord || r == newRecord) textIdx = i;
+            else if (r == styleAtom) styleIdx = i;
+        }
+
+        if (textIdx == -1) {
+            // the old record was never registered, ignore it
+            _txtbox.addChildAfter(newRecord, headerAtom);
+            textIdx = headerIdx + 1;
+        } else {
+            // swap not appropriated records - noop if unchanged
+            cr[textIdx] = newRecord;
+        }
+
+        if (styleIdx == -1) {
+            // Add the new StyleTextPropAtom after the TextCharsAtom / TextBytesAtom
+            _txtbox.addChildAfter(styleAtom, newRecord);
+        }
+
+        for (HSLFTextParagraph p : paragraphs) {
+            if (newRecord == byteAtom) {
+                p._byteAtom = byteAtom;
+                p._charAtom = null;
             } else {
-                logger.log(POILogger.WARN, "MasterSheet is not available");
+                p._byteAtom = null;
+                p._charAtom = charAtom;
+            }
+        }
+
+        // Update the text length for its Paragraph and Character stylings
+        // * reset the length, to the new string's length
+        // * add on +1 if the last block
+
+        styleAtom.clearStyles();
+
+        TextPropCollection lastPTPC = null, lastRTPC = null, ptpc = null, rtpc = null;
+        for (HSLFTextParagraph para : paragraphs) {
+            ptpc = para.getParagraphStyle();
+            ptpc.updateTextSize(0);
+            if (!ptpc.equals(lastPTPC)) {
+                lastPTPC = styleAtom.addParagraphTextPropCollection(0);
+                lastPTPC.copy(ptpc);
+            }
+            for (HSLFTextRun tr : para.getTextRuns()) {
+                rtpc = tr.getCharacterStyle();
+                rtpc.updateTextSize(0);
+                if (!rtpc.equals(lastRTPC)) {
+                    lastRTPC = styleAtom.addCharacterTextPropCollection(0);
+                    lastRTPC.copy(rtpc);
+                }
+                int len = tr.getLength();
+                ptpc.updateTextSize(ptpc.getCharactersCovered() + len);
+                rtpc.updateTextSize(len);
+                lastPTPC.updateTextSize(lastPTPC.getCharactersCovered() + len);
+                lastRTPC.updateTextSize(lastRTPC.getCharactersCovered() + len);
             }
         }
 
-        return prop == null ? false : prop.getSubValue(index);
+        assert (lastPTPC != null && lastRTPC != null && ptpc != null && rtpc != null);
+        ptpc.updateTextSize(ptpc.getCharactersCovered() + 1);
+        rtpc.updateTextSize(rtpc.getCharactersCovered() + 1);
+        lastPTPC.updateTextSize(lastPTPC.getCharactersCovered() + 1);
+        lastRTPC.updateTextSize(lastRTPC.getCharactersCovered() + 1);
+
+        /**
+         * If TextSpecInfoAtom is present, we must update the text size in it,
+         * otherwise the ppt will be corrupted
+         */
+        for (Record r : paragraphs.get(0).getRecords()) {
+            if (r instanceof TextSpecInfoAtom) {
+                ((TextSpecInfoAtom) r).setParentSize(rawText.length() + 1);
+                break;
+            }
+        }
+
+        if (_txtbox instanceof EscherTextboxWrapper) {
+            try {
+                ((EscherTextboxWrapper) _txtbox).writeOut(null);
+            } catch (IOException e) {
+                throw new RuntimeException("failed dummy write", e);
+            }
+        }
     }
 
-   protected void setFlag(int index, boolean value) {
-       // Ensure we have the StyleTextProp atom we're going to need
-       assert(_paragraphStyle!=null);
-       BitMaskTextProp prop = (BitMaskTextProp) fetchOrAddTextProp(_paragraphStyle, ParagraphFlagsTextProp.NAME);
-       prop.setSubValue(value,index);
-   }
-
-   /**
-    * Check and add linebreaks to text runs leading other paragraphs
-    *
-    * @param paragraphs
-    */
-   protected static void fixLineEndings(List<HSLFTextParagraph> paragraphs) {
-       HSLFTextRun lastRun = null;
-       for (HSLFTextParagraph p : paragraphs) {
-           if (lastRun != null && !lastRun.getRawText().endsWith("\r")) {
-               lastRun.setText(lastRun.getRawText()+"\r");
-           }
-           List<HSLFTextRun> ltr = p.getTextRuns();
-           if (ltr.isEmpty()) {
-               throw new RuntimeException("paragraph without textruns found");
-           }
-           lastRun = ltr.get(ltr.size()-1);
-           assert(lastRun.getRawText() != null);
-       }
-   }
-
-   /**
-    * Search for a StyleTextPropAtom is for this text header (list of paragraphs)
-    * 
-    * @param header the header
-    * @param textLen the length of the rawtext, or -1 if the length is not known
-    */
-   private static StyleTextPropAtom findStyleAtomPresent(TextHeaderAtom header, int textLen) {
-       boolean afterHeader = false;
-       StyleTextPropAtom style = null;
-       for (Record record : header.getParentRecord().getChildRecords()) {
-           long rt = record.getRecordType();
-           if (afterHeader && rt == RecordTypes.TextHeaderAtom.typeID) {
-               // already on the next header, quit searching
-               break;
-           }
-           afterHeader |= (header == record);
-           if (afterHeader && rt == RecordTypes.StyleTextPropAtom.typeID) {
-               // found it
-               style = (StyleTextPropAtom)record;
-           }
-       }
-
-       if (style == null) {
-           logger.log(POILogger.INFO, "styles atom doesn't exist. Creating dummy record for later saving.");
-           style = new StyleTextPropAtom((textLen < 0) ? 1 : textLen);
-       } else {
-           if (textLen >= 0) {
-               style.setParentTextSize(textLen);
-           }
-       }
-       
-       return style;
-   }
-
-
-   /**
-    * Saves the modified paragraphs/textrun to the records.
-    * Also updates the styles to the correct text length.
-    */
-   protected static void storeText(List<HSLFTextParagraph> paragraphs) {
-       fixLineEndings(paragraphs);
-
-       String rawText = toInternalString(getRawText(paragraphs));
-
-       // Will it fit in a 8 bit atom?
-       boolean isUnicode = StringUtil.hasMultibyte(rawText);
-       // isUnicode = true;
-
-       TextHeaderAtom headerAtom = paragraphs.get(0)._headerAtom;
-       TextBytesAtom byteAtom = paragraphs.get(0)._byteAtom;
-       TextCharsAtom charAtom = paragraphs.get(0)._charAtom;
-       StyleTextPropAtom styleAtom = findStyleAtomPresent(headerAtom, rawText.length());
-
-       // Store in the appropriate record
-       Record oldRecord = null, newRecord = null;
-       if (isUnicode) {
-           if (byteAtom != null || charAtom == null) {
-               oldRecord = byteAtom;
-               charAtom = new TextCharsAtom();
-           }
-           newRecord = charAtom;
-           charAtom.setText(rawText);
-       } else {
-           if (charAtom != null || byteAtom == null) {
-               oldRecord = charAtom;
-               byteAtom = new TextBytesAtom();
-           }
-           newRecord = byteAtom;
-           byte[] byteText = new byte[rawText.length()];
-           StringUtil.putCompressedUnicode(rawText,byteText,0);
-           byteAtom.setText(byteText);
-       }
-       assert(newRecord != null);
-       
-       RecordContainer _txtbox = headerAtom.getParentRecord();
-       Record[] cr = _txtbox.getChildRecords();
-       int headerIdx = -1, textIdx = -1, styleIdx = -1;
-       for (int i=0; i<cr.length; i++) {
-           Record r = cr[i];
-           if (r == headerAtom) headerIdx = i;
-           else if (r == oldRecord || r == newRecord) textIdx = i;
-           else if (r == styleAtom) styleIdx = i;
-       }
-
-       if (textIdx == -1) {
-           // the old record was never registered, ignore it
-           _txtbox.addChildAfter(newRecord, headerAtom);
-           textIdx = headerIdx+1;
-       } else {
-           // swap not appropriated records - noop if unchanged
-           cr[textIdx] = newRecord;
-       }
-
-       if (styleIdx == -1) {
-           // Add the new StyleTextPropAtom after the TextCharsAtom / TextBytesAtom
-           _txtbox.addChildAfter(styleAtom, newRecord);
-       }
-       
-       for (HSLFTextParagraph p : paragraphs) {
-           if (newRecord == byteAtom) {
-               p._byteAtom = byteAtom;
-               p._charAtom = null;
-           } else {
-               p._byteAtom = null;
-               p._charAtom = charAtom;
-           }
-       }
-       
-       // Update the text length for its Paragraph and Character stylings
-       //   * reset the length, to the new string's length
-       //   * add on +1 if the last block
-
-       styleAtom.clearStyles();
-
-       TextPropCollection lastPTPC = null, lastRTPC = null, ptpc = null, rtpc = null;
-       for (HSLFTextParagraph para : paragraphs) {
-           ptpc = para.getParagraphStyle();
-           ptpc.updateTextSize(0);
-           if (!ptpc.equals(lastPTPC)) {
-               lastPTPC = styleAtom.addParagraphTextPropCollection(0);
-               lastPTPC.copy(ptpc);
-           }
-           for (HSLFTextRun tr : para.getTextRuns()) {
-               rtpc = tr.getCharacterStyle();
-               rtpc.updateTextSize(0);
-               if (!rtpc.equals(lastRTPC)) {
-                   lastRTPC = styleAtom.addCharacterTextPropCollection(0);
-                   lastRTPC.copy(rtpc);
-               }
-               int len = tr.getLength();
-               ptpc.updateTextSize(ptpc.getCharactersCovered()+len);
-               rtpc.updateTextSize(len);
-               lastPTPC.updateTextSize(lastPTPC.getCharactersCovered()+len);
-               lastRTPC.updateTextSize(lastRTPC.getCharactersCovered()+len);
-           }
-       }
-
-       assert(lastPTPC != null && lastRTPC != null && ptpc != null && rtpc != null);
-       ptpc.updateTextSize(ptpc.getCharactersCovered()+1);
-       rtpc.updateTextSize(rtpc.getCharactersCovered()+1);
-       lastPTPC.updateTextSize(lastPTPC.getCharactersCovered()+1);
-       lastRTPC.updateTextSize(lastRTPC.getCharactersCovered()+1);
-
-       /**
-        * If TextSpecInfoAtom is present, we must update the text size in it,
-        * otherwise the ppt will be corrupted
-        */
-       for (Record r : paragraphs.get(0).getRecords()) {
-           if (r instanceof TextSpecInfoAtom) {
-               ((TextSpecInfoAtom)r).setParentSize(rawText.length()+1);
-               break;
-           }
-       }
-       
-       if (_txtbox instanceof EscherTextboxWrapper) {
-           try {
-               ((EscherTextboxWrapper)_txtbox).writeOut(null);
-           } catch (IOException e) {
-               throw new RuntimeException("failed dummy write", e);
-           }
-       }
-   }
-
-   /**
-    * Adds the supplied text onto the end of the TextParagraphs,
-    * creating a new RichTextRun for it to sit in.
-    *
-    * @param text the text string used by this object.
-    */
-   protected static HSLFTextRun appendText(List<HSLFTextParagraph> paragraphs, String text, boolean newParagraph) {
-       text = toInternalString(text);
-
-       // check paragraphs
-       assert(!paragraphs.isEmpty() && !paragraphs.get(0).getTextRuns().isEmpty());
-
-       HSLFTextParagraph htp = paragraphs.get(paragraphs.size()-1);
-       HSLFTextRun htr = htp.getTextRuns().get(htp.getTextRuns().size()-1);
-
-       boolean isFirst = !newParagraph;
-       for (String rawText : text.split("(?<=\r)")) {
-           if (!isFirst) {
-               TextPropCollection tpc = htp.getParagraphStyle();
-               HSLFTextParagraph prevHtp = htp;
-               htp = new HSLFTextParagraph(htp._headerAtom, htp._byteAtom, htp._charAtom);
-               htp.getParagraphStyle().copy(tpc);
-               htp.setParentShape(prevHtp.getParentShape());
-               htp.setShapeId(prevHtp.getShapeId());
-               htp.supplySheet(prevHtp.getSheet());
-               paragraphs.add(htp);
-           }
-           isFirst = false;
-           
-           TextPropCollection tpc = htr.getCharacterStyle();
-           // special case, last text run is empty, we will reuse it
-           if (htr.getLength() > 0) {
-               htr = new HSLFTextRun(htp);
-               htr.getCharacterStyle().copy(tpc);
-               htp.addTextRun(htr);
-           }
-           htr.setText(rawText);
-       }
-       
-       storeText(paragraphs);
-
-       return htr;
-   }
-
-   /**
-    * Sets (overwrites) the current text.
-    * Uses the properties of the first paragraph / textrun
-    *
-    * @param text the text string used by this object.
-    */
-   public static HSLFTextRun setText(List<HSLFTextParagraph> paragraphs, String text) {
-       // check paragraphs
-       assert(!paragraphs.isEmpty() && !paragraphs.get(0).getTextRuns().isEmpty());
-
-       Iterator<HSLFTextParagraph> paraIter = paragraphs.iterator();
-       HSLFTextParagraph htp = paraIter.next(); // keep first
-       assert(htp != null);
-       while (paraIter.hasNext()) {
-           paraIter.next();
-           paraIter.remove();
-       }
-
-       Iterator<HSLFTextRun> runIter = htp.getTextRuns().iterator();
-       HSLFTextRun htr = runIter.next();
-       htr.setText("");
-       assert(htr != null);
-       while (runIter.hasNext()) {
-           runIter.next();
-           runIter.remove();
-       }
-
-       return appendText(paragraphs, text, false);
-   }
-
-   public static String getText(List<HSLFTextParagraph> paragraphs) {
-       assert(!paragraphs.isEmpty());
-       String rawText = getRawText(paragraphs);
-       return toExternalString(rawText, paragraphs.get(0).getRunType());
-   }
-   
-   public static String getRawText(List<HSLFTextParagraph> paragraphs) {
-       StringBuilder sb = new StringBuilder();
-       for (HSLFTextParagraph p : paragraphs) {
-           for (HSLFTextRun r : p.getTextRuns()) {
-               sb.append(r.getRawText());
-           }
-       }
-       return sb.toString();
-   }
-
-   /**
-    * Returns a new string with line breaks converted into internal ppt
-    * representation
-    */
-   protected static String toInternalString(String s) {
-       String ns = s.replaceAll("\\r?\\n", "\r");
-       return ns;
-   }
-
-   /**
-    * Converts raw text from the text paragraphs to a formatted string,
-    * i.e. it converts certain control characters used in the raw txt
-    *
-    * @param rawText the raw text
-    * @param runType the run type of the shape, paragraph or headerAtom.
-    *        use -1 if unknown
-    * @return the formatted string
-    */
-   public static String toExternalString(String rawText, int runType) {
-       // PowerPoint seems to store files with \r as the line break
-       // The messes things up on everything but a Mac, so translate
-       // them to \n
-       String text = rawText.replace('\r', '\n');
-
-       switch (runType) {
-           // 0xB acts like cariage return in page titles and like blank in the
-           // others
-           case -1:
-           case org.apache.poi.hslf.record.TextHeaderAtom.TITLE_TYPE:
-           case org.apache.poi.hslf.record.TextHeaderAtom.CENTER_TITLE_TYPE:
-               text = text.replace((char) 0x0B, '\n');
-               break;
-           default:
-               text = text.replace((char) 0x0B, ' ');
-               break;
-       }
-
-       return text;
-   }
-
-   /**
-    * For a given PPDrawing, grab all the TextRuns
-    */
+    /**
+     * Adds the supplied text onto the end of the TextParagraphs,
+     * creating a new RichTextRun for it to sit in.
+     * 
+     * @param text the text string used by this object.
+     */
+    protected static HSLFTextRun appendText(List<HSLFTextParagraph> paragraphs, String text, boolean newParagraph) {
+        text = toInternalString(text);
+
+        // check paragraphs
+        assert(!paragraphs.isEmpty() && !paragraphs.get(0).getTextRuns().isEmpty());
+
+        HSLFTextParagraph htp = paragraphs.get(paragraphs.size() - 1);
+        HSLFTextRun htr = htp.getTextRuns().get(htp.getTextRuns().size() - 1);
+
+        boolean isFirst = !newParagraph;
+        for (String rawText : text.split("(?<=\r)")) {
+            if (!isFirst) {
+                TextPropCollection tpc = htp.getParagraphStyle();
+                HSLFTextParagraph prevHtp = htp;
+                htp = new HSLFTextParagraph(htp._headerAtom, htp._byteAtom, htp._charAtom);
+                htp.getParagraphStyle().copy(tpc);
+                htp.setParentShape(prevHtp.getParentShape());
+                htp.setShapeId(prevHtp.getShapeId());
+                htp.supplySheet(prevHtp.getSheet());
+                paragraphs.add(htp);
+            }
+            isFirst = false;
+
+            TextPropCollection tpc = htr.getCharacterStyle();
+            // special case, last text run is empty, we will reuse it
+            if (htr.getLength() > 0) {
+                htr = new HSLFTextRun(htp);
+                htr.getCharacterStyle().copy(tpc);
+                htp.addTextRun(htr);
+            }
+            htr.setText(rawText);
+        }
+
+        storeText(paragraphs);
+
+        return htr;
+    }
+
+    /**
+     * Sets (overwrites) the current text.
+     * Uses the properties of the first paragraph / textrun
+     * 
+     * @param text the text string used by this object.
+     */
+    public static HSLFTextRun setText(List<HSLFTextParagraph> paragraphs, String text) {
+        // check paragraphs
+        assert(!paragraphs.isEmpty() && !paragraphs.get(0).getTextRuns().isEmpty());
+
+        Iterator<HSLFTextParagraph> paraIter = paragraphs.iterator();
+        HSLFTextParagraph htp = paraIter.next(); // keep first
+        assert (htp != null);
+        while (paraIter.hasNext()) {
+            paraIter.next();
+            paraIter.remove();
+        }
+
+        Iterator<HSLFTextRun> runIter = htp.getTextRuns().iterator();
+        HSLFTextRun htr = runIter.next();
+        htr.setText("");
+        assert (htr != null);
+        while (runIter.hasNext()) {
+            runIter.next();
+            runIter.remove();
+        }
+
+        return appendText(paragraphs, text, false);
+    }
+
+    public static String getText(List<HSLFTextParagraph> paragraphs) {
+        assert (!paragraphs.isEmpty());
+        String rawText = getRawText(paragraphs);
+        return toExternalString(rawText, paragraphs.get(0).getRunType());
+    }
+
+    public static String getRawText(List<HSLFTextParagraph> paragraphs) {
+        StringBuilder sb = new StringBuilder();
+        for (HSLFTextParagraph p : paragraphs) {
+            for (HSLFTextRun r : p.getTextRuns()) {
+                sb.append(r.getRawText());
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Returns a new string with line breaks converted into internal ppt
+     * representation
+     */
+    protected static String toInternalString(String s) {
+        String ns = s.replaceAll("\\r?\\n", "\r");
+        return ns;
+    }
+
+    /**
+     * Converts raw text from the text paragraphs to a formatted string,
+     * i.e. it converts certain control characters used in the raw txt
+     * 
+     * @param rawText the raw text
+     * @param runType the run type of the shape, paragraph or headerAtom.
+     *        use -1 if unknown
+     * @return the formatted string
+     */
+    public static String toExternalString(String rawText, int runType) {
+        // PowerPoint seems to store files with \r as the line break
+        // The messes things up on everything but a Mac, so translate
+        // them to \n
+        String text = rawText.replace('\r', '\n');
+
+        switch (runType) {
+        // 0xB acts like cariage return in page titles and like blank in the
+        // others
+        case -1:
+        case org.apache.poi.hslf.record.TextHeaderAtom.TITLE_TYPE:
+        case org.apache.poi.hslf.record.TextHeaderAtom.CENTER_TITLE_TYPE:
+            text = text.replace((char) 0x0B, '\n');
+            break;
+        default:
+            text = text.replace((char) 0x0B, ' ');
+            break;
+        }
+
+        return text;
+    }
+
+    /**
+     * For a given PPDrawing, grab all the TextRuns
+     */
    public static List<List<HSLFTextParagraph>> findTextParagraphs(PPDrawing ppdrawing, HSLFSheet sheet) {
-       List<List<HSLFTextParagraph>> runsV = new ArrayList<List<HSLFTextParagraph>>();
-       for (EscherTextboxWrapper wrapper : ppdrawing.getTextboxWrappers()) {
-           runsV.add(findTextParagraphs(wrapper, sheet));
-       }
-       return runsV;
-   }
-
-   /**
-    * Scans through the supplied record array, looking for
-    * a TextHeaderAtom followed by one of a TextBytesAtom or
-    * a TextCharsAtom. Builds up TextRuns from these
-    *
-    * @param wrapper an EscherTextboxWrapper
-    */
-   protected static List<HSLFTextParagraph> findTextParagraphs(EscherTextboxWrapper wrapper, HSLFSheet sheet) {
-       // propagate parents to parent-aware records
-       RecordContainer.handleParentAwareRecords(wrapper);
-       int shapeId = wrapper.getShapeId();
-       List<HSLFTextParagraph> rv = null;
-       
-       OutlineTextRefAtom ota = (OutlineTextRefAtom)wrapper.findFirstOfType(OutlineTextRefAtom.typeID);
-       if (ota != null) {
-           // if we are based on an outline, there are no further records to be parsed from the wrapper
-           if (sheet == null) {
-               throw new RuntimeException("Outline atom reference can't be solved without a sheet record");
-           }
-           
-           List<List<HSLFTextParagraph>> sheetRuns = sheet.getTextParagraphs();
-           assert(sheetRuns != null);
-           
-           int idx = ota.getTextIndex();
-           for (List<HSLFTextParagraph> r : sheetRuns) {
-               if (r.isEmpty()) continue;
-               int ridx = r.get(0).getIndex();
-               if (ridx > idx) break;
-               if (ridx == idx) {
-                   if (rv == null) {
-                       rv = r;
-                   } else {
-                       // create a new container
-                       // TODO: ... is this case really happening?
-                       rv = new ArrayList<HSLFTextParagraph>(rv);
-                       rv.addAll(r);
-                   }
-               }
-           }
-           if(rv == null || rv.isEmpty()) {
-               logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx);
-           }
-       } else {
-           if (sheet != null) {
-               // check sheet runs first, so we get exactly the same paragraph list
-               List<List<HSLFTextParagraph>> sheetRuns = sheet.getTextParagraphs();
-               assert(sheetRuns != null);
+        List<List<HSLFTextParagraph>> runsV = new ArrayList<List<HSLFTextParagraph>>();
+        for (EscherTextboxWrapper wrapper : ppdrawing.getTextboxWrappers()) {
+            runsV.add(findTextParagraphs(wrapper, sheet));
+        }
+        return runsV;
+    }
 
-               for (List<HSLFTextParagraph> paras : sheetRuns) {
+    /**
+     * Scans through the supplied record array, looking for
+     * a TextHeaderAtom followed by one of a TextBytesAtom or
+     * a TextCharsAtom. Builds up TextRuns from these
+     * 
+     * @param wrapper an EscherTextboxWrapper
+     */
+    protected static List<HSLFTextParagraph> findTextParagraphs(EscherTextboxWrapper wrapper, HSLFSheet sheet) {
+        // propagate parents to parent-aware records
+        RecordContainer.handleParentAwareRecords(wrapper);
+        int shapeId = wrapper.getShapeId();
+        List<HSLFTextParagraph> rv = null;
+
+        OutlineTextRefAtom ota = (OutlineTextRefAtom)wrapper.findFirstOfType(OutlineTextRefAtom.typeID);
+        if (ota != null) {
+            // if we are based on an outline, there are no further records to be parsed from the wrapper
+            if (sheet == null) {
+                throw new RuntimeException("Outline atom reference can't be solved without a sheet record");
+            }
+
+            List<List<HSLFTextParagraph>> sheetRuns = sheet.getTextParagraphs();
+            assert (sheetRuns != null);
+
+            int idx = ota.getTextIndex();
+            for (List<HSLFTextParagraph> r : sheetRuns) {
+                if (r.isEmpty()) continue;
+                int ridx = r.get(0).getIndex();
+                if (ridx > idx) break;
+                if (ridx == idx) {
+                    if (rv == null) {
+                        rv = r;
+                    } else {
+                        // create a new container
+                        // TODO: ... is this case really happening?
+                        rv = new ArrayList<HSLFTextParagraph>(rv);
+                        rv.addAll(r);
+                    }
+                }
+            }
+            if (rv == null || rv.isEmpty()) {
+                logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx);
+            }
+        } else {
+            if (sheet != null) {
+                // check sheet runs first, so we get exactly the same paragraph list
+                List<List<HSLFTextParagraph>> sheetRuns = sheet.getTextParagraphs();
+                assert (sheetRuns != null);
+
+                for (List<HSLFTextParagraph> paras : sheetRuns) {
                    if (!paras.isEmpty() && paras.get(0)._headerAtom.getParentRecord() == wrapper) {
-                       rv = paras;
-                       break;
-                   }
-               }
-           }
-           
-           if (rv == null) {
-               // if we haven't found the wrapper in the sheet runs, create a new paragraph list from its record
-               List<List<HSLFTextParagraph>> rvl = findTextParagraphs(wrapper.getChildRecords());
-               switch (rvl.size()) {
-               case 0: break; // nothing found
-               case 1: rv = rvl.get(0); break; // normal case
-               default:
-                   throw new RuntimeException("TextBox contains more than one list of paragraphs.");
-               }
-           }
-       }
-       
-       if (rv !=  null) {
-           StyleTextProp9Atom styleTextProp9Atom = wrapper.getStyleTextProp9Atom();
-           
-           for (HSLFTextParagraph htp : rv) {
-               htp.setShapeId(shapeId);
-               htp.setStyleTextProp9Atom(styleTextProp9Atom);
-           }
-       }
-       return rv;
-   }
-
-   /**
-    * Scans through the supplied record array, looking for
-    * a TextHeaderAtom followed by one of a TextBytesAtom or
-    * a TextCharsAtom. Builds up TextRuns from these
-    *
-    * @param records the records to build from
-    */
+                        rv = paras;
+                        break;
+                    }
+                }
+            }
+
+            if (rv == null) {
+                // if we haven't found the wrapper in the sheet runs, create a new paragraph list from its record
+                List<List<HSLFTextParagraph>> rvl = findTextParagraphs(wrapper.getChildRecords());
+                switch (rvl.size()) {
+                case 0: break; // nothing found
+                case 1: rv = rvl.get(0); break; // normal case
+                default:
+                    throw new RuntimeException("TextBox contains more than one list of paragraphs.");
+                }
+            }
+        }
+
+        if (rv != null) {
+            StyleTextProp9Atom styleTextProp9Atom = wrapper.getStyleTextProp9Atom();
+
+            for (HSLFTextParagraph htp : rv) {
+                htp.setShapeId(shapeId);
+                htp.setStyleTextProp9Atom(styleTextProp9Atom);
+            }
+        }
+        return rv;
+    }
+
+    /**
+     * Scans through the supplied record array, looking for
+     * a TextHeaderAtom followed by one of a TextBytesAtom or
+     * a TextCharsAtom. Builds up TextRuns from these
+     * 
+     * @param records the records to build from
+     */
     protected static List<List<HSLFTextParagraph>> findTextParagraphs(Record[] records) {
         List<List<HSLFTextParagraph>> paragraphCollection = new ArrayList<List<HSLFTextParagraph>>();
 
-        int[] recordIdx = {0};
-        
+        int[] recordIdx = { 0 };
+
         for (int slwtIndex = 0; recordIdx[0] < records.length; slwtIndex++) {
-            TextHeaderAtom    header = null;
-            TextBytesAtom     tbytes = null;
-            TextCharsAtom     tchars = null;
-            TextRulerAtom     ruler  = null;
+            TextHeaderAtom header = null;
+            TextBytesAtom tbytes = null;
+            TextCharsAtom tchars = null;
+            TextRulerAtom ruler = null;
             MasterTextPropAtom indents = null;
 
             for (Record r : getRecords(records, recordIdx, null)) {
                 long rt = r.getRecordType();
                 if (RecordTypes.TextHeaderAtom.typeID == rt) {
-                    header = (TextHeaderAtom)r;
+                    header = (TextHeaderAtom) r;
                 } else if (RecordTypes.TextBytesAtom.typeID == rt) {
-                    tbytes = (TextBytesAtom)r;
+                    tbytes = (TextBytesAtom) r;
                 } else if (RecordTypes.TextCharsAtom.typeID == rt) {
-                    tchars = (TextCharsAtom)r;
+                    tchars = (TextCharsAtom) r;
                 } else if (RecordTypes.TextRulerAtom.typeID == rt) {
-                    ruler = (TextRulerAtom)r;
+                    ruler = (TextRulerAtom) r;
                 } else if (RecordTypes.MasterTextPropAtom.typeID == rt) {
-                    indents = (MasterTextPropAtom)r;
+                    indents = (MasterTextPropAtom) r;
                 }
                 // don't search for RecordTypes.StyleTextPropAtom.typeID here ... see findStyleAtomPresent below
             }
 
             if (header == null) break;
-            
+
             if (header.getParentRecord() instanceof SlideListWithText) {
                 // runs found in PPDrawing are not linked with SlideListWithTexts
                 header.setIndex(slwtIndex);
@@ -1093,7 +1071,7 @@ public final class HSLFTextParagraph imp
 
             List<HSLFTextParagraph> paragraphs = new ArrayList<HSLFTextParagraph>();
             paragraphCollection.add(paragraphs);
-            
+
             // split, but keep delimiter
             for (String para : rawText.split("(?<=\r)")) {
                 HSLFTextParagraph tpara = new HSLFTextParagraph(header, tbytes, tchars);
@@ -1116,7 +1094,7 @@ public final class HSLFTextParagraph imp
         if (paragraphCollection.isEmpty()) {
             logger.log(POILogger.DEBUG, "No text records found.");
         }
-        
+
         return paragraphCollection;
     }
 
@@ -1124,25 +1102,25 @@ public final class HSLFTextParagraph imp
         int paraIdx = 0, runIdx = 0;
         HSLFTextRun trun;
 
-        for (int csIdx=0; csIdx<charStyles.size(); csIdx++) {
+        for (int csIdx = 0; csIdx < charStyles.size(); csIdx++) {
             TextPropCollection p = charStyles.get(csIdx);
-            for (int ccRun = 0, ccStyle = p.getCharactersCovered(); ccRun < ccStyle; ) {
+            for (int ccRun = 0, ccStyle = p.getCharactersCovered(); ccRun < ccStyle;) {
                 HSLFTextParagraph para = paragraphs.get(paraIdx);
                 List<HSLFTextRun> runs = para.getTextRuns();
                 trun = runs.get(runIdx);
                 int len = trun.getLength();
 
-                if (ccRun+len <= ccStyle) {
+                if (ccRun + len <= ccStyle) {
                     ccRun += len;
                 } else {
                     String text = trun.getRawText();
-                    trun.setText(text.substring(0,ccStyle-ccRun));
+                    trun.setText(text.substring(0, ccStyle - ccRun));
 
                     HSLFTextRun nextRun = new HSLFTextRun(para);
-                    nextRun.setText(text.substring(ccStyle-ccRun));
-                    runs.add(runIdx+1, nextRun);
+                    nextRun.setText(text.substring(ccStyle - ccRun));
+                    runs.add(runIdx + 1, nextRun);
 
-                    ccRun += ccStyle-ccRun;
+                    ccRun += ccStyle - ccRun;
                 }
 
                 TextPropCollection pCopy = new TextPropCollection(0, TextPropType.character);
@@ -1151,7 +1129,7 @@ public final class HSLFTextParagraph imp
 
                 len = trun.getLength();
                 if (paraIdx == paragraphs.size()-1 && runIdx == runs.size()-1) {
-                    if (csIdx < charStyles.size()-1) {
+                    if (csIdx < charStyles.size() - 1) {
                         // special case, empty trailing text run
                         HSLFTextRun nextRun = new HSLFTextRun(para);
                         nextRun.setText("");
@@ -1204,7 +1182,7 @@ public final class HSLFTextParagraph imp
                     len += trun.getLength();
                 }
                 para.setIndentLevel(p.getIndentLevel());
-                ccPara += len+1;
+                ccPara += len + 1;
             }
         }
     }
@@ -1237,6 +1215,6 @@ public final class HSLFTextParagraph imp
     }
 
     public EscherTextboxWrapper getTextboxWrapper() {
-        return (EscherTextboxWrapper)_headerAtom.getParentRecord();
+        return (EscherTextboxWrapper) _headerAtom.getParentRecord();
     }
 }

Modified: poi/branches/common_sl/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java
URL: http://svn.apache.org/viewvc/poi/branches/common_sl/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java?rev=1686117&r1=1686116&r2=1686117&view=diff
==============================================================================
--- poi/branches/common_sl/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java (original)
+++ poi/branches/common_sl/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java Wed Jun 17 22:21:13 2015
@@ -17,7 +17,8 @@
 
 package org.apache.poi.hslf.usermodel;
 
-import static org.apache.poi.hslf.usermodel.HSLFTextParagraph.fetchOrAddTextProp;
+import static org.apache.poi.hslf.usermodel.HSLFTextParagraph.setPropVal;
+import static org.apache.poi.hslf.usermodel.HSLFTextParagraph.getPropVal;
 
 import java.awt.Color;
 
@@ -132,39 +133,17 @@ public final class HSLFTextRun implement
 	 *  it if required.
 	 */
 	private void setCharFlagsTextPropVal(int index, boolean value) {
-		if(getFlag(index) != value) setFlag(index, value);
+	    // TODO: check if paragraph/chars can be handled the same ...
+		if (getFlag(index) != value) setFlag(index, value);
 	}
 
 	/**
-	 * Fetch the value of the given Character related TextProp.
-	 * Returns -1 if that TextProp isn't present.
-	 * If the TextProp isn't present, the value from the appropriate
-	 *  Master Sheet will apply.
-	 */
-	private int getCharTextPropVal(String propName) {
-		TextProp prop = null;
-		if (characterStyle != null){
-			prop = characterStyle.findByName(propName);
-		}
-
-		if (prop == null){
-			HSLFSheet sheet = parentParagraph.getSheet();
-			int txtype = parentParagraph.getRunType();
-			HSLFMasterSheet master = sheet.getMasterSheet();
-			if (master != null)
-				prop = master.getStyleAttribute(txtype, parentParagraph.getIndentLevel(), propName, true);
-		}
-		return prop == null ? -1 : prop.getValue();
-	}
-	
-	/**
 	 * Sets the value of the given Paragraph TextProp, add if required
 	 * @param propName The name of the Paragraph TextProp
 	 * @param val The value to set for the TextProp
 	 */
 	public void setCharTextPropVal(String propName, int val) {
-		TextProp tp = fetchOrAddTextProp(characterStyle, propName);
-		tp.setValue(val);
+	    setPropVal(characterStyle, propName, val);
 	}
 
 
@@ -260,8 +239,8 @@ public final class HSLFTextRun implement
 	 * @return the percentage of the font size. If the value is positive, it is superscript, otherwise it is subscript
 	 */
 	public int getSuperscript() {
-		int val = getCharTextPropVal("superscript");
-		return val == -1 ? 0 : val;
+		TextProp tp = getPropVal(characterStyle, "superscript", parentParagraph);
+		return tp == null ? 0 : tp.getValue();
 	}
 
 	/**
@@ -270,14 +249,15 @@ public final class HSLFTextRun implement
 	 * @param val the percentage of the font size. If the value is positive, it is superscript, otherwise it is subscript
 	 */
 	public void setSuperscript(int val) {
-		setCharTextPropVal("superscript", val);
+	    setPropVal(characterStyle, "superscript", val);
 	}
 
 	/**
 	 * Gets the font size
 	 */
-	public double getFontSize() {
-		return getCharTextPropVal("font.size");
+	public Double getFontSize() {
+        TextProp tp = getPropVal(characterStyle, "font.size", parentParagraph);
+        return tp == null ? null : (double)tp.getValue();
 	}
 
 
@@ -292,7 +272,8 @@ public final class HSLFTextRun implement
 	 * Gets the font index
 	 */
 	public int getFontIndex() {
-		return getCharTextPropVal("font.index");
+        TextProp tp = getPropVal(characterStyle, "font.index", parentParagraph);
+        return tp == null ? -1 : tp.getValue();
 	}
 
 	/**
@@ -329,9 +310,9 @@ public final class HSLFTextRun implement
 		if (sheet == null || slideShow == null) {
 			return _fontFamily;
 		}
-		int fontIdx = getCharTextPropVal("font.index");
-		if(fontIdx == -1) { return null; }
-		return slideShow.getFontCollection().getFontWithId(fontIdx);
+        TextProp tp = getPropVal(characterStyle, "font.index", parentParagraph);
+        if (tp == null) { return null; }
+		return slideShow.getFontCollection().getFontWithId(tp.getValue());
 	}
 
 	/**
@@ -339,7 +320,9 @@ public final class HSLFTextRun implement
 	 * @see java.awt.Color
 	 */
 	public Color getFontColor() {
-		int rgb = getCharTextPropVal("font.color");
+		TextProp tp = getPropVal(characterStyle, "font.color", parentParagraph);
+		if (tp == null) return null;
+		int rgb = tp.getValue();
 
 		int cidx = rgb >> 24;
 		if (rgb % 0x1000000 == 0){
@@ -370,7 +353,7 @@ public final class HSLFTextRun implement
 	}
 
     protected void setFlag(int index, boolean value) {
-        BitMaskTextProp prop = (BitMaskTextProp) fetchOrAddTextProp(characterStyle, CharFlagsTextProp.NAME);
+        BitMaskTextProp prop = (BitMaskTextProp)characterStyle.addWithName(CharFlagsTextProp.NAME);
         prop.setSubValue(value, index);
     }
 

Modified: poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextParagraph.java
URL: http://svn.apache.org/viewvc/poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextParagraph.java?rev=1686117&r1=1686116&r2=1686117&view=diff
==============================================================================
--- poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextParagraph.java (original)
+++ poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextParagraph.java Wed Jun 17 22:21:13 2015
@@ -55,12 +55,21 @@ public class DrawTextParagraph<T extends
         double rightInset = insets.right;
         double penY = y;
 
-        double leftMargin = paragraph.getLeftMargin();
         boolean firstLine = true;
-        double indent = paragraph.getIndent();
+        Double leftMargin = paragraph.getLeftMargin();
+        Double indent = paragraph.getIndent();
+        if (leftMargin == null) {
+            leftMargin = (indent != null) ? -indent : 0;
+        }
+        if (indent == null) {
+            indent = (leftMargin != null) ? -leftMargin : 0;
+        }
+
 
         //The vertical line spacing
-        double spacing = paragraph.getLineSpacing();
+        Double spacing = paragraph.getLineSpacing();
+        if (spacing == null) spacing = 100d;
+        
         for(DrawTextFragment line : lines){
             double penX = x + leftMargin;
 
@@ -77,7 +86,7 @@ public class DrawTextParagraph<T extends
                         bullet.setPosition(penX + indent, penY);
                     } else if(indent > 0){
                         // a positive value means the "First Line" indentation:
-                        // the first line is indented and other lines start at the bullet ofset
+                        // the first line is indented and other lines start at the bullet offset
                         bullet.setPosition(penX, penY);
                         penX += indent;
                     } else {
@@ -96,7 +105,9 @@ public class DrawTextParagraph<T extends
 
             Rectangle2D anchor = DrawShape.getAnchor(graphics, paragraph.getParentShape());
 
-            switch (paragraph.getTextAlign()) {
+            TextAlign ta = paragraph.getTextAlign();
+            if (ta == null) ta = TextAlign.LEFT;
+            switch (ta) {
                 case CENTER:
                     penX += (anchor.getWidth() - leftMargin - line.getWidth() - leftInset - rightInset) / 2;
                     break;
@@ -219,9 +230,10 @@ public class DrawTextParagraph<T extends
         if (buColor == null) buColor = (Color)firstLineAttr.getAttribute(TextAttribute.FOREGROUND);
 
         float fontSize = (Float)firstLineAttr.getAttribute(TextAttribute.SIZE);
-        float buSz = (float)bulletStyle.getBulletFontSize();
-        if(buSz > 0) fontSize *= buSz* 0.01;
-        else fontSize = -buSz;
+        Double buSz = bulletStyle.getBulletFontSize();
+        if (buSz == null) buSz = 100d; 
+        if (buSz > 0) fontSize *= buSz* 0.01;
+        else fontSize = (float)-buSz;
 
         
         AttributedString str = new AttributedString(buCharacter);
@@ -237,10 +249,13 @@ public class DrawTextParagraph<T extends
     protected String getRenderableText(TextRun tr) {
         StringBuilder buf = new StringBuilder();
         TextCap cap = tr.getTextCap();
+        String tabs = null;
         for (char c : tr.getRawText().toCharArray()) {
             if(c == '\t') {
-                // TODO: finish support for tabs
-                buf.append("  ");
+                if (tabs == null) {
+                    tabs = tab2space(tr);
+                }
+                buf.append(tabs);
                 continue;
             }
 
@@ -255,6 +270,34 @@ public class DrawTextParagraph<T extends
 
         return buf.toString();
     }
+    
+    /**
+     * Replace a tab with the effective number of white spaces.
+     */
+    private String tab2space(TextRun tr) {
+        AttributedString string = new AttributedString(" ");
+        String typeFace = tr.getFontFamily();
+        if (typeFace == null) typeFace = "Lucida Sans";
+        string.addAttribute(TextAttribute.FAMILY, typeFace);
+
+        Double fs = tr.getFontSize();
+        if (fs == null) fs = 12d;
+        string.addAttribute(TextAttribute.SIZE, fs.floatValue());
+        
+        TextLayout l = new TextLayout(string.getIterator(), new FontRenderContext(null, true, true));
+        double wspace = l.getAdvance();
+
+        Double tabSz = paragraph.getDefaultTabSize();
+        if (tabSz == null) tabSz = wspace*4;
+
+        int numSpaces = (int)Math.ceil(tabSz / wspace);
+        StringBuilder buf = new StringBuilder();
+        for(int i = 0; i < numSpaces; i++) {
+            buf.append(' ');
+        }
+        return buf.toString();
+    }
+    
 
     /**
      * Returns wrapping width to break lines in this paragraph
@@ -271,8 +314,14 @@ public class DrawTextParagraph<T extends
 
         Rectangle2D anchor = DrawShape.getAnchor(graphics, paragraph.getParentShape());
 
-        double leftMargin = paragraph.getLeftMargin();
-        double indent = paragraph.getIndent();
+        Double leftMargin = paragraph.getLeftMargin();
+        Double indent = paragraph.getIndent();
+        if (leftMargin == null) {
+            leftMargin = (indent != null) ? -indent : 0;
+        }
+        if (indent == null) {
+            indent = (leftMargin != null) ? -leftMargin : 0;
+        }
 
         double width;
         TextShape<? extends TextParagraph<T>> ts = paragraph.getParentShape();
@@ -323,7 +372,9 @@ public class DrawTextParagraph<T extends
             text.append(runText);
             int endIndex = text.length();
 
-            attList.add(new AttributedStringData(TextAttribute.FOREGROUND, run.getFontColor(), beginIndex, endIndex));
+            Color fgColor = run.getFontColor();
+            if (fgColor == null) fgColor = Color.BLACK;
+            attList.add(new AttributedStringData(TextAttribute.FOREGROUND, fgColor, beginIndex, endIndex));
 
             // user can pass an custom object to convert fonts
             String fontFamily = run.getFontFamily();
@@ -335,10 +386,14 @@ public class DrawTextParagraph<T extends
             if(fontHandler != null) {
                 fontFamily = fontHandler.getRendererableFont(fontFamily, run.getPitchAndFamily());
             }
+            if (fontFamily == null) {
+                fontFamily = paragraph.getDefaultFontFamily();
+            }
             attList.add(new AttributedStringData(TextAttribute.FAMILY, fontFamily, beginIndex, endIndex));
 
-            float fontSz = (float)run.getFontSize();
-            attList.add(new AttributedStringData(TextAttribute.SIZE, fontSz, beginIndex, endIndex));
+            Double fontSz = run.getFontSize();
+            if (fontSz == null) fontSz = paragraph.getDefaultFontSize();
+            attList.add(new AttributedStringData(TextAttribute.SIZE, fontSz.floatValue(), beginIndex, endIndex));
 
             if(run.isBold()) {
                 attList.add(new AttributedStringData(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, beginIndex, endIndex));
@@ -364,9 +419,9 @@ public class DrawTextParagraph<T extends
         // ensure that the paragraph contains at least one character
         // We need this trick to correctly measure text
         if (text.length() == 0) {
-            float fontSz = (float)paragraph.getDefaultFontSize();
+            Double fontSz = paragraph.getDefaultFontSize();
             text.append(" ");
-            attList.add(new AttributedStringData(TextAttribute.SIZE, fontSz, 0, 1));
+            attList.add(new AttributedStringData(TextAttribute.SIZE, fontSz.floatValue(), 0, 1));
         }
 
         AttributedString string = new AttributedString(text.toString());

Modified: poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextShape.java
URL: http://svn.apache.org/viewvc/poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextShape.java?rev=1686117&r1=1686116&r2=1686117&view=diff
==============================================================================
--- poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextShape.java (original)
+++ poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextShape.java Wed Jun 17 22:21:13 2015
@@ -95,7 +95,8 @@ public class DrawTextShape<T extends Tex
 
             if (!isFirstLine) {
                 // the amount of vertical white space before the paragraph
-                double spaceBefore = p.getSpaceBefore();
+                Double spaceBefore = p.getSpaceBefore();
+                if (spaceBefore == null) spaceBefore = 0d;
                 if(spaceBefore > 0) {
                     // positive value means percentage spacing of the height of the first line, e.g.
                     // the higher the first line, the bigger the space before the paragraph
@@ -112,7 +113,8 @@ public class DrawTextShape<T extends Tex
             y += dp.getY();
 
             if (paragraphs.hasNext()) {
-                double spaceAfter = p.getSpaceAfter();
+                Double spaceAfter = p.getSpaceAfter();
+                if (spaceAfter == null) spaceAfter = 0d;
                 if(spaceAfter > 0) {
                     // positive value means percentage spacing of the height of the last line, e.g.
                     // the higher the last line, the bigger the space after the paragraph



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org


Mime
View raw message