poi-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From n...@apache.org
Subject svn commit: r676209 - in /poi/branches/ooxml: ./ src/documentation/content/xdocs/ src/documentation/content/xdocs/spreadsheet/ src/java/org/apache/poi/hssf/model/ src/java/org/apache/poi/hssf/record/ src/java/org/apache/poi/hssf/record/formula/function...
Date Sat, 12 Jul 2008 18:17:17 GMT
Author: nick
Date: Sat Jul 12 11:17:16 2008
New Revision: 676209

URL: http://svn.apache.org/viewvc?rev=676209&view=rev
Log:
Merged revisions 638786-638802,638805-638811,638813-638814,638816-639230,639233-639241,639243-639253,639255-639486,639488-639601,639603-639835,639837-639917,639919-640056,640058-640710,640712-641156,641158-641184,641186-641795,641797-641798,641800-641933,641935-641963,641965-641966,641968-641995,641997-642230,642232-642562,642564-642565,642568-642570,642572-642573,642576-642736,642739-642877,642879,642881-642890,642892-642903,642905-642945,642947-643624,643626-643653,643655-643669,643671,643673-643830,643832-643833,643835-644342,644344-644472,644474-644508,644510-645347,645349-645351,645353-645559,645561-645565,645568-645951,645953-646193,646195-646311,646313-646404,646406-646665,646667-646853,646855-646869,646871-647151,647153-647185,647187-647277,647279-647566,647568-647573,647575,647578-647711,647714-647737,647739-647823,647825-648155,648157-648202,648204-648273,648275,648277-648302,648304-648333,648335-648588,648590-648622,648625-648673,648675-649141,649144,649146-649556,
 649558-649795,649799,649801-649910,649912-649913,649915-650128,650131-650132,650134-650137,650140-650914,650916-651991,651993-652284,652286-652287,652289,652291,652293-652297,652299-652328,652330-652425,652427-652445,652447-652560,652562-652933,652935,652937-652993,652995-653116,653118-653124,653126-653483,653487-653519,653522-653550,653552-653607,653609-653667,653669-653674,653676-653814,653817-653830,653832-653891,653893-653944,653946-654055,654057-654355,654357-654365,654367-654648,654651-655215,655217-655277,655279-655281,655283-655911,655913-656212,656214,656216-656251,656253-656698,656700-656756,656758-656892,656894-657135,657137-657165,657168-657179,657181-657354,657356-657357,657359-657701,657703-657874,657876-658032,658034-658284,658286,658288-658301,658303-658307,658309-658321,658323-658335,658337-658348,658351,658353-658832,658834-658983,658985,658987-659066,659068-659402,659404-659428,659430-659451,659453-659454,659456-659461,659463-659477,659479-659524,659526-65
 9571,659574,659576-660255,660257-660262,660264-660279,660281-660343,660345-660473,660475-660827,660829-660833,660835-660888,660890-663321,663323-663435,663437-663764,663766-663854,663856-664219,664221-664489,664494-664514,664516-668013,668015-668142,668144-668152,668154,668156-668256,668258,668260-669139,669141-669455,669457-669657,669659-669808,669810-670189,670191-671321,671323-672229,672231-672549,672551-672552,672554-672561,672563-672566,672568,672571-673049,673051-673852,673854-673862,673864-673986,673988-673996,673998-674347,674349-674890,674892-674910,674912-674936,674938-674952,674954-675078,675080-675085,675087-675217,675219-675660,675662-675670,675672-675716,675718-675726,675728-675733,675735-675775,675777-675782,675784,675786-675791,675794-676205 via svnmerge from 
https://svn.apache.org:443/repos/asf/poi/trunk

........
  r675853 | josh | 2008-07-11 08:59:44 +0100 (Fri, 11 Jul 2008) | 1 line
  
  Patch 45289 - finished support for special comparison operators in COUNTIF
........
  r676201 | nick | 2008-07-12 17:56:55 +0100 (Sat, 12 Jul 2008) | 1 line
  
  Support for cloning one font record onto another, plus tests
........
  r676203 | nick | 2008-07-12 18:21:54 +0100 (Sat, 12 Jul 2008) | 1 line
  
  Support for cloning one extended format record onto another, plus tests
........
  r676205 | nick | 2008-07-12 18:38:10 +0100 (Sat, 12 Jul 2008) | 1 line
  
  Allow the cloning of one HSSFCellStyle onto another, including cloning styles from one HSSFWorkbook onto another
........

Added:
    poi/branches/ooxml/src/testcases/org/apache/poi/hssf/data/countifExamples.xls
      - copied unchanged from r676205, poi/trunk/src/testcases/org/apache/poi/hssf/data/countifExamples.xls
    poi/branches/ooxml/src/testcases/org/apache/poi/hssf/model/TestWorkbook.java
      - copied unchanged from r676205, poi/trunk/src/testcases/org/apache/poi/hssf/model/TestWorkbook.java
    poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/TestExtendedFormatRecord.java
      - copied unchanged from r676205, poi/trunk/src/testcases/org/apache/poi/hssf/record/TestExtendedFormatRecord.java
    poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/TestFontRecord.java
      - copied unchanged from r676205, poi/trunk/src/testcases/org/apache/poi/hssf/record/TestFontRecord.java
Modified:
    poi/branches/ooxml/   (props changed)
    poi/branches/ooxml/src/documentation/content/xdocs/changes.xml
    poi/branches/ooxml/src/documentation/content/xdocs/spreadsheet/converting.xml
    poi/branches/ooxml/src/documentation/content/xdocs/status.xml
    poi/branches/ooxml/src/java/org/apache/poi/hssf/model/Workbook.java
    poi/branches/ooxml/src/java/org/apache/poi/hssf/record/ExtendedFormatRecord.java
    poi/branches/ooxml/src/java/org/apache/poi/hssf/record/FontRecord.java
    poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/Countif.java
    poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/Offset.java
    poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
    poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java
    poi/branches/ooxml/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/CellStyle.java
    poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java
    poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCellStyle.java
    poi/branches/ooxml/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFCell.java
    poi/branches/ooxml/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFCellStyle.java
    poi/branches/ooxml/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls
    poi/branches/ooxml/src/testcases/org/apache/poi/hssf/model/AllModelTests.java
    poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java
    poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java
    poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestCellStyle.java
    poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java

Propchange: poi/branches/ooxml/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Sat Jul 12 11:17:16 2008
@@ -1 +1 @@
-/poi/trunk:1-638784,638786-639486,639488-639601,639603-640056,640058-642562,642564-642566,642568-642574,642576-642736,642739-650914,650916-675794
+/poi/trunk:1-638784,638786-639486,639488-639601,639603-640056,640058-642562,642564-642566,642568-642574,642576-642736,642739-650914,650916-676205

Modified: poi/branches/ooxml/src/documentation/content/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/documentation/content/xdocs/changes.xml?rev=676209&r1=676208&r2=676209&view=diff
==============================================================================
--- poi/branches/ooxml/src/documentation/content/xdocs/changes.xml (original)
+++ poi/branches/ooxml/src/documentation/content/xdocs/changes.xml Sat Jul 12 11:17:16 2008
@@ -50,6 +50,8 @@
            <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.1-alpha1" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="add">Allow the cloning of one HSSFCellStyle onto another, including cloning styles from one HSSFWorkbook onto another</action>
+           <action dev="POI-DEVELOPERS" type="fix">45289 - finished support for special comparison operators in COUNTIF</action>
            <action dev="POI-DEVELOPERS" type="fix">45126 - Avoid generating multiple NamedRanges with the same name, which Excel dislikes</action>
            <action dev="POI-DEVELOPERS" type="fix">Fix cell.getRichStringCellValue() for formula cells with string results</action>
            <action dev="POI-DEVELOPERS" type="fix">45365 - Handle more excel number formatting rules in FormatTrackingHSSFListener / XLS2CSVmra</action>

