]> source.dussan.org Git - poi.git/commitdiff
merged TRUNK changes r608809 into REL_3_0_2_BETA2 tags/REL_3_0_2_BETA2 REL_3_0_2_BETA2
authorYegor Kozlov <yegor@apache.org>
Fri, 4 Jan 2008 14:19:14 +0000 (14:19 +0000)
committerYegor Kozlov <yegor@apache.org>
Fri, 4 Jan 2008 14:19:14 +0000 (14:19 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/tags/REL_3_0_2_BETA2@608846 13f79535-47bb-0310-9956-ffa450edef68

81 files changed:
build.xml
poi.pom
src/documentation/content/xdocs/book.xml
src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/hslf/how-to-shapes.xml
src/documentation/content/xdocs/hssf/eval.xml
src/documentation/content/xdocs/hssf/quick-guide.xml
src/documentation/content/xdocs/index.xml
src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/hssf/record/DVALRecord.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/record/DVRecord.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/record/RecordFactory.java
src/java/org/apache/poi/hssf/record/StringRecord.java
src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java
src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java
src/java/org/apache/poi/hssf/usermodel/HSSFDateUtil.java
src/java/org/apache/poi/hssf/usermodel/HSSFFont.java
src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
src/java/org/apache/poi/hssf/util/HSSFCellRangeAddress.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/util/HSSFDataValidation.java [new file with mode: 0644]
src/java/org/apache/poi/poifs/storage/SmallBlockTableWriter.java
src/java/org/apache/poi/util/IOUtils.java
src/java/org/apache/poi/util/StringUtil.java
src/scratchpad/examples/src/org/apache/poi/hslf/examples/TableDemo.java [new file with mode: 0755]
src/scratchpad/examples/src/org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra.java
src/scratchpad/src/org/apache/poi/hslf/model/Fill.java
src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java
src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java
src/scratchpad/src/org/apache/poi/hslf/model/Table.java [new file with mode: 0755]
src/scratchpad/src/org/apache/poi/hslf/model/TableCell.java [new file with mode: 0755]
src/scratchpad/src/org/apache/poi/hslf/model/TextBox.java
src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java
src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java
src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunks.java
src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Date.java
src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Day.java
src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Mid.java
src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Month.java
src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Replace.java
src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Substitute.java
src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Trim.java
src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Year.java
src/scratchpad/src/org/apache/poi/hwpf/model/ListTables.java
src/scratchpad/src/org/apache/poi/hwpf/sprm/TableSprmUncompressor.java
src/scratchpad/src/org/apache/poi/hwpf/usermodel/ListEntry.java
src/scratchpad/testcases/org/apache/poi/hslf/data/43781.ppt [new file with mode: 0755]
src/scratchpad/testcases/org/apache/poi/hslf/data/sample.pptx [new file with mode: 0644]
src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java
src/scratchpad/testcases/org/apache/poi/hsmf/model/TestBlankFileRead.java
src/scratchpad/testcases/org/apache/poi/hsmf/model/TestSimpleFileRead.java
src/scratchpad/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls
src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestEverything.java
src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestEverything.java
src/scratchpad/testcases/org/apache/poi/hwpf/data/AIOOB-Tap.doc [new file with mode: 0644]
src/scratchpad/testcases/org/apache/poi/hwpf/data/IllustrativeCases.docx [new file with mode: 0644]
src/scratchpad/testcases/org/apache/poi/hwpf/data/ListEntryNoListTable.doc [new file with mode: 0644]
src/scratchpad/testcases/org/apache/poi/hwpf/data/sample.docx [new file with mode: 0644]
src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/data/1900DateWindowing.xls
src/testcases/org/apache/poi/hssf/data/1904DateWindowing.xls
src/testcases/org/apache/poi/hssf/data/AverageTaxRates.xlsx [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/data/SimpleWithColours.xls [new file with mode: 0755]
src/testcases/org/apache/poi/hssf/data/StringContinueRecords.xls [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/data/Tables.xlsx [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/data/TestDataValidation.xls [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/data/TwoSheetsNoneHidden.xls [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/data/TwoSheetsOneHidden.xls [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/data/sample-beta.xlsx [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/data/sample.xlsx
src/testcases/org/apache/poi/hssf/data/templateExcelWithAutofilter.xls [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/extractor/TestExcelExtractor.java
src/testcases/org/apache/poi/hssf/usermodel/TestDataValidation.java [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFClientAnchor.java
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPalette.java
src/testcases/org/apache/poi/hssf/usermodel/TestReadWriteChart.java
src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.java [new file with mode: 0644]
src/testcases/org/apache/poi/poifs/filesystem/TestEmptyDocument.java

index 73338a2a7d44139c180d1b1070a84fff33b404a4..8661595b8d7f8b5814da1b3108b25ce3775b862d 100644 (file)
--- a/build.xml
+++ b/build.xml
@@ -70,6 +70,7 @@ under the License.
   <property name="main.output.dir" location="build/classes"/>
   <property name="main.output.test.dir" location="build/test-classes"/>
   <property name="main.lib" location="lib"/>
+  <property name="ooxml.lib" location="ooxml-lib"/>
   <property name="main.reports.test" location="build/test-results"/>
   <property name="main.jar1.dir" location="${main.lib}/commons-logging-1.1.jar"/>
   <property name="main.jar1.url" value="${repository}/commons-logging/jars/commons-logging-1.1.jar"/>
@@ -77,6 +78,9 @@ under the License.
   <property name="main.jar2.url" value="${repository}/log4j/jars/log4j-1.2.13.jar"/>
   <property name="main.testokfile" location="build/main-testokfile.txt"/>
 
+  <property name="junit.jar1.dir" location="${main.lib}/junit-3.8.1.jar"/>
+  <property name="junit.jar1.url" value="${repository}/junit/jars/junit-3.8.1.jar"/>
+
   <!-- Scratchpad: -->
   <property name="scratchpad.src" location="src/scratchpad/src"/>
   <property name="scratchpad.src.test" location="src/scratchpad/testcases"/>
@@ -116,8 +120,33 @@ under the License.
   <property name="examples.jar3.url" value="${repository}/commons-lang/jars/commons-lang-2.1.jar"/>
   <property name="examples.testokfile" location="build/examples-testokfile.txt"/>
 
-  <property name="junit.jar1.dir" location="${main.lib}/junit-3.8.1.jar"/>
-  <property name="junit.jar1.url" value="${repository}/junit/jars/junit-3.8.1.jar"/>
+  <!-- Experimental OOXML support: -->
+  <property name="ooxml.src" location="src/scratchpad/ooxml-src"/>
+  <property name="ooxml.src.test" location="src/scratchpad/ooxml-testcases"/>
+  <property name="ooxml.reports.test" location="build/ooxml-test-results"/>
+  <property name="ooxml.output.dir" location="build/ooxml-classes"/>
+  <property name="ooxml.output.test.dir" location="build/ooxml-test-classes"/>
+  <property name="ooxml.testokfile" location="build/ooxml-testokfile.txt"/>
+
+  <property name="ooxml.jar1.dir" location="${ooxml.lib}/dom4j-1.6.1.jar"/>
+  <property name="ooxml.jar1.url" value="${repository}/dom4j/jars/dom4j-1.6.1.jar"/>
+  <property name="ooxml.jar2.dir" location="${ooxml.lib}/jaxen-1.1.jar"/>
+  <property name="ooxml.jar2.url" value="${repository}/jaxen/jars/jaxen-1.1.jar"/>
+  <property name="ooxml.jar3.dir" location="${ooxml.lib}/xmlbeans-2.3.0.jar"/>
+  <property name="ooxml.jar3.url" value="${repository}/org.apache.xmlbeans/jars/xmlbeans-2.3.0.jar"/>
+  <property name="ooxml.jar4.dir" location="${ooxml.lib}/jsr173_1.0_api.jar"/>
+  <property name="ooxml.jar4.url" value="${repository}/xmlbeans/jars/jsr173_1.0_api.jar"/>
+  <!-- No official release of openxml4j yet -->
+  <property name="ooxml.jar5.dir" location="${ooxml.lib}/openxml4j-bin-prealpha-071224.jar"/>
+  <property name="ooxml.jar5.url" value="http://people.apache.org/~nick/openxml4j-bin-prealpha-071224.jar"/>
+
+  <!-- See http://www.ecma-international.org/publications/standards/Ecma-376.htm -->
+  <!-- "Copy these file(s), free of charge" -->
+  <property name="ooxml.xsds.ozip" location="${ooxml.lib}/OfficeOpenXML-Part4.zip"/>
+  <property name="ooxml.xsds.izip" location="${ooxml.lib}/OfficeOpenXML-XMLSchema.zip"/>
+  <property name="ooxml.xsds.url" value="http://www.ecma-international.org/publications/files/ECMA-ST/Office%20Open%20XML%20Part%204%20(DOCX).zip" />
+  <property name="ooxml.xsds.jar" location="${ooxml.lib}/ooxml-schemas.jar"/>
+
   <property name="build.site" location="build/tmp/site/build/site"/>
   <property name="build.site.src" location="build/tmp/site"/>
   <property name="junit.report.dir" location="${build.site}/junit"/>
@@ -130,7 +159,7 @@ under the License.
   <property name="mavendist.poi.dir" location="build/maven-dist/poi"/>
   <property name="mavendist.oap.dir" location="build/maven-dist/org.apache.poi"/>
   <property name="jar.name" value="poi"/>
-  <property name="version.id" value="3.0.2-beta1"/>
+  <property name="version.id" value="3.0.2-beta2"/>
   <property name="halt.on.test.failure" value="true"/>
   <property name="jdk.version.source" value="1.3"
     description="JDK version of source code"/>
@@ -162,6 +191,15 @@ under the License.
         <pathelement location="${contrib.output.test.dir}"/>
     </path>
 
+    <path id="ooxml.classpath">
+        <path refid="main.classpath"/>
+        <path refid="scratchpad.classpath"/>
+        <fileset dir="${ooxml.lib}">
+                       <include name="*.jar" />
+               </fileset>
+    </path>
+
+
   <path id="examples.classpath">
     <path refid="main.classpath"/>
     <pathelement location="${main.output.dir}"/>
@@ -225,12 +263,15 @@ under the License.
         <mkdir dir="${scratchpad.output.dir}"/>
         <mkdir dir="${contrib.output.dir}"/>
         <mkdir dir="${examples.output.dir}"/>
+        <mkdir dir="${ooxml.output.dir}"/>
         <mkdir dir="${main.output.test.dir}"/>
         <mkdir dir="${contrib.output.test.dir}"/>
         <mkdir dir="${scratchpad.output.test.dir}"/>
+        <mkdir dir="${ooxml.output.test.dir}"/>
         <mkdir dir="${main.reports.test}"/>
         <mkdir dir="${scratchpad.reports.test}"/>
         <mkdir dir="${contrib.reports.test}"/>
+        <mkdir dir="${ooxml.reports.test}"/>
         <mkdir dir="${junit.report.dir}"/>
         <mkdir dir="${jdepend.report.dir}"/>
         <mkdir dir="${jdepend.report.out.dir}"/>
@@ -281,6 +322,57 @@ under the License.
         <get src="${junit.jar1.url}" dest="${junit.jar1.dir}"/>
     </target>
 
+       <target name="check-ooxml-xsds">
+        <condition property="ooxml-xsds.present">
+            <or>
+                <and>
+                    <available file="${ooxml.xsds.izip}"/>
+                </and>
+                <isset property="disconnected"/>
+            </or>
+        </condition>
+       </target>
+    <target name="fetch-ooxml-xsds" unless="ooxml-xsds.present"
+     description="Fetches needed OOXML xsd files from the Internet">
+        <get src="${ooxml.xsds.url}" dest="${ooxml.xsds.ozip}"/>
+               <unzip src="${ooxml.xsds.ozip}" dest="${ooxml.lib}">
+                       <patternset>
+                               <include name="OfficeOpenXML-XMLSchema.zip" />
+                       </patternset>
+               </unzip>
+       </target>
+       <target name="check-compiled-ooxml-xsds">
+        <condition property="ooxml-compiled-xsds.present">
+            <or>
+                <and>
+                    <available file="${ooxml.xsds.jar}"/>
+                </and>
+                <isset property="disconnected"/>
+            </or>
+        </condition>
+       </target>
+       <target name="compile-ooxml-xsds" unless="ooxml-compiled-xsds.present"
+        depends="check-jars,fetch-jars,check-ooxml-xsds,fetch-ooxml-xsds,check-compiled-ooxml-xsds"
+        description="Unpacks the OOXML xsd files, and compiles them into XmlBeans">
+               <taskdef name="xmlbean"
+                       classname="org.apache.xmlbeans.impl.tool.XMLBean"
+                       classpath="${ooxml.jar3.dir}:${ooxml.jar4.dir}" />
+
+               <unzip src="${ooxml.xsds.izip}" dest="build/ooxml-xsds/" />
+               <!--
+                       schema="build/ooxml-xsds/"
+                       schema="build/ooxml-xsds/sml-workbook.xsd"
+               -->
+               <xmlbean
+                       schema="build/ooxml-xsds/"
+                       destfile="${ooxml.xsds.jar}"
+                       javasource="1.4"
+                       failonerror="false"
+               >
+                       <classpath refid="ooxml.classpath"/>
+               </xmlbean>
+       </target>
+
   <target name="compile" depends="init, compile-main, compile-scratchpad,
     compile-contrib, compile-examples"
     description="Compiles the POI main classes, scratchpad, contrib, and examples"/>
@@ -305,7 +397,7 @@ under the License.
     </javac>
   </target>
 
-  <target name="compile-scratchpad" depends="init">
+  <target name="compile-scratchpad" depends="init,compile-main">
     <javac target="${jdk.version.class}" source="${jdk.version.source}"
       failonerror="true" destdir="${scratchpad.output.dir}" debug="on"
       fork="yes" srcdir="${scratchpad.src}">
@@ -363,6 +455,14 @@ under the License.
     </javac>
   </target>
 
+  <target name="compile-ooxml" depends="init, check-ooxml-xsds, fetch-ooxml-xsds, compile-ooxml-xsds, compile-main">
+       <!-- openxml4j requires java 1.5, so so must we, for now -->
+    <javac target="1.5" source="1.5"
+      destdir="${ooxml.output.dir}" debug="on" srcdir="${ooxml.src}">
+      <classpath refid="ooxml.classpath"/>
+    </javac>
+  </target>
+
   <target name="test" depends="test-main,test-scratchpad,test-contrib"
     description="Tests main, contrib and scratchpad"/>
 
@@ -590,6 +690,43 @@ under the License.
         <echo file="${contrib.testokfile}" append="false" message="testok"/>
     </target>
 
+    <target name="-test-ooxml-check">
+        <uptodate property="ooxml.test.notRequired" targetfile="${ooxml.testokfile}">
+            <srcfiles dir="${ooxml.src}"/>
+            <srcfiles dir="${ooxml.src.test}"/>
+        </uptodate>
+    </target>
+
+    <target name="test-ooxml" depends="compile-main,compile-ooxml,-test-ooxml-check" unless="ooxml.test.notRequired">
+        <junit printsummary="yes" fork="no" haltonfailure="${halt.on.test.failure}" failureproperty="ooxml.test.failed">
+            <classpath>
+                <path refid="ooxml.classpath"/>
+                <pathelement location="${main.output.dir}"/>
+                <pathelement location="${ooxml.output.dir}"/>
+                <pathelement location="${ooxml.output.test.dir}"/>
+                <pathelement location="${junit.jar1.dir}"/>
+            </classpath>
+            <sysproperty key="HSSF.testdata.path" file="${main.src.test}/org/apache/poi/hssf/data"/>
+            <sysproperty key="HWPF.testdata.path" file="${scratchpad.src.test}/org/apache/poi/hwpf/data"/>
+            <sysproperty key="HSLF.testdata.path" file="${scratchpad.src.test}/org/apache/poi/hslf/data"/>
+            <sysproperty key="java.awt.headless" value="true"/>
+            <formatter type="plain"/>
+            <formatter type="xml"/>
+            <batchtest todir="${ooxml.reports.test}">
+                <fileset dir="${ooxml.src.test}">
+                    <include name="**/Test*.java"/>
+                    <exclude name="**/AllTests.java"/>
+                </fileset>
+            </batchtest>
+        </junit>
+        <delete file="${ooxml.testokfile}"/>
+        <antcall target="-test-ooxml-write-testfile"/>
+    </target>
+
+    <target name="-test-ooxml-write-testfile" unless="ooxml.test.failed">
+        <echo file="${ooxml.testokfile}" append="false" message="testok"/>
+    </target>
+
     <target name="-check-docs">
         <uptodate property="main.docs.notRequired" targetfile="${build.site}/index.html">
             <srcfiles dir="${build.site.src}"/>
@@ -976,6 +1113,21 @@ FORREST_HOME environment variable!</echo>
             </manifest>        
         </jar>
     </target>
+    <target name="jar-ooxml" depends="compile-ooxml" description="Creates the ooxml jar files for distribution">
+        <jar destfile="${dist.dir}/${jar.name}-ooxml-${version.id}-${DSTAMP}.jar">
+                       <fileset dir="${ooxml.output.dir}" />
+                       <fileset dir="legal/" />
+            <manifest>
+                <attribute name="Built-By" value="${user.name}"/>
+                <attribute name="Specification-Title" value="Apache POI"/>
+                <attribute name="Specification-Version" value="${version.id}-${DSTAMP}"/>
+                <attribute name="Specification-Vendor" value="Apache"/>
+                <attribute name="Implementation-Title" value="Apache POI"/>
+                <attribute name="Implementation-Version" value="${version.id}-${DSTAMP}"/>
+                <attribute name="Implementation-Vendor" value="Apache"/>
+            </manifest>        
+        </jar>
+    </target>
 
   <target name="dist" depends="clean, fail-unless-tools-are-available, compile, site, jar"
     description="Creates the entire distribution into build/dist, from scratch">
diff --git a/poi.pom b/poi.pom
index 7395157c2fc857711a79c1cf7631fcf5da759ff2..ed6923b62853d246527c09c90d237d60a7670d60 100644 (file)
--- a/poi.pom
+++ b/poi.pom
@@ -77,8 +77,8 @@ under the License.
                </license>
        </licenses>
        <scm>
-               <url>http://svn.apache.org/viewvc/jakarta/poi/trunk</url>
-               <connection>scm:svn:http://svn.apache.org/repos/asf/jakarta/poi/trunk</connection>
+               <url>http://svn.apache.org/viewvc/poi/trunk</url>
+               <connection>scm:svn:http://svn.apache.org/repos/asf/poi/trunk</connection>
        </scm>
        <issueManagement>
                <system>bugzilla</system>
index 36c50e6fe9cbe064b6f90c48ac4b421ddbc9b07e..e8e6eb6741a8463a77469735e1646a28d51fb3d2 100644 (file)
@@ -57,6 +57,7 @@
         <menu-item label="History and Future" href="historyandfuture.html"/>
         <menu-item label="Who We Are" href="who.html"/>
         <menu-item label="Resolutions" href="resolutions/index.html"/>
+        <menu-item label="Sponsors" href="http://www.apache.org/foundation/thanks.html" />
     </menu>
 
     <menu label="Docs">
index f429eb361cd65535573b07a47fe3ad2ee132aed7..23ed0537c58b3c1117e409478b257f3445eaa59e 100644 (file)
     </devs>
 
                <!-- Don't forget to update status.xml too! -->
-        <release version="3.0.2-FINAL" date="2007-??-??">
-          <action dev="POI-DEVELOPERS" type="fix">43877 and 39512 - Fix for handling mixed OBJ and CONTINUE records.</action>
+        <release version="3.0.2-FINAL" date="2008-??-??">
+            <action dev="POI-DEVELOPERS" type="add">Support for tables in HSLF</action>
+            <action dev="POI-DEVELOPERS" type="fix">43781 - Fix for extracting text from TextBoxes HSLF in</action>
+            <action dev="POI-DEVELOPERS" type="fix">Improve JavaDocs relating to hssf font and fill colourings</action>
+            <action dev="POI-DEVELOPERS" type="add">44095, 44097, 44099 - [PATCH] Support for Mid, Replace and Substitute excel functions</action>
+            <action dev="POI-DEVELOPERS" type="add">44055 - [PATCH] Support for getting the from field from HSMF messages</action>
+            <action dev="POI-DEVELOPERS" type="add">43551 - [PATCH] Support for 1904 date windowing in HSSF (previously only supported 1900 date windowing)</action>
+            <action dev="POI-DEVELOPERS" type="add">41064 - [PATCH] Support for String continue records</action>
+            <action dev="POI-DEVELOPERS" type="add">27511 - [PATCH] Support for data validation, via DVRecord and DVALRecord</action>
+        </release>
+
+        <release version="3.0.2-BETA1" date="2007-12-04">
+            <action dev="POI-DEVELOPERS" type="fix">43877 and 39512 - Fix for handling mixed OBJ and CONTINUE records.</action>
             <action dev="POI-DEVELOPERS" type="fix">43807 - Throw an IllegalArgumentException if asked to create a merged region with invalid columns or rows, rather than writing out a corrupt file</action>
             <action dev="POI-DEVELOPERS" type="fix">43837 - [PATCH] Support for unicode NameRecords</action>
             <action dev="POI-DEVELOPERS" type="add">43721 - [PATCH] Support for Chart Title Format records</action>
index df40776a53b1b7e759f4bd53918faf633e6bee3a..36e4a1138733b8e94c2f9ed89d7be8a90278c5f0 100644 (file)
@@ -39,6 +39,7 @@
                     <li><link href="#Fill">How to work with slide/shape background</link></li>
                     <li><link href="#Bullets">How to create bulleted lists</link></li>
                     <li><link href="#Hyperlinks">Hyperlinks</link></li>
+                    <li><link href="#Tables">Tables</link></li>
                 </ul>
             </section>
             <section><title>Features</title>
     }
                 </source>
                 </section>
+                <anchor id="Tables"/>
+                <section><title>How to create tables</title>
+                  <source>
+      //table data              
+      String[][] data = {
+          {"INPUT FILE", "NUMBER OF RECORDS"},
+          {"Item File", "11,559"},
+          {"Vendor File", "300"},
+          {"Purchase History File", "10,000"},
+          {"Total # of requisitions", "10,200,038"}
+      };
+
+      SlideShow ppt = new SlideShow();
+
+      Slide slide = ppt.createSlide();
+      //create a table of 5 rows and 2 columns
+      Table table = new Table(5, 2);
+      for (int i = 0; i &lt; data.length; i++) {
+          for (int j = 0; j &lt; data[i].length; j++) {
+              TableCell cell = table.getCell(i, j);
+              cell.setText(data[i][j]);
+
+              RichTextRun rt = cell.getTextRun().getRichTextRuns()[0];
+              rt.setFontName("Arial");
+              rt.setFontSize(10);
+
+              cell.setVerticalAlignment(TextBox.AnchorMiddle);
+              cell.setHorizontalAlignment(TextBox.AlignCenter);
+          }
+      }
+
+      //set table borders
+      Line border = table.createBorder();
+      border.setLineColor(Color.black);
+      border.setLineWidth(1.0);
+      table.setAllBorders(border);
+
+      //set width of the 1st column
+      table.setColumnWidth(0, 300);
+      //set width of the 2nd column
+      table.setColumnWidth(1, 150);
+
+      slide.addShape(table);
+      table.moveTo(100, 100);
+
+      FileOutputStream out = new FileOutputStream("hslf-table.ppt");
+      ppt.write(out);
+      out.close();
+    
+                    </source>
+                </section>
                   
             </section>
         </section>
index 548df78e763400e5a532c9946e4d95d634671831..d697eb082bcede2e093273276f5a8640e30ef7d0 100644 (file)
@@ -63,6 +63,8 @@ HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb);
 CellReference cellReference = new CellReference("B3"); 
 HSSFRow row = sheet.getRow(cellReference.getRow());
 HSSFCell cell = row.getCell(cellReference.getCol()); 
+
+evaluator.setCurrentRow(row);
 HSSFFormulaEvaluator.CellValue cellValue = evaluator.evaluate(cell);
 
 switch (cellValue.getCellType()) {
@@ -106,7 +108,7 @@ HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb);
 CellReference cellReference = new CellReference("B3"); 
 HSSFRow row = sheet.getRow(cellReference.getRow());
 HSSFCell cell = row.getCell(cellReference.getCol()); 
-
+evaluator.setCurrentRow(row);
 
 if (cell!=null) {
        switch (<strong>evaluator.evaluateInCell</strong>(cell).getCellType()) {
index 6dc4dc909b907c55c8c30280b7de9deb547cda5d..ddbd447fd13427b17a66c15e759370ee3cbee2b0 100644 (file)
@@ -41,6 +41,7 @@
                     <li><link href="#CreateCells">How to create cells</link></li>
                     <li><link href="#CreateDateCells">How to create date cells</link></li>
                     <li><link href="#CellTypes">Working with different types of cells</link></li>
+                    <li><link href="#Iterator">Iterate over rows and cells</link></li>
                     <li><link href="#TextExtraction">Text Extraction</link></li>
                     <li><link href="#Alignment">Aligning cells</link></li>
                     <li><link href="#Borders">Working with borders</link></li>
     fileOut.close();
                     </source>
                 </section>
+                <anchor id="Iterator"/>
+                <section><title>Iterate over rows and cells (including Java 5 foreach loops)</title>
+                               <p>Sometimes, you'd like to just iterate over all the rows in
+                               a sheet, or all the cells in a row. If you are using Java
+                               5 or later, then this is especially handy, as it'll allow the
+                               new foreach loop support to work.</p>
+                               <p>Luckily, this is very easy. HSSFRow defines a 
+                               <em>CellIterator</em> inner class to handle iterating over 
+                               the cells (get one with a call to <em>row.cellIterator()</em>),
+                               and HSSFSheet provides a <em>rowIterator()</em> method to
+                               give an iterator over all the rows.</p>
+                               <source>
+       HSSFSheet sheet = wb.getSheetAt(0);
+       for (HSSFRow row : sheet.rowIterator()) {
+               for (HSSFCell cell : row.cellIterator()) {
+                       // Do something here
+               }
+       }
+                               </source>
+                </section>
                 <anchor id="TextExtraction"/>
                 <section><title>Text Extraction</title>
                                        <p>For most text extraction requirements, the standard
index 80700939659a176f387ed7ca94395cb54fb43762..45b27b0b09f802c45366545f03090236a62dc8f6 100644 (file)
   </header>
 
   <body>
-       <section><title>POI 3.0.1 Release</title>
+    <section><title>POI 3.0.2 BETA1 Release</title>
+         <p>The latest release of Apache POI is 3.0.2 BETA1 which was promoted to "Beta" on 04 December 2007. It contains a mixture of
+               new features and bug fixes, compared to 3.0.1. A full list of changes
+               is available in 
+               <link href="./changes.html">the changelog</link>, and 
+               <link href="http://www.apache.org/dyn/closer.cgi/poi/release/">download</link>
+               the source and binaries from your
+    <link href="http://www.apache.org/dyn/closer.cgi/poi/release/">local mirror</link>.
+     The release is also available from the central Maven repository under Group ID "org.apache.poi".
+  </p>
+  </section>
+
+  <section><title>POI 3.0.1 Release</title>
          <p>The latest release of Apache POI (formerly Apache Jakarta POI),
                version 3.0.1, has now been released. It contains a mixture of
                new features and bug fixes, compared to 3.0. A full list of changes
index e4ed1065f046461dc1aceafc588e3e1df59466ef..72761cf9c00ef3ae94f24b379b78cd48e7783ec4 100644 (file)
 
        <!-- Don't forget to update changes.xml too! -->
     <changes>
-        <release version="3.0.2-FINAL" date="2007-??-??">
+        <release version="3.0.2-FINAL" date="2008-??-??">
+            <action dev="POI-DEVELOPERS" type="add">Support for tables in HSLF</action>
+            <action dev="POI-DEVELOPERS" type="fix">43781 - Fix for extracting text from TextBoxes HSLF in</action>
+            <action dev="POI-DEVELOPERS" type="fix">Improve JavaDocs relating to hssf font and fill colourings</action>
+            <action dev="POI-DEVELOPERS" type="add">44095, 44097, 44099 - [PATCH] Support for Mid, Replace and Substitute excel functions</action>
+            <action dev="POI-DEVELOPERS" type="add">44055 - [PATCH] Support for getting the from field from HSMF messages</action>
+            <action dev="POI-DEVELOPERS" type="add">43551 - [PATCH] Support for 1904 date windowing in HSSF (previously only supported 1900 date windowing)</action>
+            <action dev="POI-DEVELOPERS" type="add">41064 - [PATCH] Support for String continue records</action>
+            <action dev="POI-DEVELOPERS" type="add">27511 - [PATCH] Support for data validation, via DVRecord and DVALRecord</action>
+        </release>
+        <release version="3.0.2-BETA1" date="2007-12-04">
             <action dev="POI-DEVELOPERS" type="fix">43877 - Fix for handling mixed OBJ and CONTINUE records</action>
             <action dev="POI-DEVELOPERS" type="fix">39512 - Fix for handling mixed OBJ and CONTINUE records</action>
             <action dev="POI-DEVELOPERS" type="fix">43837 - [PATCH] Support for unicode NameRecords</action>
diff --git a/src/java/org/apache/poi/hssf/record/DVALRecord.java b/src/java/org/apache/poi/hssf/record/DVALRecord.java
new file mode 100644 (file)
index 0000000..858f525
--- /dev/null
@@ -0,0 +1,157 @@
+
+/* ====================================================================
+   Copyright 2002-2004   Apache Software Foundation
+
+   Licensed 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.hssf.record;
+
+import org.apache.poi.util.LittleEndian;
+
+/**
+ * Title:        DVAL Record<P>
+ * Description:  used in data validation ;
+ *               This record is the list header of all data validation records in the current sheet.
+ * @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
+ * @version 2.0-pre
+ */
+
+public class DVALRecord extends Record
+{
+    public final static short sid = 0x01B2;
+
+    //unknown field ; it's size should be 10
+    private short field_unknown     = 0x0000;
+
+    //Object ID of the drop down arrow object for list boxes ;
+    //in our case this will be always FFFF , until
+    //MSODrawingGroup and MSODrawing records are implemented
+    private int  field_cbo_id      = 0xFFFFFFFF;
+
+    //Number of following DV records
+    //Default value is 1
+    private int  field_3_dv_no     = 0x00000000;
+
+    public DVALRecord()
+    {
+    }
+
+    /**
+     * Constructs a DVAL record and sets its fields appropriately.
+     *
+     * @param in the RecordInputstream to read the record from
+     */
+
+    public DVALRecord(RecordInputStream in)
+    {
+        super(in);
+    }
+
+    protected void validateSid(short id)
+    {
+        if (id != sid)
+        {
+            throw new RecordFormatException("NOT A valid DVAL RECORD");
+        }
+    }
+
+    protected void fillFields(RecordInputStream in)
+    {
+        for ( int i=0; i<5; i++)
+        {
+               this.field_unknown = in.readShort();
+        }
+        this.field_cbo_id    = in.readInt(); 
+        this.field_3_dv_no   = in.readInt();
+    }
+
+    /**
+     * set the object ID of the drop down arrow object for list boxes
+     * @param cboID - Object ID
+     */
+    public void setObjectID(int cboID)
+    {
+        this.field_cbo_id = cboID;
+    }
+
+    /**
+     * Set the number of following DV records
+     * @param dvNo - the DV records number
+     */
+    public void setDVRecNo(int dvNo)
+    {
+        this.field_3_dv_no = dvNo;
+    }
+
+    /**
+     * get Object ID of the drop down arrow object for list boxes
+     */
+    public int getObjectID( )
+    {
+        return this.field_cbo_id;
+    }
+
+    /**
+     * Get number of following DV records
+     */
+    public int getDVRecNo( )
+    {
+        return this.field_3_dv_no;
+    }
+
+
+    public String toString()
+    {
+        StringBuffer buffer = new StringBuffer();
+
+        buffer.append("[DVAL]\n");
+        buffer.append("    .comboObjectID   = ").append(Integer.toHexString(this.getObjectID())).append("\n");
+        buffer.append("    .DVRecordsNumber = ").append(Integer.toHexString(this.getDVRecNo())).append("\n");
+        buffer.append("[/DVAL]\n");
+        return buffer.toString();
+    }
+
+    public int serialize(int offset, byte [] data)
+    {
+        LittleEndian.putShort(data, 0 + offset, this.sid);
+        LittleEndian.putShort(data, 2 + offset, ( short)(this.getRecordSize()-4));
+        for ( int i=0; i<5; i++)
+        {
+          LittleEndian.putShort(data, 4 + i*2 + offset, (short)this.field_unknown);
+        }
+        LittleEndian.putInt(data, 14 + offset, this.getObjectID());
+        LittleEndian.putInt(data, 18 + offset, this.getDVRecNo());
+        return getRecordSize();
+    }
+
+    //with 4 bytes header
+    public int getRecordSize()
+    {
+        return 22;
+    }
+
+    public short getSid()
+    {
+        return this.sid;
+    }
+
+    public Object clone()
+    {
+      DVALRecord rec = new DVALRecord();
+      rec.field_unknown = this.field_unknown;
+      rec.field_cbo_id = this.field_cbo_id;
+      rec.field_3_dv_no = this.field_3_dv_no;
+      return rec;
+    }
+}
\ No newline at end of file
diff --git a/src/java/org/apache/poi/hssf/record/DVRecord.java b/src/java/org/apache/poi/hssf/record/DVRecord.java
new file mode 100644 (file)
index 0000000..0bae009
--- /dev/null
@@ -0,0 +1,590 @@
+/* ====================================================================
+   Copyright 2002-2004   Apache Software Foundation
+
+   Licensed 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.hssf.record;
+
+import org.apache.poi.util.BitField;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.StringUtil;
+import org.apache.poi.hssf.util.HSSFCellRangeAddress;
+import org.apache.poi.hssf.record.formula.Ptg;
+
+import java.io.IOException;
+import java.util.Stack;
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+/**
+ * Title:        DV Record<P>
+ * Description:  This record stores data validation settings and a list of cell ranges
+ *               which contain these settings. The data validation settings of a sheet
+ *               are stored in a sequential list of DV records. This list is followed by
+ *               DVAL record(s)
+ * @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
+ * @version 2.0-pre
+ */
+public class DVRecord extends Record
+{
+    public final static short sid = 0x01BE;
+
+    /**
+     * Option flags
+     */
+    private int                field_option_flags;
+
+    /**
+     * Title of the prompt box
+     */
+    private String             field_title_prompt;
+
+    /**
+     * Title of the error box
+     */
+    private String             field_title_error;
+
+    /**
+     * Text of the prompt box
+     */
+    private String             field_text_prompt;
+
+    /**
+     * Text of the error box
+     */
+    private String             field_text_error;
+
+    /**
+     * Size of the formula data for first condition
+     */
+    private short             field_size_first_formula;
+
+    /**
+     * Not used
+     */
+    private short             field_not_used_1 = 0x3FE0;
+
+    /**
+     * Formula data for first condition (RPN token array without size field)
+     */
+    private Stack             field_rpn_token_1 ;
+
+    /**
+     * Size of the formula data for second condition
+     */
+    private short             field_size_sec_formula;
+
+    /**
+     * Not used
+     */
+    private short             field_not_used_2 = 0x0000;
+
+    /**
+     * Formula data for second condition (RPN token array without size field)
+     */
+    private Stack             field_rpn_token_2 ;
+
+    /**
+     * Cell range address list with all affected ranges
+     */
+    private HSSFCellRangeAddress         field_regions;
+
+    public static final Integer STRING_PROMPT_TITLE = new Integer(0);
+    public static final Integer STRING_ERROR_TITLE  = new Integer(1);
+    public static final Integer STRING_PROMPT_TEXT  = new Integer(2);
+    public static final Integer STRING_ERROR_TEXT   = new Integer(3);
+    private Hashtable _hash_strings ;
+
+    /**
+     * Option flags field
+     * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
+     */
+    private BitField          opt_data_type                    = new BitField(0x0000000F);
+    private BitField          opt_error_style                  = new BitField(0x00000070);
+    private BitField          opt_string_list_formula          = new BitField(0x00000080);
+    private BitField          opt_empty_cell_allowed           = new BitField(0x00000100);
+    private BitField          opt_surppres_dropdown_arrow      = new BitField(0x00000200);
+    private BitField          opt_show_prompt_on_cell_selected = new BitField(0x00040000);
+    private BitField          opt_show_error_on_invalid_value  = new BitField(0x00080000);
+    private BitField          opt_condition_operator           = new BitField(0x00F00000);
+
+    public DVRecord()
+    {
+    }
+
+    /**
+     * Constructs a DV record and sets its fields appropriately.
+     *
+     * @param in the RecordInputstream to read the record from
+     */
+
+    public DVRecord(RecordInputStream in)
+    {
+        super(in);
+    }
+
+    protected void validateSid(short id)
+    {
+        if (id != sid)
+        {
+            throw new RecordFormatException("NOT a valid DV RECORD");
+        }
+    }
+
+    protected void fillFields(RecordInputStream in)
+    {
+       field_rpn_token_1 = new Stack();
+       field_rpn_token_2 = new Stack();
+        
+       this.field_option_flags = in.readInt();
+       this._hash_strings = new Hashtable(4);
+       
+       StringHandler strHandler_prompt_title = new StringHandler( in );
+       this.field_title_prompt = strHandler_prompt_title.getStringData();
+       this._hash_strings.put(DVRecord.STRING_PROMPT_TITLE, strHandler_prompt_title);
+
+       StringHandler strHandler_error_title = new StringHandler( in );
+       this.field_title_error = strHandler_error_title.getStringData();
+       this._hash_strings.put(DVRecord.STRING_ERROR_TITLE, strHandler_error_title);
+
+       StringHandler strHandler_prompt_text = new StringHandler( in );
+       this.field_text_prompt = strHandler_prompt_text.getStringData();
+       this._hash_strings.put(DVRecord.STRING_PROMPT_TEXT, strHandler_prompt_text);
+
+       StringHandler strHandler_error_text = new StringHandler( in );
+       this.field_text_error = strHandler_error_text.getStringData();
+       this._hash_strings.put(DVRecord.STRING_ERROR_TEXT, strHandler_error_text);
+
+       this.field_size_first_formula = in.readShort(); 
+       this.field_not_used_1 = in.readShort();
+
+       //read first formula data condition
+       // Not sure if this was needed or not...
+//       try {
+//        in.skip(this.field_size_first_formula);
+//       } catch(IOException e) { throw new IllegalStateException(e); } 
+
+       int token_pos = 0;
+       while (token_pos < this.field_size_first_formula)
+       {
+           Ptg ptg = Ptg.createPtg(in);
+           token_pos += ptg.getSize();
+           field_rpn_token_1.push(ptg);
+       }
+
+       this.field_size_sec_formula = in.readShort(); 
+       this.field_not_used_2 = in.readShort();
+
+       //read sec formula data condition
+       // Not sure if this was needed or not...
+       try {
+           in.skip(this.field_size_sec_formula);
+       } catch(IOException e) { throw new IllegalStateException(e); } 
+
+       token_pos = 0;
+       while (token_pos < this.field_size_sec_formula)
+       {
+           Ptg ptg = Ptg.createPtg(in);
+           token_pos += ptg.getSize();
+           field_rpn_token_2.push(ptg);
+       }
+
+       //read cell range address list with all affected ranges
+       this.field_regions = new HSSFCellRangeAddress(in);
+    }
+
+
+    // --> start option flags
+    /**
+     * set the condition data type
+     * @param type - condition data type
+     * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
+     */
+    public void setDataType(int type)
+    {
+        this.field_option_flags =  this.opt_data_type.setValue(this.field_option_flags, type);
+    }
+
+    /**
+     * get the condition data type
+     * @return the condition data type
+     * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
+     */
+    public int getDataType()
+    {
+       return this.opt_data_type.getValue(this.field_option_flags);
+    }
+
+    /**
+     * set the condition error style
+     * @param type - condition error style
+     * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
+     */
+    public void setErrorStyle(int style)
+    {
+        this.field_option_flags =  this.opt_error_style.setValue(this.field_option_flags, style);
+    }
+
+    /**
+     * get the condition error style
+     * @return the condition error style
+     * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
+     */
+    public int getErrorStyle()
+    {
+       return this.opt_error_style.getValue(this.field_option_flags);
+    }
+
+    /**
+     * set if in list validations the string list is explicitly given in the formula
+     * @param type - true if in list validations the string list is explicitly given in the formula; false otherwise
+     * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
+     */
+    public void setListExplicitFormula(boolean explicit)
+    {
+        this.field_option_flags = this.opt_string_list_formula.setBoolean(this.field_option_flags, explicit);
+    }
+
+    /**
+     * return true if in list validations the string list is explicitly given in the formula, false otherwise
+     * @return true if in list validations the string list is explicitly given in the formula, false otherwise
+     * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
+     */
+    public boolean getListExplicitFormula()
+    {
+       return (this.opt_string_list_formula.isSet(this.field_option_flags));
+    }
+
+    /**
+     * set if empty values are allowed in cells
+     * @param type - true if empty values are allowed in cells, false otherwise
+     * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
+     */
+    public void setEmptyCellAllowed(boolean allowed)
+    {
+        this.field_option_flags =  this.opt_empty_cell_allowed.setBoolean(this.field_option_flags, allowed);
+    }
+
+    /**
+     * return true if empty values are allowed in cells, false otherwise
+     * @return if empty values are allowed in cells, false otherwise
+     * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
+     */
+    public boolean getEmptyCellAllowed()
+    {
+       return (this.opt_empty_cell_allowed.isSet(this.field_option_flags));
+    }
+
+    /**
+     * set if drop down arrow should be surppressed when list validation is used
+     * @param type - true if drop down arrow should be surppressed when list validation is used, false otherwise
+     * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
+     */
+    public void setSurppresDropdownArrow(boolean surppress)
+    {
+        this.field_option_flags =  this.opt_surppres_dropdown_arrow.setBoolean(this.field_option_flags, surppress);
+    }
+
+    /**
+     * return true if drop down arrow should be surppressed when list validation is used, false otherwise
+     * @return if drop down arrow should be surppressed when list validation is used, false otherwise
+     * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
+     */
+    public boolean getSurppresDropdownArrow()
+    {
+       return (this.opt_surppres_dropdown_arrow.isSet(this.field_option_flags));
+    }
+
+    /**
+     * set if a prompt window should appear when cell is selected
+     * @param type - true if a prompt window should appear when cell is selected, false otherwise
+     * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
+     */
+    public void setShowPromptOnCellSelected(boolean show)
+    {
+        this.field_option_flags =  this.opt_show_prompt_on_cell_selected.setBoolean(this.field_option_flags, show);
+    }
+
+    /**
+     * return true if a prompt window should appear when cell is selected, false otherwise
+     * @return if a prompt window should appear when cell is selected, false otherwise
+     * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
+     */
+    public boolean getShowPromptOnCellSelected()
+    {
+       return (this.opt_show_prompt_on_cell_selected.isSet(this.field_option_flags));
+    }
+
+    /**
+     * set if an error window should appear when an invalid value is entered in the cell
+     * @param type - true if an error window should appear when an invalid value is entered in the cell, false otherwise
+     * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
+     */
+    public void setShowErrorOnInvalidValue(boolean show)
+    {
+        this.field_option_flags =  this.opt_show_error_on_invalid_value.setBoolean(this.field_option_flags, show);
+    }
+
+    /**
+     * return true if an error window should appear when an invalid value is entered in the cell, false otherwise
+     * @return if an error window should appear when an invalid value is entered in the cell, false otherwise
+     * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
+     */
+    public boolean getShowErrorOnInvalidValue()
+    {
+       return (this.opt_show_error_on_invalid_value.isSet(this.field_option_flags));
+    }
+
+    /**
+     * set the condition operator
+     * @param type - condition operator
+     * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
+     */
+    public void setConditionOperator(int operator)
+    {
+        this.field_option_flags =  this.opt_condition_operator.setValue(this.field_option_flags, operator);
+    }
+
+    /**
+     * get the condition operator
+     * @return the condition operator
+     * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
+     */
+    public int getConditionOperator()
+    {
+       return this.opt_condition_operator.getValue(this.field_option_flags);
+    }
+    // <-- end option flags
+
+    public void setFirstFormulaRPN( Stack rpn )
+    {
+        this.field_rpn_token_1 = rpn;
+    }
+
+    public void setFirstFormulaSize( short size )
+    {
+        this.field_size_first_formula = size;
+    }
+
+    public void setSecFormulaRPN( Stack rpn )
+    {
+        this.field_rpn_token_2 = rpn;
+    }
+
+    public void setSecFormulaSize( short size )
+    {
+        this.field_size_sec_formula = size;
+    }
+
+    public void setStringField( Integer type, String str_data )
+    {
+       if ( this._hash_strings == null )
+       {
+          this._hash_strings = new Hashtable();
+       }
+       StringHandler strHandler = new StringHandler();
+       if ( str_data == null )
+       {
+          str_data = "";
+       }
+       else
+       {
+          strHandler.setStringLength(str_data.length());
+       }
+       strHandler.setStringData(str_data);
+
+       strHandler.setUnicodeFlag((byte)0x00);
+       this._hash_strings.put( type, strHandler);
+    }
+
+    public String getStringField( Integer type )
+    {
+        return ((StringHandler)this._hash_strings.get(type)).getStringData();
+    }
+
+    public void setCellRangeAddress( HSSFCellRangeAddress range )
+    {
+        this.field_regions = range;
+    }
+
+    public HSSFCellRangeAddress getCellRangeAddress( )
+    {
+        return this.field_regions;
+    }
+
+    /**
+     * gets the option flags field.
+     * @return options - the option flags field
+     */
+    public int getOptionFlags()
+    {
+       return this.field_option_flags;
+    }
+
+    public String toString()
+    {
+      /** @todo DVRecord string representation */
+        StringBuffer buffer = new StringBuffer();
+
+        return buffer.toString();
+    }
+
+    public int serialize(int offset, byte [] data)
+    {
+        int size = this.getRecordSize();
+        LittleEndian.putShort(data, 0 + offset, sid);
+        LittleEndian.putShort(data, 2 + offset, ( short ) (size-4));
+
+        int pos = 4;
+        LittleEndian.putInt(data, pos + offset, this.getOptionFlags());
+        pos += 4;
+        pos += ((StringHandler)this._hash_strings.get( DVRecord.STRING_PROMPT_TITLE )).serialize(pos+offset, data);
+        pos += ((StringHandler)this._hash_strings.get( DVRecord.STRING_ERROR_TITLE )).serialize(pos+offset, data);
+        pos += ((StringHandler)this._hash_strings.get( DVRecord.STRING_PROMPT_TEXT )).serialize(pos+offset, data);
+        pos += ((StringHandler)this._hash_strings.get( DVRecord.STRING_ERROR_TEXT )).serialize(pos+offset, data);
+        LittleEndian.putShort(data, offset+pos, this.field_size_first_formula);
+        pos += 2;
+        LittleEndian.putShort(data, offset+pos, this.field_not_used_1);
+        pos += 2;
+
+        for (int k = 0; k < this.field_rpn_token_1.size(); k++)
+        {
+            Ptg ptg = ( Ptg ) this.field_rpn_token_1.get(k);
+            ptg.writeBytes(data, pos+offset);
+            pos += ptg.getSize();
+        }
+
+        LittleEndian.putShort(data, offset+pos, this.field_size_sec_formula);
+        pos += 2;
+        LittleEndian.putShort(data, offset+pos, this.field_not_used_2);
+        pos += 2;
+        if ( this.field_size_sec_formula > 0 )
+        {
+          for (int k = 0; k < this.field_rpn_token_2.size(); k++)
+          {
+              Ptg ptg = ( Ptg ) this.field_rpn_token_2.get(k);
+              ptg.writeBytes(data, pos+offset);
+              pos += ptg.getSize();
+          }
+        }
+        this.field_regions.serialize(pos+offset, data);
+        return size;
+    }
+
+    public int getRecordSize()
+    {
+        int size = 4+4+2+2+2+2;//header+options_field+first_formula_size+first_unused+sec_formula_size+sec+unused;
+        if ( this._hash_strings != null )
+        {
+            Enumeration enum_keys = this._hash_strings.keys();
+            while ( enum_keys.hasMoreElements() )
+            {
+                size += ((StringHandler)this._hash_strings.get( (Integer)enum_keys.nextElement() )).getSize();
+            }
+        }
+        size += this.field_size_first_formula+ this.field_size_sec_formula;
+        size += this.field_regions.getSize();
+        return size;
+    }
+
+    public short getSid()
+    {
+        return this.sid;
+    }
+
+    /**@todo DVRecord = Serializare */
+
+    private class StringHandler
+    {
+        private int     _string_length       = 0x0001;
+        private byte    _string_unicode_flag = 0x00;
+        private String  _string_data         = "0x00";
+        private int     _start_offset;
+        private int     _end_offset;
+
+        StringHandler()
+        {
+
+        }
+
+        StringHandler(RecordInputStream in)
+        {
+            this.fillFields(in);
+        }
+
+        protected void fillFields(RecordInputStream in) 
+        {
+            this._string_length       = in.readUShort(); 
+            this._string_unicode_flag = in.readByte(); 
+            if (this._string_unicode_flag == 1)
+            {
+               this._string_data = in.readUnicodeLEString(this._string_length);
+            }
+            else
+            {
+                this._string_data = in.readCompressedUnicode(this._string_length);
+            }
+        }
+
+        private void setStringData( String string_data )
+        {
+          this._string_data = string_data;
+        }
+
+        private String getStringData()
+        {
+            return this._string_data;
+        }
+
+        private int getEndOffset()
+        {
+            return this._end_offset;
+        }
+
+        public int serialize( int offset, byte[] data )
+        {
+            LittleEndian.putUShort(data, offset, this._string_length );
+            data[2 + offset] = this._string_unicode_flag;
+            if (this._string_unicode_flag == 1)
+            {
+                StringUtil.putUnicodeLE(this._string_data, data, 3 + offset);
+            }
+            else
+            {
+                StringUtil.putCompressedUnicode(this._string_data, data, 3 + offset);
+            }
+            return getSize();
+        }
+
+        private void setUnicodeFlag( byte flag )
+        {
+            this._string_unicode_flag = flag;
+        }
+
+        private void setStringLength( int len )
+        {
+           this._string_length = len;
+        }
+
+        private int getStringByteLength()
+        {
+            return (this._string_unicode_flag == 1) ? this._string_length * 2 : this._string_length;
+        }
+
+        public int getSize()
+        {
+            return 2 + 1 + getStringByteLength();
+        }
+    }
+}
index 927d5f08beee04ba3aee3dfc323564edced6ee16..cf705a316d2a8bca396c356e14f3e587cd60be56 100644 (file)
@@ -75,7 +75,8 @@ public class RecordFactory
                 HorizontalPageBreakRecord.class, VerticalPageBreakRecord.class, 
                 WriteProtectRecord.class, FilePassRecord.class, PaneRecord.class,
                 NoteRecord.class, ObjectProtectRecord.class, ScenarioProtectRecord.class, 
-                FileSharingRecord.class, ChartTitleFormatRecord.class
+                FileSharingRecord.class, ChartTitleFormatRecord.class,
+                DVRecord.class, DVALRecord.class
             };
     }
     private static Map           recordsMap  = recordsToMap(records);
@@ -146,6 +147,9 @@ public class RecordFactory
                         } else if (record.getSid() == ContinueRecord.sid &&
                                    (lastRecord instanceof DrawingGroupRecord)) {
                             ((DrawingGroupRecord)lastRecord).processContinueRecord(((ContinueRecord)record).getData());
+                        } else if (record.getSid() == ContinueRecord.sid &&
+                                               (lastRecord instanceof StringRecord)) {
+                               ((StringRecord)lastRecord).processContinueRecord(((ContinueRecord)record).getData());
                         } else if (record.getSid() == ContinueRecord.sid) {
                           if (lastRecord instanceof UnknownRecord) {
                             //Gracefully handle records that we dont know about,
index a880d7235b1e4d7fb7c59fea7861622b95fc25fb..b3a42aaba4eeb5853a428b19fb3a136a25270619 100644 (file)
@@ -83,6 +83,14 @@ public class StringRecord
             field_3_string = StringUtil.getFromCompressedUnicode(data, 0, field_1_string_length);
         }
     }
+    
+    public void processContinueRecord(byte[] data) {
+       if(isUnCompressedUnicode()) {
+               field_3_string += StringUtil.getFromUnicodeLE(data, 0, field_1_string_length - field_3_string.length());
+       } else {
+               field_3_string += StringUtil.getFromCompressedUnicode(data, 0, field_1_string_length - field_3_string.length());
+       }
+    }
 
     public boolean isInValueSection()
     {
index ac3943da46fc4e9f2bc5138ebe6b7b6ee028fa67..9cc45507199217d11631321eec12b38d5b632044 100644 (file)
@@ -521,7 +521,7 @@ public class HSSFCell
      */
     public void setCellValue(Date value)
     {
-        setCellValue(HSSFDateUtil.getExcelDate(value));
+        setCellValue(HSSFDateUtil.getExcelDate(value, this.book.isUsing1904DateWindowing()));
     }
 
     /**
index e2725937fa76aa8cd0eef9af9c2d17fdc44623c4..cdea9ee5be4f8d4564b5f7628e70953e9ec75a38 100644 (file)
@@ -294,10 +294,24 @@ public class HSSFCellStyle
         format.setFontIndex(fontindex);
     }
 
+    /**
+     * gets the index of the font for this style
+     * @see org.apache.poi.hssf.usermodel.HSSFWorkbook#getFontAt(short)
+     */
     public short getFontIndex()
     {
         return format.getFontIndex();
     }
+    
+    /**
+     * gets the font for this style
+     * @param parentWorkbook The HSSFWorkbook that this style belongs to
+     * @see org.apache.poi.hssf.usermodel.HSSFCellStyle#getFontIndex()
+     * @see org.apache.poi.hssf.usermodel.HSSFWorkbook#getFontAt(short)
+     */
+    public HSSFFont getFont(HSSFWorkbook parentWorkbook) {
+       return parentWorkbook.getFontAt(getFontIndex());
+    }
 
     /**
      * set the cell's using this style to be hidden
@@ -689,7 +703,6 @@ public class HSSFCellStyle
      * @see #BORDER_MEDIUM_DASH_DOT_DOT
      * @see #BORDER_SLANTED_DASH_DOT
      */
-
     public short getBorderBottom()
     {
         return format.getBorderBottom();
@@ -697,9 +710,8 @@ public class HSSFCellStyle
 
     /**
      * set the color to use for the left border
-     * @param color
+     * @param color The index of the color definition
      */
-
     public void setLeftBorderColor(short color)
     {
         format.setLeftBorderPaletteIdx(color);
@@ -707,9 +719,9 @@ public class HSSFCellStyle
 
     /**
      * get the color to use for the left border
-     * @return color
+     * @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short)
+     * @param color The index of the color definition
      */
-
     public short getLeftBorderColor()
     {
         return format.getLeftBorderPaletteIdx();
@@ -717,9 +729,8 @@ public class HSSFCellStyle
 
     /**
      * set the color to use for the right border
-     * @param color
+     * @param color The index of the color definition
      */
-
     public void setRightBorderColor(short color)
     {
         format.setRightBorderPaletteIdx(color);
@@ -727,9 +738,9 @@ public class HSSFCellStyle
 
     /**
      * get the color to use for the left border
-     * @return color
+     * @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short)
+     * @param color The index of the color definition
      */
-
     public short getRightBorderColor()
     {
         return format.getRightBorderPaletteIdx();
@@ -737,9 +748,8 @@ public class HSSFCellStyle
 
     /**
      * set the color to use for the top border
-     * @param color
+     * @param color The index of the color definition
      */
-
     public void setTopBorderColor(short color)
     {
         format.setTopBorderPaletteIdx(color);
@@ -747,9 +757,9 @@ public class HSSFCellStyle
 
     /**
      * get the color to use for the top border
-     * @return color
+     * @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short)
+     * @param color The index of the color definition
      */
-
     public short getTopBorderColor()
     {
         return format.getTopBorderPaletteIdx();
@@ -757,9 +767,8 @@ public class HSSFCellStyle
 
     /**
      * set the color to use for the bottom border
-     * @param color
+     * @param color The index of the color definition
      */
-
     public void setBottomBorderColor(short color)
     {
         format.setBottomBorderPaletteIdx(color);
@@ -767,9 +776,9 @@ public class HSSFCellStyle
 
     /**
      * get the color to use for the left border
-     * @return color
+     * @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short)
+     * @param color The index of the color definition
      */
-
     public short getBottomBorderColor()
     {
         return format.getBottomBorderPaletteIdx();
@@ -871,9 +880,9 @@ public class HSSFCellStyle
 
     /**
      * get the background fill color
+     * @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short)
      * @return fill color
      */
-
     public short getFillBackgroundColor()
     {
        short result = format.getFillBackground();
@@ -889,7 +898,6 @@ public class HSSFCellStyle
      * <i>Note: Ensure Foreground color is set prior to background color.</i>
      * @param bg  color
      */
-
     public void setFillForegroundColor(short bg)
     {
         format.setFillForeground(bg);
@@ -898,12 +906,11 @@ public class HSSFCellStyle
 
     /**
      * get the foreground fill color
+     * @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short)
      * @return fill color
      */
-
     public short getFillForegroundColor()
     {
         return format.getFillForeground();
     }
-
 }
index 04a0f5732840d9f2ba7daddf0de0bb7dca459ca0..4d9098d75ae09d8f421ae3f48e9dd40b93a733de 100644 (file)
@@ -82,8 +82,8 @@ public class HSSFClientAnchor
      */
     public float getAnchorHeightInPoints(HSSFSheet sheet )
     {
-        int y1 = Math.min( getDy1(), getDy2() );
-        int y2 = Math.max( getDy1(), getDy2() );
+        int y1 = getDy1();
+        int y2 = getDy2();
         int row1 = Math.min( getRow1(), getRow2() );
         int row2 = Math.max( getRow1(), getRow2() );
 
index fc9ac3a3b3793790d994f0b0281f5c9543445bc3..fb3a92df86fa420c3c312bfe347dae2034145a75 100644 (file)
@@ -35,6 +35,8 @@ import java.util.GregorianCalendar;
  * @author  Glen Stampoultzis (glens at apache.org)
  * @author  Dan Sherman (dsherman at isisph.com)
  * @author  Hack Kampbjorn (hak at 2mba.dk)
+ * @author  Alex Jacoby (ajacoby at gmail.com)
+ * @author  Pavel Krupets (pkrupets at palmtreebusiness dot com)
  */
 
 public class HSSFDateUtil
@@ -54,19 +56,26 @@ public class HSSFDateUtil
      * @return Excel representation of Date (-1 if error - test for error by checking for less than 0.1)
      * @param  date the Date
      */
-
-    public static double getExcelDate(Date date)
-    {
+    public static double getExcelDate(Date date) {
+       return getExcelDate(date, false);
+    }
+    /**
+     * Given a Date, converts it into a double representing its internal Excel representation,
+     *   which is the number of days since 1/1/1900. Fractional days represent hours, minutes, and seconds.
+     *
+     * @return Excel representation of Date (-1 if error - test for error by checking for less than 0.1)
+     * @param date the Date
+     * @param use1904windowing Should 1900 or 1904 date windowing be used?
+     */
+    public static double getExcelDate(Date date, boolean use1904windowing) {
         Calendar calStart = new GregorianCalendar();
-
-        calStart.setTime(
-            date);   // If date includes hours, minutes, and seconds, set them to 0
-        if (calStart.get(Calendar.YEAR) < 1900)
+        calStart.setTime(date);   // If date includes hours, minutes, and seconds, set them to 0
+        
+        if ((!use1904windowing && calStart.get(Calendar.YEAR) < 1900) || 
+            (use1904windowing && calStart.get(Calendar.YEAR) < 1904)) 
         {
             return BAD_DATE;
-        }
-        else
-        {
+        } else {
            // Because of daylight time saving we cannot use
            //     date.getTime() - calStart.getTimeInMillis()
            // as the difference in milliseconds between 00:00 and 04:00
@@ -80,32 +89,39 @@ public class HSSFDateUtil
                                ) * 1000 + calStart.get(Calendar.MILLISECOND)
                               ) / ( double ) DAY_MILLISECONDS;
             calStart = dayStart(calStart);
-
-            double value = fraction + absoluteDay(calStart);
             
-            if (value >= 60) {
-                value += 1;
+            double value = fraction + absoluteDay(calStart, use1904windowing);
+            
+            if (!use1904windowing && value >= 60) {
+                value++;
+            } else if (use1904windowing) {
+                value--;
             }
             
             return value;
         }
     }
-
+    
     /**
-     * Given a excel date, converts it into a Date.
-     * Assumes 1900 date windowing.
+     *  Given an Excel date with using 1900 date windowing, and
+     *   converts it to a java.util.Date.
      *
-     * @param  date the Excel Date
-     *
-     * @return Java representation of a date (null if error)
-     * @see #getJavaDate(double,boolean)
+     *  NOTE: If the default <code>TimeZone</code> in Java uses Daylight
+     *  Saving Time then the conversion back to an Excel date may not give
+     *  the same value, that is the comparison
+     *  <CODE>excelDate == getExcelDate(getJavaDate(excelDate,false))</CODE>
+     *  is not always true. For example if default timezone is
+     *  <code>Europe/Copenhagen</code>, on 2004-03-28 the minute after
+     *  01:59 CET is 03:00 CEST, if the excel date represents a time between
+     *  02:00 and 03:00 then it is converted to past 03:00 summer time
+     *  
+     *  @param date  The Excel date.
+     *  @return Java representation of the date, or null if date is not a valid Excel date
+     *  @see java.util.TimeZone
      */
-
-    public static Date getJavaDate(double date)
-    {
-        return getJavaDate(date,false);
+    public static Date getJavaDate(double date) {
+       return getJavaDate(date, false);
     }
-    
     /**
      *  Given an Excel date with either 1900 or 1904 date windowing,
      *  converts it to a java.util.Date.
@@ -142,7 +158,7 @@ public class HSSFDateUtil
             GregorianCalendar calendar = new GregorianCalendar(startYear,0,
                                                      wholeDays + dayAdjust);
             int millisecondsInDay = (int)((date - Math.floor(date)) * 
-                                          (double) DAY_MILLISECONDS + 0.5);
+                                          DAY_MILLISECONDS + 0.5);
             calendar.set(GregorianCalendar.MILLISECOND, millisecondsInDay);
             return calendar.getTime();
         }
@@ -238,7 +254,7 @@ public class HSSFDateUtil
      *  Check if a cell contains a date
      *  Since dates are stored internally in Excel as double values 
      *  we infer it is a date if it is formatted as such. 
-     *  @see #isADateFormat(int,string)
+     *  @see #isADateFormat(int, String)
      *  @see #isInternalDateFormat(int)
      */
     public static boolean isCellDateFormatted(HSSFCell cell) {
@@ -259,7 +275,7 @@ public class HSSFDateUtil
      *   excel date formats.
      *  As Excel stores a great many of its dates in "non-internal"
      *   date formats, you will not normally want to use this method.
-     *  @see #isADateFormat(int,string)
+     *  @see #isADateFormat(int,String)
      *  @see #isInternalDateFormat(int)
      */
     public static boolean isCellInternalDateFormatted(HSSFCell cell) {
@@ -296,10 +312,10 @@ public class HSSFDateUtil
      * @exception IllegalArgumentException if date is invalid
      */
 
-    private static int absoluteDay(Calendar cal)
+    static int absoluteDay(Calendar cal, boolean use1904windowing)
     {
         return cal.get(Calendar.DAY_OF_YEAR)
-               + daysInPriorYears(cal.get(Calendar.YEAR));
+               + daysInPriorYears(cal.get(Calendar.YEAR), use1904windowing);
     }
 
     /**
@@ -307,14 +323,14 @@ public class HSSFDateUtil
      *
      * @return    days  number of days in years prior to yr.
      * @param     yr    a year (1900 < yr < 4000)
+     * @param use1904windowing 
      * @exception IllegalArgumentException if year is outside of range.
      */
 
-    private static int daysInPriorYears(int yr)
+    private static int daysInPriorYears(int yr, boolean use1904windowing)
     {
-        if (yr < 1900) {
-            throw new IllegalArgumentException(
-                "'year' must be 1900 or greater");
+        if ((!use1904windowing && yr < 1900) || (use1904windowing && yr < 1900)) {
+            throw new IllegalArgumentException("'year' must be 1900 or greater");
         }
         
         int yr1  = yr - 1;
@@ -323,7 +339,7 @@ public class HSSFDateUtil
                        + yr1 / 400 // plus years divisible by 400 
                        - 460;      // leap days in previous 1900 years
         
-        return 365 * (yr - 1900) + leapDays;
+        return 365 * (yr - (use1904windowing ? 1904 : 1900)) + leapDays;
     }
     
     // set HH:MM:SS fields of cal to 00:00:00:000
index 852e15ee28026107bd6304df6dfeda752fd0a53c..cfaa5e4f4827855dc5476c9d031460565834d808 100644 (file)
@@ -281,8 +281,8 @@ public class HSSFFont
      * @return color to use
      * @see #COLOR_NORMAL
      * @see #COLOR_RED
+     * @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short)
      */
-
     public short getColor()
     {
         return font.getColorPaletteIndex();
index 91098c2dcb238c672da80624bc13ae65d29f69fb..b52fa1e5b20a29f24317e0aa0500cb13b2edfc13 100644 (file)
 package org.apache.poi.hssf.usermodel;
 
 import org.apache.poi.ddf.EscherRecord;
+import org.apache.poi.hssf.model.FormulaParser;
 import org.apache.poi.hssf.model.Sheet;
 import org.apache.poi.hssf.model.Workbook;
 import org.apache.poi.hssf.record.*;
+import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.hssf.util.HSSFCellRangeAddress;
+import org.apache.poi.hssf.util.HSSFDataValidation;
 import org.apache.poi.hssf.util.Region;
 import org.apache.poi.hssf.util.PaneInformation;
 import org.apache.poi.util.POILogFactory;
@@ -35,6 +39,7 @@ import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Stack;
 import java.util.TreeMap;
 import java.text.AttributedString;
 import java.text.NumberFormat;
@@ -353,6 +358,94 @@ public class HSSFSheet
     {
         return lastrow;
     }
+    
+    /**
+     * Creates a data validation object
+     * @param obj_validation The Data validation object settings
+     */
+    public void addValidationData(HSSFDataValidation obj_validation)
+    {
+       if ( obj_validation == null )
+       {
+         return;
+       }
+       DVALRecord dvalRec = (DVALRecord)sheet.findFirstRecordBySid( DVALRecord.sid );
+       int eofLoc = sheet.findFirstRecordLocBySid( EOFRecord.sid );
+       if ( dvalRec == null )
+       {
+          dvalRec = new DVALRecord();
+          sheet.getRecords().add( eofLoc, dvalRec );
+       }
+       int curr_dvRecNo = dvalRec.getDVRecNo();
+       dvalRec.setDVRecNo(curr_dvRecNo+1);
+
+       //create dv record
+       DVRecord dvRecord = new DVRecord();
+
+       //dv record's option flags
+       dvRecord.setDataType( obj_validation.getDataValidationType() );
+       dvRecord.setErrorStyle(obj_validation.getErrorStyle());
+       dvRecord.setEmptyCellAllowed(obj_validation.getEmptyCellAllowed());
+       dvRecord.setSurppresDropdownArrow(obj_validation.getSurppressDropDownArrow());
+       dvRecord.setShowPromptOnCellSelected(obj_validation.getShowPromptBox());
+       dvRecord.setShowErrorOnInvalidValue(obj_validation.getShowErrorBox());
+       dvRecord.setConditionOperator(obj_validation.getOperator());
+
+       //string fields
+       dvRecord.setStringField( DVRecord.STRING_PROMPT_TITLE,obj_validation.getPromptBoxTitle());
+       dvRecord.setStringField( DVRecord.STRING_PROMPT_TEXT, obj_validation.getPromptBoxText());
+       dvRecord.setStringField( DVRecord.STRING_ERROR_TITLE, obj_validation.getErrorBoxTitle());
+       dvRecord.setStringField( DVRecord.STRING_ERROR_TEXT, obj_validation.getErrorBoxText());
+
+       //formula fields ( size and data )
+       String str_formula = obj_validation.getFirstFormula();
+       FormulaParser fp = new FormulaParser(str_formula+";",book);
+       fp.parse();
+       Stack ptg_arr = new Stack();
+       Ptg[] ptg  = fp.getRPNPtg();
+       int size = 0;
+       for (int k = 0; k < ptg.length; k++)
+       {
+           if ( ptg[k] instanceof org.apache.poi.hssf.record.formula.AreaPtg )
+           {
+              //we should set ptgClass to Ptg.CLASS_REF and explicit formula string to false
+              ptg[k].setClass(Ptg.CLASS_REF);
+              obj_validation.setExplicitListFormula(false);
+           }
+           size += ptg[k].getSize();
+           ptg_arr.push(ptg[k]);
+       }
+       dvRecord.setFirstFormulaRPN(ptg_arr);
+       dvRecord.setFirstFormulaSize((short)size);
+
+       dvRecord.setListExplicitFormula(obj_validation.getExplicitListFormula());
+
+       if ( obj_validation.getSecondFormula() != null )
+       {
+         str_formula = obj_validation.getSecondFormula();
+         fp = new FormulaParser(str_formula+";",book);
+         fp.parse();
+         ptg_arr = new Stack();
+         ptg  = fp.getRPNPtg();
+         size = 0;
+         for (int k = 0; k < ptg.length; k++)
+         {
+             size += ptg[k].getSize();
+             ptg_arr.push(ptg[k]);
+         }
+         dvRecord.setSecFormulaRPN(ptg_arr);
+         dvRecord.setSecFormulaSize((short)size);
+       }
+
+       //dv records cell range field
+       HSSFCellRangeAddress cell_range = new HSSFCellRangeAddress();
+       cell_range.addADDRStructure(obj_validation.getFirstRow(), obj_validation.getFirstColumn(), obj_validation.getLastRow(), obj_validation.getLastColumn());
+       dvRecord.setCellRangeAddress(cell_range);
+
+       //add dv record
+       eofLoc = sheet.findFirstRecordLocBySid( EOFRecord.sid );
+       sheet.getRecords().add( eofLoc, dvRecord );
+    }
 
     /**
      * Get the visibility state for a given column.
diff --git a/src/java/org/apache/poi/hssf/util/HSSFCellRangeAddress.java b/src/java/org/apache/poi/hssf/util/HSSFCellRangeAddress.java
new file mode 100644 (file)
index 0000000..438f5e5
--- /dev/null
@@ -0,0 +1,253 @@
+/* ====================================================================
+   Copyright 2002-2004   Apache Software Foundation
+
+   Licensed 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.hssf.util;
+
+import org.apache.poi.hssf.record.RecordInputStream;
+import org.apache.poi.util.LittleEndian;
+import java.util.ArrayList;
+
+/**
+ * <p>Title: HSSFCellRangeAddress</p>
+ * <p>Description:
+ *          Implementation of the cell range address lists,like is described in
+ *          OpenOffice.org's Excel Documentation .
+ *          In BIFF8 there is a common way to store absolute cell range address
+ *          lists in several records (not formulas). A cell range address list
+ *          consists of a field with the number of ranges and the list of the range
+ *          addresses. Each cell range address (called an ADDR structure) contains
+ *          4 16-bit-values.</p>
+ * <p>Copyright: Copyright (c) 2004</p>
+ * <p>Company: </p>
+ * @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
+ * @version 2.0-pre
+ */
+
+public class HSSFCellRangeAddress
+{
+    /**
+     * Number of following ADDR structures
+     */
+    private short             field_addr_number;
+
+    /**
+     * List of ADDR structures. Each structure represents a cell range
+     */
+    private ArrayList         field_regions_list;
+
+    public HSSFCellRangeAddress()
+    {
+
+    }
+
+    /**
+     * Construct a new HSSFCellRangeAddress object and sets its fields appropriately .
+     * Even this isn't an Excel record , I kept the same behavior for reading/writing
+     * the object's data as for a regular record .
+     * 
+     * @param in the RecordInputstream to read the record from
+     */
+    public HSSFCellRangeAddress(RecordInputStream in)
+    {
+        this.fillFields(in);
+    }
+
+    public void fillFields(RecordInputStream in)
+    {
+        this.field_addr_number = in.readShort(); 
+               this.field_regions_list = new ArrayList(this.field_addr_number);
+
+               for (int k = 0; k < this.field_addr_number; k++)
+               {
+            short first_row = in.readShort(); 
+            short first_col = in.readShort();
+            short last_row  = in.readShort();
+            short last_col  = in.readShort();
+
+                       AddrStructure region = new AddrStructure(first_row, first_col, last_row, last_col);
+                       this.field_regions_list.add(region);
+               }
+    }
+
+    /**
+     * Get the number of following ADDR structures.
+     * The number of this structures is automatically set when reading an Excel file
+     * and/or increased when you manually add a new ADDR structure .
+     * This is the reason there isn't a set method for this field .
+     * @return number of ADDR structures
+     */
+    public short getADDRStructureNumber()
+    {
+        return this.field_addr_number;
+    }
+
+    /**
+     * Add an ADDR structure .
+     * @param first_row - the upper left hand corner's row
+     * @param first_col - the upper left hand corner's col
+     * @param last_row  - the lower right hand corner's row
+     * @param last_col  - the lower right hand corner's col
+     * @return the index of this ADDR structure
+     */
+    public int addADDRStructure(short first_row, short first_col, short last_row, short last_col)
+    {
+        if (this.field_regions_list == null)
+        {
+            //just to be sure :-)
+            this.field_addr_number= 0;
+            this.field_regions_list = new ArrayList(10);
+        }
+        AddrStructure region = new AddrStructure(first_row, last_row, first_col, last_col);
+
+        this.field_regions_list.add(region);
+        this.field_addr_number++;
+        return this.field_addr_number;
+    }
+
+    /**
+     * Remove the ADDR structure stored at the passed in index
+     * @param index The ADDR structure's index
+     */
+    public void removeADDRStructureAt(int index)
+    {
+        this.field_regions_list.remove(index);
+        this.field_addr_number--;
+    }
+
+    /**
+     * return the ADDR structure at the given index.
+     * @return AddrStructure representing
+     */
+    public AddrStructure getADDRStructureAt(int index)
+    {
+        return ( AddrStructure ) this.field_regions_list.get(index);
+    }
+
+    public int serialize(int offset, byte [] data)
+    {
+        int pos  = 2;
+
+        LittleEndian.putShort(data, offset, this.getADDRStructureNumber());
+        for (int k = 0; k < this.getADDRStructureNumber(); k++)
+        {
+            AddrStructure region = this.getADDRStructureAt(k);
+            LittleEndian.putShort(data, offset + pos, region.getFirstRow());
+            pos += 2;
+            LittleEndian.putShort(data, offset + pos, region.getLastRow());
+            pos += 2;
+            LittleEndian.putShort(data, offset + pos, region.getFirstColumn());
+            pos += 2;
+            LittleEndian.putShort(data, offset + pos, region.getLastColumn());
+            pos += 2;
+        }
+        return this.getSize();
+    }
+
+    public int getSize()
+    {
+       return 2 + this.field_addr_number*8;
+    }
+
+    public class AddrStructure
+    {
+        private short _first_row;
+        private short _first_col;
+        private short _last_row;
+        private short _last_col;
+
+        public AddrStructure(short first_row, short last_row, short first_col, short last_col)
+        {
+            this._first_row = first_row;
+            this._last_row   = last_row;
+            this._first_col = first_col;
+            this._last_col   = last_col;
+        }
+
+               /**
+                * get the upper left hand corner column number
+                * @return column number for the upper left hand corner
+                */
+               public short getFirstColumn()
+               {
+                       return this._first_col;
+               }
+
+               /**
+                * get the upper left hand corner row number
+                * @return row number for the upper left hand corner
+                */
+               public short getFirstRow()
+               {
+                       return this._first_row;
+               }
+
+               /**
+                * get the lower right hand corner column number
+                * @return column number for the lower right hand corner
+                */
+               public short getLastColumn()
+               {
+                       return this._last_col;
+               }
+
+               /**
+                * get the lower right hand corner row number
+                * @return row number for the lower right hand corner
+                */
+               public short getLastRow()
+               {
+                       return this._last_row;
+               }
+
+               /**
+                * set the upper left hand corner column number
+                * @param this._first_col  column number for the upper left hand corner
+                */
+               public void setFirstColumn(short first_col)
+               {
+                       this._first_col = first_col;
+               }
+
+               /**
+                * set the upper left hand corner row number
+                * @param rowFrom  row number for the upper left hand corner
+                */
+               public void setFirstRow(short first_row)
+               {
+                       this._first_row = first_row;
+               }
+
+               /**
+                * set the lower right hand corner column number
+                * @param colTo  column number for the lower right hand corner
+                */
+               public void setLastColumn(short last_col)
+               {
+                       this._last_col = last_col;
+               }
+
+               /**
+                * get the lower right hand corner row number
+                * @param rowTo  row number for the lower right hand corner
+                */
+               public void setLastRow(short last_row)
+               {
+                       this._last_row = last_row;
+               }
+       }
+}
+
+
diff --git a/src/java/org/apache/poi/hssf/util/HSSFDataValidation.java b/src/java/org/apache/poi/hssf/util/HSSFDataValidation.java
new file mode 100644 (file)
index 0000000..af578be
--- /dev/null
@@ -0,0 +1,471 @@
+/* ====================================================================
+   Copyright 2002-2004   Apache Software Foundation
+
+   Licensed 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.hssf.util;
+
+/**
+ * <p>Title: HSSFDataValidation</p>
+ * <p>Description: Utilty class for creating data validation cells</p>
+ * <p>Copyright: Copyright (c) 2004</p>
+ * <p>Company: </p>
+ * @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
+ * @version 2.0-pre
+ */
+
+public class HSSFDataValidation
+{
+  /**
+   * Validation data type constants
+   */
+  /**
+   * Any type
+   */
+  public static final int DATA_TYPE_ANY              = 0x00;
+  /**
+   * Integer type
+   */
+  public static final int DATA_TYPE_INTEGER          = 0x01;
+  /**
+   * Decimal type
+   */
+  public static final int DATA_TYPE_DECIMAL          = 0x02;
+  /**
+   * List type ( combo box type )
+   */
+  public static final int DATA_TYPE_LIST             = 0x03;
+  /**
+   * Date type
+   */
+  public static final int DATA_TYPE_DATE             = 0x04;
+  /**
+   * Time type
+   */
+  public static final int DATA_TYPE_TIME             = 0x05;
+  /**
+   * String length type
+   */
+  public static final int DATA_TYPE_TEXT_LENGTH      = 0x06;
+  /**
+   * Formula ( custom ) type
+   */
+  public static final int DATA_TYPE_FORMULA          = 0x07;
+
+  /**
+   * Error style constants for error box
+   */
+  /**
+   * STOP style like
+   */
+  public static final int ERROR_STYLE_STOP           = 0x00;
+  /**
+   * WARNING style like
+   */
+  public static final int ERROR_STYLE_WARNING        = 0x01;
+  /**
+   * INFO style like
+   */
+  public static final int ERROR_STYLE_INFO           = 0x02;
+
+  /**
+   * Condition operator
+   */
+  public static final int OPERATOR_BETWEEN           = 0x00;
+  public static final int OPERATOR_NOT_BETWEEN       = 0x01;
+  public static final int OPERATOR_EQUAL             = 0x02;
+  public static final int OPERATOR_NOT_EQUAL         = 0x03;
+  public static final int OPERATOR_GREATER_THAN      = 0x04;
+  public static final int OPERATOR_LESS_THAN         = 0x05;
+  public static final int OPERATOR_GREATER_OR_EQUAL  = 0x06;
+  public static final int OPERATOR_LESS_OR_EQUAL     = 0x07;
+
+  private short _first_row                  = 0;
+  private short _first_col                  = 0;
+  private short _last_row                   = 0;
+  private short _last_col                   = 0;
+
+  private String _prompt_title              = null;
+  private String _prompt_text               = null;
+  private String _error_title               = null;
+  private String _error_text                = null;
+  private String _string_first_formula      = null;
+  private String _string_sec_formula        = null;
+
+  private int  _data_type                   = HSSFDataValidation.DATA_TYPE_ANY;
+  private int  _error_style                 = HSSFDataValidation.ERROR_STYLE_STOP;
+  private boolean  _list_explicit_formula   = true;
+  private boolean  _empty_cell_allowed      = true;
+  private boolean  _surpress_dropdown_arrow = false;
+  private boolean  _show_prompt_box         = true;
+  private boolean  _show_error_box          = true;
+  private int _operator                     = HSSFDataValidation.OPERATOR_BETWEEN;
+
+
+  /**
+   * Empty constructor
+   */
+  public HSSFDataValidation( )
+  {
+  }
+
+  /**
+   * Constructor wich initializes the cell range on wich this object will be applied
+   * @param first_row First row
+   * @param first_col First column
+   * @param last_row Last row
+   * @param last_col Last column
+   */
+  public HSSFDataValidation( short first_row, short first_col, short last_row, short last_col )
+  {
+      this._first_row = first_row;
+      this._first_col = first_col;
+      this._last_row  = last_row;
+      this._last_col  = last_col;
+  }
+
+  /**
+   * Set the type of this object
+   * @param data_type The type
+   * @see DATA_TYPE_ANY, DATA_TYPE_INTEGER, DATA_TYPE_DECIMNAL, DATA_TYPE_LIST, DATA_TYPE_DATE,
+   *      DATA_TYPE_TIME, DATA_TYPE_TEXT_LENTGH, DATA_TYPE_FORMULA
+   */
+  public void setDataValidationType( int data_type )
+  {
+      this._data_type = data_type;
+  }
+
+  /**
+   * The data type of this object
+   * @return The type
+   * @see DATA_TYPE_ANY, DATA_TYPE_INTEGER, DATA_TYPE_DECIMNAL, DATA_TYPE_LIST, DATA_TYPE_DATE,
+   *      DATA_TYPE_TIME, DATA_TYPE_TEXT_LENTGH, DATA_TYPE_FORMULA
+   */
+  public int getDataValidationType()
+  {
+     return this._data_type;
+  }
+
+  /**
+   * Sets the error style for error box
+   * @param error_style Error style constant
+   * @see ERROR_STYLE_STOP, ERROR_STYLE_WARNING, ERROR_STYLE_INFO
+   */
+  public void setErrorStyle( int error_style )
+  {
+      this._error_style = error_style;
+  }
+
+  /**
+   * returns the error style of errror box
+   * @return the style constant
+   * @see ERROR_STYLE_STOP, ERROR_STYLE_WARNING, ERROR_STYLE_INFO
+   */
+  public int getErrorStyle( )
+  {
+      return this._error_style;
+  }
+
+  /**
+   * If this object has an explicit formula . This is useful only for list data validation object
+   * @param explicit True if use an explicit formula
+   */
+  public void setExplicitListFormula( boolean explicit )
+  {
+     this._list_explicit_formula = explicit;
+  }
+
+  /**
+   * Returns the settings for explicit formula . This is useful only for list data validation objects.
+   * This method always returns false if the object isn't a list validation object
+   * @see setDataValidationType( int data_type )
+   * @return
+   */
+  public boolean getExplicitListFormula( )
+  {
+    if ( this._data_type != HSSFDataValidation.DATA_TYPE_LIST )
+    {
+        return false;
+    }
+    return this._list_explicit_formula ;
+  }
+
+  /**
+   * Sets if this object allows empty as a valid value
+   * @param allowed True if this object should treats empty as valid value , false otherwise
+   */
+  public void setEmptyCellAllowed( boolean allowed )
+  {
+     this._empty_cell_allowed = allowed;
+  }
+
+  /**
+   * Retrieve the settings for empty cells allowed
+   * @return True if this object should treats empty as valid value , false otherwise
+   */
+  public boolean getEmptyCellAllowed( )
+  {
+     return this._empty_cell_allowed ;
+  }
+
+  /**
+   * Useful for list validation objects .
+   * @param surppres True if a list should display the values into a drop down list , false otherwise .
+   *                 In other words , if a list should display the arrow sign on its right side
+   */
+  public void setSurppressDropDownArrow( boolean surppres )
+  {
+     this._surpress_dropdown_arrow = surppres;
+  }
+
+  /**
+   * Useful only list validation objects .
+   * This method always returns false if the object isn't a list validation object
+   * @return True if a list should display the values into a drop down list , false otherwise .
+   * @see setDataValidationType( int data_type )
+   */
+  public boolean getSurppressDropDownArrow( )
+  {
+     if ( this._data_type != HSSFDataValidation.DATA_TYPE_LIST )
+     {
+         return false;
+     }
+     return this._surpress_dropdown_arrow ;
+  }
+
+  /**
+   * Sets the behaviour when a cell which belongs to this object is selected
+   * @param show True if an prompt box should be displayed , false otherwise
+   */
+  public void setShowPromptBox( boolean show )
+  {
+     this._show_prompt_box = show;
+  }
+
+  /**
+   * @param show True if an prompt box should be displayed , false otherwise
+   */
+  public boolean getShowPromptBox( )
+  {
+     if ( (this.getPromptBoxText() == null) && (this.getPromptBoxTitle() == null) )
+     {
+       return false;
+     }
+     return this._show_prompt_box ;
+  }
+
+  /**
+   * Sets the behaviour when an invalid value is entered
+   * @param show True if an error box should be displayed , false otherwise
+   */
+  public void setShowErrorBox( boolean show )
+  {
+     this._show_error_box = show;
+  }
+
+  /**
+   * @return True if an error box should be displayed , false otherwise
+   */
+  public boolean getShowErrorBox( )
+  {
+    if ( (this.getErrorBoxText() == null) && (this.getErrorBoxTitle() == null) )
+    {
+      return false;
+    }
+    return this._show_error_box ;
+  }
+
+  /**
+   * Sets the operator involved in the formula whic governs this object
+   * Example : if you wants that a cell to accept only values between 1 and 5 , which
+   * mathematically means 1 <= value <= 5 , then the operator should be OPERATOR_BETWEEN
+   * @param operator A constant for operator
+   * @see OPERATOR_BETWEEN, OPERATOR_NOT_BETWEEN, OPERATOR_EQUAL, OPERATOR_NOT_EQUAL
+   * OPERATOR_GREATER_THAN, OPERATOR_LESS_THAN, OPERATOR_GREATER_OR_EQUAL,
+   * OPERATOR_LESS_OR_EQUAL
+   */
+  public void setOperator( int operator )
+  {
+      this._operator = operator;
+  }
+
+  /**
+   * Retrieves the operator used for this object's formula
+   * @return
+   * @see OPERATOR_BETWEEN, OPERATOR_NOT_BETWEEN, OPERATOR_EQUAL, OPERATOR_NOT_EQUAL
+   * OPERATOR_GREATER_THAN, OPERATOR_LESS_THAN, OPERATOR_GREATER_OR_EQUAL,
+   * OPERATOR_LESS_OR_EQUAL
+   */
+  public int getOperator()
+  {
+      return this._operator;
+  }
+
+  /**
+   * Sets the title and text for the prompt box . Prompt box is displayed when the user
+   * selects a cell which belongs to this validation object . In order for a prompt box
+   * to be displayed you should also use method setShowPromptBox( boolean show )
+   * @param title The prompt box's title
+   * @param text The prompt box's text
+   * @see setShowPromptBox( boolean show )
+   */
+  public void createPromptBox( String title, String text )
+  {
+      this._prompt_title = title;
+      this._prompt_text  = text;
+      this.setShowPromptBox(true);
+  }
+
+  /**
+   * Returns the prompt box's title
+   * @return Prompt box's title or null
+   */
+  public String getPromptBoxTitle( )
+  {
+    return this._prompt_title;
+  }
+
+  /**
+   * Returns the prompt box's text
+   * @return Prompt box's text or null
+   */
+  public String getPromptBoxText( )
+  {
+    return this._prompt_text;
+  }
+
+  /**
+   * Sets the title and text for the error box . Error box is displayed when the user
+   * enters an invalid value int o a cell which belongs to this validation object .
+   * In order for an error box to be displayed you should also use method
+   * setShowErrorBox( boolean show )
+   * @param title The error box's title
+   * @param text The error box's text
+   * @see setShowErrorBox( boolean show )
+   */
+  public void createErrorBox( String title, String text )
+  {
+      this._error_title = title;
+      this._error_text  = text;
+      this.setShowErrorBox(true);
+  }
+
+  /**
+   * Returns the error box's title
+   * @return Error box's title or null
+   */
+  public String getErrorBoxTitle( )
+  {
+    return this._error_title;
+  }
+
+  /**
+   * Returns the error box's text
+   * @return Error box's text or null
+   */
+  public String getErrorBoxText( )
+  {
+    return this._error_text;
+  }
+
+  /**
+   * Sets the first formula for this object .
+   * A formula is divided into three parts : first formula , operator and second formula .
+   * In other words , a formula contains a left oprand , an operator and a right operand.
+   * This is the general rule . An example is 1<= value <= 5 . In this case ,
+   * the left operand ( or the first formula ) is the number 1 . The operator is
+   * OPERATOR_BETWEEN and the right operand ( or the second formula ) is 5 .
+   * @param formula
+   */
+  public void setFirstFormula( String formula )
+  {
+     this._string_first_formula = formula;
+  }
+
+  /**
+   * Returns the first formula
+   * @return
+   */
+  public String getFirstFormula( )
+  {
+     return this._string_first_formula;
+  }
+
+  /**
+   * Sets the first formula for this object .
+   * A formula is divided into three parts : first formula , operator and second formula .
+   * In other words , a formula contains a left oprand , an operator and a right operand.
+   * This is the general rule . An example is 1<= value <=5 . In this case ,
+   * the left operand ( or the first formula ) is the number 1 . The operator is
+   * OPERATOR_BETWEEN and the right operand ( or the second formula ) is 5 .
+   * But there are cases when a second formula isn't needed :
+   * You want somethink like : all values less than 5 . In this case , there's only a first
+   * formula ( in our case 5 ) and the operator OPERATOR_LESS_THAN
+   * @param formula
+   */
+  public void setSecondFormula( String formula )
+  {
+     this._string_sec_formula = formula;
+  }
+
+  /**
+   * Returns the second formula
+   * @return
+   */
+  public String getSecondFormula( )
+  {
+     return this._string_sec_formula;
+  }
+
+  public void setFirstRow( short first_row )
+  {
+    this._first_row = first_row;
+  }
+
+  public void setFirstColumn( short first_column )
+  {
+    this._first_col = first_column;
+  }
+
+  public void setLastRow( short last_row )
+  {
+    this._last_row = last_row;
+  }
+
+  public void setLastColumn( short last_column )
+  {
+    this._last_col = last_column;
+  }
+
+  public short getFirstRow()
+  {
+    return this._first_row;
+  }
+
+  public short getFirstColumn()
+  {
+    return this._first_col;
+  }
+
+  public short getLastRow()
+  {
+    return this._last_row;
+  }
+
+  public short getLastColumn()
+  {
+    return this._last_col;
+  }
+
+}
\ No newline at end of file
index f5bb58a76fabd45eb8013d61f62d757e80ce5107..4f89af154597f965349dc951e5224ff513dde37f 100644 (file)
@@ -19,6 +19,7 @@
 
 package org.apache.poi.poifs.storage;
 
+import org.apache.poi.poifs.common.POIFSConstants;
 import org.apache.poi.poifs.filesystem.BATManaged;
 import org.apache.poi.poifs.filesystem.POIFSDocument;
 import org.apache.poi.poifs.property.RootProperty;
@@ -69,6 +70,8 @@ public class SmallBlockTableWriter
                 {
                     _small_blocks.add(blocks[ j ]);
                 }
+            } else {
+               doc.setStartBlock(POIFSConstants.END_OF_CHAIN);
             }
         }
         _sbat.simpleCreateBlocks();
index 7126b2b9bee6da09189af753bb1f5594a3a19730..42b69c850b8de1c67511737ed1e429c687bd347a 100644 (file)
@@ -19,6 +19,7 @@
 
 package org.apache.poi.util;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 
@@ -28,6 +29,25 @@ public class IOUtils
     {
     }
 
+    /**
+     * Reads all the data from the input stream, and returns
+     *  the bytes read.
+     */
+    public static byte[] toByteArray(InputStream stream) throws IOException {
+       ByteArrayOutputStream baos = new ByteArrayOutputStream();
+       
+       byte[] buffer = new byte[4096];
+       int read = 0;
+       while(read != -1) {
+               read = stream.read(buffer);
+               if(read > 0) {
+                       baos.write(buffer, 0, read);
+               }
+       }
+       
+       return baos.toByteArray();
+    }
+
     /**
      * Helper method, just calls <tt>readFully(in, b, 0, b.length)</tt>
      */
index 9dd8e4838ec4a73aa1902f5e7afc607d5d7eaa6d..673b5246e147c9de21ca6be0951e22ee360eaacd 100644 (file)
@@ -161,7 +161,8 @@ public class StringUtil {
                final int offset,
                final int len) {
                try {
-                       return new String(string, offset, len, "ISO-8859-1");
+                       int len_to_use = Math.min(len, string.length - offset);
+                       return new String(string, offset, len_to_use, "ISO-8859-1");
                } catch (UnsupportedEncodingException e) {
                        throw new InternalError(); /* unreachable */
                }
diff --git a/src/scratchpad/examples/src/org/apache/poi/hslf/examples/TableDemo.java b/src/scratchpad/examples/src/org/apache/poi/hslf/examples/TableDemo.java
new file mode 100755 (executable)
index 0000000..25ff9ad
--- /dev/null
@@ -0,0 +1,127 @@
+\r
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.hslf.examples;\r
+\r
+import org.apache.poi.hslf.usermodel.SlideShow;\r
+import org.apache.poi.hslf.usermodel.RichTextRun;\r
+import org.apache.poi.hslf.model.*;\r
+\r
+import java.awt.*;\r
+import java.io.FileOutputStream;\r
+\r
+/**\r
+ * Demonstrates how to create tables\r
+ * \r
+ * @author Yegor Kozlov\r
+ */\r
+public class TableDemo {\r
+\r
+    public static void main(String[] args) throws Exception {\r
+\r
+        //test data for the first taable\r
+        String[][] txt1 = {\r
+            {"INPUT FILE", "NUMBER OF RECORDS"},\r
+            {"Item File", "11,559"},\r
+            {"Vendor File", "502"},\r
+            {"Purchase History File - # of PO\u2019s\r(12/01/04 - 05/31/06)", "12,852"},\r
+            {"Purchase History File - # of PO Lines\r(12/01/04 - 05/31/06)", "53,523" },\r
+            {"Total PO History Spend", "$10,172,038"}\r
+        };\r
+\r
+        SlideShow ppt = new SlideShow();\r
+\r
+        Slide slide = ppt.createSlide();\r
+\r
+        //six rows, two columns\r
+        Table table1 = new Table(6, 2);\r
+        for (int i = 0; i < txt1.length; i++) {\r
+            for (int j = 0; j < txt1[i].length; j++) {\r
+                TableCell cell = table1.getCell(i, j);\r
+                cell.setText(txt1[i][j]);\r
+                RichTextRun rt = cell.getTextRun().getRichTextRuns()[0];\r
+                rt.setFontName("Arial");\r
+                rt.setFontSize(10);\r
+                if(i == 0){\r
+                    cell.getFill().setForegroundColor(new Color(227, 227, 227));\r
+                } else {\r
+                    rt.setBold(true);\r
+                }\r
+                cell.setVerticalAlignment(TextBox.AnchorMiddle);\r
+                cell.setHorizontalAlignment(TextBox.AlignCenter);\r
+            }\r
+        }\r
+\r
+        Line border1 = table1.createBorder();\r
+        border1.setLineColor(Color.black);\r
+        border1.setLineWidth(1.0);\r
+        table1.setAllBorders(border1);\r
+\r
+        table1.setColumnWidth(0, 300);\r
+        table1.setColumnWidth(1, 150);\r
+\r
+        slide.addShape(table1);\r
+        int pgWidth = ppt.getPageSize().width;\r
+        table1.moveTo((pgWidth - table1.getAnchor().width)/2, 100);\r
+\r
+        //test data for the second taable\r
+        String[][] txt2 = {\r
+            {"Data Source"},\r
+            {"CAS Internal Metrics - Item Master Summary\r" +\r
+             "CAS Internal Metrics - Vendor Summary\r" +\r
+             "CAS Internal Metrics - PO History Summary"}\r
+        };\r
+\r
+        //two rows, one column\r
+        Table table2 = new Table(2, 1);\r
+        for (int i = 0; i < txt2.length; i++) {\r
+            for (int j = 0; j < txt2[i].length; j++) {\r
+                TableCell cell = table2.getCell(i, j);\r
+                cell.setText(txt2[i][j]);\r
+                RichTextRun rt = cell.getTextRun().getRichTextRuns()[0];\r
+                rt.setFontSize(10);\r
+                rt.setFontName("Arial");\r
+                if(i == 0){\r
+                    cell.getFill().setForegroundColor(new Color(0, 51, 102));\r
+                    rt.setFontColor(Color.white);\r
+                    rt.setBold(true);\r
+                    rt.setFontSize(14);\r
+                    cell.setHorizontalAlignment(TextBox.AlignCenter);\r
+                } else {\r
+                    rt.setBullet(true);\r
+                    rt.setFontSize(12);\r
+                    cell.setHorizontalAlignment(TextBox.AlignLeft);\r
+                }\r
+                cell.setVerticalAlignment(TextBox.AnchorMiddle);\r
+            }\r
+        }\r
+        table2.setColumnWidth(0, 300);\r
+        table2.setRowHeight(0, 30);\r
+        table2.setRowHeight(1, 70);\r
+\r
+        Line border2 = table2.createBorder();\r
+        table2.setOutsideBorders(border2);\r
+\r
+        slide.addShape(table2);\r
+        table2.moveTo(200, 400);\r
+\r
+        FileOutputStream out = new FileOutputStream("hslf-table.ppt");\r
+        ppt.write(out);\r
+        out.close();\r
+\r
+    }\r
+}\r
index 5f7392739fb22157dc160b1cfd31f0512ff0ee76..1c8d994bfec3d93af4a1a7f0b2bfa2e6b2fb4424 100644 (file)
@@ -283,7 +283,7 @@ public class XLS2CSVmra implements HSSFListener {
                        format = format.replaceAll("\\\\-","-");
                        
                        // Format as a date
-                       Date d = HSSFDateUtil.getJavaDate(value);
+                       Date d = HSSFDateUtil.getJavaDate(value, false);
                        DateFormat df = new SimpleDateFormat(format);
                    return df.format(d);
                } else {
index f0d85400be5e74e097f0b56005081c8829022c86..7eae4edc4c3c56fab39af76d0a575bcfc8730f48 100644 (file)
@@ -150,10 +150,12 @@ public class Fill {
         EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
         if (color == null) {
             Shape.setEscherProperty(opt, EscherProperties.FILL__FILLCOLOR, -1);
+            Shape.setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150010);
         }
         else {
             int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB();
             Shape.setEscherProperty(opt, EscherProperties.FILL__FILLCOLOR, rgb);
+            Shape.setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150011);
         }
     }
 
index b1761b2d9a50b077015434da8c74b8c2a8a444bf..d8ddc7d2f2e9013b6c7cde4cf9d04cd1edba782e 100644 (file)
@@ -153,7 +153,7 @@ public abstract class Sheet {
      */
     protected static void findTextRuns(Record[] records, Vector found) {
         // Look for a TextHeaderAtom
-        for (int i = 0; i < (records.length - 1); i++) {
+        for (int i = 0, slwtIndex=0; i < (records.length - 1); i++) {
             if (records[i] instanceof TextHeaderAtom) {
                 TextRun trun = null;
                 TextHeaderAtom tha = (TextHeaderAtom) records[i];
@@ -179,7 +179,6 @@ public abstract class Sheet {
                     // TextSpecInfoAtom - Safe to ignore
                 } else {
                     System.err.println("Found a TextHeaderAtom not followed by a TextBytesAtom or TextCharsAtom: Followed by " + records[i + 1].getRecordType());
-                    continue;
                 }
 
                 if (trun != null) {
@@ -191,12 +190,14 @@ public abstract class Sheet {
                     Record[] recs = new Record[lst.size()];
                     lst.toArray(recs);
                     trun._records = recs;
+                    trun.setIndex(slwtIndex);
                     
                     found.add(trun);
                     i++;
                 } else {
                     // Not a valid one, so skip on to next and look again
                 }
+                slwtIndex++;
             }
         }
     }
index 2f634ccd17aeced262076feb2432f4447413194e..10749160042cfba744a4b328581c87b62256caad 100644 (file)
@@ -124,8 +124,10 @@ public class SimpleShape extends Shape {
             int rgb = p1.getPropertyValue();
             if (rgb >= 0x8000000) {
                 int idx = rgb % 0x8000000;
-                ColorSchemeAtom ca = getSheet().getColorScheme();
-                if(idx >= 0 && idx <= 7) rgb = ca.getColor(idx);
+                if(getSheet() != null) {
+                    ColorSchemeAtom ca = getSheet().getColorScheme();
+                    if(idx >= 0 && idx <= 7) rgb = ca.getColor(idx);
+                }
             }
             Color tmp = new Color(rgb, true);
             clr = new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed());
@@ -192,8 +194,10 @@ public class SimpleShape extends Shape {
             int rgb = p1.getPropertyValue();
             if (rgb >= 0x8000000) {
                 int idx = rgb % 0x8000000;
-                ColorSchemeAtom ca = getSheet().getColorScheme();
-                rgb = ca.getColor(idx);
+                if(getSheet() != null) {
+                    ColorSchemeAtom ca = getSheet().getColorScheme();
+                    rgb = ca.getColor(idx);
+                }
             }
             Color tmp = new Color(rgb, true);
             clr = new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed());
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Table.java b/src/scratchpad/src/org/apache/poi/hslf/model/Table.java
new file mode 100755 (executable)
index 0000000..a9f21b5
--- /dev/null
@@ -0,0 +1,291 @@
+\r
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.hslf.model;\r
+\r
+import org.apache.poi.ddf.*;\r
+import org.apache.poi.util.LittleEndian;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+import java.util.Iterator;\r
+import java.awt.*;\r
+\r
+/**\r
+ * Represents a table in a PowerPoint presentation\r
+ * \r
+ * @author Yegor Kozlov\r
+ */\r
+public class Table extends ShapeGroup {\r
+\r
+    protected static final int BORDER_TOP = 1;\r
+    protected static final int BORDER_RIGHT = 2;\r
+    protected static final int BORDER_BOTTOM = 3;\r
+    protected static final int BORDER_LEFT = 4;\r
+\r
+    protected static final int BORDERS_ALL = 5;\r
+    protected static final int BORDERS_OUTSIDE = 6;\r
+    protected static final int BORDERS_INSIDE = 7;\r
+    protected static final int BORDERS_NONE = 8;\r
+\r
+\r
+    protected TableCell[][] cells;\r
+\r
+    /**\r
+     * Create a new Table of the given number of rows and columns\r
+     *\r
+     * @param numrows the number of rows\r
+     * @param numcols the number of columns\r
+     */\r
+    public Table(int numrows, int numcols) {\r
+        super();\r
+\r
+        int x=0, y=0, tblWidth=0, tblHeight=0;\r
+        cells = new TableCell[numrows][numcols];\r
+        for (int i = 0; i < cells.length; i++) {\r
+            x = 0;\r
+            for (int j = 0; j < cells[i].length; j++) {\r
+                cells[i][j] = new TableCell(this);\r
+                Rectangle anchor = new Rectangle(x, y, TableCell.DEFAULT_WIDTH, TableCell.DEFAULT_HEIGHT);\r
+                cells[i][j].setAnchor(anchor);\r
+                x += TableCell.DEFAULT_WIDTH;\r
+            }\r
+            y += TableCell.DEFAULT_HEIGHT;\r
+        }\r
+        tblWidth = x;\r
+        tblHeight = y;\r
+        setAnchor(new Rectangle(0, 0, tblWidth, tblHeight));\r
+\r
+        EscherContainerRecord spCont = (EscherContainerRecord) getSpContainer().getChild(0);\r
+        List lst = spCont.getChildRecords();\r
+        EscherOptRecord opt = new EscherOptRecord();\r
+        opt.setRecordId((short)0xF122);\r
+        opt.addEscherProperty(new EscherSimpleProperty((short)0x39F, 1));\r
+        EscherArrayProperty p = new EscherArrayProperty((short)0x43A0, false, null);\r
+        p.setSizeOfElements(0x0004);\r
+        p.setNumberOfElementsInArray(numrows);\r
+        p.setNumberOfElementsInMemory(numrows);\r
+        opt.addEscherProperty(p);\r
+        lst.add(lst.size()-1, opt);\r
+\r
+    }\r
+\r
+    /**\r
+     * Create a Table object and initilize it from the supplied Record container.\r
+     *\r
+     * @param escherRecord <code>EscherSpContainer</code> container which holds information about this shape\r
+     * @param parent       the parent of the shape\r
+     */\r
+    protected Table(EscherContainerRecord escherRecord, Shape parent) {\r
+        super(escherRecord, parent);\r
+    }\r
+\r
+    /**\r
+     * Gets a cell\r
+     *\r
+     * @param row the row index (0-based)\r
+     * @param col the column index (0-based)\r
+     * @return the cell\r
+     */\r
+    public TableCell getCell(int row, int col) {\r
+        return cells[row][col];\r
+    }\r
+\r
+    public int getNumberOfColumns() {\r
+        return cells[0].length;\r
+    }\r
+    public int getNumberOfRows() {\r
+        return cells.length;\r
+    }\r
+\r
+    protected void afterInsert(Sheet sh){\r
+        EscherContainerRecord spCont = (EscherContainerRecord) getSpContainer().getChild(0);\r
+        List lst = spCont.getChildRecords();\r
+        EscherOptRecord opt = (EscherOptRecord)lst.get(lst.size()-2);\r
+        EscherArrayProperty p = (EscherArrayProperty)opt.getEscherProperty(1);\r
+        for (int i = 0; i < cells.length; i++) {\r
+            TableCell cell = cells[i][0];\r
+            int rowHeight = cell.getAnchor().height*MASTER_DPI/POINT_DPI;\r
+            byte[] val = new byte[4];\r
+            LittleEndian.putInt(val, rowHeight);\r
+            p.setElement(i, val);\r
+            for (int j = 0; j < cells[i].length; j++) {\r
+                TableCell c = cells[i][j];\r
+                addShape(c);\r
+\r
+                Line bt = c.getBorderTop();\r
+                if(bt != null) addShape(bt);\r
+\r
+                Line br = c.getBorderRight();\r
+                if(br != null) addShape(br);\r
+\r
+                Line bb = c.getBorderBottom();\r
+                if(bb != null) addShape(bb);\r
+\r
+                Line bl = c.getBorderLeft();\r
+                if(bl != null) addShape(bl);\r
+\r
+            }\r
+        }\r
+\r
+    }\r
+\r
+    /**\r
+     * Sets the row height.\r
+     *\r
+     * @param row the row index (0-based)\r
+     * @param height the height to set (in pixels)\r
+     */\r
+    public void setRowHeight(int row, int height){\r
+        int currentHeight = cells[row][0].getAnchor().height;\r
+        int dy = height - currentHeight;\r
+\r
+        for (int i = row; i < cells.length; i++) {\r
+            for (int j = 0; j < cells[i].length; j++) {\r
+                Rectangle anchor = cells[i][j].getAnchor();\r
+                if(i == row) anchor.height = height;\r
+                else anchor.y += dy;\r
+                cells[i][j].setAnchor(anchor);\r
+            }\r
+        }\r
+        Rectangle tblanchor = getAnchor();\r
+        tblanchor.height += dy;\r
+        setAnchor(tblanchor);\r
+\r
+    }\r
+\r
+    /**\r
+     * Sets the column width.\r
+     *\r
+     * @param col the column index (0-based)\r
+     * @param width the width to set (in pixels)\r
+     */\r
+    public void setColumnWidth(int col, int width){\r
+        int currentWidth = cells[0][col].getAnchor().width;\r
+        int dx = width - currentWidth;\r
+        for (int i = 0; i < cells.length; i++) {\r
+            Rectangle anchor = cells[i][col].getAnchor();\r
+            anchor.width = width;\r
+            cells[i][col].setAnchor(anchor);\r
+\r
+            if(col < cells[i].length - 1) for (int j = col+1; j < cells[i].length; j++) {\r
+                anchor = cells[i][j].getAnchor();\r
+                anchor.x += dx;\r
+                cells[i][j].setAnchor(anchor);\r
+            }\r
+        }\r
+        Rectangle tblanchor = getAnchor();\r
+        tblanchor.width += dx;\r
+        setAnchor(tblanchor);\r
+    }\r
+\r
+    /**\r
+     * Format the table and apply the specified Line to all cell boundaries,\r
+     * both outside and inside\r
+     *\r
+     * @param line the border line\r
+     */\r
+    public void setAllBorders(Line line){\r
+        for (int i = 0; i < cells.length; i++) {\r
+            for (int j = 0; j < cells[i].length; j++) {\r
+                TableCell cell = cells[i][j];\r
+                cell.setBorderTop(cloneBorder(line));\r
+                cell.setBorderLeft(cloneBorder(line));\r
+                if(j == cells[i].length - 1) cell.setBorderRight(cloneBorder(line));\r
+                if(i == cells.length - 1) cell.setBorderBottom(cloneBorder(line));\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Format the outside border using the specified Line object\r
+     *\r
+     * @param line the border line\r
+     */\r
+    public void setOutsideBorders(Line line){\r
+        for (int i = 0; i < cells.length; i++) {\r
+            for (int j = 0; j < cells[i].length; j++) {\r
+                TableCell cell = cells[i][j];\r
+\r
+                if(j == 0) cell.setBorderLeft(cloneBorder(line));\r
+                if(j == cells[i].length - 1) cell.setBorderRight(cloneBorder(line));\r
+                else {\r
+                    cell.setBorderLeft(null);\r
+                    cell.setBorderLeft(null);\r
+                }\r
+\r
+                if(i == 0) cell.setBorderTop(cloneBorder(line));\r
+                else if(i == cells.length - 1) cell.setBorderBottom(cloneBorder(line));\r
+                else {\r
+                    cell.setBorderTop(null);\r
+                    cell.setBorderBottom(null);\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Format the inside border using the specified Line object\r
+     *\r
+     * @param line the border line\r
+     */\r
+    public void setInsideBorders(Line line){\r
+        for (int i = 0; i < cells.length; i++) {\r
+            for (int j = 0; j < cells[i].length; j++) {\r
+                TableCell cell = cells[i][j];\r
+\r
+                if(j != cells[i].length - 1)\r
+                    cell.setBorderRight(cloneBorder(line));\r
+                else {\r
+                    cell.setBorderLeft(null);\r
+                    cell.setBorderLeft(null);\r
+                }\r
+                if(i != cells.length - 1) cell.setBorderBottom(cloneBorder(line));\r
+                else {\r
+                    cell.setBorderTop(null);\r
+                    cell.setBorderBottom(null);\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    private Line cloneBorder(Line line){\r
+        Line border = createBorder();\r
+        border.setLineWidth(line.getLineWidth());\r
+        border.setLineStyle(line.getLineStyle());\r
+        border.setLineDashing(line.getLineDashing());\r
+        border.setLineColor(line.getLineColor());\r
+        return border;\r
+    }\r
+\r
+    /**\r
+     * Create a border to format this table\r
+     *\r
+     * @return the created border\r
+     */\r
+    public Line createBorder(){\r
+        Line line = new Line(this);\r
+\r
+        EscherOptRecord opt = (EscherOptRecord)getEscherChild(line.getSpContainer(), EscherOptRecord.RECORD_ID);\r
+        setEscherProperty(opt, EscherProperties.GEOMETRY__SHAPEPATH, -1);\r
+        setEscherProperty(opt, EscherProperties.GEOMETRY__FILLOK, -1);\r
+        setEscherProperty(opt, EscherProperties.SHADOWSTYLE__SHADOWOBSURED, 0x20000);\r
+        setEscherProperty(opt, EscherProperties.THREED__LIGHTFACE, 0x80000);\r
+\r
+        return line;\r
+    }\r
+}\r
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/TableCell.java b/src/scratchpad/src/org/apache/poi/hslf/model/TableCell.java
new file mode 100755 (executable)
index 0000000..bb93e06
--- /dev/null
@@ -0,0 +1,155 @@
+\r
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.hslf.model;\r
+\r
+import org.apache.poi.ddf.*;\r
+import org.apache.poi.hslf.record.EscherTextboxWrapper;\r
+import org.apache.poi.hslf.record.TextHeaderAtom;\r
+import org.apache.poi.hslf.usermodel.RichTextRun;\r
+\r
+import java.awt.*;\r
+\r
+/**\r
+ * Represents a cell in a ppt table\r
+ * \r
+ * @author Yegor Kozlov\r
+ */\r
+public class TableCell extends TextBox {\r
+    protected static final int DEFAULT_WIDTH = 100;\r
+    protected static final int DEFAULT_HEIGHT = 40;\r
+\r
+    private Line borderLeft;\r
+    private Line borderRight;\r
+    private Line borderTop;\r
+    private Line borderBottom;\r
+\r
+    /**\r
+     * Create a TableCell object and initialize it from the supplied Record container.\r
+     *\r
+     * @param escherRecord       <code>EscherSpContainer</code> container which holds information about this shape\r
+     * @param parent    the parent of the shape\r
+     */\r
+   protected TableCell(EscherContainerRecord escherRecord, Shape parent){\r
+        super(escherRecord, parent);\r
+    }\r
+\r
+    /**\r
+     * Create a new TableCell. This constructor is used when a new shape is created.\r
+     *\r
+     * @param parent    the parent of this Shape. For example, if this text box is a cell\r
+     * in a table then the parent is Table.\r
+     */\r
+    public TableCell(Shape parent){\r
+        super(parent);\r
+\r
+        setShapeType(ShapeTypes.Rectangle);\r
+        _txtrun.setRunType(TextHeaderAtom.HALF_BODY_TYPE);\r
+        _txtrun.getRichTextRuns()[0].setFlag(false, 0, false);\r
+    }\r
+\r
+    protected EscherContainerRecord createSpContainer(boolean isChild){\r
+        EscherContainerRecord spContainer = super.createSpContainer(isChild);\r
+        EscherOptRecord opt = (EscherOptRecord)getEscherChild(spContainer, EscherOptRecord.RECORD_ID);\r
+        setEscherProperty(opt, EscherProperties.TEXT__TEXTID, 0);\r
+        setEscherProperty(opt, EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x20000);\r
+        setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150001);\r
+        setEscherProperty(opt, EscherProperties.SHADOWSTYLE__SHADOWOBSURED, 0x20000);\r
+        setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x40000);\r
+\r
+        return spContainer;\r
+    }\r
+\r
+    protected void anchorBorder(int type, Line line){\r
+        Rectangle cellAnchor = getAnchor();\r
+        Rectangle lineAnchor = new Rectangle();\r
+        switch(type){\r
+            case Table.BORDER_TOP:\r
+                lineAnchor.x = cellAnchor.x;\r
+                lineAnchor.y = cellAnchor.y;\r
+                lineAnchor.width = cellAnchor.width;\r
+                lineAnchor.height = 0;\r
+                break;\r
+            case Table.BORDER_RIGHT:\r
+                lineAnchor.x = cellAnchor.x + cellAnchor.width;\r
+                lineAnchor.y = cellAnchor.y;\r
+                lineAnchor.width = 0;\r
+                lineAnchor.height = cellAnchor.height;\r
+                break;\r
+            case Table.BORDER_BOTTOM:\r
+                lineAnchor.x = cellAnchor.x;\r
+                lineAnchor.y = cellAnchor.y + cellAnchor.height;\r
+                lineAnchor.width = cellAnchor.width;\r
+                lineAnchor.height = 0;\r
+                break;\r
+            case Table.BORDER_LEFT:\r
+                lineAnchor.x = cellAnchor.x;\r
+                lineAnchor.y = cellAnchor.y;\r
+                lineAnchor.width = 0;\r
+                lineAnchor.height = cellAnchor.height;\r
+                break;\r
+            default:\r
+                throw new IllegalArgumentException("Unknown border type: " + type);\r
+        }\r
+        line.setAnchor(lineAnchor);\r
+    }\r
+\r
+    public Line getBorderLeft() {\r
+        return borderLeft;\r
+    }\r
+\r
+    public void setBorderLeft(Line line) {\r
+        if(line != null) anchorBorder(Table.BORDER_LEFT, line);\r
+        this.borderLeft = line;\r
+    }\r
+\r
+    public Line getBorderRight() {\r
+        return borderRight;\r
+    }\r
+\r
+    public void setBorderRight(Line line) {\r
+        if(line != null) anchorBorder(Table.BORDER_RIGHT, line);\r
+        this.borderRight = line;\r
+    }\r
+\r
+    public Line getBorderTop() {\r
+        return borderTop;\r
+    }\r
+\r
+    public void setBorderTop(Line line) {\r
+        if(line != null) anchorBorder(Table.BORDER_TOP, line);\r
+        this.borderTop = line;\r
+    }\r
+\r
+    public Line getBorderBottom() {\r
+        return borderBottom;\r
+    }\r
+\r
+    public void setBorderBottom(Line line) {\r
+        if(line != null) anchorBorder(Table.BORDER_BOTTOM, line);\r
+        this.borderBottom = line;\r
+    }\r
+\r
+    public void setAnchor(Rectangle anchor){\r
+        super.setAnchor(anchor);\r
+\r
+        if(borderTop != null) anchorBorder(Table.BORDER_TOP, borderTop);\r
+        if(borderRight != null) anchorBorder(Table.BORDER_RIGHT, borderRight);\r
+        if(borderBottom != null) anchorBorder(Table.BORDER_BOTTOM, borderBottom);\r
+        if(borderLeft != null) anchorBorder(Table.BORDER_LEFT, borderLeft);\r
+    }\r
+}\r
index 2d5c866f775534639fc5b08fbdab89415bae3b2a..1f9a489a78be29eb2b08babd6e1922e6a487a5f0 100644 (file)
@@ -196,7 +196,7 @@ public class TextBox extends SimpleShape {
         } catch (IOException e){
             throw new HSLFException(e);
         }
-        if(getAnchor().equals(new java.awt.Rectangle())) resizeToFitText();
+        if(getAnchor().equals(new java.awt.Rectangle()) && !"".equals(getText())) resizeToFitText();
     }
 
     /**
@@ -264,6 +264,14 @@ public class TextBox extends SimpleShape {
         EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
         setEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT, align);
     }
+
+    public void setHorizontalAlignment(int align){
+        _txtrun.getRichTextRuns()[0].setAlignment(align);
+    }
+    public int getHorizontalAlignment(){
+        return _txtrun.getRichTextRuns()[0].getAlignment();
+    }
+
     /**
      * Returns the distance (in points) between the bottom of the text frame
      * and the bottom of the inscribed rectangle of the shape that contains the text.
@@ -466,7 +474,11 @@ public class TextBox extends SimpleShape {
         TextRun[] runs = sheet.getTextRuns();
         if (ota != null) {
             int idx = ota.getTextIndex();
-            if(idx < runs.length) _txtrun = runs[idx];
+            for (int i = 0; i < runs.length; i++) {
+                if(runs[i].getIndex() == idx){
+                    _txtrun = runs[i];
+                }
+            }
             if(_txtrun == null) {
                 logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx);
             }
@@ -478,9 +490,6 @@ public class TextBox extends SimpleShape {
                     break;
                 }
             }
-            if(_txtrun == null) {
-                logger.log(POILogger.WARN, "text run not found for shapeId=" + shapeId);
-            }
         }
 
     }
index 4999df758168f6342fbd26c7a4ea7b57215afa84..ca6e02d69b0568671c3ad3e1a4821f7ac5171688 100644 (file)
@@ -50,6 +50,7 @@ public class TextRun
        private SlideShow slideShow;
     private Sheet sheet;
     private int shapeId;
+    private int slwtIndex; //position in the owning SlideListWithText
     /**
      * all text run records that follow TextHeaderAtom.
      * (there can be misc InteractiveInfo, TxInteractiveInfo and other records)
@@ -537,6 +538,20 @@ public class TextRun
         shapeId = id;
     }
 
+    /**
+     * @return  0-based index of the text run in the SLWT container
+     */
+    protected int getIndex(){
+        return slwtIndex;
+    }
+
+    /**
+     *  @param id 0-based index of the text run in the SLWT container
+     */
+    protected void setIndex(int id){
+        slwtIndex = id;
+    }
+
     /**
      * Returns the array of all hyperlinks in this text run
      *
index 0ee01b9a96e7af19ea2bc01aee60129969cc4978..d16bf7bc02303fa5af22f7cb9888a19e08f1aa11 100644 (file)
@@ -198,7 +198,7 @@ public class RichTextRun
         setFlag(true, index, value);
        }
 
-    private void setFlag(boolean isCharacter, int index, boolean value) {
+    public void setFlag(boolean isCharacter, int index, boolean value) {
         TextPropCollection props;
         String propname;
         if (isCharacter){
@@ -282,7 +282,7 @@ public class RichTextRun
         * @param propName The name of the Character TextProp
         * @param val The value to set for the TextProp
         */
-       private void setParaTextPropVal(String propName, int val) {
+       public void setParaTextPropVal(String propName, int val) {
                // Ensure we have the StyleTextProp atom we're going to need
                if(paragraphStyle == null) {
                        parentRun.ensureStyleAtomPresent();
@@ -297,7 +297,7 @@ public class RichTextRun
         * @param propName The name of the Paragraph TextProp
         * @param val The value to set for the TextProp
         */
-       private void setCharTextPropVal(String propName, int val) {
+       public void setCharTextPropVal(String propName, int val) {
                // Ensure we have the StyleTextProp atom we're going to need
                if(characterStyle == null) {
                        parentRun.ensureStyleAtomPresent();
index ed215f6382569ce047d9695ac5655c8d558df023..eb915160b35d7b546eecb67b14b7a2ebdcfc9823 100644 (file)
@@ -48,15 +48,24 @@ public class MAPIMessage {
        
        
        /**
-        * Constructor for reading MSG Files.
+        * Constructor for reading MSG Files from the file system.
         * @param filename
         * @throws IOException
         */
        public MAPIMessage(String filename) throws IOException {
-               InputStream in = new FileInputStream(new File(filename));
+               this(new FileInputStream(new File(filename)));
+       }
+       
+       /**
+        * Constructor for reading MSG Files from an input stream.
+        * @param in
+        * @throws IOException
+        */
+       public MAPIMessage(InputStream in) throws IOException {
                this.fs = new POIFSFileSystem(in);
                chunkParser = new POIFSChunkParser(this.fs);
        }
+       
 
        /**
         * Gets a string value based on the passed chunk.
@@ -101,6 +110,16 @@ public class MAPIMessage {
                return getStringFromChunk(Chunks.getInstance().displayToChunk);
        }
        
+       /**
+        * Gets the display value of the "FROM" line of the outlook message
+        * This is not the actual address that was sent from but the formated display of the user name.
+        * @return
+        * @throws ChunkNotFoundException
+        */
+       public String getDisplayFrom() throws ChunkNotFoundException {
+               return getStringFromChunk(Chunks.getInstance().displayFromChunk);
+       }
+       
        /**
         * Gets the display value of the "TO" line of the outlook message
         * This is not the actual list of addresses/values that will be sent to if you click Reply in the email.
index 309efeac9db499d5bd88f612a1af18dd4a93dca4..6a3936d964c8e6662c6509d38bf15987b255442c 100644 (file)
@@ -29,6 +29,7 @@ public class Chunks {
        public StringChunk textBodyChunk = new StringChunk(0x1000);             //BODY Chunk, for plain/text messages
        public StringChunk subjectChunk = new StringChunk(0x0037);      //Subject link chunk, in plain/text
        public StringChunk displayToChunk = new StringChunk(0x0E04);    //Value that is in the TO field (not actually the addresses as they are stored in recip directory nodes
+       public StringChunk displayFromChunk = new StringChunk(0x0C1A);  //Value that is in the FROM field
        public StringChunk displayCCChunk = new StringChunk(0x0E03);    //value that shows in the CC field
        public StringChunk displayBCCChunk = new StringChunk(0x0E02);   //Value that shows in the BCC field
        public StringChunk conversationTopic = new StringChunk(0x0070); //Sort of like the subject line, but without the RE: and FWD: parts.
index 34dcc7cdae4421966d50946fb53f043df5624f1e..6861a025242255bd0cc27e8462f9fcdce20cafb1 100644 (file)
@@ -70,7 +70,7 @@ public class Date extends NumericFunction {
                 c.set(year, month, day, 0, 0, 0);
                 c.set(Calendar.MILLISECOND, 0);
                 
-                return new NumberEval(HSSFDateUtil.getExcelDate(c.getTime()));
+                return new NumberEval(HSSFDateUtil.getExcelDate(c.getTime(), false)); // XXX fix 1900/1904 problem
             }
         }
         
index 283633442e936db754c9a99e7682bf4c20a28944..0ae5694767c95ab6749b107ac0ab0f0a93a14da9 100644 (file)
@@ -46,7 +46,7 @@ srcCellRow, srcCellCol);
             if (ve instanceof NumericValueEval) {
                 NumericValueEval ne = (NumericValueEval) ve;
                 if (HSSFDateUtil.isValidExcelDate(ne.getNumberValue())) {
-                    java.util.Date d = HSSFDateUtil.getJavaDate(ne.getNumberValue());
+                    java.util.Date d = HSSFDateUtil.getJavaDate(ne.getNumberValue(), false); // XXX fix 1900/1904 problem
                     java.util.Calendar c = java.util.Calendar.getInstance();
                     c.setTime(d);
                     retval = new NumberEval(c.get(java.util.Calendar.DAY_OF_MONTH));
index 30593142e864544b5db13bc202ac1bf03c5cbcec..d6c4399ae33ac9b0dfba899edf0aff61c6995ae1 100644 (file)
  */
 package org.apache.poi.hssf.record.formula.functions;
 
-public class Mid extends NotImplementedFunction {
+import org.apache.poi.hssf.record.formula.eval.BlankEval;
+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.NumericValueEval;
+import org.apache.poi.hssf.record.formula.eval.StringEval;
+import org.apache.poi.hssf.record.formula.eval.StringValueEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+
+/**
+ * An implementation of the MID function:
+ * Returns a specific number of characters from a text string, 
+ * starting at the position you specify, based on the number 
+ * of characters you specify.
+ * @author Manda Wilson &lt; wilson at c bio dot msk cc dot org &gt;
+ */
+public class Mid extends TextFunction {
+       /**
+        * Returns a specific number of characters from a text string, 
+        * starting at the position you specify, based on the number 
+        * of characters you specify.
+        * 
+        * @see org.apache.poi.hssf.record.formula.eval.Eval
+        */
+    public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {          
+       Eval retval = null;
+        String str = null;
+        int startNum = 0;
+        int numChars = 0;
+        
+        switch (operands.length) {
+               default:
+                   retval = ErrorEval.VALUE_INVALID;
+               case 3:
+                       // first operand is text string containing characters to extract
+                   // second operand is position of first character to extract
+                   // third operand is the number of characters to return
+                   ValueEval firstveval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
+                   ValueEval secondveval = singleOperandEvaluate(operands[1], srcCellRow, srcCellCol);
+                   ValueEval thirdveval = singleOperandEvaluate(operands[2], srcCellRow, srcCellCol);
+                   if (firstveval instanceof StringValueEval
+                       && secondveval instanceof NumericValueEval
+                       && thirdveval instanceof NumericValueEval) {
+                       
+                       StringValueEval strEval = (StringValueEval) firstveval;
+                       str = strEval.getStringValue();
+                       
+                       NumericValueEval startNumEval = (NumericValueEval) secondveval;
+                       // NOTE: it is safe to cast to int here
+                       // because in Excel =MID("test", 1, 1.7) returns t 
+                       // so 1.7 must be truncated to 1
+                       // and =MID("test", 1.9, 2) returns te 
+                       // so 1.9 must be truncated to 1
+                       startNum = (int) startNumEval.getNumberValue();
+                       
+                       NumericValueEval numCharsEval = (NumericValueEval) thirdveval;
+                       numChars = (int) numCharsEval.getNumberValue();
+                       
+                   } else {
+                       retval = ErrorEval.VALUE_INVALID;
+                   }
+           }
+               
+        if (retval == null) {
+                       if (startNum < 1 || numChars < 0) {
+                               retval = ErrorEval.VALUE_INVALID;
+                       } else if (startNum > str.length() || numChars == 0) {
+                               retval = BlankEval.INSTANCE;
+                       } else if (startNum + numChars > str.length()) {
+                               retval = new StringEval(str.substring(startNum - 1));
+                       } else {
+                               retval = new StringEval(str.substring(startNum - 1, numChars));
+                       } 
+        } 
+               return retval;
+    }
 
 }
index 065c565d14f95cc40176dd625ad023bbe467f739..d5178b22df9c8716d03492b02e2eacb59fa4883c 100644 (file)
@@ -50,7 +50,7 @@ public class Month extends NumericFunction {
             if (ve instanceof NumericValueEval) {
                 NumericValueEval ne = (NumericValueEval) ve;
                 if (HSSFDateUtil.isValidExcelDate(ne.getNumberValue())) {
-                    java.util.Date d = HSSFDateUtil.getJavaDate(ne.getNumberValue());
+                    java.util.Date d = HSSFDateUtil.getJavaDate(ne.getNumberValue(), false); // XXX fix 1900/1904 problem
                     retval = new NumberEval(d.getMonth()+1);
                 } else {
                     retval = ErrorEval.NUM_ERROR;
index 3ba7a2b2ce0bc58d0506134c2e31e5e67181c122..95413f08238bb1d4f088b6e82e1dbe493445aad9 100644 (file)
  */
 package org.apache.poi.hssf.record.formula.functions;
 
-public class Replace extends NotImplementedFunction {
+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.NumericValueEval;
+import org.apache.poi.hssf.record.formula.eval.StringEval;
+import org.apache.poi.hssf.record.formula.eval.StringValueEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+
+/**
+ * An implementation of the REPLACE function:
+ * Replaces part of a text string based on the number of characters 
+ * you specify, with another text string.
+ * @author Manda Wilson &lt; wilson at c bio dot msk cc dot org &gt;
+ */
+public class Replace extends TextFunction {
+
+       /**
+        * Replaces part of a text string based on the number of characters 
+        * you specify, with another text string.
+        * 
+        * @see org.apache.poi.hssf.record.formula.eval.Eval
+        */
+    public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {          
+       Eval retval = null;
+        String oldStr = null;
+        String newStr = null;
+        int startNum = 0;
+        int numChars = 0;
+        
+        switch (operands.length) {
+               default:
+                   retval = ErrorEval.VALUE_INVALID;
+               case 4:         
+                       // first operand is text string containing characters to replace
+                   // second operand is position of first character to replace
+                   // third operand is the number of characters in the old string
+                   // you want to replace with new string
+                   // fourth operand is the new string
+                   ValueEval firstveval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
+                   ValueEval secondveval = singleOperandEvaluate(operands[1], srcCellRow, srcCellCol);
+                   ValueEval thirdveval = singleOperandEvaluate(operands[2], srcCellRow, srcCellCol);
+                   ValueEval fourthveval = singleOperandEvaluate(operands[3], srcCellRow, srcCellCol);
+                   if (firstveval instanceof StringValueEval
+                       && secondveval instanceof NumericValueEval
+                       && thirdveval instanceof NumericValueEval
+                       && fourthveval instanceof StringValueEval) {
+                       
+                       StringValueEval oldStrEval = (StringValueEval) firstveval;
+                       oldStr = oldStrEval.getStringValue();
+                       
+                       NumericValueEval startNumEval = (NumericValueEval) secondveval;
+                       // NOTE: it is safe to cast to int here
+                       // because in Excel =REPLACE("task", 2.7, 3, "est") 
+                       // returns test 
+                       // so 2.7 must be truncated to 2
+                       // and =REPLACE("task", 1, 1.9, "") returns ask 
+                       // so 1.9 must be truncated to 1
+                       startNum = (int) startNumEval.getNumberValue();
+                       
+                       NumericValueEval numCharsEval = (NumericValueEval) thirdveval;
+                       numChars = (int) numCharsEval.getNumberValue();
+                                    
+                       StringValueEval newStrEval = (StringValueEval) fourthveval;
+                       newStr = newStrEval.getStringValue();
+                   } else {
+                       retval = ErrorEval.VALUE_INVALID;
+                   }
+           }
+               
+        if (retval == null) {
+                       if (startNum < 1 || numChars < 0) {
+                               retval = ErrorEval.VALUE_INVALID;
+                       } else {
+                               StringBuffer strBuff = new StringBuffer(oldStr);
+                               // remove any characters that should be replaced
+                               if (startNum <= oldStr.length() && numChars != 0) {
+                                       strBuff.delete(startNum - 1, startNum - 1 + numChars);
+                               } 
+                               // now insert (or append) newStr
+                               if (startNum > strBuff.length()) {
+                                       strBuff.append(newStr);
+                               } else {
+                                       strBuff.insert(startNum - 1, newStr);
+                               }
+                               retval = new StringEval(strBuff.toString());
+                       }
+        } 
+               return retval;
+    }
 
 }
index 8a975c569e65604fd39b4ccd4be8f7a9bab6f3c8..9d2e9ce3618a1a2d570a8c90f670ec268e9e1620 100644 (file)
  */
 package org.apache.poi.hssf.record.formula.functions;
 
-public class Substitute extends NotImplementedFunction {
+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.NumericValueEval;
+import org.apache.poi.hssf.record.formula.eval.StringEval;
+import org.apache.poi.hssf.record.formula.eval.StringValueEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
 
+/**
+ * An implementation of the SUBSTITUTE function:
+ * Substitutes text in a text string with new text, some number of times.
+ * @author Manda Wilson &lt; wilson at c bio dot msk cc dot org &gt;
+ */
+public class Substitute extends TextFunction {
+       private static final int REPLACE_ALL = -1;
+       
+       /**
+        *Substitutes text in a text string with new text, some number of times.
+        * 
+        * @see org.apache.poi.hssf.record.formula.eval.Eval
+        */
+    public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {          
+       Eval retval = null;
+        String oldStr = null;
+        String searchStr = null;
+        String newStr = null;
+        int numToReplace = REPLACE_ALL;
+        
+        switch (operands.length) {
+               default:
+                   retval = ErrorEval.VALUE_INVALID;
+               case 4:
+                       ValueEval fourthveval = singleOperandEvaluate(operands[3], srcCellRow, srcCellCol);
+                       if (fourthveval instanceof NumericValueEval) {
+                               NumericValueEval numToReplaceEval = (NumericValueEval) fourthveval;
+                               // NOTE: it is safe to cast to int here
+                       // because in Excel =SUBSTITUTE("teststr","t","T",1.9) 
+                       // returns Teststr 
+                       // so 1.9 must be truncated to 1
+                               numToReplace = (int) numToReplaceEval.getNumberValue();
+                       } else {
+                               retval = ErrorEval.VALUE_INVALID;
+                       }
+               case 3: 
+                       // first operand is text string containing characters to replace
+                   // second operand is text to find
+                   // third operand is replacement text
+                   ValueEval firstveval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
+                   ValueEval secondveval = singleOperandEvaluate(operands[1], srcCellRow, srcCellCol);
+                   ValueEval thirdveval = singleOperandEvaluate(operands[2], srcCellRow, srcCellCol);
+                   if (firstveval instanceof StringValueEval
+                       && secondveval instanceof StringValueEval
+                       && thirdveval instanceof StringValueEval) {
+                       
+                       StringValueEval oldStrEval = (StringValueEval) firstveval;
+                       oldStr = oldStrEval.getStringValue();
+                       
+                       StringValueEval searchStrEval = (StringValueEval) secondveval;
+                       searchStr = searchStrEval.getStringValue();
+                       
+                       StringValueEval newStrEval = (StringValueEval) thirdveval;
+                       newStr = newStrEval.getStringValue();
+                   } else {
+                       retval = ErrorEval.VALUE_INVALID;
+                   }
+           }
+               
+        if (retval == null) {
+                       if (numToReplace != REPLACE_ALL && numToReplace < 1) {
+                               retval = ErrorEval.VALUE_INVALID;
+                       } else if (searchStr.length() == 0) {
+                               retval = new StringEval(oldStr);
+                       } else {
+                               StringBuffer strBuff = new StringBuffer();
+                               int startIndex = 0;
+                               int nextMatch = -1;
+                               for (int leftToReplace = numToReplace; 
+                                       (leftToReplace > 0 || numToReplace == REPLACE_ALL) 
+                                               && (nextMatch = oldStr.indexOf(searchStr, startIndex)) != -1;
+                                       leftToReplace--) {
+                                       // store everything from end of last match to start of this match
+                                       strBuff.append(oldStr.substring(startIndex, nextMatch));
+                                       strBuff.append(newStr);
+                                       startIndex = nextMatch + searchStr.length();
+                               }
+                               // store everything from end of last match to end of string
+                               if (startIndex < oldStr.length()) {
+                                       strBuff.append(oldStr.substring(startIndex));
+                               }
+                               retval = new StringEval(strBuff.toString());
+                       }
+        } 
+               return retval;
+    }
+    
 }
index 69b3ce6f55c51fba79e1c0062bb1d9e9b1b5ae54..5e9d91c7cc7682eb40c6a5f0715d5697dd4c83d6 100644 (file)
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
-/*
- * Created on May 15, 2005
- *
- */
 package org.apache.poi.hssf.record.formula.functions;
 
-public class Trim extends NotImplementedFunction {
+import org.apache.poi.hssf.record.formula.eval.BlankEval;
+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.StringEval;
+import org.apache.poi.hssf.record.formula.eval.StringValueEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+
+/**
+ * An implementation of the TRIM function:
+ * Removes leading and trailing spaces from value if evaluated operand
+ *  value is string.
+ * @author Manda Wilson &lt; wilson at c bio dot msk cc dot org &gt;
+ */
+public class Trim extends TextFunction {
 
+       /**
+        * Removes leading and trailing spaces from value if evaluated 
+        *  operand value is string.
+        * Returns StringEval only if evaluated operand is of type string 
+        *  (and is not blank or null) or number. If evaluated operand is 
+        *  of type string and is blank or null, or if evaluated operand is 
+        *  of type blank, returns BlankEval.  Otherwise returns ErrorEval.
+        * 
+        * @see org.apache.poi.hssf.record.formula.eval.Eval
+        */
+    public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
+       Eval retval = ErrorEval.VALUE_INVALID;
+        String str = null;
+        
+        switch (operands.length) {
+               default:
+                   break;
+               case 1:
+                   ValueEval veval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
+                   if (veval instanceof StringValueEval) {
+                       StringValueEval sve = (StringValueEval) veval;
+                       str = sve.getStringValue();
+                       if (str == null || str.trim().equals("")) {
+                               return BlankEval.INSTANCE;
+                       }
+                   }
+                   else if (veval instanceof NumberEval) {
+                       NumberEval neval = (NumberEval) veval;
+                       str = neval.getStringValue();
+                   } 
+                   else if (veval instanceof BlankEval) {
+                       return BlankEval.INSTANCE;
+                   }
+           }
+               
+        if (str != null) {
+            retval = new StringEval(str.trim());
+        } 
+        return retval;
+    }
 }
index 76ea617cc687d1821e7ad651a4fd0c28309679dc..b461a09668f93fe911bc4926ac21417747455bb1 100644 (file)
@@ -51,7 +51,7 @@ public class Year extends NumericFunction {
             if (ve instanceof NumericValueEval) {
                 NumericValueEval ne = (NumericValueEval) ve;
                 if (HSSFDateUtil.isValidExcelDate(ne.getNumberValue())) {
-                    java.util.Date d = HSSFDateUtil.getJavaDate(ne.getNumberValue());
+                    java.util.Date d = HSSFDateUtil.getJavaDate(ne.getNumberValue(), false); // XXX fix 1900/1904 problem
                     retval = new NumberEval(d.getYear()+1900);
                 } else {
                     retval = ErrorEval.NUM_ERROR;
index cec20c91e650a1f2b8b3e4b798c32dee3b7268f1..4196566d9ad9a1faa0745be9a831bf30eb0af1e9 100644 (file)
@@ -19,6 +19,8 @@
 package org.apache.poi.hwpf.model;
 
 import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
 
 import org.apache.poi.hwpf.model.io.*;
 
@@ -37,6 +39,7 @@ public class ListTables
 {
   private static final int LIST_DATA_SIZE = 28;
   private static final int LIST_FORMAT_OVERRIDE_SIZE = 16;
+  private static POILogger log = POILogFactory.getLogger(ListTables.class);
 
   HashMap _listMap = new HashMap();
   ArrayList _overrideList = new ArrayList();
@@ -189,8 +192,13 @@ public class ListTables
   public ListLevel getLevel(int listID, int level)
   {
     ListData lst = (ListData)_listMap.get(new Integer(listID));
-    ListLevel lvl = lst.getLevels()[level];
-    return lvl;
+    if(level < lst.numLevels()) {
+       ListLevel lvl = lst.getLevels()[level];
+       return lvl;
+    } else {
+       log.log(POILogger.WARN, "Requested level " + level + " which was greater than the maximum defined (" + lst.numLevels() + ")"); 
+       return null;
+    }
   }
 
   public ListData getListData(int listID)
index 87547565f234b2f9c097a782836986f713fb733f..f8fc91f1232b865beaf0377e1fc62c9d14c083c6 100644 (file)
@@ -148,8 +148,10 @@ public class TableSprmUncompressor
 
         for (int x = 0; x < itcMac; x++)
         {
-          if(hasTCs) rgtc[x] = TableCellDescriptor.convertBytesToTC(grpprl,
-              offset + (1 + ( (itcMac + 1) * 2) + (x * 20)));
+          // Sometimes, the grpprl does not contain data at every offset. I have no idea why this happens.
+          if(hasTCs && offset + (1 + ( (itcMac + 1) * 2) + (x * 20)) < grpprl.length)
+            rgtc[x] = TableCellDescriptor.convertBytesToTC(grpprl,
+               offset + (1 + ( (itcMac + 1) * 2) + (x * 20)));
           else
             rgtc[x] = new TableCellDescriptor();
         }
index 1b0ba626c20c2fc2e8dc63662e7dc598d5b88a0d..9bafce792761a3e6c6fb604d28e7f4b0693632f3 100644 (file)
@@ -23,21 +23,28 @@ import org.apache.poi.hwpf.model.ListFormatOverrideLevel;
 import org.apache.poi.hwpf.model.ListLevel;
 import org.apache.poi.hwpf.model.ListTables;
 import org.apache.poi.hwpf.model.PAPX;
-
-import org.apache.poi.hwpf.sprm.SprmBuffer;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
 
 public class ListEntry
   extends Paragraph
 {
-  ListLevel _level;
-  ListFormatOverrideLevel _overrideLevel;
+       private static POILogger log = POILogFactory.getLogger(ListEntry.class);
+       
+       ListLevel _level;
+       ListFormatOverrideLevel _overrideLevel;
 
   ListEntry(PAPX papx, Range parent, ListTables tables)
   {
     super(papx, parent);
-    ListFormatOverride override = tables.getOverride(_props.getIlfo());
-    _overrideLevel = override.getOverrideLevel(_props.getIlvl());
-    _level = tables.getLevel(override.getLsid(), _props.getIlvl());
+    
+    if(tables != null) {
+           ListFormatOverride override = tables.getOverride(_props.getIlfo());
+           _overrideLevel = override.getOverrideLevel(_props.getIlvl());
+           _level = tables.getLevel(override.getLsid(), _props.getIlvl());
+    } else {
+       log.log(POILogger.WARN, "No ListTables found for ListEntry - document probably partly corrupt, and you may experience problems");
+    }
   }
 
   public int type()
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/data/43781.ppt b/src/scratchpad/testcases/org/apache/poi/hslf/data/43781.ppt
new file mode 100755 (executable)
index 0000000..ddea91f
Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hslf/data/43781.ppt differ
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/data/sample.pptx b/src/scratchpad/testcases/org/apache/poi/hslf/data/sample.pptx
new file mode 100644 (file)
index 0000000..fbd540c
Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hslf/data/sample.pptx differ
index 933aa176b7fcdbae347580271ee8391b9b643018..996a733ac981a5ea444cb099a0416bbad5ea9f98 100644 (file)
@@ -25,6 +25,7 @@ import org.apache.poi.hslf.model.Shape;
 import java.io.*;\r
 import java.util.HashSet;\r
 import java.util.HashMap;\r
+import java.util.ArrayList;\r
 import java.awt.*;\r
 \r
 /**\r
@@ -298,4 +299,35 @@ public class TestBugs extends TestCase {
 \r
     }\r
 \r
+    /**\r
+     * Bug 38256:  RuntimeException: Couldn't instantiate the class for type with id 0.\r
+     * ( also fixed followup: getTextRuns() returns no text )\r
+     */\r
+    public void test43781 () throws Exception {\r
+        FileInputStream is = new FileInputStream(new File(cwd, "43781.ppt"));\r
+        SlideShow ppt = new SlideShow(is);\r
+        is.close();\r
+\r
+        assertTrue("No Exceptions while reading file", true);\r
+\r
+        Slide slide = ppt.getSlides()[0];\r
+        TextRun[] tr1 = slide.getTextRuns();\r
+\r
+        ArrayList lst = new ArrayList();\r
+        Shape[] shape = slide.getShapes();\r
+        for (int i = 0; i < shape.length; i++) {\r
+            if( shape[i] instanceof TextBox){\r
+                TextRun textRun = ((TextBox)shape[i]).getTextRun();\r
+                if(textRun != null) lst.add(textRun);\r
+            }\r
+\r
+        }\r
+        TextRun[] tr2 = new TextRun[lst.size()];\r
+        lst.toArray(tr2);\r
+\r
+        assertEquals(tr1.length, tr2.length);\r
+        for (int i = 0; i < tr1.length; i++) {\r
+            assertEquals(tr1[i].getText(), tr2[i].getText());\r
+        }\r
+    }\r
 }\r
index 05735870b4ecf5a0267cb6ae4ac2b8f6a65ccca2..314cc506c4c1ef6c727012ded3852a0eb6083e30 100644 (file)
@@ -83,6 +83,21 @@ public class TestBlankFileRead extends TestCase {
                TestCase.assertEquals(obtained, expected);
        }
        
+       /**
+        * Test to see if we can read the FROM Chunk.
+        * @throws ChunkNotFoundException 
+        * 
+        */
+       public void testReadDisplayFrom() throws ChunkNotFoundException {
+               try {
+                       mapiMessage.getDisplayFrom();           
+               } catch(ChunkNotFoundException exp) {
+                       return;
+               }
+               
+               TestCase.fail("Should have thrown a ChunkNotFoundException but didn't");
+       }
+       
        /**
         * Test to see if we can read the CC Chunk.
         * @throws ChunkNotFoundException 
index 0ede68965a8cd45fddbfb32212d4491c5afb1a6c..925685218d5d98662fab0487a384fd277efaf472 100644 (file)
@@ -66,6 +66,18 @@ private MAPIMessage mapiMessage;
                TestCase.assertEquals(obtained, expected);
        }
        
+       /**
+        * Test to see if we can read the From Chunk.
+        * @throws ChunkNotFoundException 
+        * 
+        */
+       public void testReadDisplayFrom() throws ChunkNotFoundException {
+               String obtained = mapiMessage.getDisplayFrom();
+               String expected = "Travis Ferguson";
+               
+               TestCase.assertEquals(obtained, expected);
+       }
+       
        /**
         * Test to see if we can read the CC Chunk.
         * @throws ChunkNotFoundException 
index b2388f1d032309609e1e4b14c3510545a76aee86..cf4b6fa5011723ad05fd24152a3a3e4a451d2c98 100644 (file)
Binary files a/src/scratchpad/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls and b/src/scratchpad/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls differ
index d1ab0c7076b7d06ff98ab5f79edfb77da1b9bcd4..ac3ca2eb2925c006910a36839ae941685712c784 100644 (file)
@@ -23,27 +23,37 @@ package org.apache.poi.hssf.record.formula.eval;
 import junit.framework.TestSuite;
 
 /**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
+ * This is a test of all the Eval functions we have implemented.
+ * Add newly implemented Eval functions in here to have them
+ *  tested.
+ * For newly implemented functions, 
+ *  @see org.apache.poi.hssf.record.formula.functions.TestEverything
  *
+ * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
  */
 public class TestEverything extends TestSuite {
 
     public static TestSuite suite() throws Exception {
         TestSuite suite = new TestSuite("Tests for OperationEval concrete implementation classes.");
-        suite.addTest(new GenericFormulaTestCase("D23"));
-        suite.addTest(new GenericFormulaTestCase("D27"));
-        suite.addTest(new GenericFormulaTestCase("D31"));
-        suite.addTest(new GenericFormulaTestCase("D35"));
-        suite.addTest(new GenericFormulaTestCase("D39"));
-        suite.addTest(new GenericFormulaTestCase("D43"));
-        suite.addTest(new GenericFormulaTestCase("D47"));
-        suite.addTest(new GenericFormulaTestCase("D51"));
-        suite.addTest(new GenericFormulaTestCase("D55"));
-        suite.addTest(new GenericFormulaTestCase("D59"));
-        suite.addTest(new GenericFormulaTestCase("D63"));
-        suite.addTest(new GenericFormulaTestCase("D67"));
-        suite.addTest(new GenericFormulaTestCase("D71"));
-        suite.addTest(new GenericFormulaTestCase("D75"));
+        suite.addTest(new GenericFormulaTestCase("D23")); // Add
+        suite.addTest(new GenericFormulaTestCase("D27")); // ConcatEval
+        suite.addTest(new GenericFormulaTestCase("D31")); // DivideEval
+        suite.addTest(new GenericFormulaTestCase("D35")); // EqualEval
+        suite.addTest(new GenericFormulaTestCase("D39")); // GreaterEqualEval
+        suite.addTest(new GenericFormulaTestCase("D43")); // GreaterThanEval
+        suite.addTest(new GenericFormulaTestCase("D47")); // LessEqualEval
+        suite.addTest(new GenericFormulaTestCase("D51")); // LessThanEval
+        suite.addTest(new GenericFormulaTestCase("D55")); // MultiplyEval
+        suite.addTest(new GenericFormulaTestCase("D59")); // NotEqualEval
+        suite.addTest(new GenericFormulaTestCase("D63")); // PowerEval
+        suite.addTest(new GenericFormulaTestCase("D67")); // SubtractEval
+        suite.addTest(new GenericFormulaTestCase("D71")); // UnaryMinusEval
+        suite.addTest(new GenericFormulaTestCase("D75")); // UnaryPlusEval
+        
+               // Add newly implemented Eval functions here
+               // (Formula functions go in 
+               //  @see org.apache.poi.hssf.record.formula.functions.TestEverything )
+        
         return suite;
     }
 }
index ad9399633991d566215851b8b272daed4d925d39..833781021609a2b6f350d22c940ff772114ccbb1 100644 (file)
@@ -25,11 +25,16 @@ import org.apache.poi.hssf.record.formula.eval.GenericFormulaTestCase;
 import junit.framework.TestSuite;
 
 /**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
+ * This is a test of all the normal formula functions we have implemented.
+ * It should pick up newly implemented functions which are correctly added
+ *  to the test formula excel file, but tweak the rows below if you
+ *  add any past the end of what's currently checked.
+ * For newly implemented eval functions, 
+ *  @see org.apache.poi.hssf.record.formula.eval.TestEverything
  *
+ * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
  */
 public class TestEverything extends TestSuite {
-
     public static TestSuite suite() throws Exception {
         TestSuite suite = new TestSuite("Tests for individual function classes");
         String s;
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/AIOOB-Tap.doc b/src/scratchpad/testcases/org/apache/poi/hwpf/data/AIOOB-Tap.doc
new file mode 100644 (file)
index 0000000..bfd5906
Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hwpf/data/AIOOB-Tap.doc differ
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/IllustrativeCases.docx b/src/scratchpad/testcases/org/apache/poi/hwpf/data/IllustrativeCases.docx
new file mode 100644 (file)
index 0000000..29dacb6
Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hwpf/data/IllustrativeCases.docx differ
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/ListEntryNoListTable.doc b/src/scratchpad/testcases/org/apache/poi/hwpf/data/ListEntryNoListTable.doc
new file mode 100644 (file)
index 0000000..939f5a4
Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hwpf/data/ListEntryNoListTable.doc differ
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/sample.docx b/src/scratchpad/testcases/org/apache/poi/hwpf/data/sample.docx
new file mode 100644 (file)
index 0000000..8dd04bc
Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hwpf/data/sample.docx differ
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java
new file mode 100644 (file)
index 0000000..8e7f47e
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+* 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.Iterator;
+import java.util.List;
+
+import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.hwpf.model.StyleSheet;
+import org.apache.poi.hwpf.model.TextPiece;
+import org.apache.poi.hwpf.usermodel.Paragraph;
+import org.apache.poi.hwpf.usermodel.Range;
+import org.apache.poi.util.LittleEndian;
+
+import junit.framework.TestCase;
+
+/**
+ * Test various problem documents
+ *
+ * @author Nick Burch (nick at torchbox dot com)
+ */
+public class TestProblems extends TestCase {
+       private String dirname = System.getProperty("HWPF.testdata.path");
+       
+    protected void setUp() throws Exception {
+    }                  
+    
+    /**
+     * ListEntry passed no ListTable
+     */
+    public void testListEntryNoListTable() throws Exception {
+       HWPFDocument doc = new HWPFDocument(new FileInputStream(dirname + "/ListEntryNoListTable.doc"));
+       
+       Range r = doc.getRange();
+       StyleSheet styleSheet = doc.getStyleSheet();
+       for (int x = 0; x < r.numSections(); x++) {
+               Section s = r.getSection(x);
+               for (int y = 0; y < s.numParagraphs(); y++) {
+                       Paragraph paragraph = s.getParagraph(y);
+                       //System.out.println(paragraph.getCharacterRun(0).text());
+               }
+       }
+    }
+
+       /**
+        * AIOOB for TableSprmUncompressor.unCompressTAPOperation
+        */
+       public void testSprmAIOOB() throws Exception {
+       HWPFDocument doc = new HWPFDocument(new FileInputStream(dirname + "/AIOOB-Tap.doc"));
+       
+       Range r = doc.getRange();
+       StyleSheet styleSheet = doc.getStyleSheet();
+       for (int x = 0; x < r.numSections(); x++) {
+               Section s = r.getSection(x);
+               for (int y = 0; y < s.numParagraphs(); y++) {
+                       Paragraph paragraph = s.getParagraph(y);
+                       //System.out.println(paragraph.getCharacterRun(0).text());
+               }
+       }
+       }
+}
index e6d966456e01e6e9ae5aa8dc1c32d3741c4c12e3..94fe5c1becedcfb8db91d9f8afcb81bec9588255 100644 (file)
Binary files a/src/testcases/org/apache/poi/hssf/data/1900DateWindowing.xls and b/src/testcases/org/apache/poi/hssf/data/1900DateWindowing.xls differ
index 142d3148f312d0d03a7e5d709ecabf22a0a6ee26..8c0dba1d7ac2415cc48f5678d0cd4450f0d9cded 100644 (file)
Binary files a/src/testcases/org/apache/poi/hssf/data/1904DateWindowing.xls and b/src/testcases/org/apache/poi/hssf/data/1904DateWindowing.xls differ
diff --git a/src/testcases/org/apache/poi/hssf/data/AverageTaxRates.xlsx b/src/testcases/org/apache/poi/hssf/data/AverageTaxRates.xlsx
new file mode 100644 (file)
index 0000000..fee8059
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/AverageTaxRates.xlsx differ
diff --git a/src/testcases/org/apache/poi/hssf/data/SimpleWithColours.xls b/src/testcases/org/apache/poi/hssf/data/SimpleWithColours.xls
new file mode 100755 (executable)
index 0000000..ab3cdec
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/SimpleWithColours.xls differ
diff --git a/src/testcases/org/apache/poi/hssf/data/StringContinueRecords.xls b/src/testcases/org/apache/poi/hssf/data/StringContinueRecords.xls
new file mode 100644 (file)
index 0000000..f2ada9e
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/StringContinueRecords.xls differ
diff --git a/src/testcases/org/apache/poi/hssf/data/Tables.xlsx b/src/testcases/org/apache/poi/hssf/data/Tables.xlsx
new file mode 100644 (file)
index 0000000..705e0ae
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/Tables.xlsx differ
diff --git a/src/testcases/org/apache/poi/hssf/data/TestDataValidation.xls b/src/testcases/org/apache/poi/hssf/data/TestDataValidation.xls
new file mode 100644 (file)
index 0000000..6b71a77
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/TestDataValidation.xls differ
diff --git a/src/testcases/org/apache/poi/hssf/data/TwoSheetsNoneHidden.xls b/src/testcases/org/apache/poi/hssf/data/TwoSheetsNoneHidden.xls
new file mode 100644 (file)
index 0000000..969f014
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/TwoSheetsNoneHidden.xls differ
diff --git a/src/testcases/org/apache/poi/hssf/data/TwoSheetsOneHidden.xls b/src/testcases/org/apache/poi/hssf/data/TwoSheetsOneHidden.xls
new file mode 100644 (file)
index 0000000..940ffc0
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/TwoSheetsOneHidden.xls differ
diff --git a/src/testcases/org/apache/poi/hssf/data/sample-beta.xlsx b/src/testcases/org/apache/poi/hssf/data/sample-beta.xlsx
new file mode 100644 (file)
index 0000000..2eb36ee
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/sample-beta.xlsx differ
index 2eb36ee2a0a1c3d1ce59617161d522cf86f0564b..a275cf417e01a78f9562b1b13725a404f234d5d1 100644 (file)
Binary files a/src/testcases/org/apache/poi/hssf/data/sample.xlsx and b/src/testcases/org/apache/poi/hssf/data/sample.xlsx differ
diff --git a/src/testcases/org/apache/poi/hssf/data/templateExcelWithAutofilter.xls b/src/testcases/org/apache/poi/hssf/data/templateExcelWithAutofilter.xls
new file mode 100644 (file)
index 0000000..5813fde
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/templateExcelWithAutofilter.xls differ
index 027495a1b086168d91efeb9281782c6964519bb3..0aef5c765a1a52add6604cd386fdef4531593310 100644 (file)
@@ -68,6 +68,19 @@ public class TestExcelExtractor extends TestCase {
                );
        }
        
+       public void testwithContinueRecords() throws Exception {
+               String path = System.getProperty("HSSF.testdata.path");
+               FileInputStream fin = new FileInputStream(path + File.separator + "StringContinueRecords.xls");
+               
+               ExcelExtractor extractor = new ExcelExtractor(new POIFSFileSystem(fin));
+               
+               extractor.getText();
+               
+               // Has masses of text
+               // Until we fixed bug #41064, this would've
+               //   failed by now
+               assertTrue(extractor.getText().length() > 40960);
+       }
        
        public void testStringConcat() throws Exception {
                String path = System.getProperty("HSSF.testdata.path");
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestDataValidation.java b/src/testcases/org/apache/poi/hssf/usermodel/TestDataValidation.java
new file mode 100644 (file)
index 0000000..f970ff2
--- /dev/null
@@ -0,0 +1,910 @@
+/* ====================================================================
+   Copyright 2002-2004   Apache Software Foundation
+
+   Licensed 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.hssf.usermodel;
+
+import junit.framework.TestCase;
+
+import org.apache.poi.hssf.util.*;
+
+import java.io.*;
+import java.util.*;
+import java.text.SimpleDateFormat;
+
+/**
+ * <p>Title: TestDataValidation</p>
+ * <p>Description: Class for testing Excel's data validation mechanism
+ *    Second test :
+ *        -
+ * </p>
+ * @author Dragos Buleandra ( dragos.buleandra@trade2b.ro )
+ */
+public class TestDataValidation extends TestCase
+{
+  public TestDataValidation(String name)
+  {
+    super(name);
+  }
+
+  protected void setUp()
+  {
+    String filename = System.getProperty("HSSF.testdata.path");
+    if (filename == null)
+    {
+       System.setProperty("HSSF.testdata.path", "src/testcases/org/apache/poi/hssf/data");
+    }
+  }
+
+  public void testDataValidation() throws Exception
+  {
+    System.out.println("\nTest no. 2 - Test Excel's Data validation mechanism");
+    String resultFile   = System.getProperty("HSSF.testdata.path")+"/TestDataValidation.xls";
+    HSSFWorkbook wb = new HSSFWorkbook();
+
+    HSSFCellStyle style_1 = this.createStyle( wb, HSSFCellStyle.ALIGN_LEFT );
+    HSSFCellStyle style_2 = this.createStyle( wb, HSSFCellStyle.ALIGN_CENTER );
+    HSSFCellStyle style_3 = this.createStyle( wb, HSSFCellStyle.ALIGN_CENTER, HSSFColor.GREY_25_PERCENT.index, true );
+    HSSFCellStyle style_4 = this.createHeaderStyle(wb);
+    HSSFDataValidation data_validation = null;
+
+    //data validation's number types
+    System.out.print("    Create sheet for Data Validation's number types ... ");
+    HSSFSheet fSheet = wb.createSheet("Number types");
+
+    //"Whole number" validation type
+    this.createDVTypeRow( wb, 0, style_3, "Whole number");
+    this.createHeaderRow( wb, 0, style_4 );
+
+    short start_row = (short)fSheet.getPhysicalNumberOfRows();
+    data_validation = new HSSFDataValidation((short)(start_row),(short)0,(short)(start_row),(short)0);
+    data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_INTEGER);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_BETWEEN);
+    data_validation.setFirstFormula("2");
+    data_validation.setSecondFormula("6");
+    data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !");
+    data_validation.createPromptBox("Hi , dear user !", "So , you just selected me ! Thanks !");
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Between 2 and 6 ", true, true, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" );
+
+    data_validation.setFirstRow((short)(start_row+1));
+    data_validation.setLastRow((short)(start_row+1));
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_NOT_BETWEEN);
+    data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_INFO);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Not between 2 and 6 ", false, true, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = INFO" );
+
+    data_validation.setFirstRow((short)(start_row+2));
+    data_validation.setLastRow((short)(start_row+2));
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setShowPromptBox(false);
+    data_validation.setFirstFormula("3");
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_EQUAL);
+    data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_WARNING);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Equal to 3", false, false, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = WARNING" );
+
+    data_validation.setFirstRow((short)(start_row+3));
+    data_validation.setLastRow((short)(start_row+3));
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setShowPromptBox(false);
+    data_validation.setShowErrorBox(false);
+    data_validation.setFirstFormula("3");
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_NOT_EQUAL);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Not equal to 3", false, false, false );
+    this.writeOtherSettings( fSheet, style_1, "-" );
+
+    data_validation.setFirstRow((short)(start_row+4));
+    data_validation.setLastRow((short)(start_row+4));
+    data_validation.setEmptyCellAllowed(true);
+    data_validation.setShowPromptBox(false);
+    data_validation.setShowErrorBox(false);
+    data_validation.setFirstFormula("3");
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_GREATER_THAN);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Greater than 3", true, false, false );
+    this.writeOtherSettings( fSheet, style_1, "-" );
+
+    data_validation.setFirstRow((short)(start_row+5));
+    data_validation.setLastRow((short)(start_row+5));
+    data_validation.setEmptyCellAllowed(true);
+    data_validation.setShowPromptBox(true);
+    data_validation.setShowErrorBox(false);
+    data_validation.setFirstFormula("3");
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_LESS_THAN);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Less than 3", true, true, false );
+    this.writeOtherSettings( fSheet, style_1, "-" );
+
+    data_validation.setFirstRow((short)(start_row+6));
+    data_validation.setLastRow((short)(start_row+6));
+    data_validation.setEmptyCellAllowed(true);
+    data_validation.setShowPromptBox(false);
+    data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_STOP);
+    data_validation.setShowErrorBox(true);
+    data_validation.setFirstFormula("4");
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_GREATER_OR_EQUAL);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Greater than or equal to 4", true, false, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" );
+
+    data_validation.setFirstRow((short)(start_row+7));
+    data_validation.setLastRow((short)(start_row+7));
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setShowPromptBox(true);
+    data_validation.setShowErrorBox(false);
+    data_validation.setFirstFormula("4");
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_LESS_OR_EQUAL);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Less than or equal to 4", false, true, false );
+    this.writeOtherSettings( fSheet, style_1, "-" );
+
+    //"Decimal" validation type
+    this.createDVTypeRow( wb, 0, style_3, "Decimal");
+    this.createHeaderRow( wb, 0, style_4 );
+
+    start_row += (short)(8+4);
+    data_validation = new HSSFDataValidation((short)(start_row),(short)0,(short)(start_row),(short)0);
+    data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_DECIMAL);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_BETWEEN);
+    data_validation.setFirstFormula("2");
+    data_validation.setSecondFormula("6");
+    data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !");
+    data_validation.createPromptBox("Hi , dear user !", "So , you just selected me ! Thanks !");
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Between 2 and 6 ", true, true, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" );
+
+    data_validation.setFirstRow((short)(start_row+1));
+    data_validation.setLastRow((short)(start_row+1));
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_NOT_BETWEEN);
+    data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_INFO);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Not between 2 and 6 ", false, true, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = INFO" );
+
+    data_validation.setFirstRow((short)(start_row+2));
+    data_validation.setLastRow((short)(start_row+2));
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setShowPromptBox(false);
+    data_validation.setFirstFormula("3");
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_EQUAL);
+    data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_WARNING);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Equal to 3", false, false, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = WARNING" );
+
+    data_validation.setFirstRow((short)(start_row+3));
+    data_validation.setLastRow((short)(start_row+3));
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setShowPromptBox(false);
+    data_validation.setShowErrorBox(false);
+    data_validation.setFirstFormula("3");
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_NOT_EQUAL);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Not equal to 3", false, false, false );
+    this.writeOtherSettings( fSheet, style_1, "-" );
+
+    data_validation.setFirstRow((short)(start_row+4));
+    data_validation.setLastRow((short)(start_row+4));
+    data_validation.setEmptyCellAllowed(true);
+    data_validation.setShowPromptBox(false);
+    data_validation.setShowErrorBox(false);
+    data_validation.setFirstFormula("3");
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_GREATER_THAN);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Greater than 3", true, false, false );
+    this.writeOtherSettings( fSheet, style_1, "-" );
+
+    data_validation.setFirstRow((short)(start_row+5));
+    data_validation.setLastRow((short)(start_row+5));
+    data_validation.setEmptyCellAllowed(true);
+    data_validation.setShowPromptBox(true);
+    data_validation.setShowErrorBox(false);
+    data_validation.setFirstFormula("3");
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_LESS_THAN);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Less than 3", true, true, false );
+    this.writeOtherSettings( fSheet, style_1, "-" );
+
+    data_validation.setFirstRow((short)(start_row+6));
+    data_validation.setLastRow((short)(start_row+6));
+    data_validation.setEmptyCellAllowed(true);
+    data_validation.setShowPromptBox(false);
+    data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_STOP);
+    data_validation.setShowErrorBox(true);
+    data_validation.setFirstFormula("4");
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_GREATER_OR_EQUAL);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Greater than or equal to 4", true, false, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" );
+
+    data_validation.setFirstRow((short)(start_row+7));
+    data_validation.setLastRow((short)(start_row+7));
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setShowPromptBox(true);
+    data_validation.setShowErrorBox(false);
+    data_validation.setFirstFormula("4");
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_LESS_OR_EQUAL);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Less than or equal to 4", false, true, false );
+    this.writeOtherSettings( fSheet, style_1, "-" );
+
+    System.out.println("done !");
+
+    //"List" Data Validation type
+    /** @todo  List*/
+    System.out.print("    Create sheet for 'List' Data Validation type ... ");
+    fSheet = wb.createSheet("Lists");
+
+    this.createDVTypeRow( wb, 1, style_3, "Explicit lists - list items are explicitly provided");
+    this.createDVDeescriptionRow( wb, 1, style_3, "Disadvantage - sum of item's length should be less than 255 characters");
+    this.createHeaderRow( wb, 1, style_4 );
+
+    start_row = (short)fSheet.getPhysicalNumberOfRows();
+    data_validation = new HSSFDataValidation((short)(start_row),(short)0,(short)(start_row),(short)0);
+    data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_LIST);
+    data_validation.setFirstFormula("1+2+3");
+    data_validation.setSecondFormula(null);
+    data_validation.setSurppressDropDownArrow(false);
+    data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !");
+    data_validation.createPromptBox("Hi , dear user !", "So , you just selected me ! Thanks !");
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "POIFS,HSSF,HWPF,HPSF", true, true, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type=STOP ; In-cell dropdown=yes" );
+
+    data_validation = new HSSFDataValidation((short)(start_row+1),(short)0,(short)(start_row+1),(short)0);
+    data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_LIST);
+    data_validation.setFirstFormula("4+5+6+7");
+    data_validation.setSecondFormula(null);
+    data_validation.setSurppressDropDownArrow(false);
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setShowPromptBox(false);
+    data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !");
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "POIFS,HSSF,HWPF,HPSF", false, false, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type=STOP ; In-cell dropdown=yes" );
+
+    data_validation = new HSSFDataValidation((short)(start_row+2),(short)0,(short)(start_row+2),(short)0);
+    data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_LIST);
+    data_validation.setFirstFormula("7+21");
+    data_validation.setSecondFormula(null);
+    data_validation.setSurppressDropDownArrow(true);
+    data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !");
+    data_validation.createPromptBox("Hi , dear user !", "So , you just selected me ! Thanks !");
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "POIFS,HSSF,HWPF,HPSF", true, true, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type=STOP ; In-cell dropdown=no" );
+
+    data_validation = new HSSFDataValidation((short)(start_row+3),(short)0,(short)(start_row+3),(short)0);
+    data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_LIST);
+    data_validation.setFirstFormula("8/2");
+    data_validation.setSecondFormula(null);
+    data_validation.setSurppressDropDownArrow(true);
+    data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !");
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setShowPromptBox(false);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "POIFS,HSSF,HWPF,HPSF", false, false, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type=STOP ; In-cell dropdown=no" );
+
+    this.createDVTypeRow( wb, 1, style_3, "Reference lists - list items are taken from others cells");
+    this.createDVDeescriptionRow( wb, 1, style_3, "Advantage - no restriction regarding the sum of item's length");
+    this.createHeaderRow( wb, 1, style_4 );
+
+    start_row += (short)(4+5);
+    String cellStrValue = "a b c d e f g h i j k l m n o p r s t u v x y z w 0 1 2 3 4 "+
+                          "a b c d e f g h i j k l m n o p r s t u v x y z w 0 1 2 3 4 "+
+                          "a b c d e f g h i j k l m n o p r s t u v x y z w 0 1 2 3 4 "+
+                          "a b c d e f g h i j k l m n o p r s t u v x y z w 0 1 2 3 4 ";
+
+    String strFormula = "$A$100:$A$120";
+    data_validation = new HSSFDataValidation((short)(start_row),(short)0,(short)(start_row),(short)0);
+    data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_LIST);
+    data_validation.setFirstFormula(strFormula);
+    data_validation.setSecondFormula(null);
+    data_validation.setSurppressDropDownArrow(false);
+    data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !");
+    data_validation.createPromptBox("Hi , dear user !", "So , you just selected me ! Thanks !");
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, strFormula, true, true, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type=STOP ; In-cell dropdown=yes" );
+
+    data_validation = new HSSFDataValidation((short)(start_row+1),(short)0,(short)(start_row+1),(short)0);
+    data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_LIST);
+    data_validation.setFirstFormula(strFormula);
+    data_validation.setSecondFormula(null);
+    data_validation.setSurppressDropDownArrow(false);
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setShowPromptBox(false);
+    data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !");
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, strFormula, false, false, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type=STOP ; In-cell dropdown=yes" );
+
+    data_validation = new HSSFDataValidation((short)(start_row+2),(short)0,(short)(start_row+2),(short)0);
+    data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_LIST);
+    data_validation.setFirstFormula(strFormula);
+    data_validation.setSecondFormula(null);
+    data_validation.setSurppressDropDownArrow(true);
+    data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !");
+    data_validation.createPromptBox("Hi , dear user !", "So , you just selected me ! Thanks !");
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, strFormula, true, true, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type=STOP ; In-cell dropdown=no" );
+
+    data_validation = new HSSFDataValidation((short)(start_row+3),(short)0,(short)(start_row+3),(short)0);
+    data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_LIST);
+    data_validation.setFirstFormula(strFormula);
+    data_validation.setSecondFormula(null);
+    data_validation.setSurppressDropDownArrow(true);
+    data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !");
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setShowPromptBox(false);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, strFormula, false, false, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type=STOP ; In-cell dropdown=no" );
+
+    for (int i=100; i<=120; i++)
+    {
+       HSSFRow currRow = fSheet.createRow(i);
+       currRow.createCell((short)0).setCellValue(cellStrValue);
+//       currRow.hide( true );
+    }
+
+    System.out.println("done !");
+
+    //Date/Time Validation type
+    System.out.print("    Create sheet for 'Date' and 'Time' Data Validation types ... ");
+    fSheet = wb.createSheet("Date_Time");
+    SimpleDateFormat df = new SimpleDateFormat("m/d/yyyy");
+    HSSFDataFormat dataFormat = wb.createDataFormat();
+    short fmtDate = dataFormat.getFormat("m/d/yyyy");
+    short fmtTime = dataFormat.getFormat("h:mm");
+    HSSFCellStyle cellStyle_data = wb.createCellStyle();
+    cellStyle_data.setDataFormat(fmtDate);
+    HSSFCellStyle cellStyle_time = wb.createCellStyle();
+    cellStyle_time.setDataFormat(fmtTime);
+
+    this.createDVTypeRow( wb, 2, style_3, "Date ( cells are already formated as date - m/d/yyyy)");
+    this.createHeaderRow( wb, 2, style_4 );
+
+    start_row = (short)fSheet.getPhysicalNumberOfRows();
+    data_validation = new HSSFDataValidation((short)(start_row),(short)0,(short)(start_row),(short)0);
+    data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_DATE);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_BETWEEN);
+
+    data_validation.setFirstFormula( String.valueOf((int)HSSFDateUtil.getExcelDate(df.parse("1/2/2004"))) );
+    data_validation.setSecondFormula( String.valueOf((int)HSSFDateUtil.getExcelDate(df.parse("1/6/2004"))) );
+
+    data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !");
+    data_validation.createPromptBox("Hi , dear user !", "So , you just selected me ! Thanks !");
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Between 1/2/2004 and 1/6/2004 ", true, true, true );
+    this.setCellFormat( fSheet, cellStyle_data );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" );
+
+    data_validation.setFirstRow((short)(start_row+1));
+    data_validation.setLastRow((short)(start_row+1));
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_NOT_BETWEEN);
+    data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_INFO);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Not between 1/2/2004 and 1/6/2004 ", false, true, true );
+    this.setCellFormat( fSheet, cellStyle_data );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = INFO" );
+
+    data_validation.setFirstRow((short)(start_row+2));
+    data_validation.setLastRow((short)(start_row+2));
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setShowPromptBox(false);
+    data_validation.setFirstFormula(String.valueOf((int)HSSFDateUtil.getExcelDate(df.parse("3/2/2004"))));
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_EQUAL);
+    data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_WARNING);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Equal to 3/2/2004", false, false, true );
+    this.setCellFormat( fSheet, cellStyle_data );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = WARNING" );
+
+    data_validation.setFirstRow((short)(start_row+3));
+    data_validation.setLastRow((short)(start_row+3));
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setShowPromptBox(false);
+    data_validation.setShowErrorBox(false);
+    data_validation.setFirstFormula(String.valueOf((int)HSSFDateUtil.getExcelDate(df.parse("3/2/2004"))));
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_NOT_EQUAL);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Not equal to 3/2/2004", false, false, false );
+    this.setCellFormat( fSheet, cellStyle_data );
+    this.writeOtherSettings( fSheet, style_1, "-" );
+
+    data_validation.setFirstRow((short)(start_row+4));
+    data_validation.setLastRow((short)(start_row+4));
+    data_validation.setEmptyCellAllowed(true);
+    data_validation.setShowPromptBox(false);
+    data_validation.setShowErrorBox(false);
+    data_validation.setFirstFormula(String.valueOf((int)HSSFDateUtil.getExcelDate(df.parse("3/2/2004"))));
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_GREATER_THAN);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Greater than 3/2/2004", true, false, false );
+    this.setCellFormat( fSheet, cellStyle_data );
+    this.writeOtherSettings( fSheet, style_1, "-" );
+
+    data_validation.setFirstRow((short)(start_row+5));
+    data_validation.setLastRow((short)(start_row+5));
+    data_validation.setEmptyCellAllowed(true);
+    data_validation.setShowPromptBox(true);
+    data_validation.setShowErrorBox(false);
+    data_validation.setFirstFormula(String.valueOf((int)HSSFDateUtil.getExcelDate(df.parse("3/2/2004"))));
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_LESS_THAN);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Less than 3/2/2004", true, true, false );
+    this.setCellFormat( fSheet, cellStyle_data );
+    this.writeOtherSettings( fSheet, style_1, "-" );
+
+    data_validation.setFirstRow((short)(start_row+6));
+    data_validation.setLastRow((short)(start_row+6));
+    data_validation.setEmptyCellAllowed(true);
+    data_validation.setShowPromptBox(false);
+    data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_STOP);
+    data_validation.setShowErrorBox(true);
+    data_validation.setFirstFormula(String.valueOf((int)HSSFDateUtil.getExcelDate(df.parse("3/2/2004"))));
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_GREATER_OR_EQUAL);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Greater than or equal to 3/2/2004", true, false, true );
+    this.setCellFormat( fSheet, cellStyle_data );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" );
+
+    data_validation.setFirstRow((short)(start_row+7));
+    data_validation.setLastRow((short)(start_row+7));
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setShowPromptBox(true);
+    data_validation.setShowErrorBox(false);
+    data_validation.setFirstFormula(String.valueOf((int)HSSFDateUtil.getExcelDate(df.parse("3/4/2004"))));
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_LESS_OR_EQUAL);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Less than or equal to 3/4/2004", false, true, false );
+    this.setCellFormat( fSheet, cellStyle_data );
+    this.writeOtherSettings( fSheet, style_1, "-" );
+
+    //"Time" validation type
+    this.createDVTypeRow( wb, 2, style_3, "Time ( cells are already formated as time - h:mm)");
+    this.createHeaderRow( wb, 2, style_4 );
+
+    df = new SimpleDateFormat("hh:mm");
+
+    start_row += (short)(8+4);
+    data_validation = new HSSFDataValidation((short)(start_row),(short)0,(short)(start_row),(short)0);
+    data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_TIME);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_BETWEEN);
+    data_validation.setFirstFormula(String.valueOf(HSSFDateUtil.getExcelDate(df.parse("12:00"))));
+    data_validation.setSecondFormula(String.valueOf(HSSFDateUtil.getExcelDate(df.parse("16:00"))));
+    data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !");
+    data_validation.createPromptBox("Hi , dear user !", "So , you just selected me ! Thanks !");
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Between 12:00 and 16:00 ", true, true, true );
+    this.setCellFormat( fSheet, cellStyle_time );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" );
+
+    data_validation.setFirstRow((short)(start_row+1));
+    data_validation.setLastRow((short)(start_row+1));
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_NOT_BETWEEN);
+    data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_INFO);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Not between 12:00 and 16:00 ", false, true, true );
+    this.setCellFormat( fSheet, cellStyle_time );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = INFO" );
+
+    data_validation.setFirstRow((short)(start_row+2));
+    data_validation.setLastRow((short)(start_row+2));
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setShowPromptBox(false);
+    data_validation.setFirstFormula(String.valueOf((int)HSSFDateUtil.getExcelDate(df.parse("13:35"))));
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_EQUAL);
+    data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_WARNING);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Equal to 13:35", false, false, true );
+    this.setCellFormat( fSheet, cellStyle_time );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = WARNING" );
+
+    data_validation.setFirstRow((short)(start_row+3));
+    data_validation.setLastRow((short)(start_row+3));
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setShowPromptBox(false);
+    data_validation.setShowErrorBox(false);
+    data_validation.setFirstFormula(String.valueOf(HSSFDateUtil.getExcelDate(df.parse("13:35"))));
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_NOT_EQUAL);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Not equal to 13:35", false, false, false );
+    this.setCellFormat( fSheet, cellStyle_time );
+    this.writeOtherSettings( fSheet, style_1, "-" );
+
+    data_validation.setFirstRow((short)(start_row+4));
+    data_validation.setLastRow((short)(start_row+4));
+    data_validation.setEmptyCellAllowed(true);
+    data_validation.setShowPromptBox(false);
+    data_validation.setShowErrorBox(false);
+    data_validation.setFirstFormula(String.valueOf(HSSFDateUtil.getExcelDate(df.parse("12:00"))));
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_GREATER_THAN);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Greater than 12:00", true, false, false );
+    this.setCellFormat( fSheet, cellStyle_time );
+    this.writeOtherSettings( fSheet, style_1, "-" );
+
+    data_validation.setFirstRow((short)(start_row+5));
+    data_validation.setLastRow((short)(start_row+5));
+    data_validation.setEmptyCellAllowed(true);
+    data_validation.setShowPromptBox(true);
+    data_validation.setShowErrorBox(false);
+    data_validation.setFirstFormula(String.valueOf(HSSFDateUtil.getExcelDate(df.parse("12:00"))));
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_LESS_THAN);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Less than 12:00", true, true, false );
+    this.setCellFormat( fSheet, cellStyle_time );
+    this.writeOtherSettings( fSheet, style_1, "-" );
+
+    data_validation.setFirstRow((short)(start_row+6));
+    data_validation.setLastRow((short)(start_row+6));
+    data_validation.setEmptyCellAllowed(true);
+    data_validation.setShowPromptBox(false);
+    data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_STOP);
+    data_validation.setShowErrorBox(true);
+    data_validation.setFirstFormula(String.valueOf(HSSFDateUtil.getExcelDate(df.parse("14:00"))));
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_GREATER_OR_EQUAL);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Greater than or equal to 14:00", true, false, true );
+    this.setCellFormat( fSheet, cellStyle_time );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" );
+
+    data_validation.setFirstRow((short)(start_row+7));
+    data_validation.setLastRow((short)(start_row+7));
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setShowPromptBox(true);
+    data_validation.setShowErrorBox(false);
+    data_validation.setFirstFormula(String.valueOf(HSSFDateUtil.getExcelDate(df.parse("14:00"))));
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_LESS_OR_EQUAL);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Less than or equal to 14:00", false, true, false );
+    this.setCellFormat( fSheet, cellStyle_time );
+    this.writeOtherSettings( fSheet, style_1, "-" );
+
+    System.out.println("done !");
+
+    //"Text length" validation type
+    System.out.print("    Create sheet for 'Text length' Data Validation type... ");
+    fSheet = wb.createSheet("Text length");
+    this.createHeaderRow( wb, 3, style_4 );
+
+    data_validation = new HSSFDataValidation((short)1,(short)0,(short)1,(short)0);
+    data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_TEXT_LENGTH);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_BETWEEN);
+    data_validation.setFirstFormula("2");
+    data_validation.setSecondFormula("6");
+    data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !");
+    data_validation.createPromptBox("Hi , dear user !", "So , you just selected me ! Thanks !");
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Between 2 and 6 ", true, true, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" );
+
+    data_validation.setFirstRow((short)2);
+    data_validation.setLastRow((short)2);
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_NOT_BETWEEN);
+    data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_INFO);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Not between 2 and 6 ", false, true, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = INFO" );
+
+    data_validation.setFirstRow((short)3);
+    data_validation.setLastRow((short)3);
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setShowPromptBox(false);
+    data_validation.setFirstFormula("3");
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_EQUAL);
+    data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_WARNING);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Equal to 3", false, false, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = WARNING" );
+
+    data_validation.setFirstRow((short)4);
+    data_validation.setLastRow((short)4);
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setShowPromptBox(false);
+    data_validation.setShowErrorBox(false);
+    data_validation.setFirstFormula("3");
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_NOT_EQUAL);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Not equal to 3", false, false, false );
+    this.writeOtherSettings( fSheet, style_1, "-" );
+
+    data_validation.setFirstRow((short)5);
+    data_validation.setLastRow((short)5);
+    data_validation.setEmptyCellAllowed(true);
+    data_validation.setShowPromptBox(false);
+    data_validation.setShowErrorBox(false);
+    data_validation.setFirstFormula("3");
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_GREATER_THAN);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Greater than 3", true, false, false );
+    this.writeOtherSettings( fSheet, style_1, "-" );
+
+    data_validation.setFirstRow((short)6);
+    data_validation.setLastRow((short)6);
+    data_validation.setEmptyCellAllowed(true);
+    data_validation.setShowPromptBox(true);
+    data_validation.setShowErrorBox(false);
+    data_validation.setFirstFormula("3");
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_LESS_THAN);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Less than 3", true, true, false );
+    this.writeOtherSettings( fSheet, style_1, "-" );
+
+    data_validation.setFirstRow((short)7);
+    data_validation.setLastRow((short)7);
+    data_validation.setEmptyCellAllowed(true);
+    data_validation.setShowPromptBox(false);
+    data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_STOP);
+    data_validation.setShowErrorBox(true);
+    data_validation.setFirstFormula("4");
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_GREATER_OR_EQUAL);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Greater than or equal to 4", true, false, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" );
+
+    data_validation.setFirstRow((short)8);
+    data_validation.setLastRow((short)8);
+    data_validation.setEmptyCellAllowed(false);
+    data_validation.setShowPromptBox(true);
+    data_validation.setShowErrorBox(false);
+    data_validation.setFirstFormula("4");
+    data_validation.setSecondFormula(null);
+    data_validation.setOperator(HSSFDataValidation.OPERATOR_LESS_OR_EQUAL);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "Less than or equal to 4", false, true, false );
+    this.writeOtherSettings( fSheet, style_1, "-" );
+    System.out.println("done !");
+
+    //Custom Validation type
+    System.out.print("    Create sheet for 'Custom' Data Validation type ... ");
+    fSheet = wb.createSheet("Custom");
+    this.createHeaderRow( wb, 4, style_4 );
+
+    data_validation = new HSSFDataValidation((short)1,(short)0,(short)1,(short)0);
+    data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_FORMULA);
+    data_validation.setFirstFormula("ISNUMBER($A2)");
+    data_validation.setSecondFormula(null);
+    data_validation.setShowPromptBox(true);
+    data_validation.setShowErrorBox(true);
+    data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !");
+    data_validation.createPromptBox("Hi , dear user !", "So , you just selected me ! Thanks !");
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "ISNUMBER(A2)", true, true, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = STOP" );
+
+    data_validation = new HSSFDataValidation((short)2,(short)0,(short)2,(short)0);
+    data_validation.setDataValidationType(HSSFDataValidation.DATA_TYPE_FORMULA);
+    data_validation.setFirstFormula("IF(SUM(A2:A3)=5,TRUE,FALSE)");
+    data_validation.setSecondFormula(null);
+    data_validation.setShowPromptBox(false);
+    data_validation.setShowErrorBox(true);
+    data_validation.setErrorStyle(HSSFDataValidation.ERROR_STYLE_WARNING);
+    data_validation.createErrorBox("Invalid input !", "Something is wrong ; check condition !");
+    data_validation.setEmptyCellAllowed(false);
+    fSheet.addValidationData(data_validation);
+    this.writeDataValidationSettings( fSheet, style_1, style_2, "IF(SUM(A2:A3)=5,TRUE,FALSE)", false, false, true );
+    this.writeOtherSettings( fSheet, style_1, "Error box type = WARNING" );
+
+    System.out.println("done !");
+
+    //so , everything it's ok for now ; it remains for you to open the file
+    System.out.println("\n    Everything it's ok since we've got so far -:) !\n"+
+                       "    In order to complete the test , it remains for you to open the file \n"+
+                       "    and see if there are four sheets , as described !");
+    System.out.println("        File was saved in \""+resultFile+"\"");
+
+    FileOutputStream fileOut = new FileOutputStream(resultFile);
+    wb.write(fileOut);
+    fileOut.close();
+  }
+
+  private void createDVTypeRow(  HSSFWorkbook wb, int sheetNo , HSSFCellStyle cellStyle, String strTypeDescription)
+  {
+    HSSFSheet sheet = wb.getSheetAt(sheetNo);
+    HSSFRow row = sheet.createRow(sheet.getPhysicalNumberOfRows());
+    row = sheet.createRow(sheet.getPhysicalNumberOfRows());
+    sheet.addMergedRegion(new Region((short)(sheet.getPhysicalNumberOfRows()-1),(short)0,(short)(sheet.getPhysicalNumberOfRows()-1),(short)5));
+    HSSFCell cell = row.createCell((short)0);
+    cell.setCellValue(strTypeDescription);
+    cell.setCellStyle(cellStyle);
+    row = sheet.createRow(sheet.getPhysicalNumberOfRows());
+  }
+
+  private void createDVDeescriptionRow(  HSSFWorkbook wb, int sheetNo , HSSFCellStyle cellStyle, String strTypeDescription )
+  {
+    HSSFSheet sheet = wb.getSheetAt(sheetNo);
+    HSSFRow row = sheet.getRow(sheet.getPhysicalNumberOfRows()-1);
+    sheet.addMergedRegion(new Region((short)(sheet.getPhysicalNumberOfRows()-1),(short)0,(short)(sheet.getPhysicalNumberOfRows()-1),(short)5));
+    HSSFCell cell = row.createCell((short)0);
+    cell.setCellValue(strTypeDescription);
+    cell.setCellStyle(cellStyle);
+    row = sheet.createRow(sheet.getPhysicalNumberOfRows());
+  }
+
+  private void createHeaderRow( HSSFWorkbook wb, int sheetNo , HSSFCellStyle cellStyle )
+  {
+      HSSFSheet sheet = wb.getSheetAt(sheetNo);
+      HSSFRow row = sheet.createRow(sheet.getPhysicalNumberOfRows());
+      row.setHeight((short)400);
+      for ( int i=0; i<6; i++ )
+      {
+         row.createCell((short)i).setCellStyle( cellStyle );
+         if ( i==2 || i==3 || i==4 )
+         {
+            sheet.setColumnWidth( (short) i, (short) 3500);
+         }
+         else if ( i== 5)
+         {
+            sheet.setColumnWidth( (short) i, (short) 10000);
+         }
+         else
+         {
+            sheet.setColumnWidth( (short) i, (short) 8000);
+         }
+      }
+      HSSFCell cell = row.getCell((short)0);
+      cell.setCellValue("Data validation cells");
+      cell = row.getCell((short)1);
+      cell.setCellValue("Condition");
+      cell = row.getCell((short)2);
+      cell.setCellValue("Allow blank");
+      cell = row.getCell((short)3);
+      cell.setCellValue("Prompt box");
+      cell = row.getCell((short)4);
+      cell.setCellValue("Error box");
+      cell = row.getCell((short)5);
+      cell.setCellValue("Other settings");
+  }
+
+  private HSSFCellStyle createHeaderStyle(HSSFWorkbook wb)
+  {
+    HSSFFont font = wb.createFont();
+    font.setColor( HSSFColor.WHITE.index );
+    font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
+
+    HSSFCellStyle cellStyle = wb.createCellStyle();
+    cellStyle.setFillForegroundColor(HSSFColor.BLUE_GREY.index);
+    cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
+    cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
+    cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
+    cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
+    cellStyle.setLeftBorderColor(HSSFColor.WHITE.index);
+    cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);
+    cellStyle.setTopBorderColor(HSSFColor.WHITE.index);
+    cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);
+    cellStyle.setRightBorderColor(HSSFColor.WHITE.index);
+    cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
+    cellStyle.setBottomBorderColor(HSSFColor.WHITE.index);
+    cellStyle.setFont(font);
+    return cellStyle;
+  }
+
+  private HSSFCellStyle createStyle( HSSFWorkbook wb, short h_align, short color, boolean bold )
+  {
+    HSSFFont font = wb.createFont();
+    if ( bold )
+    {
+      font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
+    }
+
+    HSSFCellStyle cellStyle = wb.createCellStyle();
+    cellStyle.setFont(font);
+    cellStyle.setFillForegroundColor(color);
+    cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
+    cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
+    cellStyle.setAlignment(h_align);
+    cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
+    cellStyle.setLeftBorderColor(HSSFColor.BLACK.index);
+    cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);
+    cellStyle.setTopBorderColor(HSSFColor.BLACK.index);
+    cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);
+    cellStyle.setRightBorderColor(HSSFColor.BLACK.index);
+    cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
+    cellStyle.setBottomBorderColor(HSSFColor.BLACK.index);
+
+    return cellStyle;
+  }
+
+  private HSSFCellStyle createStyle( HSSFWorkbook wb, short h_align )
+  {
+     return this.createStyle(wb, h_align, HSSFColor.WHITE.index, false);
+  }
+
+  private void writeDataValidationSettings( HSSFSheet sheet, HSSFCellStyle style_1, HSSFCellStyle style_2, String strCondition, boolean allowEmpty, boolean inputBox, boolean errorBox  )
+  {
+    HSSFRow row = sheet.createRow( sheet.getPhysicalNumberOfRows() );
+    //condition's string
+    HSSFCell cell = row.createCell((short)1);
+    cell.setCellStyle(style_1);
+    cell.setCellValue(strCondition);
+    //allow empty cells
+    cell = row.createCell((short)2);
+    cell.setCellStyle(style_2);
+    cell.setCellValue( ((allowEmpty) ? "yes" : "no") );
+    //show input box
+    cell = row.createCell((short)3);
+    cell.setCellStyle(style_2);
+    cell.setCellValue( ((inputBox) ? "yes" : "no") );
+    //show error box
+    cell = row.createCell((short)4);
+    cell.setCellStyle(style_2);
+    cell.setCellValue( ((errorBox) ? "yes" : "no") );
+  }
+
+  private void setCellFormat( HSSFSheet sheet, HSSFCellStyle cell_style )
+  {
+    HSSFRow row = sheet.getRow( sheet.getPhysicalNumberOfRows() -1 );
+    HSSFCell cell = row.createCell((short)0);
+    cell.setCellStyle(cell_style);
+  }
+
+  private void writeOtherSettings( HSSFSheet sheet, HSSFCellStyle style, String strStettings )
+  {
+     HSSFRow row = sheet.getRow( sheet.getPhysicalNumberOfRows() -1 );
+     HSSFCell cell = row.createCell((short)5);
+     cell.setCellStyle(style);
+     cell.setCellValue(strStettings);
+  }
+
+  public static void main(String[] args)
+  {
+    junit.textui.TestRunner.run(TestDataValidation.class);
+  }
+}
index 57426602607452da7d9aaf9682124baf0ade0d57..ee3cace263f1c82f1776b434bf228bc6ec85069c 100644 (file)
@@ -44,6 +44,7 @@ import java.util.GregorianCalendar;
  * paticular datatypes, etc.
  * @author Andrew C. Oliver (andy at superlinksoftware dot com)
  * @author  Dan Sherman (dsherman at isisph.com)
