]> source.dussan.org Git - poi.git/commitdiff
Merged revisions 668156-671000 via svnmerge from
authorNick Burch <nick@apache.org>
Sun, 6 Jul 2008 12:11:37 +0000 (12:11 +0000)
committerNick Burch <nick@apache.org>
Sun, 6 Jul 2008 12:11:37 +0000 (12:11 +0000)
https://svn.apache.org/repos/asf/poi/trunk

........
  r668257 | yegor | 2008-06-16 19:38:59 +0100 (Mon, 16 Jun 2008) | 1 line

  TextShape.getMarginLeft() returned incorrect value. Added a unit test for text margins.
........
  r668259 | yegor | 2008-06-16 19:40:51 +0100 (Mon, 16 Jun 2008) | 1 line

  patch from bug #45177: Remove GPL reference in NOTICE
........
  r669140 | nick | 2008-06-18 12:35:04 +0100 (Wed, 18 Jun 2008) | 1 line

  A partial fix for bug #30978, but something still remains, which seems to be related to changing the ptg
........
  r669456 | nick | 2008-06-19 12:47:48 +0100 (Thu, 19 Jun 2008) | 1 line

  Improved HWPF Range.replaceText, from N. Hira in bug #45001
........
  r669658 | josh | 2008-06-19 20:07:20 +0100 (Thu, 19 Jun 2008) | 1 line

  Fix for bug 45234 - Removed incorrect shared formula conversion in CFRuleRecord
........
  r669809 | josh | 2008-06-20 08:10:03 +0100 (Fri, 20 Jun 2008) | 1 line

  Fix for bug 30978 - small re-arrangement of class Ptg hierarchy for DeletedRef3DPtg and DeletedArea3DPtg. Similar to c664220
........
  r670190 | yegor | 2008-06-21 13:41:34 +0100 (Sat, 21 Jun 2008) | 1 line

  started a new section for poi-3.2 family, updated release date of 3.2-FINAL
........

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@674287 13f79535-47bb-0310-9956-ffa450edef68