Modified: poi/branches/ooxml/src/documentation/content/xdocs/spreadsheet/converting.xml
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/documentation/content/xdocs/spreadsheet/converting.xml?rev=676209&r1=676208&r2=676209&view=diff
==============================================================================
--- poi/branches/ooxml/src/documentation/content/xdocs/spreadsheet/converting.xml (original)
+++ poi/branches/ooxml/src/documentation/content/xdocs/spreadsheet/converting.xml Sat Jul 12 11:17:16 2008
@@ -27,7 +27,21 @@
         </authors>
     </header>
   <body>
-    <section><title>Converting existing HSSF Usermodel code to SS Usermodel (for XSSF and HSSF)</title>
+<section><title>Things that have to be changed when upgrading to POI 3.5</title>
+	<p>Wherever possible, we have tried to ensure that you can use your
+     existing POI code with POI 3.5 without requiring any changes. However,
+     Java doesn't always make that easy, and unfortunately there are a 
+     few changes that may be required for some users.</p>
+    <section><title>org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue</title>
+       <p>Annoyingly, java will not let you access a static inner class via
+        a child of the parent one. So, all references to
+        <em>org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue</em>
+        will need to be changed to
+        <em>org.apache.poi.ss.usermodel.FormulaEvaluator.CellValue</em>
+       </p>
+    </section>
+</section>
+<section><title>Converting existing HSSF Usermodel code to SS Usermodel (for XSSF and HSSF)</title>
 
         <section><title>Why change?</title>
             <p>If you have existing HSSF usermodel code that works just

Modified: poi/branches/ooxml/src/documentation/content/xdocs/status.xml
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/documentation/content/xdocs/status.xml?rev=676209&r1=676208&r2=676209&view=diff
==============================================================================
--- poi/branches/ooxml/src/documentation/content/xdocs/status.xml (original)
+++ poi/branches/ooxml/src/documentation/content/xdocs/status.xml Sat Jul 12 11:17:16 2008
@@ -47,6 +47,8 @@
            <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.1-alpha1" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="add">Allow the cloning of one HSSFCellStyle onto another, including cloning styles from one HSSFWorkbook onto another</action>
+           <action dev="POI-DEVELOPERS" type="fix">45289 - finished support for special comparison operators in COUNTIF</action>
            <action dev="POI-DEVELOPERS" type="fix">45126 - Avoid generating multiple NamedRanges with the same name, which Excel dislikes</action>
            <action dev="POI-DEVELOPERS" type="fix">Fix cell.getRichStringCellValue() for formula cells with string results</action>
            <action dev="POI-DEVELOPERS" type="fix">45365 - Handle more excel number formatting rules in FormatTrackingHSSFListener / XLS2CSVmra</action>

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/model/Workbook.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/model/Workbook.java?rev=676209&r1=676208&r2=676209&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/model/Workbook.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/model/Workbook.java Sat Jul 12 11:17:16 2008
@@ -408,6 +408,24 @@
 
         return retval;
     }