+ * @author Alex Jacoby (ajacoby at gmail.com)
  */
 
 public class TestHSSFCell
@@ -107,42 +108,106 @@ extends TestCase {
     }
 
     /**
-    * Checks that the recognition of files using 1904 date windowing
-    *  is working properly. Conversion of the date is also an issue,
-    *  but there's a separate unit test for that.
-    */
-    public void testDateWindowing() throws Exception {
-        GregorianCalendar cal = new GregorianCalendar(2000,0,1); // Jan. 1, 2000
-        Date date = cal.getTime();
-        String path = System.getProperty("HSSF.testdata.path");
-
-        // first check a file with 1900 Date Windowing
-        String filename = path + "/1900DateWindowing.xls";
-        FileInputStream stream   = new FileInputStream(filename);
-        POIFSFileSystem fs       = new POIFSFileSystem(stream);
-        HSSFWorkbook    workbook = new HSSFWorkbook(fs);
-        HSSFSheet       sheet    = workbook.getSheetAt(0);
-
-        assertEquals("Date from file using 1900 Date Windowing",
-                        date.getTime(),
-                           sheet.getRow(0).getCell((short)0)
-                              .getDateCellValue().getTime());
-        stream.close();
-        
-        // now check a file with 1904 Date Windowing
-        filename = path + "/1904DateWindowing.xls";
-        stream   = new FileInputStream(filename);
-        fs       = new POIFSFileSystem(stream);
-        workbook = new HSSFWorkbook(fs);
-        sheet    = workbook.getSheetAt(0);
-
-        assertEquals("Date from file using 1904 Date Windowing",
-                        date.getTime(),
-                           sheet.getRow(0).getCell((short)0)
-                              .getDateCellValue().getTime());
-        stream.close();
-    }
-    
+     * Checks that the recognition of files using 1904 date windowing
+     *  is working properly. Conversion of the date is also an issue,
+     *  but there's a separate unit test for that.
+     */
+     public void testDateWindowingRead() throws Exception {
+         GregorianCalendar cal = new GregorianCalendar(2000,0,1); // Jan. 1, 2000
+         Date date = cal.getTime();
+         String path = System.getProperty("HSSF.testdata.path");
+
+         // first check a file with 1900 Date Windowing
+         String filename = path + "/1900DateWindowing.xls";
+         FileInputStream stream   = new FileInputStream(filename);
+         POIFSFileSystem fs       = new POIFSFileSystem(stream);
+         HSSFWorkbook    workbook = new HSSFWorkbook(fs);
+         HSSFSheet       sheet    = workbook.getSheetAt(0);
+
+         assertEquals("Date from file using 1900 Date Windowing",
+                         date.getTime(),
+                            sheet.getRow(0).getCell((short)0)
+                               .getDateCellValue().getTime());
+         stream.close();
+         
+         // now check a file with 1904 Date Windowing
+         filename = path + "/1904DateWindowing.xls";
+         stream   = new FileInputStream(filename);
+         fs       = new POIFSFileSystem(stream);
+         workbook = new HSSFWorkbook(fs);
+         sheet    = workbook.getSheetAt(0);
+
+         assertEquals("Date from file using 1904 Date Windowing",
+                         date.getTime(),
+                            sheet.getRow(0).getCell((short)0)
+                               .getDateCellValue().getTime());
+         stream.close();
+     }
+
+     /**
+      * Checks that dates are properly written to both types of files:
+      * those with 1900 and 1904 date windowing.  Note that if the
+      * previous test ({@link #testDateWindowingRead}) fails, the
+      * results of this test are meaningless.
+      */
+      public void testDateWindowingWrite() throws Exception {
+          GregorianCalendar cal = new GregorianCalendar(2000,0,1); // Jan. 1, 2000
+          Date date = cal.getTime();
+          String path = System.getProperty("HSSF.testdata.path");
+
+          // first check a file with 1900 Date Windowing
+          String filename = path + "/1900DateWindowing.xls";
+          writeCell(filename, 0, (short) 1, date);          
+          assertEquals("Date from file using 1900 Date Windowing",
+                          date.getTime(),
+                          readCell(filename, 0, (short) 1).getTime());
+          
+          // now check a file with 1904 Date Windowing
+          filename = path + "/1904DateWindowing.xls";
+          writeCell(filename, 0, (short) 1, date);          
+          assertEquals("Date from file using 1900 Date Windowing",
+                          date.getTime(),
+                          readCell(filename, 0, (short) 1).getTime());
+      }
+
+      /**
+       * Sets cell value and writes file.
+       */
+      private void writeCell(String filename,
+                int rowIdx, short colIdx, Date date) throws Exception {
+          FileInputStream stream   = new FileInputStream(filename);
+          POIFSFileSystem fs       = new POIFSFileSystem(stream);
+          HSSFWorkbook    workbook = new HSSFWorkbook(fs);
+          HSSFSheet       sheet    = workbook.getSheetAt(0);
+          HSSFRow         row      = sheet.getRow(rowIdx);
+          HSSFCell        cell     = row.getCell(colIdx);
+          
+          if (cell == null) {
+                 cell = row.createCell(colIdx);
+          }
+          cell.setCellValue(date);
+          
+          // Write the file
+          stream.close();
+          FileOutputStream oStream = new FileOutputStream(filename);
+          workbook.write(oStream);
+          oStream.close();
+      }
+      
+      /**
+       * Reads cell value from file.
+       */
+      private Date readCell(String filename,
+                int rowIdx, short colIdx) throws Exception {
+          FileInputStream stream   = new FileInputStream(filename);
+          POIFSFileSystem fs       = new POIFSFileSystem(stream);
+          HSSFWorkbook    workbook = new HSSFWorkbook(fs);
+          HSSFSheet       sheet    = workbook.getSheetAt(0);
+          HSSFRow         row      = sheet.getRow(rowIdx);
+          HSSFCell        cell     = row.getCell(colIdx);
+          return cell.getDateCellValue();
+      }
+      
     /**
      * Tests that the active cell can be correctly read and set
      */