22 files changed:
legal/NOTICE
src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/hssf/model/Workbook.java
src/java/org/apache/poi/hssf/record/CFRuleRecord.java
src/java/org/apache/poi/hssf/record/NameRecord.java
src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java
src/java/org/apache/poi/hssf/record/formula/DeletedArea3DPtg.java
src/java/org/apache/poi/hssf/record/formula/DeletedRef3DPtg.java
src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java
src/java/org/apache/poi/hssf/usermodel/HSSFErrorConstants.java
src/java/org/apache/poi/hssf/usermodel/HSSFSheetConditionalFormatting.java
src/java/org/apache/poi/ss/usermodel/ErrorConstants.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java
src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java
src/scratchpad/testcases/org/apache/poi/hslf/data/text-margins.ppt [new file with mode: 0755]
src/scratchpad/testcases/org/apache/poi/hslf/model/TestTextShape.java
src/scratchpad/testcases/org/apache/poi/hwpf/data/testRangeReplacement.doc [new file with mode: 0644]
src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeReplacement.java [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/data/30978-alt.xls [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/record/TestCFRuleRecord.java
src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java

index d5d7883b35d8dbefefa6241eca9cd9fbbe0a7c1c..848c767bc327cdfe3a9e4499030e7141aac55743 100644 (file)
@@ -10,14 +10,6 @@ Common Public License Version 1.0:
        http://www.opensource.org/licenses/cpl.php
 See http://www.junit.org/
 
-A single data file of the POI component HDGF is based on VSDump,
- and is under the GNU General Public Licence version 3 (GPL v3):
-       http://gplv3.fsf.org/
-Since this is a data file, and has no compiled version (the original
- file is distributed in both source and binary versions), there should
- be little difference in licencing requirements compared to the ASL.
-See http://www.gnome.ru/projects/vsdump_en.html
-
 
 The Office Open XML experimental support had additional dependencies,
 with their own licensing:
index 43b373d04d227cb37e1b27360eb7b1fad373ca8e..561ab0d4d290220559c725f8a035d3067272a668 100644 (file)
            <action dev="POI-DEVELOPERS" type="add">Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx</action>
            <action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
         </release>
-        <release version="3.1-final" date="2008-06-??">
+        <release version="3.2-alpha1" date="2008-??-??">
+          <action dev="POI-DEVELOPERS" type="add"><!-- to keep forrest dtd quiet--></action>
+        </release>
+        <release version="3.1-final" date="2008-06-29">
+           <action dev="POI-DEVELOPERS" type="fix">30978 - Fixed re-serialization of tRefErr3d and tAreaErr3d</action>
+           <action dev="POI-DEVELOPERS" type="fix">45234 - Removed incorrect shared formula conversion in CFRuleRecord</action>
+           <action dev="POI-DEVELOPERS" type="fix">45001 - Improved HWPF Range.replaceText()</action>
            <action dev="POI-DEVELOPERS" type="fix">44692 - Fixed HSSFPicture.resize() to properly resize pictures if the underlying columns/rows have modified size</action>
            <action dev="POI-DEVELOPERS" type="add">Support custom image renderers in HSLF</action>
            <action dev="POI-DEVELOPERS" type="fix">Correctly increment the reference count of a blip when a picture is inserted</action>
index 3ad07a2162690ea09e9ab9208536049a04d23928..ca47e0f20975674d7991ecbbe5b4b9861f346c05 100644 (file)
            <action dev="POI-DEVELOPERS" type="add">Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx</action>
            <action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
         </release>
-        <release version="3.1-final" date="2008-06-??">
+        <release version="3.2-alpha1" date="2008-??-??">
+          <action dev="POI-DEVELOPERS" type="add"><!-- to keep forrest dtd quiet--></action>
+        </release>
+        <release version="3.1-final" date="2008-06-29">
+           <action dev="POI-DEVELOPERS" type="fix">30978 - Fixed re-serialization of tRefErr3d and tAreaErr3d</action>
+           <action dev="POI-DEVELOPERS" type="fix">45234 - Removed incorrect shared formula conversion in CFRuleRecord</action>
+           <action dev="POI-DEVELOPERS" type="fix">45001 - Improved HWPF Range.replaceText()</action>
            <action dev="POI-DEVELOPERS" type="fix">44692 - Fixed HSSFPicture.resize() to properly resize pictures if the underlying columns/rows have modified size</action>
            <action dev="POI-DEVELOPERS" type="add">Support custom image renderers in HSLF</action>
            <action dev="POI-DEVELOPERS" type="fix">Correctly increment the reference count of a blip when a picture is inserted</action>
index 5b38935f4c593d38cc4858ae4686e4b675212c29..fa22cfb6889161f94b5d25ff75caf828d251bf1a 100644 (file)
@@ -604,8 +604,28 @@ public class Workbook implements Model
             fixTabIdRecord();
         }
         
-        // If we decide that we need to fix up
-        //  NameRecords, do it here
+        // Within NameRecords, it's ok to have the formula
+        //  part point at deleted sheets. It's also ok to
+        //  have the ExternSheetNumber point at deleted
+        //  sheets. 
+        // However, the sheet index must be adjusted, or
+        //  excel will break. (Sheet index is either 0 for
+        //  global, or 1 based index to sheet)
+        int sheetNum1Based = sheetnum + 1;
+        for(int i=0; i<getNumNames(); i++) {
+               NameRecord nr = getNameRecord(i);
+               
+               if(nr.getIndexToSheet() == sheetNum1Based) {
+                       // Excel re-writes these to point to no sheet
+                       nr.setEqualsToIndexToSheet((short)0);
+               } else if(nr.getIndexToSheet() > sheetNum1Based) {
+                       // Bump down by one, so still points
+                       //  at the same sheet
+                       nr.setEqualsToIndexToSheet((short)(
+                                       nr.getEqualsToIndexToSheet()-1
+                       ));
+               }
+        }
     }
 
     /**
index 2b1705abe2d382e20f2034192e7cff04d6169ec8..d000b5311dce906f228338a83da0cf51f8a788b6 100644 (file)
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.hssf.record;
 
-import java.util.Stack;
-
 import org.apache.poi.hssf.model.FormulaParser;
-import org.apache.poi.hssf.model.Workbook;
 import org.apache.poi.hssf.record.cf.BorderFormatting;
 import org.apache.poi.hssf.record.cf.FontFormatting;
 import org.apache.poi.hssf.record.cf.PatternFormatting;
@@ -30,7 +26,6 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
 import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.StringUtil;
 
 /**
  * Conditional Formatting Rule Record.
@@ -59,9 +54,6 @@ public final class CFRuleRecord extends Record
 
        private byte  field_2_comparison_operator;
 
-       private short field_3_formula1_len;
-       private short field_4_formula2_len;
-
        private int   field_5_options;
 
        private static final BitField modificationBits = bf(0x003FFFFF); // Bits: font,align,bord,patt,prot
@@ -121,8 +113,6 @@ public final class CFRuleRecord extends Record
        {
                field_1_condition_type=conditionType;
                field_2_comparison_operator=comparisonOperation;
-               field_3_formula1_len = (short)0;
-               field_4_formula2_len = (short)0;
 
                // Set modification flags to 1: by default options are not modified
                field_5_options = modificationBits.setValue(field_5_options, -1);
@@ -147,8 +137,8 @@ public final class CFRuleRecord extends Record
                this(conditionType, comparisonOperation); 
                field_1_condition_type = CONDITION_TYPE_CELL_VALUE_IS;
                field_2_comparison_operator = comparisonOperation;
-               setParsedExpression1(formula1);
-               setParsedExpression2(formula2);
+               field_17_formula1 = formula1;
+               field_18_formula2 = formula2;
        }
 
        /**
@@ -167,63 +157,38 @@ public final class CFRuleRecord extends Record
                Ptg[] formula1 = parseFormula(formulaText1, workbook);
                Ptg[] formula2 = parseFormula(formulaText2, workbook);
                return new CFRuleRecord(CONDITION_TYPE_CELL_VALUE_IS, comparisonOperation, formula1, formula2);
-               
        }
 
-       /**
-        * Constructs a Formula record and sets its fields appropriately.
-        * Note - id must be 0x06 (NOT 0x406 see MSKB #Q184647 for an 
-        * "explanation of this bug in the documentation) or an exception
-        *  will be throw upon validation
-        *
-        * @param in the RecordInputstream to read the record from
-        */
-
-       public CFRuleRecord(RecordInputStream in)
-       {
+       public CFRuleRecord(RecordInputStream in) {
                super(in);
        }
 
+       protected void fillFields(RecordInputStream in) {
+               field_1_condition_type = in.readByte();
+               field_2_comparison_operator = in.readByte();
+               int field_3_formula1_len = in.readUShort();
+               int field_4_formula2_len = in.readUShort();
+               field_5_options = in.readInt();
+               field_6_not_used = in.readShort();
 
+               if (containsFontFormattingBlock()) {
+                       fontFormatting = new FontFormatting(in);
+               }
 
-       protected void fillFields(RecordInputStream in) {
-               try {
-                       field_1_condition_type = in.readByte();
-                       field_2_comparison_operator = in.readByte();
-                       field_3_formula1_len = in.readShort();
-                       field_4_formula2_len = in.readShort();
-                       field_5_options = in.readInt();
-                       field_6_not_used = in.readShort();
-
-                       if (containsFontFormattingBlock()) {
-                               fontFormatting = new FontFormatting(in);
-                       }
-
-                       if (containsBorderFormattingBlock()) {
-                               borderFormatting = new BorderFormatting(in);
-                       }
-
-                       if (containsPatternFormattingBlock()) {
-                               patternFormatting = new PatternFormatting(in);
-                       }
-
-                       if (field_3_formula1_len > 0) {
-                               Stack ptgs = Ptg.createParsedExpressionTokens(field_3_formula1_len, in);
-                               // Now convert any fields as required
-                               ptgs = SharedFormulaRecord.convertSharedFormulas(ptgs, 0, 0);
-                               field_17_formula1 = toArray(ptgs);
-                       }
-                       if (field_4_formula2_len > 0) {
-                               Stack ptgs = Ptg.createParsedExpressionTokens(field_4_formula2_len, in);
-
-                               // Now convert any fields as required
-                               ptgs = SharedFormulaRecord.convertSharedFormulas(ptgs, 0, 0);
-                               field_18_formula2 = toArray(ptgs);
-                       }
-               } catch (java.lang.UnsupportedOperationException uoe) {
-                       throw new RecordFormatException(uoe);
+               if (containsBorderFormattingBlock()) {
+                       borderFormatting = new BorderFormatting(in);
+               }
+
+               if (containsPatternFormattingBlock()) {
+                       patternFormatting = new PatternFormatting(in);
                }
 
+               if (field_3_formula1_len > 0) {
+                       field_17_formula1 = Ptg.readTokens(field_3_formula1_len, in);
+               }
+               if (field_4_formula2_len > 0) {
+                       field_18_formula2 = Ptg.readTokens(field_4_formula2_len, in);
+               }
        }
 
        public byte getConditionType()
@@ -323,24 +288,6 @@ public final class CFRuleRecord extends Record
        }
        
 
-       /**
-        * get the length (in number of tokens) of the expression 1
-        * @return  expression length
-        */
-       private short getExpression1Length()
-       {
-               return field_3_formula1_len;
-       }
-       
-
-       /**
-        * get the length (in number of tokens) of the expression 2
-        * @return  expression length
-        */
-       private short getExpression2Length()
-       {
-               return field_4_formula2_len;
-       }
        /**
         * get the option flags
         *
@@ -489,16 +436,6 @@ public final class CFRuleRecord extends Record
                return field_18_formula2;
        }
        
-       private void setParsedExpression1(Ptg[] ptgs) {
-               short len = getTotalPtgSize(field_17_formula1 = ptgs);
-               field_3_formula1_len = len;
-       }
-
-       private void setParsedExpression2(Ptg[] ptgs) {
-               short len = getTotalPtgSize(field_18_formula2 = ptgs);
-               field_4_formula2_len = len;
-       }
-       
        /**
         * called by constructor, should throw runtime exception in the event of a
         * record passed with a differing ID.
@@ -519,6 +456,17 @@ public final class CFRuleRecord extends Record
                return sid;
        }
 
+       /**
+        * @param ptgs may be <code>null</code>
+        * @return encoded size of the formula
+        */
+       private static int getFormulaSize(Ptg[] ptgs) {
+               if (ptgs == null) {
+                       return 0;
+               }
+               return Ptg.getEncodedSize(ptgs);
+       }
+       
        /**
         * called by the class that is responsible for writing this sucker.
         * Subclasses should implement this so that their data is passed back in a
@@ -528,18 +476,20 @@ public final class CFRuleRecord extends Record
         * @param data byte array containing instance data
         * @return number of bytes written
         */
-
        public int serialize(int pOffset, byte [] data)
        {
                
+               int formula1Len=getFormulaSize(field_17_formula1);
+               int formula2Len=getFormulaSize(field_18_formula2);
+               
                int offset = pOffset;
                int recordsize = getRecordSize();
                LittleEndian.putShort(data, 0 + offset, sid);
                LittleEndian.putShort(data, 2 + offset, (short)(recordsize-4));
                data[4 + offset] = field_1_condition_type;
                data[5 + offset] = field_2_comparison_operator;
-               LittleEndian.putShort(data, 6 + offset, field_3_formula1_len);
-               LittleEndian.putShort(data, 8 + offset, field_4_formula2_len);
+               LittleEndian.putUShort(data, 6 + offset, formula1Len);
+               LittleEndian.putUShort(data, 8 + offset, formula2Len);
                LittleEndian.putInt(data,  10 + offset, field_5_options);
                LittleEndian.putShort(data,14 + offset, field_6_not_used);
                
@@ -562,16 +512,12 @@ public final class CFRuleRecord extends Record
                        offset += patternFormatting.serialize(offset, data);
                }
                
-               if (getExpression1Length()>0)
-               {
-                       Ptg.serializePtgStack(convertToTokenStack(field_17_formula1), data, offset);
-                       offset += getExpression1Length();
+               if (field_17_formula1 != null) {
+                       offset += Ptg.serializePtgs(field_17_formula1, data, offset);
                }
 
-               if (getExpression2Length()>0)
-               {
-                       Ptg.serializePtgStack(convertToTokenStack(field_18_formula2), data, offset);
-                       offset += getExpression2Length();
+               if (field_18_formula2 != null) {
+                       offset += Ptg.serializePtgs(field_18_formula2, data, offset);
                }
                if(offset - pOffset != recordsize) {
                        throw new IllegalStateException("write mismatch (" + (offset - pOffset) + "!=" + recordsize + ")");
@@ -586,24 +532,12 @@ public final class CFRuleRecord extends Record
                                        (containsFontFormattingBlock()?fontFormatting.getRawRecord().length:0)+
                                        (containsBorderFormattingBlock()?8:0)+
                                        (containsPatternFormattingBlock()?4:0)+
-                                       getExpression1Length()+
-                                       getExpression2Length()
+                                       getFormulaSize(field_17_formula1)+
+                                       getFormulaSize(field_18_formula2)
                                        ;
                return retval;
        }
 
-       private short getTotalPtgSize(Ptg[] ptgs)
-       {
-               if( ptgs == null) {
-                       return 0;
-               }
-               short  retval = 0;
-               for (int i = 0; i < ptgs.length; i++)
-               {
-                       retval += ptgs[i].getSize();
-               }
-               return retval;
-       }
 
        public String toString()
        {
@@ -629,8 +563,6 @@ public final class CFRuleRecord extends Record
        
        public Object clone() {
                CFRuleRecord rec = new CFRuleRecord(field_1_condition_type, field_2_comparison_operator);
-               rec.field_3_formula1_len = field_3_formula1_len;
-               rec.field_4_formula2_len = field_4_formula2_len;
                rec.field_5_options = field_5_options;
                rec.field_6_not_used = field_6_not_used;
                if (containsFontFormattingBlock()) {
@@ -642,10 +574,10 @@ public final class CFRuleRecord extends Record
                if (containsPatternFormattingBlock()) {
                        rec.patternFormatting = (PatternFormatting) patternFormatting.clone();
                }
-               if (field_3_formula1_len > 0) {
+               if (field_17_formula1 != null) {
                        rec.field_17_formula1 = (Ptg[]) field_17_formula1.clone();
                }
-               if (field_4_formula2_len > 0) {
+               if (field_18_formula2 != null) {
                        rec.field_18_formula2 = (Ptg[]) field_18_formula2.clone();
                }
 
@@ -653,30 +585,17 @@ public final class CFRuleRecord extends Record
        }
 
        /**
+        * TODO - parse conditional format formulas properly i.e. produce tRefN and tAreaN instead of tRef and tArea
+        * this call will produce the wrong results if the formula contains any cell references
+        * One approach might be to apply the inverse of SharedFormulaRecord.convertSharedFormulas(Stack, int, int)
+        * Note - two extra parameters (rowIx & colIx) will be required. They probably come from one of the Region objects.
+        * 
         * @return <code>null</code> if <tt>formula</tt> was null.
         */
-       private static Ptg[] parseFormula(String formula, HSSFWorkbook workbook)
-       {
+       private static Ptg[] parseFormula(String formula, HSSFWorkbook workbook) {
                if(formula == null) {
                        return null;
                }
                return FormulaParser.parse(formula, workbook);
        }
-
-       // TODO - treat formulas as token arrays instead of Stacks throughout the rest of POI
-       private static Stack convertToTokenStack(Ptg[] ptgs)
-       {
-               Stack parsedExpression = new Stack();
-               // fill the Ptg Stack with Ptgs of new formula
-               for (int k = 0; k < ptgs.length; k++) 
-               {
-                       parsedExpression.push(ptgs[ k ]);
-               }
-               return parsedExpression;
-       }
-       private static Ptg[] toArray(Stack ptgs) {
-               Ptg[] result = new Ptg[ptgs.size()];
-               ptgs.toArray(result);
-               return result;
-       }
 }
index 786c0b3d6ba3a6586694562f627de48be48a4787..dbd796991c69656a525e80eebc782d3e4c00e838 100644 (file)
@@ -14,7 +14,6 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.hssf.record;
 
@@ -22,9 +21,8 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Stack;
 
+import org.apache.poi.hssf.model.FormulaParser;
 import org.apache.poi.hssf.record.formula.Area3DPtg;
-import org.apache.poi.hssf.record.formula.DeletedArea3DPtg;
-import org.apache.poi.hssf.record.formula.DeletedRef3DPtg;
 import org.apache.poi.hssf.record.formula.Ptg;
 import org.apache.poi.hssf.record.formula.Ref3DPtg;
 import org.apache.poi.hssf.record.formula.UnionPtg;
@@ -44,8 +42,7 @@ import org.apache.poi.util.StringUtil;
  * @author Glen Stampoultzis (glens at apache.org)
  * @version 1.0-pre
  */
-
-public class NameRecord extends Record {
+public final class NameRecord extends Record {
     /**
      */
     public final static short sid = 0x18; //Docs says that it is 0x218
@@ -650,50 +647,9 @@ public class NameRecord extends Record {
     /** gets the reference , the area only (range)
      * @return area reference
      */
-    public String getAreaReference(HSSFWorkbook book){
-        if (field_13_name_definition == null || field_13_name_definition.isEmpty()) return "Error";
-        Ptg ptg = (Ptg) field_13_name_definition.peek();
-        String result = "";
-
-        // If it's a union, descend in and process
-        if (ptg.getClass() == UnionPtg.class) {
-            Iterator it =field_13_name_definition.iterator();
-            while( it.hasNext() ) {
-                Ptg p = (Ptg)it.next();
-
-                String thisRes = getAreaRefString(p, book);
-                if(thisRes.length() > 0) {
-                    // Add a comma to the end if needed
-                    if(result.length() > 0 && !result.endsWith(",")) {
-                        result += ",";
-                    }
-                    // And add the string it corresponds to
-                    result += thisRes;
-                }
-            }
-        } else {
-            // Otherwise just get the string
-            result = getAreaRefString(ptg, book);
-        }
-
-        return result;
-    }
-
-    /**
-     * Turn the given ptg into a string, or
-     *  return an empty string if nothing is possible
-     *  for it.
-     */
-    private String getAreaRefString(Ptg ptg,HSSFWorkbook book) {
-        if (ptg.getClass() == Area3DPtg.class){
-            return ptg.toFormulaString(book);
-        } else if (ptg.getClass() == Ref3DPtg.class){
-            return ptg.toFormulaString(book);
-        } else if (ptg.getClass() == DeletedArea3DPtg.class || ptg.getClass() == DeletedRef3DPtg.class) {
-               return "#REF!";
-        }
-        return "";
-    }
+       public String getAreaReference(HSSFWorkbook book){
+               return FormulaParser.toFormulaString(book, field_13_name_definition);
+       }
 
     /** sets the reference , the area only (range)
      * @param ref area reference
index 2804e37c3d88fc677ca76105f33aaf12c1def3ca..8deaa919f11e5ca2e1376571958040ab8b687607 100644 (file)
@@ -35,7 +35,7 @@ import org.apache.poi.util.LittleEndian;
  * @author Jason Height (jheight at chariot dot net dot au)
  * @version 1.0-pre
  */
-public class Area3DPtg extends OperandPtg implements AreaI {
+public final class Area3DPtg extends OperandPtg implements AreaI {
        public final static byte sid = 0x3b;
        private final static int SIZE = 11; // 10 + 1 for Ptg
        private short field_1_index_extern_sheet;
index 36d7e16860b69528a3f9716ccb1a4b761c1c80ab..a1c5b3db59e126a444756bff04c4c4fefb21c1af 100644 (file)
@@ -18,6 +18,9 @@
 package org.apache.poi.hssf.record.formula;
 
 import org.apache.poi.hssf.record.RecordInputStream;
+import org.apache.poi.ss.usermodel.ErrorConstants;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.util.LittleEndian;
 
 /**
  * Title:        Deleted Area 3D Ptg - 3D referecnce (Sheet + Area)<P>
@@ -26,19 +29,30 @@ import org.apache.poi.hssf.record.RecordInputStream;
  * @author Patrick Luby
  * @version 1.0-pre
  */
-
-public class DeletedArea3DPtg extends Area3DPtg
-{
+public final class DeletedArea3DPtg extends OperandPtg {
        public final static byte sid = 0x3d;
-
-    /** Creates new DeletedArea3DPtg */
-    public DeletedArea3DPtg( String arearef, short externIdx )
-    {
-        super(arearef, externIdx);
-    }
-
-    public DeletedArea3DPtg( RecordInputStream in)
-    {
-        super(in);
-    }
+       private final int field_1_index_extern_sheet;
+       private final int unused1;
+       private final int unused2;
+
+       public DeletedArea3DPtg( RecordInputStream in) {
+               field_1_index_extern_sheet = in.readUShort();
+               unused1 = in.readInt();
+               unused2 = in.readInt();
+       }
+       public String toFormulaString(Workbook book) {
+               return ErrorConstants.getText(ErrorConstants.ERROR_REF);
+       }
+       public byte getDefaultOperandClass() {
+               return Ptg.CLASS_REF;
+       }
+       public int getSize() {
+               return 11;
+       }
+       public void writeBytes(byte[] data, int offset) {
+               LittleEndian.putByte(data, 0 + offset, sid + getPtgClass());
+               LittleEndian.putUShort(data, 1 + offset, field_1_index_extern_sheet);
+               LittleEndian.putInt(data, 3 + offset, unused1);
+               LittleEndian.putInt(data, 7 + offset, unused2);
+       }
 }
index a3c7809655b63f7cb502ff80a876f1274a5d27e7..9312b2d766d416d1177b5946f83775a23cec6e87 100644 (file)
    limitations under the License.
 ==================================================================== */
 
-
 package org.apache.poi.hssf.record.formula;
 
 
 import org.apache.poi.hssf.record.RecordInputStream;
+import org.apache.poi.ss.usermodel.ErrorConstants;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.util.LittleEndian;
 
 /**
  * Title:        Deleted Reference 3D Ptg <P>
@@ -28,16 +30,29 @@ import org.apache.poi.hssf.record.RecordInputStream;
  * @author Patrick Luby
  * @version 1.0-pre
  */
-
-public class DeletedRef3DPtg extends Ref3DPtg {
-    public final static byte sid  = 0x3c;
-
-    /** Creates new DeletedRef3DPtg */
-    public DeletedRef3DPtg(RecordInputStream in) {
-        super(in);
-    }
-
-    public DeletedRef3DPtg(String cellref, short externIdx ) {
-        super(cellref, externIdx);
-    }
+public final class DeletedRef3DPtg extends OperandPtg {
+       public final static byte sid  = 0x3c;
+       private final int field_1_index_extern_sheet;
+       private final int unused1;
+
+       /** Creates new DeletedRef3DPtg */
+       public DeletedRef3DPtg(RecordInputStream in) {
+               field_1_index_extern_sheet = in.readUShort();
+               unused1 = in.readInt();
+       }
+
+       public String toFormulaString(Workbook book) {
+               return ErrorConstants.getText(ErrorConstants.ERROR_REF);
+       }
+       public byte getDefaultOperandClass() {
+               return Ptg.CLASS_REF;
+       }
+       public int getSize() {
+               return 7;
+       }
+       public void writeBytes(byte[] data, int offset) {
+               LittleEndian.putByte(data, 0 + offset, sid + getPtgClass());
+               LittleEndian.putUShort(data, 1 + offset, field_1_index_extern_sheet);
+               LittleEndian.putInt(data, 3 + offset, unused1);
+       }
 }
index 0ec0645815b74d47f414560d853c9baf083b37b5..52a5518e40e025702b12d58f103742d0146834ab 100644 (file)
@@ -34,7 +34,7 @@ import org.apache.poi.util.LittleEndian;
  * @author Jason Height (jheight at chariot dot net dot au)
  * @version 1.0-pre
  */
-public class Ref3DPtg extends OperandPtg {
+public final class Ref3DPtg extends OperandPtg {
     public final static byte sid  = 0x3a;
     private final static int  SIZE = 7; // 6 + 1 for Ptg
     private short             field_1_index_extern_sheet;
index 89c25d1e8727b2030c2d0c1eb8c7d12b9a76d313..f82ee721d0426ca802d5b7a724058925cf02c1b1 100644 (file)
 ==================================================================== */
 
 package org.apache.poi.hssf.usermodel;
+import org.apache.poi.ss.usermodel.ErrorConstants;
 
 /**
  * Contains raw Excel error codes (as defined in OOO's excelfileformat.pdf (2.5.6)
  * 
  * @author  Michael Harhen
  */
-public final class HSSFErrorConstants {
-    private HSSFErrorConstants() {
-        // no instances of this class
-    }
-    
-    /** <b>#NULL!</b>  - Intersection of two cell ranges is empty */
-    public static final int ERROR_NULL = 0x00;
-    /** <b>#DIV/0!</b> - Division by zero */
-    public static final int ERROR_DIV_0 = 0x07;
-    /** <b>#VALUE!</b> - Wrong type of operand */
-    public static final int ERROR_VALUE = 0x0F; 
-    /** <b>#REF!</b> - Illegal or deleted cell reference */
-    public static final int ERROR_REF = 0x17;  
-    /** <b>#NAME?</b> - Wrong function or range name */
-    public static final int ERROR_NAME = 0x1D; 
-    /** <b>#NUM!</b> - Value range overflow */
-    public static final int ERROR_NUM = 0x24; 
-    /** <b>#N/A</b> - Argument or function not available */
-    public static final int ERROR_NA = 0x2A;
-    
-    
-    /**
-     * @return Standard Excel error literal for the specified error code. 
-     * @throws IllegalArgumentException if the specified error code is not one of the 7 
-     * standard error codes
-     */
-    public static final String getText(int errorCode) {
-        switch(errorCode) {
-            case ERROR_NULL:  return "#NULL!";
-            case ERROR_DIV_0: return "#DIV/0!";
-            case ERROR_VALUE: return "#VALUE!";
-            case ERROR_REF:   return "#REF!";
-            case ERROR_NAME:  return "#NAME?";
-            case ERROR_NUM:   return "#NUM!";
-            case ERROR_NA:    return "#N/A";
-        }
-        throw new IllegalArgumentException("Bad error code (" + errorCode + ")");
-    }
-    
-    /**
-     * @return <code>true</code> if the specified error code is a standard Excel error code. 
-     */
-    public static final boolean isValidCode(int errorCode) {
-        // This method exists because it would be bad to force clients to catch 
-        // IllegalArgumentException if there were potential for passing an invalid error code.  
-        switch(errorCode) {
-            case ERROR_NULL:
-            case ERROR_DIV_0:
-            case ERROR_VALUE:
-            case ERROR_REF:
-            case ERROR_NAME:
-            case ERROR_NUM:
-            case ERROR_NA:
-                return true;
-        }
-        return false;
-    }
+public final class HSSFErrorConstants extends ErrorConstants {
 }
index c042456a4f2e8befeebf9b0b6465d76d5de9c818..8e8cf40a1bcdaef78735268d2f70d122641045d4 100644 (file)
@@ -39,7 +39,8 @@ public final class HSSFSheetConditionalFormatting {
 \r
        /**\r
         * A factory method allowing to create a conditional formatting rule\r
-        * with a cell comparison operator \r
+        * with a cell comparison operator<p/>\r
+        * TODO - formulas containing cell references are currently not parsed properly \r
         *\r
         * @param comparisonOperation - a constant value from\r
         *               <tt>{@link HSSFConditionalFormattingRule.ComparisonOperator}</tt>: <p>\r
@@ -72,8 +73,8 @@ public final class HSSFSheetConditionalFormatting {
        /**\r
         * A factory method allowing to create a conditional formatting rule with a formula.<br>\r
         *\r
-        * The formatting rules are applied by Excel when the value of the formula not equal to 0.\r
-        *\r
+        * The formatting rules are applied by Excel when the value of the formula not equal to 0.<p/>\r
+        * TODO - formulas containing cell references are currently not parsed properly\r
         * @param formula - formula for the valued, compared with the cell\r
         */\r
        public HSSFConditionalFormattingRule createConditionalFormattingRule(String formula) {\r
diff --git a/src/java/org/apache/poi/ss/usermodel/ErrorConstants.java b/src/java/org/apache/poi/ss/usermodel/ErrorConstants.java
new file mode 100644 (file)
index 0000000..1bfa184
--- /dev/null
@@ -0,0 +1,82 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.ss.usermodel;
+
+/**
+ * Contains raw Excel error codes (as defined in OOO's excelfileformat.pdf (2.5.6)
+ * 
+ * @author  Michael Harhen
+ */
+public class ErrorConstants {
+    protected ErrorConstants() {
+        // no instances of this class
+    }
+    
+    /** <b>#NULL!</b>  - Intersection of two cell ranges is empty */
+    public static final int ERROR_NULL = 0x00;
+    /** <b>#DIV/0!</b> - Division by zero */
+    public static final int ERROR_DIV_0 = 0x07;
+    /** <b>#VALUE!</b> - Wrong type of operand */
+    public static final int ERROR_VALUE = 0x0F; 
+    /** <b>#REF!</b> - Illegal or deleted cell reference */
+    public static final int ERROR_REF = 0x17;  
+    /** <b>#NAME?</b> - Wrong function or range name */
+    public static final int ERROR_NAME = 0x1D; 
+    /** <b>#NUM!</b> - Value range overflow */
+    public static final int ERROR_NUM = 0x24; 
+    /** <b>#N/A</b> - Argument or function not available */
+    public static final int ERROR_NA = 0x2A;
+    
+    
+    /**
+     * @return Standard Excel error literal for the specified error code. 
+     * @throws IllegalArgumentException if the specified error code is not one of the 7 
+     * standard error codes
+     */
+    public static final String getText(int errorCode) {
+        switch(errorCode) {
+            case ERROR_NULL:  return "#NULL!";
+            case ERROR_DIV_0: return "#DIV/0!";
+            case ERROR_VALUE: return "#VALUE!";
+            case ERROR_REF:   return "#REF!";
+            case ERROR_NAME:  return "#NAME?";
+            case ERROR_NUM:   return "#NUM!";
+            case ERROR_NA:    return "#N/A";
+        }
+        throw new IllegalArgumentException("Bad error code (" + errorCode + ")");
+    }
+    
+    /**
+     * @return <code>true</code> if the specified error code is a standard Excel error code. 
+     */
+    public static final boolean isValidCode(int errorCode) {
+        // This method exists because it would be bad to force clients to catch 
+        // IllegalArgumentException if there were potential for passing an invalid error code.  
+        switch(errorCode) {
+            case ERROR_NULL:
+            case ERROR_DIV_0:
+            case ERROR_VALUE:
+            case ERROR_REF:
+            case ERROR_NAME:
+            case ERROR_NUM:
+            case ERROR_NA:
+                return true;
+        }
+        return false;
+    }
+}
index d1a84a5e44416f130975697e268d71ddc5c2d8bd..44cb2b2412124828b8618e19bf732606cc3fef8c 100755 (executable)
@@ -355,7 +355,7 @@ public abstract class TextShape extends SimpleShape {
      */
     public float getMarginLeft(){
         EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
-        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM);
+        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTLEFT);
         int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue();
         return (float)val/EMU_PER_POINT;
     }
index 6324cd86a2bf6c1dec60ad5b3bb5a1231738a5ca..80e9b7526c0c182a61ba6e5ec3a2d1b29d442b05 100644 (file)
@@ -635,27 +635,24 @@ public class Range
   /**
    * Replace (one instance of) a piece of text with another...
    *
-   * @param pPlaceHolder    The text to be replaced (e.g., "${company}")
-   * @param pValue          The replacement text (e.g., "Cognocys, Inc.")
-   * @param pDocument       The <code>HWPFDocument</code> in which the placeholder was found
-   * @param pStartOffset    The offset or index where the <code>CharacterRun</code> begins
-   * @param pPlaceHolderIndex   The offset or index of the placeholder, 
-   *  relative to the <code>CharacterRun</code> where 
-   *  <code>pPlaceHolder</code> was found
-   */
-  protected void replaceText(String pPlaceHolder, String pValue, 
-        int pStartOffset, int pPlaceHolderIndex, HWPFDocument pDocument) {
-    int absPlaceHolderIndex = pStartOffset + pPlaceHolderIndex;
+   * @param pPlaceHolder    The text to be replaced (e.g., "${organization}")
+   * @param pValue          The replacement text (e.g., "Apache Software Foundation")
+   * @param pOffset         The offset or index where the text to be replaced begins
+   *                        (relative to/within this <code>Range</code>)
+   */
+  public void replaceText(String pPlaceHolder, String pValue, int pOffset)
+  {
+       int absPlaceHolderIndex = getStartOffset() + pOffset;
     Range subRange = new Range(
                 absPlaceHolderIndex, 
-                (absPlaceHolderIndex + pPlaceHolder.length()), pDocument
+                               (absPlaceHolderIndex + pPlaceHolder.length()), getDocument()
     );
     if (subRange.usesUnicode()) {
-            absPlaceHolderIndex = pStartOffset + (pPlaceHolderIndex * 2);
+                       absPlaceHolderIndex = getStartOffset() + (pOffset * 2);
             subRange = new Range(
                       absPlaceHolderIndex, 
                       (absPlaceHolderIndex + (pPlaceHolder.length() * 2)), 
-                      pDocument
+                                         getDocument()
             );
     }
 
@@ -665,13 +662,13 @@ public class Range
     subRange = new Range(
             (absPlaceHolderIndex + pValue.length()),
             (absPlaceHolderIndex + pPlaceHolder.length() + pValue.length()), 
-            pDocument
+                       getDocument()
     );
     if (subRange.usesUnicode())
             subRange = new Range(
                       (absPlaceHolderIndex + (pValue.length() * 2)),
                       (absPlaceHolderIndex + (pPlaceHolder.length() * 2) + 
-                      (pValue.length() * 2)), pDocument
+                                         (pValue.length() * 2)), getDocument()
             );
 
     subRange.delete();
@@ -942,4 +939,9 @@ public class Range
 
                return _end;
        }
+
+       protected HWPFDocument getDocument() {
+
+               return _doc;
+       }
 }
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/data/text-margins.ppt b/src/scratchpad/testcases/org/apache/poi/hslf/data/text-margins.ppt
new file mode 100755 (executable)
index 0000000..cf539ae
Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hslf/data/text-margins.ppt differ
index 25a8db918713d495b1fd1c50f204b61399ba63ea..7fc878756741ae720e8086962eaf050917a16108 100755 (executable)
@@ -23,6 +23,7 @@ import junit.framework.TestCase;
 \r
 import java.io.*;\r
 import java.util.ArrayList;\r
+import java.util.HashMap;\r
 \r
 import org.apache.poi.hslf.usermodel.SlideShow;\r
 import org.apache.poi.hslf.record.TextHeaderAtom;\r
@@ -157,4 +158,46 @@ public class TestTextShape extends TestCase {
         assertEquals("Testing TextShape", shape1.getTextRun().getText());\r
     }\r
 \r
+    public void testMargins() throws IOException {\r
+        FileInputStream is = new FileInputStream(new File(cwd, "text-margins.ppt"));\r
+        SlideShow ppt = new SlideShow(is);\r
+        is.close();\r
+\r
+        Slide slide = ppt.getSlides()[0];\r
+\r
+        HashMap map = new HashMap();\r
+        Shape[] shape = slide.getShapes();\r
+        for (int i = 0; i < shape.length; i++) {\r
+            if(shape[i] instanceof TextShape){\r
+                TextShape tx = (TextShape)shape[i];\r
+                map.put(tx.getText(), tx);\r
+            }\r
+        }\r
+\r
+        TextShape tx;\r
+\r
+        tx = (TextShape)map.get("TEST1");\r
+        assertEquals(0.1, tx.getMarginLeft()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);\r
+        assertEquals(0.1, tx.getMarginRight()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);\r
+        assertEquals(0.39, tx.getMarginTop()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);\r
+        assertEquals(0.05, tx.getMarginBottom()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);\r
+\r
+        tx = (TextShape)map.get("TEST2");\r
+        assertEquals(0.1, tx.getMarginLeft()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);\r
+        assertEquals(0.1, tx.getMarginRight()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);\r
+        assertEquals(0.05, tx.getMarginTop()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);\r
+        assertEquals(0.39, tx.getMarginBottom()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);\r
+\r
+        tx = (TextShape)map.get("TEST3");\r
+        assertEquals(0.39, tx.getMarginLeft()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);\r
+        assertEquals(0.1, tx.getMarginRight()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);\r
+        assertEquals(0.05, tx.getMarginTop()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);\r
+        assertEquals(0.05, tx.getMarginBottom()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);\r
+\r
+        tx = (TextShape)map.get("TEST4");\r
+        assertEquals(0.1, tx.getMarginLeft()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);\r
+        assertEquals(0.39, tx.getMarginRight()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);\r
+        assertEquals(0.05, tx.getMarginTop()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);\r
+        assertEquals(0.05, tx.getMarginBottom()*Shape.EMU_PER_POINT/Shape.EMU_PER_INCH, 0.01);\r
+    }\r
 }\r
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/testRangeReplacement.doc b/src/scratchpad/testcases/org/apache/poi/hwpf/data/testRangeReplacement.doc
new file mode 100644 (file)
index 0000000..949980d
Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hwpf/data/testRangeReplacement.doc differ
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeReplacement.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeReplacement.java
new file mode 100644 (file)
index 0000000..4b2b9ce
--- /dev/null
@@ -0,0 +1,119 @@
+
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hwpf.usermodel;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.util.List;
+
+import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.hwpf.model.PicturesTable;
+import org.apache.poi.hwpf.usermodel.Picture;
+
+import junit.framework.TestCase;
+
+/**
+ *     Test to see if Range.replaceText() works even if the Range contains a
+ *     CharacterRun that uses Unicode characters.
+ */
+public class TestRangeReplacement extends TestCase {
+
+       // u201c and u201d are "smart-quotes"
+       private String originalText =
+               "It is used to confirm that text replacement works even if Unicode characters (such as \u201c\u2014\u201d (U+2014), \u201c\u2e8e\u201d (U+2E8E), or \u201c\u2714\u201d (U+2714)) are present.  Everybody should be thankful to the ${organization} and all the POI contributors for their assistance in this matter.\r";
+       private String searchText = "${organization}";
+       private String replacementText = "Apache Software Foundation";
+       private String expectedText =
+               "It is used to confirm that text replacement works even if Unicode characters (such as \u201c\u2014\u201d (U+2014), \u201c\u2e8e\u201d (U+2E8E), or \u201c\u2714\u201d (U+2714)) are present.  Everybody should be thankful to the Apache Software Foundation and all the POI contributors for their assistance in this matter.\r";
+
+       private String illustrativeDocFile;
+
+       protected void setUp() throws Exception {
+
+               String dirname = System.getProperty("HWPF.testdata.path");
+
+               illustrativeDocFile = dirname + "/testRangeReplacement.doc";
+       }
+
+       /**
+        * Test just opening the files
+        */
+       public void testOpen() throws Exception {
+
+               HWPFDocument docA = new HWPFDocument(new FileInputStream(illustrativeDocFile));
+       }
+
+       /**
+        * Test (more "confirm" than test) that we have the general structure that we expect to have.
+        */
+       public void testDocStructure() throws Exception {
+
+               HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile));
+
+               Range range = daDoc.getRange();
+
+               assertEquals(1, range.numSections());
+               Section section = range.getSection(0);
+
+               assertEquals(5, section.numParagraphs());
+               Paragraph para = section.getParagraph(2);
+
+               assertEquals(5, para.numCharacterRuns());
+               String text = para.getCharacterRun(0).text() + para.getCharacterRun(1).text() +
+                       para.getCharacterRun(2).text() + para.getCharacterRun(3).text() + para.getCharacterRun(4).text();
+
+               assertEquals(originalText, text);
+       }
+
+       /**
+        * Test that we can replace text in our Range with Unicode text.
+        */
+       public void testRangeReplacement() throws Exception {
+
+               HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile));
+
+               Range range = daDoc.getRange();
+               assertEquals(1, range.numSections());
+
+               Section section = range.getSection(0);
+               assertEquals(5, section.numParagraphs());
+
+               Paragraph para = section.getParagraph(2);
+
+               String text = para.text();
+               assertEquals(originalText, text);
+
+               int offset = text.indexOf(searchText);
+               assertEquals(181, offset);
+
+               para.replaceText(searchText, replacementText, offset);
+
+               // we need to let the model re-calculate the Range before we evaluate it
+               range = daDoc.getRange();
+
+               assertEquals(1, range.numSections());
+               section = range.getSection(0);
+
+               assertEquals(5, section.numParagraphs());
+               para = section.getParagraph(2);
+
+               text = para.text();
+               assertEquals(expectedText, text);
+       }
+}
diff --git a/src/testcases/org/apache/poi/hssf/data/30978-alt.xls b/src/testcases/org/apache/poi/hssf/data/30978-alt.xls
new file mode 100644 (file)
index 0000000..c591582
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/30978-alt.xls differ
index afc44e7043e0d1e8a9e00b041fa8d1d4f153cc68..1eb052bec7aef725bf71716dd9862ff1edac1c86 100644 (file)
 
 package org.apache.poi.hssf.record;
 
+import junit.framework.AssertionFailedError;
 import junit.framework.TestCase;
 
 import org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator;
 import org.apache.poi.hssf.record.cf.BorderFormatting;
 import org.apache.poi.hssf.record.cf.FontFormatting;
 import org.apache.poi.hssf.record.cf.PatternFormatting;
+import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.hssf.record.formula.RefNPtg;
+import org.apache.poi.hssf.record.formula.RefPtg;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.hssf.util.HSSFColor;
 import org.apache.poi.util.LittleEndian;
@@ -296,7 +300,57 @@ public final class TestCFRuleRecord extends TestCase
                // check all remaining flag bits (some are not well understood yet)
                assertEquals(0x203FFFFF, flags);
        }
+       
+       private static final byte[] DATA_REFN = {
+               // formula extracted from bugzilla 45234 att 22141
+               1, 3, 
+               9, // formula 1 length 
+               0, 0, 0, -1, -1, 63, 32, 2, -128, 0, 0, 0, 5,
+               // formula 1: "=B3=1" (formula is relative to B4)
+               76, -1, -1, 0, -64, // tRefN(B1)
+               30, 1, 0,       
+               11,     
+       };
+
+       /**
+        * tRefN and tAreaN tokens must be preserved when re-serializing conditional format formulas
+        */
+       public void testReserializeRefNTokens() {
+               
+               RecordInputStream is = new TestcaseRecordInputStream(CFRuleRecord.sid, DATA_REFN);
+               CFRuleRecord rr = new CFRuleRecord(is);
+               Ptg[] ptgs = rr.getParsedExpression1();
+               assertEquals(3, ptgs.length);
+               if (ptgs[0] instanceof RefPtg) {
+                       throw new AssertionFailedError("Identified bug 45234");
+               }
+               assertEquals(RefNPtg.class, ptgs[0].getClass());
+               RefNPtg refNPtg = (RefNPtg) ptgs[0];
+               assertTrue(refNPtg.isColRelative());
+               assertTrue(refNPtg.isRowRelative());
+               
+               byte[] data = rr.serialize();
+               
+               if (!compareArrays(DATA_REFN, 0, data, 4, DATA_REFN.length)) {
+                       fail("Did not re-serialize correctly");
+               }
+       }
 
+       private static boolean compareArrays(byte[] arrayA, int offsetA, byte[] arrayB, int offsetB, int length) {
+               
+               if (offsetA + length > arrayA.length) {
+                       return false;
+               }
+               if (offsetB + length > arrayB.length) {
+                       return false;
+               }
+               for (int i = 0; i < length; i++) {
+                       if (arrayA[i+offsetA] != arrayB[i+offsetB]) {
+                               return false;
+                       }
+               }
+               return true;
+       }
 
        public static void main(String[] ignored_args)
        {
index 419bc33bb46322dc1b6f25b1558497af20726855..79ef47be38ddd51e0fe6d8df86384fef767a0057 100644 (file)
@@ -30,7 +30,10 @@ import junit.framework.TestCase;
 import org.apache.poi.ss.util.Region;
 
 import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.model.Workbook;
 import org.apache.poi.hssf.record.EmbeddedObjectRefSubRecord;
+import org.apache.poi.hssf.record.NameRecord;
+import org.apache.poi.hssf.record.formula.DeletedArea3DPtg;
 import org.apache.poi.util.TempFile;
 
 /**
@@ -990,4 +993,63 @@ public final class TestBugs extends TestCase {
                fail();
         } catch(FileNotFoundException e) {}
     }
+    
+    /**
+     * Test that we can delete sheets without
+     *  breaking the build in named ranges
+     *  used for printing stuff.
+     * Currently broken, as we change the Ptg
+     */
+    public void test30978() throws Exception {
+        HSSFWorkbook wb = openSample("30978-alt.xls");
+        assertEquals(1, wb.getNumberOfNames());
+        assertEquals(3, wb.getNumberOfSheets());
+        
+        // Check all names fit within range, and use
+        //  DeletedArea3DPtg
+        Workbook w = wb.getWorkbook();
+        for(int i=0; i<w.getNumNames(); i++) {
+               NameRecord r = w.getNameRecord(i);
+               assertTrue(r.getIndexToSheet() <= wb.getNumberOfSheets());
+               
+               List nd = r.getNameDefinition();
+               assertEquals(1, nd.size());
+               assertTrue(nd.get(0) instanceof DeletedArea3DPtg);
+        }
+        
+        
+        // Delete the 2nd sheet
+        wb.removeSheetAt(1);
+        
+        
+        // Re-check
+        assertEquals(1, wb.getNumberOfNames());
+        assertEquals(2, wb.getNumberOfSheets());
+        
+        for(int i=0; i<w.getNumNames(); i++) {
+               NameRecord r = w.getNameRecord(i);
+               assertTrue(r.getIndexToSheet() <= wb.getNumberOfSheets());
+               
+               List nd = r.getNameDefinition();
+               assertEquals(1, nd.size());
+               assertTrue(nd.get(0) instanceof DeletedArea3DPtg);
+        }
+        
+        
+        // Save and re-load
+        wb = writeOutAndReadBack(wb);
+        w = wb.getWorkbook();
+        
+        assertEquals(1, wb.getNumberOfNames());
+        assertEquals(2, wb.getNumberOfSheets());
+        
+        for(int i=0; i<w.getNumNames(); i++) {
+               NameRecord r = w.getNameRecord(i);
+               assertTrue(r.getIndexToSheet() <= wb.getNumberOfSheets());
+               
+               List nd = r.getNameDefinition();
+               assertEquals(1, nd.size());
+               assertTrue(nd.get(0) instanceof DeletedArea3DPtg);
+        }
+    }
 }