You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ta...@apache.org on 2013/07/31 02:19:07 UTC

svn commit: r1508691 - in /poi/trunk: src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java test-data/spreadsheet/WithTextBox.xlsx test-data/spreadsheet/WithTextBox2.xlsx

Author: tallison
Date: Wed Jul 31 00:19:07 2013
New Revision: 1508691

URL: http://svn.apache.org/r1508691
Log:
POI-55292

Added:
    poi/trunk/test-data/spreadsheet/WithTextBox2.xlsx   (with props)
Modified:
    poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java
    poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java
    poi/trunk/test-data/spreadsheet/WithTextBox.xlsx

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java?rev=1508691&r1=1508690&r2=1508691&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java Wed Jul 31 00:19:07 2013
@@ -17,6 +17,11 @@
 
 package org.apache.poi.xssf.usermodel;
 
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+
 import org.apache.poi.hssf.util.HSSFColor;
 import org.openxmlformats.schemas.drawingml.x2006.main.*;
 import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShape;
@@ -24,15 +29,19 @@ import org.openxmlformats.schemas.drawin
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRElt;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRPrElt;
 import org.apache.poi.util.Internal;
+import org.apache.poi.util.Units;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.STUnderlineValues;
 
 /**
  * Represents a shape with a predefined geometry in a SpreadsheetML drawing.
  * Possible shape types are defined in {@link org.apache.poi.ss.usermodel.ShapeTypes}
- *
- * @author Yegor Kozlov
  */