index 10c4e390cb53d6b4944ff00fe022a588376a688d..655f78eddb8838d805298a210fc58f6bbb0a626c 100644 (file)
@@ -85,4 +85,23 @@ public class TestHSSFClientAnchor extends TestCase
             assertEquals(anchor[i].getRow2(), record.getRow2());
         }
     }
+
+    public void testAnchorHeightInPoints(){
+        HSSFWorkbook wb = new HSSFWorkbook();
+        HSSFSheet sheet = wb.createSheet();
+
+        HSSFClientAnchor[] anchor = {
+            new HSSFClientAnchor( 0 , 0,    0 , 0 ,(short)0, 1,(short)1, 3),
+            new HSSFClientAnchor( 0 , 254 , 0 , 126 ,(short)0, 1,(short)1, 3),
+            new HSSFClientAnchor( 0 , 128 , 0 , 128 ,(short)0, 1,(short)1, 3),
+            new HSSFClientAnchor( 0 , 0 , 0 , 128 ,(short)0, 1,(short)1, 3),
+        };
+        float[] ref = {24.0f, 18.0f, 24.0f, 30.0f};
+        for (int i = 0; i < anchor.length; i++) {
+            float height = anchor[i].getAnchorHeightInPoints(sheet);
+            assertEquals(ref[i], height, 0);
+        }
+
+    }
+
 }