+    
+    /**
+     * Retrieves the index of the given font
+     */
+    public int getFontIndex(FontRecord font) {
+    	for(int i=0; i<=numfonts; i++) {
+            FontRecord thisFont =
+                ( FontRecord ) records.get((records.getFontpos() - (numfonts - 1)) + i);
+            if(thisFont == font) {
+            	// There is no 4!
+            	if(i > 3) {
+            		return (i+1);
+            	}
+            	return i;
+            }
+    	}
+    	throw new IllegalArgumentException("Could not find that font!"); 
+    }
 
     /**
      * creates a new font record and adds it to the "font table".  This causes the

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/ExtendedFormatRecord.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/record/ExtendedFormatRecord.java?rev=676209&r1=676208&r2=676209&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/record/ExtendedFormatRecord.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/record/ExtendedFormatRecord.java Sat Jul 12 11:17:16 2008
@@ -1814,6 +1814,27 @@
     {
         return sid;
     }
+    
+    /**
+     * Clones all the style information from another
+     *  ExtendedFormatRecord, onto this one. This 
+     *  will then hold all the same style options.
+     *  
+     * If The source ExtendedFormatRecord comes from
+     *  a different Workbook, you will need to sort
+     *  out the font and format indicies yourself!
+     */
+    public void cloneStyleFrom(ExtendedFormatRecord source) {
+        field_1_font_index           = source.field_1_font_index;
+        field_2_format_index         = source.field_2_format_index;
+        field_3_cell_options         = source.field_3_cell_options;
+        field_4_alignment_options    = source.field_4_alignment_options;
+        field_5_indention_options    = source.field_5_indention_options;
+        field_6_border_options       = source.field_6_border_options;
+        field_7_palette_options      = source.field_7_palette_options;
+        field_8_adtl_palette_options = source.field_8_adtl_palette_options;
+        field_9_fill_palette_options = source.field_9_fill_palette_options;
+    }
 
 	public int hashCode() {
 		final int prime = 31;

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/FontRecord.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/record/FontRecord.java?rev=676209&r1=676208&r2=676209&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/record/FontRecord.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/record/FontRecord.java Sat Jul 12 11:17:16 2008
@@ -531,6 +531,8 @@
 
     public int getRecordSize()
     {
+    	// Note - no matter the original, we always
+    	//  re-serialise the font name as unicode
         return (getFontNameLength() * 2) + 20;
     }
 
@@ -538,6 +540,25 @@
     {
         return sid;
     }
+    
+    /**
+     * Clones all the font style information from another
+     *  FontRecord, onto this one. This 
+     *  will then hold all the same font style options.
+     */
+    public void cloneStyleFrom(FontRecord source) {
+        field_1_font_height         = source.field_1_font_height; 
+        field_2_attributes          = source.field_2_attributes;
+        field_3_color_palette_index = source.field_3_color_palette_index;
+        field_4_bold_weight         = source.field_4_bold_weight;
+        field_5_super_sub_script    = source.field_5_super_sub_script;
+        field_6_underline           = source.field_6_underline;
+        field_7_family              = source.field_7_family;
+        field_8_charset             = source.field_8_charset;
+        field_9_zero                = source.field_9_zero;
+        field_10_font_name_len      = source.field_10_font_name_len;
+        field_11_font_name          = source.field_11_font_name;
+    }
 
 	public int hashCode() {
 		final int prime = 31;

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/Countif.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/Countif.java?rev=676209&r1=676208&r2=676209&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/Countif.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/Countif.java Sat Jul 12 11:17:16 2008
@@ -15,14 +15,17 @@
 * limitations under the License.
 */
 
-
 package org.apache.poi.hssf.record.formula.functions;
 
+import java.util.regex.Pattern;
+
 import org.apache.poi.hssf.record.formula.eval.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.BlankEval;
 import org.apache.poi.hssf.record.formula.eval.BoolEval;
 import org.apache.poi.hssf.record.formula.eval.ErrorEval;
 import org.apache.poi.hssf.record.formula.eval.Eval;
 import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.OperandResolver;
 import org.apache.poi.hssf.record.formula.eval.RefEval;
 import org.apache.poi.hssf.record.formula.eval.StringEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
@@ -40,85 +43,288 @@
  * @author Josh Micich
  */
 public final class Countif implements Function {
-	
+
+	private static final class CmpOp {
+		public static final int NONE = 0;
+		public static final int EQ = 1;
+		public static final int NE = 2;
+		public static final int LE = 3;
+		public static final int LT = 4;
+		public static final int GT = 5;
+		public static final int GE = 6;
+
+		public static final CmpOp OP_NONE = op("", NONE);
+		public static final CmpOp OP_EQ = op("=", EQ);
+		public static final CmpOp OP_NE = op("<>", NE);
+		public static final CmpOp OP_LE = op("<=", LE);
+		public static final CmpOp OP_LT = op("<", LT);
+		public static final CmpOp OP_GT = op(">", GT);
+		public static final CmpOp OP_GE = op(">=", GE);
+		private final String _representation;
+		private final int _code;
+
+		private static CmpOp op(String rep, int code) {
+			return new CmpOp(rep, code);
+		}
+		private CmpOp(String representation, int code) {
+			_representation = representation;
+			_code = code;
+		}
+		/**
+		 * @return number of characters used to represent this operator
+		 */
+		public int getLength() {
+			return _representation.length();
+		}
+		public int getCode() {
+			return _code;
+		}
+		public static CmpOp getOperator(String value) {
+			int len = value.length();
+			if (len < 1) {
+				return OP_NONE;
+			}
+
+			char firstChar = value.charAt(0);
+
+			switch(firstChar) {
+				case '=':
+					return OP_EQ;
+				case '>':
+					if (len > 1) {
+						switch(value.charAt(1)) {
+							case '=':
+								return OP_GE;
+						}
+					}
+					return OP_GT;
+				case '<':
+					if (len > 1) {
+						switch(value.charAt(1)) {
+							case '=':
+								return OP_LE;
+							case '>':
+								return OP_NE;
+						}
+					}
+					return OP_LT;
+			}
+			return OP_NONE;
+		}
+		public boolean evaluate(boolean cmpResult) {
+			switch (_code) {
+				case NONE:
+				case EQ:
+					return cmpResult;
+				case NE:
+					return !cmpResult;
+			}
+			throw new RuntimeException("Cannot call boolean evaluate on non-equality operator '" 
+					+ _representation + "'");
+		}
+		public boolean evaluate(int cmpResult) {
+			switch (_code) {
+				case NONE:
+				case EQ:
+					return cmpResult == 0;
+				case NE: return cmpResult == 0;
+				case LT: return cmpResult <  0;
+				case LE: return cmpResult <= 0;
+				case GT: return cmpResult >  0;
+				case GE: return cmpResult <= 0;
+			}
+			throw new RuntimeException("Cannot call boolean evaluate on non-equality operator '" 
+					+ _representation + "'");
+		}
+		public String toString() {
+			StringBuffer sb = new StringBuffer(64);
+			sb.append(getClass().getName());
+			sb.append(" [").append(_representation).append("]");
+			return sb.toString();
+		}
+	}
+
 	/**
 	 * Common interface for the matching criteria.
 	 */
-	private interface I_MatchPredicate {
+	/* package */ interface I_MatchPredicate {
 		boolean matches(Eval x);
 	}
-	
+
 	private static final class NumberMatcher implements I_MatchPredicate {
 
 		private final double _value;
+		private final CmpOp _operator;
 
-		public NumberMatcher(double value) {
+		public NumberMatcher(double value, CmpOp operator) {
 			_value = value;
+			_operator = operator;
 		}
 
 		public boolean matches(Eval x) {
+			double testValue;
 			if(x instanceof StringEval) {
 				// if the target(x) is a string, but parses as a number
 				// it may still count as a match
 				StringEval se = (StringEval)x;
-				Double val = parseDouble(se.getStringValue());
+				Double val = OperandResolver.parseDouble(se.getStringValue());
 				if(val == null) {
 					// x is text that is not a number
 					return false;
 				}
-				return val.doubleValue() == _value;
-			}
-			if(!(x instanceof NumberEval)) {
+				testValue = val.doubleValue();
+			} else if((x instanceof NumberEval)) {
+				NumberEval ne = (NumberEval) x;
+				testValue = ne.getNumberValue();
+			} else {
 				return false;
 			}
-			NumberEval ne = (NumberEval) x;
-			return ne.getNumberValue() == _value;
+			return _operator.evaluate(Double.compare(testValue, _value));
 		}
 	}
 	private static final class BooleanMatcher implements I_MatchPredicate {
 
-		private final boolean _value;
+		private final int _value;
+		private final CmpOp _operator;
 
-		public BooleanMatcher(boolean value) {
-			_value = value;
+		public BooleanMatcher(boolean value, CmpOp operator) {
+			_value = boolToInt(value);
+			_operator = operator;
+		}
+
+		private static int boolToInt(boolean value) {
+			return value ? 1 : 0;
 		}
 
 		public boolean matches(Eval x) {
+			int testValue;
 			if(x instanceof StringEval) {
+				if (true) { // change to false to observe more intuitive behaviour
+					// Note - Unlike with numbers, it seems that COUNTIF never matches 
+					// boolean values when the target(x) is a string
+					return false;
+				}
 				StringEval se = (StringEval)x;
 				Boolean val = parseBoolean(se.getStringValue());
 				if(val == null) {
 					// x is text that is not a boolean
 					return false;
 				}
-				if (true) { // change to false to observe more intuitive behaviour
-					// Note - Unlike with numbers, it seems that COUNTA never matches 
-					// boolean values when the target(x) is a string
-					return false;
-				}
-				return val.booleanValue() == _value;
-			}
-			if(!(x instanceof BoolEval)) {
+				testValue = boolToInt(val.booleanValue());
+			} else if((x instanceof BoolEval)) {
+				BoolEval be = (BoolEval) x;
+				testValue = boolToInt(be.getBooleanValue());
+			} else {
 				return false;
 			}
-			BoolEval be = (BoolEval) x;
-			return be.getBooleanValue() == _value;
+			return _operator.evaluate(testValue - _value);
 		}
 	}
 	private static final class StringMatcher implements I_MatchPredicate {
 
 		private final String _value;
+		private final CmpOp _operator;
+		private final Pattern _pattern;
 
-		public StringMatcher(String value) {
+		public StringMatcher(String value, CmpOp operator) {
 			_value = value;
+			_operator = operator;
+			switch(operator.getCode()) {
+				case CmpOp.NONE:
+				case CmpOp.EQ:
+				case CmpOp.NE:
+					_pattern = getWildCardPattern(value);
+					break;
+				default:
+					_pattern = null;
+			}
 		}
 
 		public boolean matches(Eval x) {
+			if (x instanceof BlankEval) {
+				switch(_operator.getCode()) {
+					case CmpOp.NONE:
+					case CmpOp.EQ:
+						return _value.length() == 0;
+				}
+				// no other criteria matches a blank cell
+				return false;
+			}
 			if(!(x instanceof StringEval)) {
+				// must always be string
+				// even if match str is wild, but contains only digits
+				// e.g. '4*7', NumberEval(4567) does not match
 				return false;
 			}
-			StringEval se = (StringEval) x;
-			return se.getStringValue() == _value;
+			String testedValue = ((StringEval) x).getStringValue();
+			if (testedValue.length() < 1 && _value.length() < 1) {
+				// odd case: criteria '=' behaves differently to criteria ''
+
+				switch(_operator.getCode()) {
+					case CmpOp.NONE: return true;
+					case CmpOp.EQ:   return false;
+					case CmpOp.NE:   return true;
+				}
+				return false;
+			}
+			if (_pattern != null) {
+				return _operator.evaluate(_pattern.matcher(testedValue).matches());
+			}
+			return _operator.evaluate(testedValue.compareTo(_value));
+		}
+		/**
+		 * Translates Excel countif wildcard strings into java regex strings
+		 * @return <code>null</code> if the specified value contains no special wildcard characters.
+		 */
+		private static Pattern getWildCardPattern(String value) {
+			int len = value.length();
+			StringBuffer sb = new StringBuffer(len);
+			boolean hasWildCard = false;
+			for(int i=0; i<len; i++) {
+				char ch = value.charAt(i);
+				switch(ch) {
+					case '?':
+						hasWildCard = true;
+						// match exactly one character
+						sb.append('.');
+						continue;
+					case '*':
+						hasWildCard = true;
+						// match one or more occurrences of any character
+						sb.append(".*");
+						continue;
+					case '~':
+						if (i+1<len) {
+							ch = value.charAt(i+1);
+							switch (ch) {
+								case '?':
+								case '*':
+									hasWildCard = true;
+									sb.append('[').append(ch).append(']');
+									i++; // Note - incrementing loop variable here
+									continue;
+							}
+						}
+						// else not '~?' or '~*'
+						sb.append('~'); // just plain '~'
+						continue;
+					case '.':
+					case '$':
+					case '^':
+					case '[':
+					case ']':
+					case '(':
+					case ')':
+						// escape literal characters that would have special meaning in regex 
+						sb.append("\\").append(ch);
+						continue;
+				}
+				sb.append(ch);
+			}
+			if (hasWildCard) {
+				return Pattern.compile(sb.toString());
+			}
+			return null;
 		}
 	}
 
@@ -132,8 +338,7 @@
 				// perhaps this should be an exception
 				return ErrorEval.VALUE_INVALID;
 		}
-		
-		AreaEval range = (AreaEval) args[0];
+
 		Eval criteriaArg = args[1];
 		if(criteriaArg instanceof RefEval) {
 			// criteria is not a literal value, but a cell reference
@@ -144,31 +349,47 @@
 			// other non literal tokens such as function calls, have been fully evaluated
 			// for example COUNTIF(B2:D4, COLUMN(E1))
 		}
+		if(criteriaArg instanceof BlankEval) {
+			// If the criteria arg is a reference to a blank cell, countif always returns zero.
+			return NumberEval.ZERO;
+		}
 		I_MatchPredicate mp = createCriteriaPredicate(criteriaArg);
-		return countMatchingCellsInArea(range, mp);
+		return countMatchingCellsInArea(args[0], mp);
 	}
 	/**
 	 * @return the number of evaluated cells in the range that match the specified criteria
 	 */
-	private Eval countMatchingCellsInArea(AreaEval range, I_MatchPredicate criteriaPredicate) {
-		ValueEval[] values = range.getValues();
+	private Eval countMatchingCellsInArea(Eval rangeArg, I_MatchPredicate criteriaPredicate) {
 		int result = 0;
-		for (int i = 0; i < values.length; i++) {
-			if(criteriaPredicate.matches(values[i])) {
+		if (rangeArg instanceof RefEval) {
+			RefEval refEval = (RefEval) rangeArg;
+			if(criteriaPredicate.matches(refEval.getInnerValueEval())) {
 				result++;
 			}
+		} else if (rangeArg instanceof AreaEval) {
+
+			AreaEval range = (AreaEval) rangeArg;
+			ValueEval[] values = range.getValues();
+			for (int i = 0; i < values.length; i++) {
+				if(criteriaPredicate.matches(values[i])) {
+					result++;
+				}
+			}
+		} else {
+			throw new IllegalArgumentException("Bad range arg type (" + rangeArg.getClass().getName() + ")");
 		}
 		return new NumberEval(result);
 	}
-	
-	private static I_MatchPredicate createCriteriaPredicate(Eval evaluatedCriteriaArg) {
+
+	/* package */ static I_MatchPredicate createCriteriaPredicate(Eval evaluatedCriteriaArg) {
+
 		if(evaluatedCriteriaArg instanceof NumberEval) {
-			return new NumberMatcher(((NumberEval)evaluatedCriteriaArg).getNumberValue());
+			return new NumberMatcher(((NumberEval)evaluatedCriteriaArg).getNumberValue(), CmpOp.OP_NONE);
 		}
 		if(evaluatedCriteriaArg instanceof BoolEval) {
-			return new BooleanMatcher(((BoolEval)evaluatedCriteriaArg).getBooleanValue());
+			return new BooleanMatcher(((BoolEval)evaluatedCriteriaArg).getBooleanValue(), CmpOp.OP_NONE);
 		}
-		
+
 		if(evaluatedCriteriaArg instanceof StringEval) {
 			return createGeneralMatchPredicate((StringEval)evaluatedCriteriaArg);
 		}
@@ -181,50 +402,29 @@
 	 */
 	private static I_MatchPredicate createGeneralMatchPredicate(StringEval stringEval) {
 		String value = stringEval.getStringValue();
-		char firstChar = value.charAt(0);
+		CmpOp operator = CmpOp.getOperator(value);
+		value = value.substring(operator.getLength());
+
 		Boolean booleanVal = parseBoolean(value);
 		if(booleanVal != null) {
-			return new BooleanMatcher(booleanVal.booleanValue());
+			return new BooleanMatcher(booleanVal.booleanValue(), operator);
 		}
-		
-		Double doubleVal = parseDouble(value);
+
+		Double doubleVal = OperandResolver.parseDouble(value);
 		if(doubleVal != null) {
-			return new NumberMatcher(doubleVal.doubleValue());
+			return new NumberMatcher(doubleVal.doubleValue(), operator);
 		}
-		switch(firstChar) {
-			case '>':
-			case '<':
-			case '=':
-				throw new RuntimeException("Incomplete code - criteria expressions such as '"
-						+ value + "' not supported yet");
-		}
-		
-		//else - just a plain string with no interpretation.
-		return new StringMatcher(value);
-	}
 
-	/**
-	 * Under certain circumstances COUNTA will equate a plain number with a string representation of that number
-	 */
-	/* package */ static Double parseDouble(String strRep) {
-		if(!Character.isDigit(strRep.charAt(0))) {
-			// avoid using NumberFormatException to tell when string is not a number
-			return null;
-		}
-		// TODO - support notation like '1E3' (==1000)
-		
-		double val;
-		try {
-			val = Double.parseDouble(strRep);
-		} catch (NumberFormatException e) {
-			return null;
-		}
-		return new Double(val);
+		//else - just a plain string with no interpretation.
+		return new StringMatcher(value, operator);
 	}
 	/**
 	 * Boolean literals ('TRUE', 'FALSE') treated similarly but NOT same as numbers. 
 	 */
 	/* package */ static Boolean parseBoolean(String strRep) {
+		if (strRep.length() < 1) {
+			return null;
+		}
 		switch(strRep.charAt(0)) {
 			case 't':
 			case 'T':

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/Offset.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/Offset.java?rev=676209&r1=676208&r2=676209&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/Offset.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/record/formula/functions/Offset.java Sat Jul 12 11:17:16 2008
@@ -25,7 +25,9 @@
 import org.apache.poi.hssf.record.formula.eval.BoolEval;
 import org.apache.poi.hssf.record.formula.eval.ErrorEval;
 import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
 import org.apache.poi.hssf.record.formula.eval.NumericValueEval;
+import org.apache.poi.hssf.record.formula.eval.OperandResolver;
 import org.apache.poi.hssf.record.formula.eval.Ref3DEval;
 import org.apache.poi.hssf.record.formula.eval.RefEval;
 import org.apache.poi.hssf.record.formula.eval.StringEval;
@@ -55,21 +57,6 @@
 	private static final int LAST_VALID_COLUMN_INDEX = 0xFF;
 	
 
-	/**
-	 * Exceptions are used within this class to help simplify flow control when error conditions
-	 * are encountered 
-	 */
-	private static final class EvalEx extends Exception {
-		private final ErrorEval _error;
-
-		public EvalEx(ErrorEval error) {
-			_error = error;
-		}
-		public ErrorEval getError() {
-			return _error;
-		}
-	}
-	
 	/** 
 	 * A one dimensional base + offset.  Represents either a row range or a column range.
 	 * Two instances of this class together specify an area range.
@@ -133,8 +120,7 @@
 			return sb.toString();
 		}
 	}
-	
-	
+
 	/**
 	 * Encapsulates either an area or cell reference which may be 2d or 3d.
 	 */
@@ -175,19 +161,15 @@
 		public int getWidth() {
 			return _width;
 		}
-
 		public int getHeight() {
 			return _height;
 		}
-
 		public int getFirstRowIndex() {
 			return _firstRowIndex;
 		}
-
 		public int getFirstColumnIndex() {
 			return _firstColumnIndex;
 		}
-
 		public boolean isIs3d() {
 			return _externalSheetIndex > 0;
 		}
@@ -198,7 +180,6 @@
 			}
 			return (short) _externalSheetIndex;
 		}
-
 	}
 	
 	public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, Workbook workbook, Sheet sheet) {
@@ -207,7 +188,6 @@
 			return ErrorEval.VALUE_INVALID;
 		}
 		
-		
 		try {
 			BaseRef baseRef = evaluateBaseRef(args[0]);
 			int rowOffset = evaluateIntArg(args[1], srcCellRow, srcCellCol);
@@ -227,24 +207,23 @@
 			LinearOffsetRange rowOffsetRange = new LinearOffsetRange(rowOffset, height);
 			LinearOffsetRange colOffsetRange = new LinearOffsetRange(columnOffset, width);
 			return createOffset(baseRef, rowOffsetRange, colOffsetRange, workbook, sheet);
-		} catch (EvalEx e) {
-			return e.getError();
+		} catch (EvaluationException e) {
+			return e.getErrorEval();
 		}
 	}
 
-
 	private static AreaEval createOffset(BaseRef baseRef, 
 			LinearOffsetRange rowOffsetRange, LinearOffsetRange colOffsetRange, 
-			Workbook workbook, Sheet sheet) throws EvalEx {
+			Workbook workbook, Sheet sheet) throws EvaluationException {
 
 		LinearOffsetRange rows = rowOffsetRange.normaliseAndTranslate(baseRef.getFirstRowIndex());
 		LinearOffsetRange cols = colOffsetRange.normaliseAndTranslate(baseRef.getFirstColumnIndex());
 		
 		if(rows.isOutOfBounds(0, LAST_VALID_ROW_INDEX)) {
-			throw new EvalEx(ErrorEval.REF_INVALID);
+			throw new EvaluationException(ErrorEval.REF_INVALID);
 		}
 		if(cols.isOutOfBounds(0, LAST_VALID_COLUMN_INDEX)) {
-			throw new EvalEx(ErrorEval.REF_INVALID);
+			throw new EvaluationException(ErrorEval.REF_INVALID);
 		}
 		if(baseRef.isIs3d()) {
 			Area3DPtg a3dp = new Area3DPtg(rows.getFirstIndex(), rows.getLastIndex(), 
@@ -260,8 +239,7 @@
 		return HSSFFormulaEvaluator.evaluateAreaPtg(sheet, workbook, ap);
 	}
 
-
-	private static BaseRef evaluateBaseRef(Eval eval) throws EvalEx {
+	private static BaseRef evaluateBaseRef(Eval eval) throws EvaluationException {
 		
 		if(eval instanceof RefEval) {
 			return new BaseRef((RefEval)eval);
@@ -270,16 +248,15 @@
 			return new BaseRef((AreaEval)eval);
 		}
 		if (eval instanceof ErrorEval) {
-			throw new EvalEx((ErrorEval) eval);
+			throw new EvaluationException((ErrorEval) eval);
 		}
-		throw new EvalEx(ErrorEval.VALUE_INVALID);
+		throw new EvaluationException(ErrorEval.VALUE_INVALID);
 	}
 
-
 	/**
 	 * OFFSET's numeric arguments (2..5) have similar processing rules
 	 */
-	private static int evaluateIntArg(Eval eval, int srcCellRow, short srcCellCol) throws EvalEx {
+	private static int evaluateIntArg(Eval eval, int srcCellRow, short srcCellCol) throws EvaluationException {
 
 		double d = evaluateDoubleArg(eval, srcCellRow, srcCellCol);
 		return convertDoubleToInt(d);
@@ -295,18 +272,17 @@
 		return (int)Math.floor(d);
 	}
 	
-	
-	private static double evaluateDoubleArg(Eval eval, int srcCellRow, short srcCellCol) throws EvalEx {
-		ValueEval ve = evaluateSingleValue(eval, srcCellRow, srcCellCol);
+	private static double evaluateDoubleArg(Eval eval, int srcCellRow, short srcCellCol) throws EvaluationException {
+		ValueEval ve = OperandResolver.getSingleValue(eval, srcCellRow, srcCellCol);
 		
 		if (ve instanceof NumericValueEval) {
 			return ((NumericValueEval) ve).getNumberValue();
 		}
 		if (ve instanceof StringEval) {
 			StringEval se = (StringEval) ve;
-			Double d = parseDouble(se.getStringValue());
+			Double d = OperandResolver.parseDouble(se.getStringValue());
 			if(d == null) {
-				throw new EvalEx(ErrorEval.VALUE_INVALID);
+				throw new EvaluationException(ErrorEval.VALUE_INVALID);
 			}
 			return d.doubleValue();
 		}
@@ -319,44 +295,4 @@
 		}
 		throw new RuntimeException("Unexpected eval type (" + ve.getClass().getName() + ")");
 	}
-	
-	private static Double parseDouble(String s) {
-		// TODO - find a home for this method
-		// TODO - support various number formats: sign char, dollars, commas
-		// OFFSET and COUNTIF seem to handle these
-		return Countif.parseDouble(s);
-	}
-	
-	private static ValueEval evaluateSingleValue(Eval eval, int srcCellRow, short srcCellCol) throws EvalEx {
-		if(eval instanceof RefEval) {
-			return ((RefEval)eval).getInnerValueEval();
-		}
-		if(eval instanceof AreaEval) {
-			return chooseSingleElementFromArea((AreaEval)eval, srcCellRow, srcCellCol);
-		}
-		if (eval instanceof ValueEval) {
-			return (ValueEval) eval;
-		}
-		throw new RuntimeException("Unexpected eval type (" + eval.getClass().getName() + ")");
-	}
-
-	// TODO - this code seems to get repeated a bit
-	private static ValueEval chooseSingleElementFromArea(AreaEval ae, int srcCellRow, short srcCellCol) throws EvalEx {
-		if (ae.isColumn()) {
-			if (ae.isRow()) {
-				return ae.getValues()[0];
-			}
-			if (!ae.containsRow(srcCellRow)) {
-				throw new EvalEx(ErrorEval.VALUE_INVALID);
-			}
-			return ae.getValueAt(srcCellRow, ae.getFirstColumn());
-		}
-		if (!ae.isRow()) {
-			throw new EvalEx(ErrorEval.VALUE_INVALID);
-		}
-		if (!ae.containsColumn(srcCellCol)) {
-			throw new EvalEx(ErrorEval.VALUE_INVALID);
-		}
-		return ae.getValueAt(ae.getFirstRow(), srcCellCol);
-	}
 }

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java?rev=676209&r1=676208&r2=676209&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java Sat Jul 12 11:17:16 2008
@@ -924,7 +924,13 @@
 
     public void setCellStyle(CellStyle style)
     {
-        record.setXFIndex(((HSSFCellStyle) style).getIndex());
+		HSSFCellStyle hStyle = (HSSFCellStyle)style;
+
+        // Verify it really does belong to our workbook
+        hStyle.verifyBelongsToWorkbook(book);
+
+        // Change our cell record to use this style
+        record.setXFIndex(hStyle.getIndex());
     }
 
     /**

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java?rev=676209&r1=676208&r2=676209&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java Sat Jul 12 11:17:16 2008
@@ -20,6 +20,7 @@
 
 import org.apache.poi.hssf.model.Workbook;
 import org.apache.poi.hssf.record.ExtendedFormatRecord;
+import org.apache.poi.hssf.record.FontRecord;
 import org.apache.poi.hssf.util.HSSFColor;
 import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.usermodel.Font;
@@ -295,6 +296,16 @@
     	
         return format.getFormat(getDataFormat());
     }
+    /**
+     * Get the contents of the format string, by looking up
+     *  the DataFormat against the supplied low level workbook
+     * @see org.apache.poi.hssf.usermodel.HSSFDataFormat
+     */
+    public String getDataFormatString(org.apache.poi.hssf.model.Workbook workbook) {
+    	HSSFDataFormat format = new HSSFDataFormat( workbook );
+    	
+        return format.getFormat(getDataFormat());
+    }
 
     /**
      * set the font for this style
@@ -930,6 +941,69 @@
         return format.getFillForeground();
     }
 
+    /**
+     * Verifies that this style belongs to the supplied Workbook.
+     * Will throw an exception if it belongs to a different one.
+     * This is normally called when trying to assign a style to a
+     *  cell, to ensure the cell and the style are from the same
+     *  workbook (if they're not, it won't work)
+     * @throws IllegalArgumentException if there's a workbook mis-match
+     */
+    public void verifyBelongsToWorkbook(HSSFWorkbook wb) {
+		if(wb.getWorkbook() != workbook) {
+			throw new IllegalArgumentException("This Style does not belong to the supplied Workbook. Are you trying to assign a style from one workbook to the cell of a differnt workbook?");
+		}
+	}
+    
+    /**
+     * Clones all the style information from another
+     *  HSSFCellStyle, onto this one. This 
+     *  HSSFCellStyle will then have all the same
+     *  properties as the source, but the two may
+     *  be edited independently.
+     * Any stylings on this HSSFCellStyle will be lost! 
+     *  
+     * The source HSSFCellStyle could be from another
+     *  HSSFWorkbook if you like. This allows you to
+     *  copy styles from one HSSFWorkbook to another.
+     */
+    public void cloneStyleFrom(CellStyle source) {
+		if(source instanceof HSSFCellStyle) {
+			this.cloneStyleFrom((HSSFCellStyle)source);
+		}
+		throw new IllegalArgumentException("Can only clone from one HSSFCellStyle to another, not between HSSFCellStyle and XSSFCellStyle");
+	}
+    public void cloneStyleFrom(HSSFCellStyle source) {
+    	// First we need to clone the extended format
+    	//  record
+    	format.cloneStyleFrom(source.format);
+    	
+    	// Handle matching things if we cross workbooks
+    	if(workbook != source.workbook) {
+			// Then we need to clone the format string,
+			//  and update the format record for this
+    		short fmt = workbook.createFormat(
+    				source.getDataFormatString()
+    		);
+    		setDataFormat(fmt);
+			
+			// Finally we need to clone the font,
+			//  and update the format record for this
+    		FontRecord fr = workbook.createNewFont();
+    		fr.cloneStyleFrom(
+    				source.workbook.getFontRecordAt(
+    						source.getFontIndex()
+    				)
+    		);
+    		
+    		HSSFFont font = new HSSFFont(
+    				(short)workbook.getFontIndex(fr), fr
+    		);
+    		setFont(font);
+    	}    	
+    }
+
+    
 	public int hashCode() {
 		final int prime = 31;
 		int result = 1;

Modified: poi/branches/ooxml/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/CellStyle.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/CellStyle.java?rev=676209&r1=676208&r2=676209&view=diff
==============================================================================
--- poi/branches/ooxml/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/CellStyle.java (original)
+++ poi/branches/ooxml/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/CellStyle.java Sat Jul 12 11:17:16 2008
@@ -705,4 +705,21 @@
      */
     short getFillForegroundColor();
 
-}
\ No newline at end of file
+    /**
+     * Clones all the style information from another
+     *  CellStyle, onto this one. This 
+     *  CellStyle will then have all the same
+     *  properties as the source, but the two may
+     *  be edited independently.
+     * Any stylings on this CellStyle will be lost! 
+     *  
+     * The source CellStyle could be from another
+     *  Workbook if you like. This allows you to
+     *  copy styles from one Workbook to another.
+     *
+     * However, both of the CellStyles will need
+     *  to be of the same type (HSSFCellStyle or
+     *  XSSFCellStyle)
+     */
+    public void cloneStyleFrom(CellStyle source);
+}

Modified: poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java?rev=676209&r1=676208&r2=676209&view=diff
==============================================================================
--- poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java (original)
+++ poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java Sat Jul 12 11:17:16 2008
@@ -333,8 +333,13 @@
         if(style == null) {
             this.cell.setS(0);
         } else {
+			XSSFCellStyle xStyle = (XSSFCellStyle)style;
+			xStyle.verifyBelongsToStylesSource(
+				row.getSheet().getWorkbook().getStylesSource()
+			);
+
             this.cell.setS(
-                row.getSheet().getWorkbook().getStylesSource().putStyle(style)
+                row.getSheet().getWorkbook().getStylesSource().putStyle(xStyle)
             );
         }
     }

Modified: poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCellStyle.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCellStyle.java?rev=676209&r1=676208&r2=676209&view=diff
==============================================================================
--- poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCellStyle.java (original)
+++ poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCellStyle.java Sat Jul 12 11:17:16 2008
@@ -84,6 +84,43 @@
 		cellXf = CTXf.Factory.newInstance();
     	cellStyleXf = null;
 	}
+
+	/**
+	 * Verifies that this style belongs to the supplied Workbook
+	 *  Styles Source.
+	 * Will throw an exception if it belongs to a different one.
+	 * This is normally called when trying to assign a style to a
+	 *  cell, to ensure the cell and the style are from the same
+	 *  workbook (if they're not, it won't work)
+	 * @throws IllegalArgumentException if there's a workbook mis-match
+	 */
+	public void verifyBelongsToStylesSource(StylesSource src) {
+		if(this.stylesSource != src) {
+			throw new IllegalArgumentException("This Style does not belong to the supplied Workbook Stlyes Source. Are you trying to assign a style from one workbook to the cell of a differnt workbook?");
+		}
+	}
+
+    /**
+     * Clones all the style information from another
+     *  XSSFCellStyle, onto this one. This 
+     *  XSSFCellStyle will then have all the same
+     *  properties as the source, but the two may
+     *  be edited independently.
+     * Any stylings on this XSSFCellStyle will be lost! 
+     *  
+     * The source XSSFCellStyle could be from another
+     *  XSSFWorkbook if you like. This allows you to
+     *  copy styles from one XSSFWorkbook to another.
+     */
+    public void cloneStyleFrom(CellStyle source) {
+		if(source instanceof XSSFCellStyle) {
+			this.cloneStyleFrom((XSSFCellStyle)source);
+		}
+		throw new IllegalArgumentException("Can only clone from one XSSFCellStyle to another, not between HSSFCellStyle and XSSFCellStyle");
+	}
+    public void cloneStyleFrom(XSSFCellStyle source) {
+		throw new IllegalStateException("TODO");
+	}
 	
 	public short getAlignment() {
 		return (short)getAlignmentEnum().intValue();

Modified: poi/branches/ooxml/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFCell.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFCell.java?rev=676209&r1=676208&r2=676209&view=diff
==============================================================================
--- poi/branches/ooxml/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFCell.java (original)
+++ poi/branches/ooxml/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFCell.java Sat Jul 12 11:17:16 2008
@@ -342,4 +342,41 @@
         XSSFRow row = new XSSFRow(sheet);
         return row;
     }
+
+    /**
+     * Test to ensure we can only assign cell styles that belong
+     *  to our workbook, and not those from other workbooks.
+     */
+    public void testCellStyleWorkbookMatch() throws Exception {
+    	XSSFWorkbook wbA = new XSSFWorkbook();
+    	XSSFWorkbook wbB = new XSSFWorkbook();
+    	
+    	XSSFCellStyle styA = (XSSFCellStyle)wbA.createCellStyle();
+    	XSSFCellStyle styB = (XSSFCellStyle)wbB.createCellStyle();
+    	
+    	styA.verifyBelongsToStylesSource(wbA.getStylesSource());
+    	styB.verifyBelongsToStylesSource(wbB.getStylesSource());
+    	try {
+    		styA.verifyBelongsToStylesSource(wbB.getStylesSource());
+    		fail();
+    	} catch(IllegalArgumentException e) {}
+    	try {
+    		styB.verifyBelongsToStylesSource(wbA.getStylesSource());
+    		fail();
+    	} catch(IllegalArgumentException e) {}
+    	
+    	Cell cellA = wbA.createSheet().createRow(0).createCell((short)0);
+    	Cell cellB = wbB.createSheet().createRow(0).createCell((short)0);
+    	
+    	cellA.setCellStyle(styA);
+    	cellB.setCellStyle(styB);
+    	try {
+        	cellA.setCellStyle(styB);
+    		fail();
+    	} catch(IllegalArgumentException e) {}
+    	try {
+        	cellB.setCellStyle(styA);
+    		fail();
+    	} catch(IllegalArgumentException e) {}
+    }
 }

Modified: poi/branches/ooxml/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFCellStyle.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFCellStyle.java?rev=676209&r1=676208&r2=676209&view=diff
==============================================================================
--- poi/branches/ooxml/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFCellStyle.java (original)
+++ poi/branches/ooxml/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFCellStyle.java Sat Jul 12 11:17:16 2008
@@ -273,4 +273,17 @@
 		cellStyle.setWrapText(false);
 		assertFalse(cellXf.getAlignment().getWrapText());
 	}
+
+	/**
+	 * Cloning one XSSFCellStyle onto Another, same XSSFWorkbook
+	 */
+	public void testCloneStyleSameWB() throws Exception {
+		// TODO
+	}
+	/**
+	 * Cloning one XSSFCellStyle onto Another, different XSSFWorkbooks
+	 */
+	public void testCloneStyleDiffWB() throws Exception {
+		// TODO
+	}
 }

Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls?rev=676209&r1=676208&r2=676209&view=diff
==============================================================================
Binary files - no diff available.

Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/model/AllModelTests.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/model/AllModelTests.java?rev=676209&r1=676208&r2=676209&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/model/AllModelTests.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/model/AllModelTests.java Sat Jul 12 11:17:16 2008
@@ -38,6 +38,7 @@
 		result.addTestSuite(TestRVA.class);
 		result.addTestSuite(TestSheet.class);
 		result.addTestSuite(TestSheetAdditional.class);
+		result.addTestSuite(TestWorkbook.class);
 		return result;
 	}
 }

Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java?rev=676209&r1=676208&r2=676209&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java Sat Jul 12 11:17:16 2008
@@ -61,7 +61,9 @@
 		result.addTestSuite(TestEmbeddedObjectRefSubRecord.class);
 		result.addTestSuite(TestEndSubRecord.class);
 		result.addTestSuite(TestEscherAggregate.class);
+		result.addTestSuite(TestExtendedFormatRecord.class);
 		result.addTestSuite(TestExternalNameRecord.class);
+		result.addTestSuite(TestFontRecord.class);
 		result.addTestSuite(TestFontBasisRecord.class);
 		result.addTestSuite(TestFontIndexRecord.class);
 		result.addTestSuite(TestFormulaRecord.class);

Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java?rev=676209&r1=676208&r2=676209&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java Sat Jul 12 11:17:16 2008
@@ -18,8 +18,10 @@
 
 package org.apache.poi.hssf.record.formula.functions;
 
+import junit.framework.AssertionFailedError;
 import junit.framework.TestCase;
 
+import org.apache.poi.hssf.HSSFTestDataSamples;
 import org.apache.poi.hssf.record.formula.AreaPtg;
 import org.apache.poi.hssf.record.formula.RefPtg;
 import org.apache.poi.hssf.record.formula.eval.Area2DEval;
@@ -31,6 +33,13 @@
 import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
 import org.apache.poi.hssf.record.formula.eval.StringEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.record.formula.functions.Countif.I_MatchPredicate;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.FormulaEvaluator.CellValue;
 
 /**
  * Test cases for COUNT(), COUNTA() COUNTIF(), COUNTBLANK()
@@ -146,4 +155,154 @@
 		double result = NumericFunctionInvoker.invoke(new Countif(), args);
 		assertEquals(expected, result, 0);
 	}
+	
+	public void testCountIfEmptyStringCriteria() {
+		I_MatchPredicate mp;
+		
+		// pred '=' matches blank cell but not empty string
+		mp = Countif.createCriteriaPredicate(new StringEval("="));
+		confirmPredicate(false, mp, "");
+		confirmPredicate(true, mp, null);
+
+		// pred '' matches both blank cell but not empty string
+		mp = Countif.createCriteriaPredicate(new StringEval(""));
+		confirmPredicate(true, mp, "");
+		confirmPredicate(true, mp, null);
+		
+		// pred '<>' matches empty string but not blank cell 
+		mp = Countif.createCriteriaPredicate(new StringEval("<>"));
+		confirmPredicate(false, mp, null);
+		confirmPredicate(true, mp, "");
+	}
+	
+	public void testCountifComparisons() {
+		I_MatchPredicate mp;
+		
+		mp = Countif.createCriteriaPredicate(new StringEval(">5"));
+		confirmPredicate(false, mp, 4);
+		confirmPredicate(false, mp, 5);
+		confirmPredicate(true, mp, 6);
+		
+		mp = Countif.createCriteriaPredicate(new StringEval("<=5"));
+		confirmPredicate(true, mp, 4);
+		confirmPredicate(true, mp, 5);
+		confirmPredicate(false, mp, 6);
+		confirmPredicate(true, mp, "4.9");
+		confirmPredicate(false, mp, "4.9t");
+		confirmPredicate(false, mp, "5.1");
+		confirmPredicate(false, mp, null);
+
+		mp = Countif.createCriteriaPredicate(new StringEval("=abc"));
+		confirmPredicate(true, mp, "abc");
+		
+		mp = Countif.createCriteriaPredicate(new StringEval("=42"));
+		confirmPredicate(false, mp, 41);
+		confirmPredicate(true, mp, 42);
+		confirmPredicate(true, mp, "42");
+
+		mp = Countif.createCriteriaPredicate(new StringEval(">abc"));
+		confirmPredicate(false, mp, 4);
+		confirmPredicate(false, mp, "abc");
+		confirmPredicate(true, mp, "abd");
+
+		mp = Countif.createCriteriaPredicate(new StringEval(">4t3"));
+		confirmPredicate(false, mp, 4);
+		confirmPredicate(false, mp, 500);
+		confirmPredicate(true, mp, "500");
+		confirmPredicate(true, mp, "4t4");
+	}
+	
+	public void testWildCards() {
+		I_MatchPredicate mp;
+		
+		mp = Countif.createCriteriaPredicate(new StringEval("a*b"));
+		confirmPredicate(false, mp, "abc");
+		confirmPredicate(true, mp, "ab");
+		confirmPredicate(true, mp, "axxb");
+		confirmPredicate(false, mp, "xab");
+		
+		mp = Countif.createCriteriaPredicate(new StringEval("a?b"));
+		confirmPredicate(false, mp, "abc");
+		confirmPredicate(false, mp, "ab");
+		confirmPredicate(false, mp, "axxb");
+		confirmPredicate(false, mp, "xab");
+		confirmPredicate(true, mp, "axb");
+		
+		mp = Countif.createCriteriaPredicate(new StringEval("a~?"));
+		confirmPredicate(false, mp, "a~a");
+		confirmPredicate(false, mp, "a~?");
+		confirmPredicate(true, mp, "a?");
+		
+		mp = Countif.createCriteriaPredicate(new StringEval("~*a"));
+		confirmPredicate(false, mp, "~aa");
+		confirmPredicate(false, mp, "~*a");
+		confirmPredicate(true, mp, "*a");
+
+		mp = Countif.createCriteriaPredicate(new StringEval("12?12"));
+		confirmPredicate(false, mp, 12812);
+		confirmPredicate(true, mp, "12812");
+		confirmPredicate(false, mp, "128812");
+	}
+	public void testNotQuiteWildCards() {
+		I_MatchPredicate mp;
+	
+		// make sure special reg-ex chars are treated like normal chars 
+		mp = Countif.createCriteriaPredicate(new StringEval("a.b"));
+		confirmPredicate(false, mp, "aab");
+		confirmPredicate(true, mp, "a.b");
+
+		
+		mp = Countif.createCriteriaPredicate(new StringEval("a~b"));
+		confirmPredicate(false, mp, "ab");
+		confirmPredicate(false, mp, "axb");
+		confirmPredicate(false, mp, "a~~b");
+		confirmPredicate(true, mp, "a~b");
+		
+		mp = Countif.createCriteriaPredicate(new StringEval(">a*b"));
+		confirmPredicate(false, mp, "a(b");
+		confirmPredicate(true, mp, "aab");
+		confirmPredicate(false, mp, "a*a");
+		confirmPredicate(true, mp, "a*c");
+	}
+	
+	private static void confirmPredicate(boolean expectedResult, I_MatchPredicate matchPredicate, int value) {
+		assertEquals(expectedResult, matchPredicate.matches(new NumberEval(value)));
+	}
+	private static void confirmPredicate(boolean expectedResult, I_MatchPredicate matchPredicate, String value) {
+		Eval ev = value == null ? (Eval)BlankEval.INSTANCE : new StringEval(value); 
+		assertEquals(expectedResult, matchPredicate.matches(ev));
+	}
+	
+	public void testCountifFromSpreadsheet() {
+		final String FILE_NAME = "countifExamples.xls";
+		final int START_ROW_IX = 1;
+		final int COL_IX_ACTUAL = 2;
+		final int COL_IX_EXPECTED = 3;
+		
+		int failureCount = 0;
+		HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook(FILE_NAME);
+		HSSFSheet sheet = wb.getSheetAt(0);
+		HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
+		int maxRow = sheet.getLastRowNum();
+		for (int rowIx=START_ROW_IX; rowIx<maxRow; rowIx++) {
+			HSSFRow row = sheet.getRow(rowIx);
+			if(row == null) {
+				continue;
+			}
+			HSSFCell cell = row.getCell(COL_IX_ACTUAL);
+			fe.setCurrentRow(row);
+			CellValue cv = fe.evaluate(cell);
+			double actualValue = cv.getNumberValue();
+			double expectedValue = row.getCell(COL_IX_EXPECTED).getNumericCellValue();
+			if (actualValue != expectedValue) {
+				System.err.println("Problem with test case on row " + (rowIx+1) + " "
+						+ "Expected = (" + expectedValue + ") Actual=(" + actualValue + ") ");
+				failureCount++;
+			}
+		}
+		
+		if (failureCount > 0) {
+			throw new AssertionFailedError(failureCount + " countif evaluations failed. See stderr for more details");
+		}
+	}
 }

Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestCellStyle.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestCellStyle.java?rev=676209&r1=676208&r2=676209&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestCellStyle.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestCellStyle.java Sat Jul 12 11:17:16 2008
@@ -229,6 +229,80 @@
 
         // assert((s.getLastRowNum() == 99));
     }
+    
+    /**
+     * Cloning one HSSFCellStyle onto Another, same
+     *  HSSFWorkbook
+     */
+    public void testCloneStyleSameWB() throws Exception {
+    	HSSFWorkbook wb = new HSSFWorkbook();
+    	HSSFFont fnt = wb.createFont();
+    	fnt.setFontName("TestingFont");
+    	assertEquals(5, wb.getNumberOfFonts());
+    	
+    	HSSFCellStyle orig = wb.createCellStyle();
+    	orig.setAlignment(HSSFCellStyle.ALIGN_RIGHT);
+    	orig.setFont(fnt);
+    	orig.setDataFormat((short)18);
+    	
+    	assertTrue(HSSFCellStyle.ALIGN_RIGHT == orig.getAlignment());
+    	assertTrue(fnt == orig.getFont(wb));
+    	assertTrue(18 == orig.getDataFormat());
+    	
+    	HSSFCellStyle clone = wb.createCellStyle();
+    	assertFalse(HSSFCellStyle.ALIGN_RIGHT == clone.getAlignment());
+    	assertFalse(fnt == clone.getFont(wb));
+    	assertFalse(18 == clone.getDataFormat());
+    	
+    	clone.cloneStyleFrom(orig);
+    	assertTrue(HSSFCellStyle.ALIGN_RIGHT == clone.getAlignment());
+    	assertTrue(fnt == clone.getFont(wb));
+    	assertTrue(18 == clone.getDataFormat());
+    	assertEquals(5, wb.getNumberOfFonts());
+    }
+    
+    /**
+     * Cloning one HSSFCellStyle onto Another, across
+     *  two different HSSFWorkbooks
+     */
+    public void testCloneStyleDiffWB() throws Exception {
+    	HSSFWorkbook wbOrig = new HSSFWorkbook();
+    	
+    	HSSFFont fnt = wbOrig.createFont();
+    	fnt.setFontName("TestingFont");
+    	assertEquals(5, wbOrig.getNumberOfFonts());
+    	
+    	HSSFDataFormat fmt = wbOrig.createDataFormat();
+    	fmt.getFormat("MadeUpOne");
+    	fmt.getFormat("MadeUpTwo");
+    	
+    	HSSFCellStyle orig = wbOrig.createCellStyle();
+    	orig.setAlignment(HSSFCellStyle.ALIGN_RIGHT);
+    	orig.setFont(fnt);
+    	orig.setDataFormat(fmt.getFormat("Test##"));
+    	
+    	assertTrue(HSSFCellStyle.ALIGN_RIGHT == orig.getAlignment());
+    	assertTrue(fnt == orig.getFont(wbOrig));
+    	assertTrue(fmt.getFormat("Test##") == orig.getDataFormat());
+    	
+    	// Now a style on another workbook
+    	HSSFWorkbook wbClone = new HSSFWorkbook();
+    	assertEquals(4, wbClone.getNumberOfFonts());
+    	HSSFDataFormat fmtClone = wbClone.createDataFormat();
+    	
+    	HSSFCellStyle clone = wbClone.createCellStyle();
+    	assertEquals(4, wbClone.getNumberOfFonts());
+    	
+    	assertFalse(HSSFCellStyle.ALIGN_RIGHT == clone.getAlignment());
+    	assertFalse("TestingFont" == clone.getFont(wbClone).getFontName());
+    	
+    	clone.cloneStyleFrom(orig);
+    	assertTrue(HSSFCellStyle.ALIGN_RIGHT == clone.getAlignment());
+    	assertTrue("TestingFont" == clone.getFont(wbClone).getFontName());
+    	assertTrue(fmtClone.getFormat("Test##") == clone.getDataFormat());
+    	assertFalse(fmtClone.getFormat("Test##") == fmt.getFormat("Test##"));
+    	assertEquals(5, wbClone.getNumberOfFonts());
+    }
 
     public static void main(String [] ignored_args)
     {

Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java?rev=676209&r1=676208&r2=676209&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java Sat Jul 12 11:17:16 2008
@@ -381,6 +381,43 @@
             throw new AssertionFailedError("Identified bug 44606");
         }
     }
+
+    /**
+     * Test to ensure we can only assign cell styles that belong
+     *  to our workbook, and not those from other workbooks.
+     */
+    public void testCellStyleWorkbookMatch() throws Exception {
+    	HSSFWorkbook wbA = new HSSFWorkbook();
+    	HSSFWorkbook wbB = new HSSFWorkbook();
+    	
+    	HSSFCellStyle styA = wbA.createCellStyle();
+    	HSSFCellStyle styB = wbB.createCellStyle();
+    	
+    	styA.verifyBelongsToWorkbook(wbA);
+    	styB.verifyBelongsToWorkbook(wbB);
+    	try {
+    		styA.verifyBelongsToWorkbook(wbB);
+    		fail();
+    	} catch(IllegalArgumentException e) {}
+    	try {
+    		styB.verifyBelongsToWorkbook(wbA);
+    		fail();
+    	} catch(IllegalArgumentException e) {}
+    	
+    	HSSFCell cellA = wbA.createSheet().createRow(0).createCell((short)0);
+    	HSSFCell cellB = wbB.createSheet().createRow(0).createCell((short)0);
+    	
+    	cellA.setCellStyle(styA);
+    	cellB.setCellStyle(styB);
+    	try {
+        	cellA.setCellStyle(styB);
+    		fail();
+    	} catch(IllegalArgumentException e) {}
+    	try {
+        	cellB.setCellStyle(styA);
+    		fail();
+    	} catch(IllegalArgumentException e) {}
+    }
     
     public static void main(String [] args) {
         junit.textui.TestRunner.run(TestHSSFCell.class);



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


Mime
View raw message