-public class XSSFSimpleShape extends XSSFShape { // TODO - instantiable superclass
+public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParagraph> { // TODO - instantiable superclass
+	/**
+	 * List of the paragraphs that make up the text in this shape
+	 */
+    private final List<XSSFTextParagraph> _paragraphs;
     /**
      * A default instance of CTShape used for creating new shapes.
      */
@@ -46,6 +55,15 @@ public class XSSFSimpleShape extends XSS
     protected XSSFSimpleShape(XSSFDrawing drawing, CTShape ctShape) {
         this.drawing = drawing;
         this.ctShape = ctShape;
+        
+        _paragraphs = new ArrayList<XSSFTextParagraph>();
+        
+        // initialize any existing paragraphs - this will be the default body paragraph in a new shape, 
+        // or existing paragraphs that have been loaded from the file
+        CTTextBody body = ctShape.getTxBody();
+        for(int i = 0; i < body.sizeOfPArray(); i++) {
+            _paragraphs.add(new XSSFTextParagraph(body.getPArray(i), ctShape));        	
+        }
     }
 
     /**
@@ -74,34 +92,18 @@ public class XSSFSimpleShape extends XSS
             geom.setPrst(STShapeType.RECT);
             geom.addNewAvLst();
 
-            CTShapeStyle style = shape.addNewStyle();
-            CTSchemeColor scheme = style.addNewLnRef().addNewSchemeClr();
-            scheme.setVal(STSchemeColorVal.ACCENT_1);
-            scheme.addNewShade().setVal(50000);
-            style.getLnRef().setIdx(2);
-
-            CTStyleMatrixReference fillref = style.addNewFillRef();
-            fillref.setIdx(1);
-            fillref.addNewSchemeClr().setVal(STSchemeColorVal.ACCENT_1);
-
-            CTStyleMatrixReference effectRef = style.addNewEffectRef();
-            effectRef.setIdx(0);
-            effectRef.addNewSchemeClr().setVal(STSchemeColorVal.ACCENT_1);
-
-            CTFontReference fontRef = style.addNewFontRef();
-            fontRef.setIdx(STFontCollectionIndex.MINOR);
-            fontRef.addNewSchemeClr().setVal(STSchemeColorVal.LT_1);
-
             CTTextBody body = shape.addNewTxBody();
             CTTextBodyProperties bodypr = body.addNewBodyPr();
-            bodypr.setAnchor(STTextAnchoringType.CTR);
+            bodypr.setAnchor(STTextAnchoringType.T);
             bodypr.setRtlCol(false);
             CTTextParagraph p = body.addNewP();
-            p.addNewPPr().setAlgn(STTextAlignType.CTR);
+            p.addNewPPr().setAlgn(STTextAlignType.L);
             CTTextCharacterProperties endPr = p.addNewEndParaRPr();
             endPr.setLang("en-US");
-            endPr.setSz(1100);
-
+            endPr.setSz(1100);   
+            CTSolidColorFillProperties scfpr = endPr.addNewSolidFill();
+            scfpr.addNewSrgbClr().setVal(new byte[] { 0, 0, 0 });
+                        
             body.addNewLstStyle();
 
             prototype = shape;
@@ -114,30 +116,255 @@ public class XSSFSimpleShape extends XSS
         return ctShape;
     }
 
+
+    public Iterator<XSSFTextParagraph> iterator(){
+        return _paragraphs.iterator();
+    }
+
     /**
-     * Gets the shape type, one of the constants defined in {@link org.apache.poi.ss.usermodel.ShapeTypes}.
-     *
-     * @return the shape type
-     * @see org.apache.poi.ss.usermodel.ShapeTypes
+     * Returns the text from all paragraphs in the shape. Paragraphs are separated by new lines.
+     * 
+     * @return  text contained within this shape or empty string
      */
-    public int getShapeType() {
-        return ctShape.getSpPr().getPrstGeom().getPrst().intValue();
+    public String getText() {
+        final int MAX_LEVELS = 9;
+        StringBuilder out = new StringBuilder();
+        List<Integer> levelCount = new ArrayList<Integer>(MAX_LEVELS);	// maximum 9 levels
+        XSSFTextParagraph p = null;
+        
+        // initialise the levelCount array - this maintains a record of the numbering to be used at each level
+        for (int k = 0; k < MAX_LEVELS; k++){
+        	levelCount.add(0);
+        }
+
+        for(int i = 0; i < _paragraphs.size(); i++) {
+            if (out.length() > 0) out.append('\n');
+            p = _paragraphs.get(i);
+
+            if(p.isBullet() && p.getText().length() > 0){
+               
+                int level = Math.min(p.getLevel(), MAX_LEVELS - 1);
+                
+                if(p.isBulletAutoNumber()){
+                    i = processAutoNumGroup(i, level, levelCount, out);
+                } else {
+                    // indent appropriately for the level
+                    for(int j = 0; j < level; j++){
+                        out.append('\t');
+                    }               
+                    String character = p.getBulletCharacter();
+                    out.append(character.length() > 0 ? character + " " : "- ");
+                    out.append(p.getText());
+                }               
+            } else {
+                out.append(p.getText());
+                
+                // this paragraph is not a bullet, so reset the count array
+                for (int k = 0; k < MAX_LEVELS; k++){
+                    levelCount.set(k, 0);
+                }
+            }            
+        }
+
+        return out.toString();
     }
 
     /**
-     * Sets the shape types.
-     *
-     * @param type the shape type, one of the constants defined in {@link org.apache.poi.ss.usermodel.ShapeTypes}.
-     * @see org.apache.poi.ss.usermodel.ShapeTypes
+     * 
      */
-    public void setShapeType(int type) {
-        ctShape.getSpPr().getPrstGeom().setPrst(STShapeType.Enum.forInt(type));
+    private int processAutoNumGroup(int index, int level, List<Integer> levelCount, StringBuilder out){
+        XSSFTextParagraph p = null;
+        XSSFTextParagraph nextp = null;
+        ListAutoNumber scheme, nextScheme;
+        int startAt, nextStartAt;
+        
+        p = _paragraphs.get(index);
+        
+        // The rules for generating the auto numbers are as follows. If the following paragraph is also
+        // an auto-number, has the same type/scheme (and startAt if defined on this paragraph) then they are
+        // considered part of the same group. An empty bullet paragraph is counted as part of the same
+        // group but does not increment the count for the group. A change of type, startAt or the paragraph
+        // not being a bullet resets the count for that level to 1.
+        
+        // first auto-number paragraph so initialise to 1 or the bullets startAt if present
+        startAt = p.getBulletAutoNumberStart();
+        scheme = p.getBulletAutoNumberScheme();
+        if(levelCount.get(level) == 0) {
+            levelCount.set(level, startAt == 0 ? 1 : startAt);
+        }
+        // indent appropriately for the level
+        for(int j = 0; j < level; j++){
+            out.append('\t');
+        }
+        if (p.getText().length() > 0){
+            out.append(getBulletPrefix(scheme, levelCount.get(level)));
+            out.append(p.getText());
+        }
+        while(true) {                        
+            nextp = (index + 1) == _paragraphs.size() ? null : _paragraphs.get(index + 1);
+            if(nextp == null) break; // out of paragraphs
+            if(!(nextp.isBullet() && p.isBulletAutoNumber())) break; // not an auto-number bullet                      
+            if(nextp.getLevel() > level) { 
+                // recurse into the new level group
+                if (out.length() > 0) out.append('\n');
+                index = processAutoNumGroup(index + 1, nextp.getLevel(), levelCount, out);
+                continue; // restart the loop given the new index
+            } else if(nextp.getLevel() < level) {
+                break; // changed level   
+            }
+            nextScheme = nextp.getBulletAutoNumberScheme();
+            nextStartAt = nextp.getBulletAutoNumberStart();
+            
+            if(nextScheme == scheme && nextStartAt == startAt) {
+                // bullet is valid, so increment i 
+                ++index;
+                if (out.length() > 0) out.append('\n');
+                // indent for the level
+                for(int j = 0; j < level; j++){
+                    out.append('\t');
+                }
+                // check for empty text - only output a bullet if there is text, but it is still part of the group
+                if(nextp.getText().length() > 0) {
+                    // increment the count for this level
+                    levelCount.set(level, levelCount.get(level) + 1);
+                    out.append(getBulletPrefix(nextScheme, levelCount.get(level)));
+                    out.append(nextp.getText());
+                }
+            } else {
+                // something doesn't match so stop
+                break; 
+            }
+        }
+        // end of the group so reset the count for this level 
+        levelCount.set(level, 0);      
+        
+        return index; 
+    }
+    /**
+     * Returns a string containing an appropriate prefix for an auto-numbering bullet
+     * @param scheme the auto-numbering scheme used by the bullet
+     * @param value the value of the bullet
+     * @return
+     */
+    private String getBulletPrefix(ListAutoNumber scheme, int value){
+        StringBuilder out = new StringBuilder();
+        
+        switch(scheme) {
+        case ALPHA_LC_PARENT_BOTH:
+        case ALPHA_LC_PARENT_R:
+            if(scheme == ListAutoNumber.ALPHA_LC_PARENT_BOTH) out.append('(');
+            out.append(valueToAlpha(value).toLowerCase());
+            out.append(')');
+            break;
+        case ALPHA_UC_PARENT_BOTH:
+        case ALPHA_UC_PARENT_R:
+            if(scheme == ListAutoNumber.ALPHA_UC_PARENT_BOTH) out.append('(');
+            out.append(valueToAlpha(value));
+            out.append(')');
+            break;        
+        case ALPHA_LC_PERIOD:
+            out.append(valueToAlpha(value).toLowerCase());
+            out.append('.');
+            break;
+        case ALPHA_UC_PERIOD:
+            out.append(valueToAlpha(value));
+            out.append('.');
+            break;
+        case ARABIC_PARENT_BOTH:
+        case ARABIC_PARENT_R:
+            if(scheme == ListAutoNumber.ARABIC_PARENT_BOTH) out.append('(');
+            out.append(value);
+            out.append(')');
+            break;
+        case ARABIC_PERIOD:
+            out.append(value);
+            out.append('.');
+            break;
+        case ARABIC_PLAIN:
+            out.append(value);
+            break;            
+        case ROMAN_LC_PARENT_BOTH:
+        case ROMAN_LC_PARENT_R:
+            if(scheme == ListAutoNumber.ROMAN_LC_PARENT_BOTH) out.append('(');
+            out.append(valueToRoman(value).toLowerCase());
+            out.append(')');
+            break;
+        case ROMAN_UC_PARENT_BOTH:
+        case ROMAN_UC_PARENT_R:
+            if(scheme == ListAutoNumber.ROMAN_UC_PARENT_BOTH) out.append('(');
+            out.append(valueToRoman(value));
+            out.append(')');
+            break;        
+        case ROMAN_LC_PERIOD:
+            out.append(valueToRoman(value).toLowerCase());
+            out.append('.');
+            break;
+        case ROMAN_UC_PERIOD:
+            out.append(valueToRoman(value));
+            out.append('.');
+            break;
+        default:
+            out.append('\u2022');   // can't set the font to wingdings so use the default bullet character
+            break;            
+        }
+        out.append(" ");        
+        return out.toString();
+    }
+    
+    /**
+     * Convert an integer to its alpha equivalent e.g. 1 = A, 2 = B, 27 = AA etc
+     */
+    private String valueToAlpha(int value) {
+        String alpha = "";
+        int modulo;
+        while (value > 0) {
+            modulo = (value - 1) % 26;
+            alpha = (char)(65 + modulo) + alpha;
+            value = (int)((value - modulo) / 26);
+        }
+        return alpha;
     }
+    
+    private static String[] _romanChars = new String[] { "M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I" };
+    private static int[] _romanAlphaValues = new int[] { 1000,900,500,400,100,90,50,40,10,9,5,4,1 };
+        
+    /**
+     * Convert an integer to its roman equivalent e.g. 1 = I, 9 = IX etc
+     */
+    private String valueToRoman(int value) {
+        StringBuilder out = new StringBuilder();
+        for(int i = 0; value > 0 && i < _romanChars.length; i++) {
+            while(_romanAlphaValues[i] <= value) {
+                out.append(_romanChars[i]);
+                value -= _romanAlphaValues[i];
+            }
+        }
+        return out.toString();
+    }
+    
+    /**
+     * Clear all text from this shape
+     */
+    public void clearText(){
+        _paragraphs.clear();
+        CTTextBody txBody = ctShape.getTxBody();
+        txBody.setPArray(null); // remove any existing paragraphs
+    }
+    
+    /**
+     * Set a single paragraph of text on the shape. Note this will replace all existing paragraphs created on the shape.
+     * @param text	string representing the paragraph text
+     */
+    public void setText(String text){
+        clearText();
 
-    protected CTShapeProperties getShapeProperties(){
-        return ctShape.getSpPr();
+        addNewTextParagraph().addNewTextRun().setText(text);
     }
 
+    /**
+     * Set a single paragraph of text on the shape. Note this will replace all existing paragraphs created on the shape.
+     * @param str	rich text string representing the paragraph text
+     */
     public void setText(XSSFRichTextString str){
 
         XSSFWorkbook wb = (XSSFWorkbook)getDrawing().getParent().getParent();
@@ -166,12 +393,426 @@ public class XSSFSimpleShape extends XSS
                 r.setT(lt.getT());
             }
         }
+        
+        clearText();                
         ctShape.getTxBody().setPArray(new CTTextParagraph[]{p});
+        _paragraphs.add(new XSSFTextParagraph(ctShape.getTxBody().getPArray(0), ctShape));
+    }    
+    
+    /**
+     * Returns a collection of the XSSFTextParagraphs that are attached to this shape
+     * 
+     * @return text paragraphs in this shape
+     */
+    public List<XSSFTextParagraph> getTextParagraphs() {
+        return _paragraphs;
+    }
+
+    /**
+     * Add a new paragraph run to this shape
+     *
+     * @return created paragraph run
+     */
+    public XSSFTextParagraph addNewTextParagraph() {
+        CTTextBody txBody = ctShape.getTxBody();
+        CTTextParagraph p = txBody.addNewP();
+        XSSFTextParagraph paragraph = new XSSFTextParagraph(p, ctShape);
+        _paragraphs.add(paragraph);
+        return paragraph;
+    }    
 
+    /**
+     * Add a new paragraph run to this shape, set to the provided string
+     *
+     * @return created paragraph run
+     */
+    public XSSFTextParagraph addNewTextParagraph(String text) {
+        XSSFTextParagraph paragraph = addNewTextParagraph();
+        paragraph.addNewTextRun().setText(text);
+        return paragraph;
+    }   
+    
+    /**
+     * Add a new paragraph run to this shape, set to the provided rich text string 
+     *
+     * @return created paragraph run
+     */
+    public XSSFTextParagraph addNewTextParagraph(XSSFRichTextString str) {
+        CTTextBody txBody = ctShape.getTxBody();
+        CTTextParagraph p = txBody.addNewP();
+       
+        if(str.numFormattingRuns() == 0){
+            CTRegularTextRun r = p.addNewR();
+            CTTextCharacterProperties rPr = r.addNewRPr();
+            rPr.setLang("en-US");
+            rPr.setSz(1100);
+            r.setT(str.getString());
+
+        } else {
+            for (int i = 0; i < str.getCTRst().sizeOfRArray(); i++) {
+                CTRElt lt = str.getCTRst().getRArray(i);
+                CTRPrElt ltPr = lt.getRPr();
+                if(ltPr == null) ltPr = lt.addNewRPr();
+
+                CTRegularTextRun r = p.addNewR();
+                CTTextCharacterProperties rPr = r.addNewRPr();
+                rPr.setLang("en-US");
+
+                applyAttributes(ltPr, rPr);
+
+                r.setT(lt.getT());
+            }
+        }
+        
+        // Note: the XSSFTextParagraph constructor will create its required XSSFTextRuns from the provided CTTextParagraph
+        XSSFTextParagraph paragraph = new XSSFTextParagraph(p, ctShape);
+        _paragraphs.add(paragraph);
+        
+        return paragraph;
+    }
+
+    /**
+     * Sets the type of horizontal overflow for the text.
+     *
+     * @param overflow - the type of horizontal overflow.
+     * A <code>null</code> values unsets this property.
+     */
+    public void setTextHorizontalOverflow(TextHorizontalOverflow overflow){
+        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+        if (bodyPr != null) {
+             if(anchor == null) {
+                if(bodyPr.isSetHorzOverflow()) bodyPr.unsetHorzOverflow();
+            } else {
+                bodyPr.setHorzOverflow(STTextHorzOverflowType.Enum.forInt(overflow.ordinal() + 1));
+            }
+        }
     }
 
     /**
+     * Returns the type of horizontal overflow for the text.
+     *
+     * @return the type of horizontal overflow
+     */
+    public TextHorizontalOverflow getTextHorizontalOverflow(){
+    	CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+    	if(bodyPr != null) {
+    		if(bodyPr.isSetHorzOverflow()){
+    			return TextHorizontalOverflow.values()[bodyPr.getVertOverflow().intValue() - 1];
+    		}    			
+    	}
+    	return TextHorizontalOverflow.OVERFLOW;
+    }    
+    
+    /**
+     * Sets the type of vertical overflow for the text.
+     *
+     * @param overflow - the type of vertical overflow.
+     * A <code>null</code> values unsets this property.
+     */
+    public void setTextVerticalOverflow(TextVerticalOverflow overflow){
+        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+        if (bodyPr != null) {
+             if(anchor == null) {
+                if(bodyPr.isSetVertOverflow()) bodyPr.unsetVertOverflow();
+            } else {
+                bodyPr.setVertOverflow(STTextVertOverflowType.Enum.forInt(overflow.ordinal() + 1));
+            }
+        }
+    }
+
+    /**
+     * Returns the type of vertical overflow for the text.
+     *
+     * @return the type of vertical overflow
+     */
+    public TextVerticalOverflow getTextVerticalOverflow(){
+    	CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+    	if(bodyPr != null) {
+    		if(bodyPr.isSetVertOverflow()){
+    			return TextVerticalOverflow.values()[bodyPr.getVertOverflow().intValue() - 1];
+    		}    			
+    	}
+    	return TextVerticalOverflow.OVERFLOW;
+    }   
+    
+    /**
+     * Sets the type of vertical alignment for the text within the shape.
      *
+     * @param anchor - the type of alignment.
+     * A <code>null</code> values unsets this property.
+     */
+    public void setVerticalAlignment(VerticalAlignment anchor){
+        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+        if (bodyPr != null) {
+             if(anchor == null) {
+                if(bodyPr.isSetAnchor()) bodyPr.unsetAnchor();
+            } else {
+                bodyPr.setAnchor(STTextAnchoringType.Enum.forInt(anchor.ordinal() + 1));
+            }
+        }
+    }
+
+    /**
+     * Returns the type of vertical alignment for the text within the shape.
+     *
+     * @return the type of vertical alignment
+     */
+    public VerticalAlignment getVerticalAlignment(){
+    	CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+    	if(bodyPr != null) {
+    		if(bodyPr.isSetAnchor()){
+    			return VerticalAlignment.values()[bodyPr.getAnchor().intValue() - 1];
+    		}    			
+    	}
+    	return VerticalAlignment.TOP;
+    }
+
+    /**
+     * Sets the vertical orientation of the text
+     * 
+     * @param orientation vertical orientation of the text
+     * A <code>null</code> values unsets this property.
+     */
+    public void setTextDirection(TextDirection orientation){
+        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+        if (bodyPr != null) {
+            if(orientation == null) {
+                if(bodyPr.isSetVert()) bodyPr.unsetVert();
+            } else {
+                bodyPr.setVert(STTextVerticalType.Enum.forInt(orientation.ordinal() + 1));
+            }
+        }
+    }
+
+    /**
+     * Gets the vertical orientation of the text
+     * 
+     * @return vertical orientation of the text
+     */
+    public TextDirection getTextDirection(){
+        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+        if (bodyPr != null) {
+            STTextVerticalType.Enum val = bodyPr.getVert();
+            if(val != null){
+                return TextDirection.values()[val.intValue() - 1];
+            }
+        }
+        return TextDirection.HORIZONTAL;
+    }
+
+
+    /**
+     * Returns the distance (in points) between the bottom of the text frame
+     * and the bottom of the inscribed rectangle of the shape that contains the text.
+     *
+     * @return the bottom inset in points
+     */
+    public double getBottomInset(){
+        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+        if (bodyPr != null) {
+        	if(bodyPr.isSetBIns()){
+        		return Units.toPoints(bodyPr.getBIns());
+        	}
+        }
+        // If this attribute is omitted, then a value of 0.05 inches is implied
+        return 3.6;	
+    }
+
+    /**
+     *  Returns the distance (in points) between the left edge of the text frame
+     *  and the left edge of the inscribed rectangle of the shape that contains
+     *  the text.
+     *
+     * @return the left inset in points
+     */
+    public double getLeftInset(){
+        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+        if (bodyPr != null) {
+        	if(bodyPr.isSetLIns()){
+        		return Units.toPoints(bodyPr.getLIns());
+        	}
+        }
+        // If this attribute is omitted, then a value of 0.05 inches is implied
+        return 3.6;
+    }
+
+    /**
+     *  Returns the distance (in points) between the right edge of the
+     *  text frame and the right edge of the inscribed rectangle of the shape
+     *  that contains the text.
+     *
+     * @return the right inset in points
+     */
+    public double getRightInset(){
+        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+        if (bodyPr != null) {
+        	if(bodyPr.isSetRIns()){
+        		return Units.toPoints(bodyPr.getRIns());
+        	}
+        }
+        // If this attribute is omitted, then a value of 0.05 inches is implied
+        return 3.6;
+    }
+
+    /**
+     *  Returns the distance (in points) between the top of the text frame
+     *  and the top of the inscribed rectangle of the shape that contains the text.
+     *
+     * @return the top inset in points
+     */
+    public double getTopInset(){
+        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+        if (bodyPr != null) {
+        	if(bodyPr.isSetTIns()){
+        		return Units.toPoints(bodyPr.getTIns());
+        	}
+        }
+        // If this attribute is omitted, then a value of 0.05 inches is implied
+        return 3.6;    	
+    }
+
+    /**
+     * Sets the bottom inset.
+     * @see #getBottomInset()
+     *
+     * @param margin    the bottom margin
+     */
+    public void setBottomInset(double margin){
+        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+        if (bodyPr != null) {
+            if(margin == -1) bodyPr.unsetBIns();
+            else bodyPr.setBIns(Units.toEMU(margin));
+        }
+    }
+
+    /**
+     * Sets the left inset.
+     * @see #getLeftInset()
+     *
+     * @param margin    the left margin
+     */
+    public void setLeftInset(double margin){
+        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+        if (bodyPr != null) {
+            if(margin == -1) bodyPr.unsetLIns();
+            else bodyPr.setLIns(Units.toEMU(margin));
+        }
+    }
+
+    /**
+     * Sets the right inset.
+     * @see #getRightInset()
+     *
+     * @param margin    the right margin
+     */
+    public void setRightInset(double margin){
+        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+        if (bodyPr != null) {
+            if(margin == -1) bodyPr.unsetRIns();
+            else bodyPr.setRIns(Units.toEMU(margin));
+        }
+    }
+
+    /**
+     * Sets the top inset.
+     * @see #getTopInset()
+     *
+     * @param margin    the top margin
+     */
+    public void setTopInset(double margin){
+        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+        if (bodyPr != null) {
+            if(margin == -1) bodyPr.unsetTIns();
+            else bodyPr.setTIns(Units.toEMU(margin));
+        }
+    }
+
+
+    /**
+     * @return whether to wrap words within the bounding rectangle
+     */
+    public boolean getWordWrap(){
+    	CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+        if (bodyPr != null) {
+        	if(bodyPr.isSetWrap()){
+        		return bodyPr.getWrap() == STTextWrappingType.SQUARE;
+        	}
+        }
+        return true;
+    }
+
+    /**
+     *
+     * @param wrap  whether to wrap words within the bounding rectangle
+     */
+    public void setWordWrap(boolean wrap){
+        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+        if (bodyPr != null) {
+            bodyPr.setWrap(wrap ? STTextWrappingType.SQUARE : STTextWrappingType.NONE);
+        }
+    }
+
+    /**
+     *
+     * Specifies that a shape should be auto-fit to fully contain the text described within it.
+     * Auto-fitting is when text within a shape is scaled in order to contain all the text inside
+     *
+     * @param value type of autofit
+     */
+    public void setTextAutofit(TextAutofit value){
+        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+        if (bodyPr != null) {
+            if(bodyPr.isSetSpAutoFit()) bodyPr.unsetSpAutoFit();
+            if(bodyPr.isSetNoAutofit()) bodyPr.unsetNoAutofit();
+            if(bodyPr.isSetNormAutofit()) bodyPr.unsetNormAutofit();
+
+            switch(value){
+                case NONE: bodyPr.addNewNoAutofit(); break;
+                case NORMAL: bodyPr.addNewNormAutofit(); break;
+                case SHAPE: bodyPr.addNewSpAutoFit(); break;
+            }
+        }
+    }
+
+    /**
+     *
+     * @return type of autofit
+     */
+    public TextAutofit getTextAutofit(){
+        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+        if (bodyPr != null) {
+            if(bodyPr.isSetNoAutofit()) return TextAutofit.NONE;
+            else if (bodyPr.isSetNormAutofit()) return TextAutofit.NORMAL;
+            else if (bodyPr.isSetSpAutoFit()) return TextAutofit.SHAPE;
+        }
+        return TextAutofit.NORMAL;
+    }
+    
+    /**
+     * Gets the shape type, one of the constants defined in {@link org.apache.poi.ss.usermodel.ShapeTypes}.
+     *
+     * @return the shape type
+     * @see org.apache.poi.ss.usermodel.ShapeTypes
+     */
+    public int getShapeType() {
+        return ctShape.getSpPr().getPrstGeom().getPrst().intValue();
+    }
+
+    /**
+     * Sets the shape types.
+     *
+     * @param type the shape type, one of the constants defined in {@link org.apache.poi.ss.usermodel.ShapeTypes}.
+     * @see org.apache.poi.ss.usermodel.ShapeTypes
+     */
+    public void setShapeType(int type) {
+        ctShape.getSpPr().getPrstGeom().setPrst(STShapeType.Enum.forInt(type));
+    }
+
+    protected CTShapeProperties getShapeProperties(){
+        return ctShape.getSpPr();
+    }
+
+    /**
      * org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRPrElt to
      * org.openxmlformats.schemas.drawingml.x2006.main.CTFont adapter
      */
@@ -186,8 +827,8 @@ public class XSSFSimpleShape extends XSS
         }
         if(pr.sizeOfIArray() > 0) rPr.setI(pr.getIArray(0).getVal());
 
-        if(pr.sizeOfFamilyArray() > 0) {
-            CTTextFont rFont = rPr.addNewLatin();
+        if(pr.sizeOfRFontArray() > 0) {
+            CTTextFont rFont = rPr.isSetLatin() ? rPr.getLatin() : rPr.addNewLatin();
             rFont.setTypeface(pr.getRFontArray(0).getVal());
         }
 

Modified: poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java?rev=1508691&r1=1508690&r2=1508691&view=diff
==============================================================================
--- poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java (original)
+++ poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java Wed Jul 31 00:19:07 2013
@@ -17,6 +17,10 @@
 package org.apache.poi.xssf.usermodel;
 
 import java.awt.*;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
 import java.util.Arrays;
 import java.util.List;
 
@@ -243,4 +247,426 @@ public class TestXSSFDrawing extends Tes
 
 
     }
+    
+    /**
+     * ensure that font and color rich text attributes defined in a XSSFRichTextString
+     * are passed to XSSFSimpleShape.
+     *
+     * See Bugzilla 54969.
+     */
+    public void testRichTextFontAndColor() {
+    	XSSFWorkbook wb = new XSSFWorkbook();
+        XSSFSheet sheet = wb.createSheet();
+        XSSFDrawing drawing = sheet.createDrawingPatriarch();
+
+        XSSFTextBox shape = drawing.createTextbox(new XSSFClientAnchor(0, 0, 0, 0, 2, 2, 3, 4));
+        XSSFRichTextString rt = new XSSFRichTextString("Test String");
+
+        XSSFFont font = wb.createFont();
+        font.setColor(new XSSFColor(new Color(0, 128, 128)));
+        font.setFontName("Arial");
+        rt.applyFont(font);
+
+        shape.setText(rt);
+
+        CTTextParagraph pr = shape.getCTShape().getTxBody().getPArray(0);
+        assertEquals(1, pr.sizeOfRArray());
+
+        CTTextCharacterProperties rPr = pr.getRArray(0).getRPr();
+        assertEquals("Arial", rPr.getLatin().getTypeface());
+        assertTrue(Arrays.equals(
+                new byte[]{0, (byte)128, (byte)128} ,
+                rPr.getSolidFill().getSrgbClr().getVal()));
+    	
+    }
+
+    /**
+     * Test setText single paragraph to ensure backwards compatibility
+     */
+    public void testSetTextSingleParagraph() {
+    
+    	XSSFWorkbook wb = new XSSFWorkbook();
+        XSSFSheet sheet = wb.createSheet();
+        XSSFDrawing drawing = sheet.createDrawingPatriarch();
+
+        XSSFTextBox shape = drawing.createTextbox(new XSSFClientAnchor(0, 0, 0, 0, 2, 2, 3, 4));
+        XSSFRichTextString rt = new XSSFRichTextString("Test String");
+
+        XSSFFont font = wb.createFont();
+        font.setColor(new XSSFColor(new Color(0, 255, 255)));
+        font.setFontName("Arial");
+        rt.applyFont(font);
+
+        shape.setText(rt);
+        
+        List<XSSFTextParagraph> paras = shape.getTextParagraphs();
+        assertEquals(1, paras.size());
+        assertEquals("Test String", paras.get(0).getText());
+        
+        List<XSSFTextRun> runs = paras.get(0).getTextRuns();
+        assertEquals(1, runs.size());
+        assertEquals("Arial", runs.get(0).getFontFamily());
+        
+        Color clr = runs.get(0).getFontColor(); 
+        assertTrue(Arrays.equals(
+                new int[] { 0, 255, 255 } ,
+                new int[] { clr.getRed(), clr.getGreen(), clr.getBlue() }));
+    }
+    
+    /**
+     * Test addNewTextParagraph 
+     */
+    public void testAddNewTextParagraph() {
+    
+    	XSSFWorkbook wb = new XSSFWorkbook();
+        XSSFSheet sheet = wb.createSheet();
+        XSSFDrawing drawing = sheet.createDrawingPatriarch();
+
+        XSSFTextBox shape = drawing.createTextbox(new XSSFClientAnchor(0, 0, 0, 0, 2, 2, 3, 4));
+        
+        XSSFTextParagraph para = shape.addNewTextParagraph();
+        para.addNewTextRun().setText("Line 1");
+                
+        List<XSSFTextParagraph> paras = shape.getTextParagraphs();
+        assertEquals(2, paras.size());	// this should be 2 as XSSFSimpleShape creates a default paragraph (no text), and then we add a string to that.
+        
+        List<XSSFTextRun> runs = para.getTextRuns();
+        assertEquals(1, runs.size());
+        assertEquals("Line 1", runs.get(0).getText());
+    }
+
+    /**
+     * Test addNewTextParagraph using RichTextString
+     */
+    public void testAddNewTextParagraphWithRTS() {
+    
+    	XSSFWorkbook wb = new XSSFWorkbook();
+        XSSFSheet sheet = wb.createSheet();
+        XSSFDrawing drawing = sheet.createDrawingPatriarch();
+
+        XSSFTextBox shape = drawing.createTextbox(new XSSFClientAnchor(0, 0, 0, 0, 2, 2, 3, 4));
+        XSSFRichTextString rt = new XSSFRichTextString("Test Rich Text String");
+
+        XSSFFont font = wb.createFont();        
+        font.setColor(new XSSFColor(new Color(0, 255, 255)));
+        font.setFontName("Arial");
+        rt.applyFont(font);
+        
+        XSSFFont midfont = wb.createFont();
+        midfont.setColor(new XSSFColor(new Color(0, 255, 0)));
+        rt.applyFont(5, 14, midfont);	// set the text "Rich Text" to be green and the default font
+        
+        XSSFTextParagraph para = shape.addNewTextParagraph(rt);
+        
+        // Save and re-load it
+        wb = XSSFTestDataSamples.writeOutAndReadBack(wb);
+        sheet = wb.getSheetAt(0);
+
+        // Check
+        drawing = sheet.createDrawingPatriarch();
+        
+        List<XSSFShape> shapes = drawing.getShapes();
+        assertEquals(1, shapes.size());
+        assertTrue(shapes.get(0) instanceof XSSFSimpleShape); 
+        
+        XSSFSimpleShape sshape = (XSSFSimpleShape) shapes.get(0);
+        
+        List<XSSFTextParagraph> paras = sshape.getTextParagraphs();
+        assertEquals(2, paras.size());	// this should be 2 as XSSFSimpleShape creates a default paragraph (no text), and then we add a string to that.  
+        
+        List<XSSFTextRun> runs = para.getTextRuns();
+        assertEquals(3, runs.size());
+        
+        // first run properties
+        assertEquals("Test ", runs.get(0).getText());
+        assertEquals("Arial", runs.get(0).getFontFamily());
+
+        Color clr = runs.get(0).getFontColor(); 
+        assertTrue(Arrays.equals(
+                new int[] { 0, 255, 255 } ,
+                new int[] { clr.getRed(), clr.getGreen(), clr.getBlue() }));
+
+        // second run properties        
+        assertEquals("Rich Text", runs.get(1).getText());
+        assertEquals(XSSFFont.DEFAULT_FONT_NAME, runs.get(1).getFontFamily());
+
+        clr = runs.get(1).getFontColor(); 
+        assertTrue(Arrays.equals(
+                new int[] { 0, 255, 0 } ,
+                new int[] { clr.getRed(), clr.getGreen(), clr.getBlue() }));        
+        
+        // third run properties
+        assertEquals(" String", runs.get(2).getText());
+        assertEquals("Arial", runs.get(2).getFontFamily());
+        clr = runs.get(2).getFontColor(); 
+        assertTrue(Arrays.equals(
+                new int[] { 0, 255, 255 } ,
+                new int[] { clr.getRed(), clr.getGreen(), clr.getBlue() }));
+    }    
+    
+    /**
+     * Test add multiple paragraphs and retrieve text
+     */
+    public void testAddMultipleParagraphs() {
+    
+    	XSSFWorkbook wb = new XSSFWorkbook();
+        XSSFSheet sheet = wb.createSheet();
+        XSSFDrawing drawing = sheet.createDrawingPatriarch();
+
+        XSSFTextBox shape = drawing.createTextbox(new XSSFClientAnchor(0, 0, 0, 0, 2, 2, 3, 4));
+        
+        XSSFTextParagraph para = shape.addNewTextParagraph();
+        para.addNewTextRun().setText("Line 1");
+                
+        para = shape.addNewTextParagraph();
+        para.addNewTextRun().setText("Line 2");
+        
+        para = shape.addNewTextParagraph();
+        para.addNewTextRun().setText("Line 3");
+        
+        List<XSSFTextParagraph> paras = shape.getTextParagraphs();
+        assertEquals(4, paras.size());	// this should be 4 as XSSFSimpleShape creates a default paragraph (no text), and then we added 3 paragraphs
+        assertEquals("Line 1\nLine 2\nLine 3", shape.getText());           
+    }
+    
+    /**
+     * Test setting the text, then adding multiple paragraphs and retrieve text
+     */
+    public void testSetAddMultipleParagraphs() {
+    
+    	XSSFWorkbook wb = new XSSFWorkbook();
+        XSSFSheet sheet = wb.createSheet();
+        XSSFDrawing drawing = sheet.createDrawingPatriarch();
+
+        XSSFTextBox shape = drawing.createTextbox(new XSSFClientAnchor(0, 0, 0, 0, 2, 2, 3, 4));
+        
+        shape.setText("Line 1");
+                
+        XSSFTextParagraph para = shape.addNewTextParagraph();
+        para.addNewTextRun().setText("Line 2");
+        
+        para = shape.addNewTextParagraph();
+        para.addNewTextRun().setText("Line 3");
+        
+        List<XSSFTextParagraph> paras = shape.getTextParagraphs();
+        assertEquals(3, paras.size());	// this should be 3 as we overwrote the default paragraph with setText, then added 2 new paragraphs
+        assertEquals("Line 1\nLine 2\nLine 3", shape.getText());
+    }
+    
+    /**
+     * Test reading text from a textbox in an existing file
+     */
+    public void testReadTextBox(){
+        XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("WithDrawing.xlsx");
+        XSSFSheet sheet = wb.getSheetAt(0);
+        //the sheet has one relationship and it is XSSFDrawing
+        List<POIXMLDocumentPart> rels = sheet.getRelations();
+        assertEquals(1, rels.size());
+        assertTrue(rels.get(0) instanceof XSSFDrawing);
+
+        XSSFDrawing drawing = (XSSFDrawing)rels.get(0);
+        //sheet.createDrawingPatriarch() should return the same instance of XSSFDrawing
+        assertSame(drawing, sheet.createDrawingPatriarch());
+        String drawingId = drawing.getPackageRelationship().getId();
+
+        //there should be a relation to this drawing in the worksheet
+        assertTrue(sheet.getCTWorksheet().isSetDrawing());
+        assertEquals(drawingId, sheet.getCTWorksheet().getDrawing().getId());
+
+        List<XSSFShape> shapes = drawing.getShapes();
+        assertEquals(6, shapes.size());
+
+        assertTrue(shapes.get(4) instanceof XSSFSimpleShape);
+
+        XSSFSimpleShape textbox = (XSSFSimpleShape) shapes.get(4); 
+        assertEquals("Sheet with various pictures\n(jpeg, png, wmf, emf and pict)", textbox.getText());
+    }
+
+    
+    /**
+     * Test reading multiple paragraphs from a textbox in an existing file
+     */
+    public void testReadTextBoxParagraphs(){
+        XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("WithTextBox.xlsx");
+        XSSFSheet sheet = wb.getSheetAt(0);
+        //the sheet has one relationship and it is XSSFDrawing
+        List<POIXMLDocumentPart> rels = sheet.getRelations();
+        assertEquals(1, rels.size());
+       
+        assertTrue(rels.get(0) instanceof XSSFDrawing);
+
+        XSSFDrawing drawing = (XSSFDrawing)rels.get(0);
+        
+        //sheet.createDrawingPatriarch() should return the same instance of XSSFDrawing
+        assertSame(drawing, sheet.createDrawingPatriarch());
+        String drawingId = drawing.getPackageRelationship().getId();
+
+        //there should be a relation to this drawing in the worksheet
+        assertTrue(sheet.getCTWorksheet().isSetDrawing());
+        assertEquals(drawingId, sheet.getCTWorksheet().getDrawing().getId());
+
+        List<XSSFShape> shapes = drawing.getShapes();
+        assertEquals(1, shapes.size());
+
+        assertTrue(shapes.get(0) instanceof XSSFSimpleShape);
+
+        XSSFSimpleShape textbox = (XSSFSimpleShape) shapes.get(0);
+        
+        List<XSSFTextParagraph> paras = textbox.getTextParagraphs();
+        assertEquals(3, paras.size());
+        
+        assertEquals("Line 2", paras.get(1).getText());	// check content of second paragraph
+
+        assertEquals("Line 1\nLine 2\nLine 3", textbox.getText());	// check content of entire textbox
+        
+        // check attributes of paragraphs
+        assertEquals(TextAlign.LEFT, paras.get(0).getTextAlign());
+        assertEquals(TextAlign.CENTER, paras.get(1).getTextAlign());
+        assertEquals(TextAlign.RIGHT, paras.get(2).getTextAlign());
+        
+        Color clr = paras.get(0).getTextRuns().get(0).getFontColor(); 
+        assertTrue(Arrays.equals(
+                new int[] { 255, 0, 0 } ,
+                new int[] { clr.getRed(), clr.getGreen(), clr.getBlue() }));
+        
+        clr = paras.get(1).getTextRuns().get(0).getFontColor(); 
+        assertTrue(Arrays.equals(
+                new int[] { 0, 255, 0 } ,
+                new int[] { clr.getRed(), clr.getGreen(), clr.getBlue() }));
+        
+        clr = paras.get(2).getTextRuns().get(0).getFontColor(); 
+        assertTrue(Arrays.equals(
+                new int[] { 0, 0, 255 } ,
+                new int[] { clr.getRed(), clr.getGreen(), clr.getBlue() }));
+    }
+    /**
+     * Test adding and reading back paragraphs as bullet points
+     */
+    public void testAddBulletParagraphs() {
+    
+        XSSFWorkbook wb = new XSSFWorkbook();
+        XSSFSheet sheet = wb.createSheet();
+        XSSFDrawing drawing = sheet.createDrawingPatriarch();
+
+        XSSFTextBox shape = drawing.createTextbox(new XSSFClientAnchor(0, 0, 0, 0, 2, 2, 10, 20));
+        
+        String paraString1 = "A normal paragraph";
+        String paraString2 = "First bullet";
+        String paraString3 = "Second bullet (level 1)";
+        String paraString4 = "Third bullet";
+        String paraString5 = "Another normal paragraph";
+        String paraString6 = "First numbered bullet";
+        String paraString7 = "Second bullet (level 1)";
+        String paraString8 = "Third bullet (level 1)";
+        String paraString9 = "Fourth bullet (level 1)";
+        String paraString10 = "Fifth Bullet";
+        
+        XSSFTextParagraph para = shape.addNewTextParagraph(paraString1);
+        para = shape.addNewTextParagraph(paraString2);
+        para.setBullet(true);
+
+        para = shape.addNewTextParagraph(paraString3);
+        para.setBullet(true);
+        para.setLevel(1);
+
+        para = shape.addNewTextParagraph(paraString4);
+        para.setBullet(true);
+        
+        para = shape.addNewTextParagraph(paraString5);
+        para = shape.addNewTextParagraph(paraString6);
+        para.setBullet(ListAutoNumber.ARABIC_PERIOD);
+
+        para = shape.addNewTextParagraph(paraString7);
+        para.setBullet(ListAutoNumber.ARABIC_PERIOD, 3);
+        para.setLevel(1);
+        
+        para = shape.addNewTextParagraph(paraString8);
+        para.setBullet(ListAutoNumber.ARABIC_PERIOD, 3);
+        para.setLevel(1);
+
+        para = shape.addNewTextParagraph("");
+        para.setBullet(ListAutoNumber.ARABIC_PERIOD, 3);
+        para.setLevel(1);
+        
+        para = shape.addNewTextParagraph(paraString9);
+        para.setBullet(ListAutoNumber.ARABIC_PERIOD, 3);
+        para.setLevel(1);
+        
+        para = shape.addNewTextParagraph(paraString10);
+        para.setBullet(ListAutoNumber.ARABIC_PERIOD);
+        
+        // Save and re-load it
+        wb = XSSFTestDataSamples.writeOutAndReadBack(wb);
+        sheet = wb.getSheetAt(0);
+
+        // Check
+        drawing = sheet.createDrawingPatriarch();
+        
+        List<XSSFShape> shapes = drawing.getShapes();
+        assertEquals(1, shapes.size());
+        assertTrue(shapes.get(0) instanceof XSSFSimpleShape); 
+        
+        XSSFSimpleShape sshape = (XSSFSimpleShape) shapes.get(0);
+        
+        List<XSSFTextParagraph> paras = sshape.getTextParagraphs();
+        assertEquals(12, paras.size());  // this should be 12 as XSSFSimpleShape creates a default paragraph (no text), and then we added to that
+        
+        StringBuilder builder = new StringBuilder();
+        
+        builder.append(paraString1);
+        builder.append("\n");
+        builder.append("\u2022 ");
+        builder.append(paraString2);
+        builder.append("\n");
+        builder.append("\t\u2022 ");
+        builder.append(paraString3);
+        builder.append("\n");
+        builder.append("\u2022 ");
+        builder.append(paraString4);
+        builder.append("\n");
+        builder.append(paraString5);
+        builder.append("\n");
+        builder.append("1. ");
+        builder.append(paraString6);
+        builder.append("\n");
+        builder.append("\t3. ");
+        builder.append(paraString7);
+        builder.append("\n");
+        builder.append("\t4. ");
+        builder.append(paraString8);
+        builder.append("\n");
+        builder.append("\t");   // should be empty
+        builder.append("\n");
+        builder.append("\t5. ");
+        builder.append(paraString9);
+        builder.append("\n");
+        builder.append("2. ");
+        builder.append(paraString10);
+        
+        assertEquals(builder.toString(), sshape.getText());
+    }  
+    
+    /**
+     * Test reading bullet numbering from a textbox in an existing file
+     */
+    public void testReadTextBox2(){
+        XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("WithTextBox2.xlsx");
+        XSSFSheet sheet = wb.getSheetAt(0);
+        XSSFDrawing drawing = sheet.createDrawingPatriarch();
+        List<XSSFShape> shapes = drawing.getShapes();
+        XSSFSimpleShape textbox = (XSSFSimpleShape) shapes.get(0);
+        String extracted = textbox.getText();
+        StringBuilder sb = new StringBuilder();
+        sb.append("1. content1A\n");
+        sb.append("\t1. content1B\n");
+        sb.append("\t2. content2B\n");
+        sb.append("\t3. content3B\n");
+        sb.append("2. content2A\n");
+        sb.append("\t3. content2BStartAt3\n");
+        sb.append("\t\n\t\n\t");
+        sb.append("4. content2BStartAt3Incremented\n");
+        sb.append("\t\n\t\n\t\n\t");
+
+        assertEquals(sb.toString(), extracted);
+    }
 }

Modified: poi/trunk/test-data/spreadsheet/WithTextBox.xlsx
URL: http://svn.apache.org/viewvc/poi/trunk/test-data/spreadsheet/WithTextBox.xlsx?rev=1508691&r1=1508690&r2=1508691&view=diff
==============================================================================
Binary files - no diff available.

Added: poi/trunk/test-data/spreadsheet/WithTextBox2.xlsx
URL: http://svn.apache.org/viewvc/poi/trunk/test-data/spreadsheet/WithTextBox2.xlsx?rev=1508691&view=auto
==============================================================================
Binary file - no diff available.

Propchange: poi/trunk/test-data/spreadsheet/WithTextBox2.xlsx
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream



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


RE: svn commit: r1508691 - in /poi/trunk: src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java test-data/spreadsheet/WithTextBox.xlsx test-data/spreadsheet/WithTextBox2...

Posted by "Allison, Timothy B." <ta...@mitre.org>.
 Committed: r1508939.  Thank you.

-----Original Message-----
From: Nick Burch [mailto:apache@gagravarr.org] 
Sent: Wednesday, July 31, 2013 11:36 AM
To: POI Developers List
Subject: RE: svn commit: r1508691 - in /poi/trunk: src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java test-data/spreadsheet/WithTextBox.xlsx test-data/spreadsheet/WithTextBox2...

On Wed, 31 Jul 2013, Allison, Timothy B. wrote:
> Sorry about that and for the ignorance exhibited by this:
>
> commit isn't working on status.xml (status -u shows the update; diff 
> doesn't)... do I "svn cp" my updated copy to 
> https://svn.apache.org/repos/asf/poi/site/src/documentation/content/xdocs/status.xml

You'll probably want to checkout 
https://svn.apache.org/repos/asf/poi/site/ independently of 
https://svn.apache.org/repos/asf/poi/trunk/ . There is a svn:external on 
the latter to part of the former, but not enough to re-build the site. Or, 
if you do want to commit from within the main checkout, you'll need to cd 
into src/documentation first

Nick

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


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


RE: svn commit: r1508691 - in /poi/trunk: src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java test-data/spreadsheet/WithTextBox.xlsx test-data/spreadsheet/WithTextBox2...

Posted by Nick Burch <ap...@gagravarr.org>.
On Wed, 31 Jul 2013, Allison, Timothy B. wrote:
> Sorry about that and for the ignorance exhibited by this:
>
> commit isn't working on status.xml (status -u shows the update; diff 
> doesn't)... do I "svn cp" my updated copy to 
> https://svn.apache.org/repos/asf/poi/site/src/documentation/content/xdocs/status.xml

You'll probably want to checkout 
https://svn.apache.org/repos/asf/poi/site/ independently of 
https://svn.apache.org/repos/asf/poi/trunk/ . There is a svn:external on 
the latter to part of the former, but not enough to re-build the site. Or, 
if you do want to commit from within the main checkout, you'll need to cd 
into src/documentation first

Nick

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


RE: svn commit: r1508691 - in /poi/trunk: src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java test-data/spreadsheet/WithTextBox.xlsx test-data/spreadsheet/WithTextBox2...

Posted by "Allison, Timothy B." <ta...@mitre.org>.
Sorry about that and for the ignorance exhibited by this: 
commit isn't working on status.xml (status -u shows the update; diff doesn't)... do I "svn cp" my updated copy to https://svn.apache.org/repos/asf/poi/site/src/documentation/content/xdocs/status.xml