index f8aeb8517e5019390bd9580703d8f88e54ae1ffa..6b37f749eefa799c8016e22edabdf797e1d41c79 100644 (file)
@@ -36,6 +36,8 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem;
  *
  * @author  Dan Sherman (dsherman at isisph.com)
  * @author  Hack Kampbjorn (hak at 2mba.dk)
+ * @author  Pavel Krupets (pkrupets at palmtreebusiness dot com)
+ * @author Alex Jacoby (ajacoby at gmail.com)
  * @version %I%, %G%
  */
 
@@ -47,7 +49,9 @@ public class TestHSSFDateUtil
        public static final int CALENDAR_FEBRUARY = 1;
        public static final int CALENDAR_MARCH = 2;
        public static final int CALENDAR_APRIL = 3;
-
+       public static final int CALENDAR_JULY = 6;
+    public static final int CALENDAR_OCTOBER = 9;
+    
     public TestHSSFDateUtil(String s)
     {
         super(s);
@@ -67,10 +71,10 @@ public class TestHSSFDateUtil
             GregorianCalendar date      = new GregorianCalendar(2002, 0, 1,
                     hour, 1, 1);
             double            excelDate =
-                    HSSFDateUtil.getExcelDate(date.getTime());
+                    HSSFDateUtil.getExcelDate(date.getTime(), false);
 
             assertEquals("Checking hour = " + hour, date.getTime().getTime(),
-                    HSSFDateUtil.getJavaDate(excelDate).getTime());
+                    HSSFDateUtil.getJavaDate(excelDate, false).getTime());
         }
 
         // check 1900 and 1904 date windowing conversions
@@ -99,7 +103,7 @@ public class TestHSSFDateUtil
     public void testExcelConversionOnDSTStart() {
         TimeZone cet = TimeZone.getTimeZone("Europe/Copenhagen");
         TimeZone.setDefault(cet);
-        Calendar cal = new GregorianCalendar(2004, Calendar.MARCH, 28);
+        Calendar cal = new GregorianCalendar(2004, CALENDAR_MARCH, 28);
         for (int hour = 0; hour < 24; hour++) {
 
             // Skip 02:00 CET as that is the Daylight change time
@@ -110,7 +114,7 @@ public class TestHSSFDateUtil
 
             cal.set(Calendar.HOUR_OF_DAY, hour);
             Date javaDate = cal.getTime();
-            double excelDate = HSSFDateUtil.getExcelDate(javaDate);
+            double excelDate = HSSFDateUtil.getExcelDate(javaDate, false);
             double difference = excelDate - Math.floor(excelDate);
             int differenceInHours = (int) (difference * 24 * 60 + 0.5) / 60;
             assertEquals("Checking " + hour + " hour on Daylight Saving Time start date",
@@ -118,7 +122,7 @@ public class TestHSSFDateUtil
                     differenceInHours);
             assertEquals("Checking " + hour + " hour on Daylight Saving Time start date",
                     javaDate.getTime(),
-                    HSSFDateUtil.getJavaDate(excelDate).getTime());
+                    HSSFDateUtil.getJavaDate(excelDate, false).getTime());
         }
     }
 