Thank you!

-----Original Message-----
From: Nick Burch [mailto:apache@gagravarr.org] 
Sent: Wednesday, July 31, 2013 4:38 AM
To: dev@poi.apache.org
Subject: Re: svn commit: r1508691 - in /poi/trunk: src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java test-data/spreadsheet/WithTextBox.xlsx test-data/spreadsheet/WithTextBox2...

On Wed, 31 Jul 2013, tallison@apache.org wrote:
> Added:
>    poi/trunk/test-data/spreadsheet/WithTextBox2.xlsx   (with props)
> Modified:
>    poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java
>    poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java
>    poi/trunk/test-data/spreadsheet/WithTextBox.xlsx

Don't forget to modify the changelog (by hand, sorry!) when you're done. 
It lives at
https://svn.apache.org/repos/asf/poi/site/src/documentation/content/xdocs/status.xml

Nick

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


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


Re: svn commit: r1508691 - in /poi/trunk: src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java test-data/spreadsheet/WithTextBox.xlsx test-data/spreadsheet/WithTextBox2.xlsx

Posted by Nick Burch <ap...@gagravarr.org>.
On Wed, 31 Jul 2013, tallison@apache.org wrote:
> Added:
>    poi/trunk/test-data/spreadsheet/WithTextBox2.xlsx   (with props)
> Modified:
>    poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java
>    poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java
>    poi/trunk/test-data/spreadsheet/WithTextBox.xlsx

Don't forget to modify the changelog (by hand, sorry!) when you're done. 
It lives at
https://svn.apache.org/repos/asf/poi/site/src/documentation/content/xdocs/status.xml

Nick

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