@@ -129,8 +133,8 @@ public class TestHSSFDateUtil
     public void testJavaConversionOnDSTStart() {
         TimeZone cet = TimeZone.getTimeZone("Europe/Copenhagen");
         TimeZone.setDefault(cet);
-        Calendar cal = new GregorianCalendar(2004, Calendar.MARCH, 28);
-        double excelDate = HSSFDateUtil.getExcelDate(cal.getTime());
+        Calendar cal = new GregorianCalendar(2004, CALENDAR_MARCH, 28);
+        double excelDate = HSSFDateUtil.getExcelDate(cal.getTime(), false);
         double oneHour = 1.0 / 24;
         double oneMinute = oneHour / 60;
         for (int hour = 0; hour < 24; hour++, excelDate += oneHour) {
@@ -142,10 +146,10 @@ public class TestHSSFDateUtil
             }
 
             cal.set(Calendar.HOUR_OF_DAY, hour);
-            Date javaDate = HSSFDateUtil.getJavaDate(excelDate);
+            Date javaDate = HSSFDateUtil.getJavaDate(excelDate, false);
             assertEquals("Checking " + hour + " hours on Daylight Saving Time start date",
                     excelDate,
-                    HSSFDateUtil.getExcelDate(javaDate), oneMinute);
+                    HSSFDateUtil.getExcelDate(javaDate, false), oneMinute);
         }
     }
 
@@ -156,11 +160,11 @@ public class TestHSSFDateUtil
     public void testExcelConversionOnDSTEnd() {
         TimeZone cet = TimeZone.getTimeZone("Europe/Copenhagen");
         TimeZone.setDefault(cet);
-        Calendar cal = new GregorianCalendar(2004, Calendar.OCTOBER, 31);
+        Calendar cal = new GregorianCalendar(2004, CALENDAR_OCTOBER, 31);
         for (int hour = 0; hour < 24; hour++) {
             cal.set(Calendar.HOUR_OF_DAY, hour);
             Date javaDate = cal.getTime();
-            double excelDate = HSSFDateUtil.getExcelDate(javaDate);
+            double excelDate = HSSFDateUtil.getExcelDate(javaDate, false);
             double difference = excelDate - Math.floor(excelDate);
             int differenceInHours = (int) (difference * 24 * 60 + 0.5) / 60;
             assertEquals("Checking " + hour + " hour on Daylight Saving Time end date",
@@ -168,7 +172,7 @@ public class TestHSSFDateUtil
                     differenceInHours);
             assertEquals("Checking " + hour + " hour on Daylight Saving Time start date",
                     javaDate.getTime(),
-                    HSSFDateUtil.getJavaDate(excelDate).getTime());
+                    HSSFDateUtil.getJavaDate(excelDate, false).getTime());
         }
     }
 
@@ -179,16 +183,16 @@ public class TestHSSFDateUtil
     public void testJavaConversionOnDSTEnd() {
         TimeZone cet = TimeZone.getTimeZone("Europe/Copenhagen");
         TimeZone.setDefault(cet);
-        Calendar cal = new GregorianCalendar(2004, Calendar.OCTOBER, 31);
-        double excelDate = HSSFDateUtil.getExcelDate(cal.getTime());
+        Calendar cal = new GregorianCalendar(2004, CALENDAR_OCTOBER, 31);
+        double excelDate = HSSFDateUtil.getExcelDate(cal.getTime(), false);
         double oneHour = 1.0 / 24;
         double oneMinute = oneHour / 60;
         for (int hour = 0; hour < 24; hour++, excelDate += oneHour) {
             cal.set(Calendar.HOUR_OF_DAY, hour);
-            Date javaDate = HSSFDateUtil.getJavaDate(excelDate);
+            Date javaDate = HSSFDateUtil.getJavaDate(excelDate, false);
             assertEquals("Checking " + hour + " hours on Daylight Saving Time start date",
                     excelDate,
-                    HSSFDateUtil.getExcelDate(javaDate), oneMinute);
+                    HSSFDateUtil.getExcelDate(javaDate, false), oneMinute);
         }
     }
     
@@ -315,25 +319,38 @@ public class TestHSSFDateUtil
     }
     
     public void testDateBug_2Excel() {
-        assertEquals(59.0, HSSFDateUtil.getExcelDate(createDate(1900, CALENDAR_FEBRUARY, 28)), 0.00001);
-        assertEquals(61.0, HSSFDateUtil.getExcelDate(createDate(1900, CALENDAR_MARCH, 1)), 0.00001);
+        assertEquals(59.0, HSSFDateUtil.getExcelDate(createDate(1900, CALENDAR_FEBRUARY, 28), false), 0.00001);
+        assertEquals(61.0, HSSFDateUtil.getExcelDate(createDate(1900, CALENDAR_MARCH, 1), false), 0.00001);
 
-        assertEquals(37315.00, HSSFDateUtil.getExcelDate(createDate(2002, CALENDAR_FEBRUARY, 28)), 0.00001);
-        assertEquals(37316.00, HSSFDateUtil.getExcelDate(createDate(2002, CALENDAR_MARCH, 1)), 0.00001);
-        assertEquals(37257.00, HSSFDateUtil.getExcelDate(createDate(2002, CALENDAR_JANUARY, 1)), 0.00001);
-        assertEquals(38074.00, HSSFDateUtil.getExcelDate(createDate(2004, CALENDAR_MARCH, 28)), 0.00001);
+        assertEquals(37315.00, HSSFDateUtil.getExcelDate(createDate(2002, CALENDAR_FEBRUARY, 28), false), 0.00001);
+        assertEquals(37316.00, HSSFDateUtil.getExcelDate(createDate(2002, CALENDAR_MARCH, 1), false), 0.00001);
+        assertEquals(37257.00, HSSFDateUtil.getExcelDate(createDate(2002, CALENDAR_JANUARY, 1), false), 0.00001);
+        assertEquals(38074.00, HSSFDateUtil.getExcelDate(createDate(2004, CALENDAR_MARCH, 28), false), 0.00001);
     }
     
     public void testDateBug_2Java() {
-        assertEquals(createDate(1900, Calendar.FEBRUARY, 28), HSSFDateUtil.getJavaDate(59.0));
-        assertEquals(createDate(1900, Calendar.MARCH, 1), HSSFDateUtil.getJavaDate(61.0));
+        assertEquals(createDate(1900, CALENDAR_FEBRUARY, 28), HSSFDateUtil.getJavaDate(59.0, false));
+        assertEquals(createDate(1900, CALENDAR_MARCH, 1), HSSFDateUtil.getJavaDate(61.0, false));
         
-        assertEquals(createDate(2002, Calendar.FEBRUARY, 28), HSSFDateUtil.getJavaDate(37315.00));
-        assertEquals(createDate(2002, Calendar.MARCH, 1), HSSFDateUtil.getJavaDate(37316.00));
-        assertEquals(createDate(2002, Calendar.JANUARY, 1), HSSFDateUtil.getJavaDate(37257.00));
-        assertEquals(createDate(2004, Calendar.MARCH, 28), HSSFDateUtil.getJavaDate(38074.00));
+        assertEquals(createDate(2002, CALENDAR_FEBRUARY, 28), HSSFDateUtil.getJavaDate(37315.00, false));
+        assertEquals(createDate(2002, CALENDAR_MARCH, 1), HSSFDateUtil.getJavaDate(37316.00, false));
+        assertEquals(createDate(2002, CALENDAR_JANUARY, 1), HSSFDateUtil.getJavaDate(37257.00, false));
+        assertEquals(createDate(2004, CALENDAR_MARCH, 28), HSSFDateUtil.getJavaDate(38074.00, false));
     }
-
+    
+    public void testDate1904() {
+        assertEquals(createDate(1904, CALENDAR_JANUARY, 2), HSSFDateUtil.getJavaDate(1.0, true));
+        assertEquals(createDate(1904, CALENDAR_JANUARY, 1), HSSFDateUtil.getJavaDate(0.0, true));
+        assertEquals(0.0, HSSFDateUtil.getExcelDate(createDate(1904, CALENDAR_JANUARY, 1), true), 0.00001);
+        assertEquals(1.0, HSSFDateUtil.getExcelDate(createDate(1904, CALENDAR_JANUARY, 2), true), 0.00001);
+        
+        assertEquals(createDate(1998, CALENDAR_JULY, 5), HSSFDateUtil.getJavaDate(35981, false));
+        assertEquals(createDate(1998, CALENDAR_JULY, 5), HSSFDateUtil.getJavaDate(34519, true));
+        
+        assertEquals(35981.0, HSSFDateUtil.getExcelDate(createDate(1998, CALENDAR_JULY, 5), false), 0.00001);
+        assertEquals(34519.0, HSSFDateUtil.getExcelDate(createDate(1998, CALENDAR_JULY, 5), true), 0.00001);
+    }
+    
     private Date createDate(int year, int month, int day) {
         Calendar c = new GregorianCalendar();
         c.set(year, month, day, 0, 0, 0);
@@ -341,10 +358,21 @@ public class TestHSSFDateUtil
         return c.getTime();
     }
     
+    /**
+     * Check if HSSFDateUtil.getAbsoluteDay works as advertised.
+     */
+    public void testAbsoluteDay() {
+        // 1 Jan 1900 is 1 day after 31 Dec 1899
+        GregorianCalendar calendar = new GregorianCalendar(1900, 0, 1);
+        assertEquals("Checking absolute day (1 Jan 1900)", 1, HSSFDateUtil.absoluteDay(calendar, false));
+        // 1 Jan 1901 is 366 days after 31 Dec 1899
+        calendar = new GregorianCalendar(1901, 0, 1);
+        assertEquals("Checking absolute day (1 Jan 1901)", 366, HSSFDateUtil.absoluteDay(calendar, false));
+    }
+    
     public static void main(String [] args) {
         System.out
                 .println("Testing org.apache.poi.hssf.usermodel.TestHSSFDateUtil");
         junit.textui.TestRunner.run(TestHSSFDateUtil.class);
     }
 }
-
index 8504b8dd7e339f9f5662139eb8acf2d60a3477d6..c5674b9e765a57c0f01284ff7a8741bac1866cf8 100644 (file)
@@ -95,6 +95,71 @@ public class TestHSSFPalette extends TestCase
         assertEquals(msg, (short) 100, actualRGB[2]);
     }
     
+    /**
+     * Uses the palette from cell stylings
+     */
+    public void testPaletteFromCellColours() throws Exception {
+        String dir = System.getProperty("HSSF.testdata.path");
+        File sample = new File(dir + "/SimpleWithColours.xls");
+        assertTrue("SimpleWithColours.xls exists and is readable", sample.canRead());
+        FileInputStream fis = new FileInputStream(sample);
+        HSSFWorkbook book = new HSSFWorkbook(fis);
+        fis.close();
+       
+        HSSFPalette p = book.getCustomPalette();
+        
+        HSSFCell cellA = book.getSheetAt(0).getRow(0).getCell((short)0);
+        HSSFCell cellB = book.getSheetAt(0).getRow(1).getCell((short)0);
+        HSSFCell cellC = book.getSheetAt(0).getRow(2).getCell((short)0);
+        HSSFCell cellD = book.getSheetAt(0).getRow(3).getCell((short)0);
+        HSSFCell cellE = book.getSheetAt(0).getRow(4).getCell((short)0);
+        
+        // Plain
+        assertEquals("I'm plain", cellA.getStringCellValue());
+        assertEquals(64, cellA.getCellStyle().getFillForegroundColor());
+        assertEquals(64, cellA.getCellStyle().getFillBackgroundColor());
+        assertEquals(HSSFFont.COLOR_NORMAL, cellA.getCellStyle().getFont(book).getColor());
+        assertEquals(0, cellA.getCellStyle().getFillPattern());
+        assertEquals("0:0:0", p.getColor((short)64).getHexString());
+        assertEquals(null, p.getColor((short)32767));
+        
+        // Red
+        assertEquals("I'm red", cellB.getStringCellValue());
+        assertEquals(64, cellB.getCellStyle().getFillForegroundColor());
+        assertEquals(64, cellB.getCellStyle().getFillBackgroundColor());
+        assertEquals(10, cellB.getCellStyle().getFont(book).getColor());
+        assertEquals(0, cellB.getCellStyle().getFillPattern());
+        assertEquals("0:0:0", p.getColor((short)64).getHexString());
+        assertEquals("FFFF:0:0", p.getColor((short)10).getHexString());
+        
+        // Red + green bg
+        assertEquals("I'm red with a green bg", cellC.getStringCellValue());
+        assertEquals(11, cellC.getCellStyle().getFillForegroundColor());
+        assertEquals(64, cellC.getCellStyle().getFillBackgroundColor());
+        assertEquals(10, cellC.getCellStyle().getFont(book).getColor());
+        assertEquals(1, cellC.getCellStyle().getFillPattern());
+        assertEquals("0:FFFF:0", p.getColor((short)11).getHexString());
+        assertEquals("FFFF:0:0", p.getColor((short)10).getHexString());
+        
+        // Pink with yellow
+        assertEquals("I'm pink with a yellow pattern (none)", cellD.getStringCellValue());
+        assertEquals(13, cellD.getCellStyle().getFillForegroundColor());
+        assertEquals(64, cellD.getCellStyle().getFillBackgroundColor());
+        assertEquals(14, cellD.getCellStyle().getFont(book).getColor());
+        assertEquals(0, cellD.getCellStyle().getFillPattern());
+        assertEquals("FFFF:FFFF:0", p.getColor((short)13).getHexString());
+        assertEquals("FFFF:0:FFFF", p.getColor((short)14).getHexString());
+        
+        // Pink with yellow - full
+        assertEquals("I'm pink with a yellow pattern (full)", cellE.getStringCellValue());
+        assertEquals(13, cellE.getCellStyle().getFillForegroundColor());
+        assertEquals(64, cellE.getCellStyle().getFillBackgroundColor());
+        assertEquals(14, cellE.getCellStyle().getFont(book).getColor());
+        assertEquals(0, cellE.getCellStyle().getFillPattern());
+        assertEquals("FFFF:FFFF:0", p.getColor((short)13).getHexString());
+        assertEquals("FFFF:0:FFFF", p.getColor((short)14).getHexString());
+    }
+    
     /**
      * Verifies that the generated gnumeric-format string values match the
      * hardcoded values in the HSSFColor default color palette
index f53b2f88da7b4790a4b8c0f30a320ee278e3704a..7f2819433bbb1372d97c0ddccf3e5626d3f89def 100644 (file)
@@ -63,7 +63,7 @@ public class TestReadWriteChart
         //System.out.println("first assertion for date");
         assertEquals(new GregorianCalendar(2000, 0, 1, 10, 51, 2).getTime(),
                      HSSFDateUtil
-                         .getJavaDate(firstCell.getNumericCellValue()));
+                         .getJavaDate(firstCell.getNumericCellValue(), false));
         HSSFRow  row  = sheet.createRow(( short ) 15);
         HSSFCell cell = row.createCell(( short ) 1);
 
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.java b/src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.java
new file mode 100644 (file)
index 0000000..9628ab2
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+* 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.hssf.usermodel;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for how HSSFWorkbook behaves with XLS files
+ *  with a WORKBOOK directory entry (instead of the more
+ *  usual, Workbook)
+ */
+public class TestSheetHiding extends TestCase {
+       private String dirPath;
+       private String xlsHidden = "TwoSheetsOneHidden.xls";
+       private String xlsShown  = "TwoSheetsNoneHidden.xls";
+
+       protected void setUp() throws Exception {
+               super.setUp();
+               
+        dirPath = System.getProperty("HSSF.testdata.path");
+       }
+
+       /**
+        * Test that we get the right number of sheets,
+        *  with the right text on them, no matter what
+        *  the hidden flags are
+        */
+       public void testTextSheets() throws Exception {
+               FileInputStream isH = new FileInputStream(dirPath + "/" + xlsHidden);
+               POIFSFileSystem fsH = new POIFSFileSystem(isH);
+               
+               FileInputStream isU = new FileInputStream(dirPath + "/" + xlsShown);
+               POIFSFileSystem fsU = new POIFSFileSystem(isU);
+
+               HSSFWorkbook wbH = new HSSFWorkbook(fsH);
+               HSSFWorkbook wbU = new HSSFWorkbook(fsU);
+               
+               // Both should have two sheets
+               assertEquals(2, wbH.sheets.size());
+               assertEquals(2, wbU.sheets.size());
+               
+               // All sheets should have one row
+               assertEquals(0, wbH.getSheetAt(0).getLastRowNum());
+               assertEquals(0, wbH.getSheetAt(1).getLastRowNum());
+               assertEquals(0, wbU.getSheetAt(0).getLastRowNum());
+               assertEquals(0, wbU.getSheetAt(1).getLastRowNum());
+               
+               // All rows should have one column
+               assertEquals(1, wbH.getSheetAt(0).getRow(0).getLastCellNum());
+               assertEquals(1, wbH.getSheetAt(1).getRow(0).getLastCellNum());
+               assertEquals(1, wbU.getSheetAt(0).getRow(0).getLastCellNum());
+               assertEquals(1, wbU.getSheetAt(1).getRow(0).getLastCellNum());
+               
+               // Text should be sheet based
+               assertEquals("Sheet1A1", wbH.getSheetAt(0).getRow(0).getCell((short)0).getStringCellValue());
+               assertEquals("Sheet2A1", wbH.getSheetAt(1).getRow(0).getCell((short)0).getStringCellValue());
+               assertEquals("Sheet1A1", wbU.getSheetAt(0).getRow(0).getCell((short)0).getStringCellValue());
+               assertEquals("Sheet2A1", wbU.getSheetAt(1).getRow(0).getCell((short)0).getStringCellValue());
+       }
+
+       /**
+        * Check that we can get and set the hidden flags
+        *  as expected
+        */
+       public void testHideUnHideFlags() throws Exception {
+               // TODO
+       }
+
+       /**
+        * Turn the sheet with none hidden into the one with
+        *  one hidden
+        */
+       public void testHide() throws Exception {
+               // TODO
+       }
+
+       /**
+        * Turn the sheet with one hidden into the one with
+        *  none hidden
+        */
+       public void testUnHide() throws Exception {
+               // TODO
+       }
+}
index a56a1d2a3a9b28f82d9e6268224df590ce79ce20..4f67f9876729a3f090b96c042f9d5d64e057c15c 100644 (file)
@@ -23,6 +23,7 @@ import java.io.ByteArrayOutputStream;
 
 import junit.framework.TestCase;
 
+import org.apache.poi.util.IOUtils;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.poifs.filesystem.POIFSWriterEvent;
 import org.apache.poi.poifs.filesystem.POIFSWriterListener;
@@ -140,4 +141,28 @@ public class TestEmptyDocument extends TestCase {
     fs.writeFilesystem(out);
     new POIFSFileSystem(new ByteArrayInputStream(out.toByteArray()));
   }
+
+  public void testEmptyDocumentBug11744() throws Exception {
+        byte[] testData = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+        POIFSFileSystem fs = new POIFSFileSystem();
+        fs.createDocument(new ByteArrayInputStream(new byte[0]), "Empty");
+        fs.createDocument(new ByteArrayInputStream(testData), "NotEmpty");
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        fs.writeFilesystem(out);
+        out.toByteArray();
+
+        // This line caused the error.
+        fs = new POIFSFileSystem(new ByteArrayInputStream(out.toByteArray()));
+
+        DocumentEntry entry = (DocumentEntry) fs.getRoot().getEntry("Empty");
+        assertEquals("Expected zero size", 0, entry.getSize());
+        assertEquals("Expected zero read from stream", 0,
+                     IOUtils.toByteArray(new DocumentInputStream(entry)).length);
+
+        entry = (DocumentEntry) fs.getRoot().getEntry("NotEmpty");
+        assertEquals("Expected size was wrong", testData.length, entry.getSize());
+        assertEquals("Expected different data read from stream", testData,
+                     IOUtils.toByteArray(new DocumentInputStream(entry)));
+    }
 }